feat(pyproject): release v1.7.0 — Python pyproject.toml version bump
Add internal/pyproject package with ReadVersion and WriteVersion for pyproject.toml files. Reads [project].version (PEP 621) first, then falls back to [tool.poetry].version. Section boundaries are detected via TOML's rule that headers always start at the beginning of a line (\n[ pattern), so inline arrays with [ characters don't interfere. Config follows the established multi-value pattern: - python.pyproject_toml: single path (opt-in, no default) - python.pyproject_tomls: list for monorepos (overrides single) - --pyproject flag overrides pyproject_toml and clears pyproject_tomls 100% per-package statement coverage maintained across all 14 packages; FuzzReadVersion and FuzzWriteVersion added per fuzzing guidelines. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,8 +17,9 @@ type Config struct {
|
||||
Git GitConfig `yaml:"git"`
|
||||
Maven MavenConfig `yaml:"maven"`
|
||||
Node NodeConfig `yaml:"node"`
|
||||
Gradle GradleConfig `yaml:"gradle"`
|
||||
GitLab GitLabConfig `yaml:"gitlab"`
|
||||
Gradle GradleConfig `yaml:"gradle"`
|
||||
Python PythonConfig `yaml:"python"`
|
||||
GitLab GitLabConfig `yaml:"gitlab"`
|
||||
GitHub GitHubConfig `yaml:"github"`
|
||||
}
|
||||
|
||||
@@ -91,6 +92,23 @@ func (g GradleConfig) EffectiveBuildFiles() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type PythonConfig struct {
|
||||
PyprojectTOML string `yaml:"pyproject_toml"` // single path (opt-in, no default)
|
||||
PyprojectTOMLs []string `yaml:"pyproject_tomls"` // multiple paths; overrides PyprojectTOML
|
||||
}
|
||||
|
||||
// EffectivePaths returns the list of pyproject.toml paths to process.
|
||||
// Returns nil when no python paths are configured (python processing is opt-in).
|
||||
func (p PythonConfig) EffectivePaths() []string {
|
||||
if len(p.PyprojectTOMLs) > 0 {
|
||||
return p.PyprojectTOMLs
|
||||
}
|
||||
if p.PyprojectTOML != "" {
|
||||
return []string{p.PyprojectTOML}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GitLabConfig struct {
|
||||
URL string `yaml:"url"`
|
||||
Token string `yaml:"token"`
|
||||
@@ -135,9 +153,11 @@ func defaultSources() Sources {
|
||||
"maven.pom_paths": "default",
|
||||
"node.package_json": "default",
|
||||
"node.package_jsons": "default",
|
||||
"gradle.build_file": "default",
|
||||
"gradle.build_files": "default",
|
||||
"gitlab.url": "default",
|
||||
"gradle.build_file": "default",
|
||||
"gradle.build_files": "default",
|
||||
"python.pyproject_toml": "default",
|
||||
"python.pyproject_tomls": "default",
|
||||
"gitlab.url": "default",
|
||||
"gitlab.token": "default",
|
||||
"gitlab.project": "default",
|
||||
"github.token": "default",
|
||||
@@ -219,6 +239,12 @@ func LoadWithSources(dir string) (Config, Sources, error) {
|
||||
if len(overlay.Gradle.BuildFiles) > 0 {
|
||||
src["gradle.build_files"] = "config file"
|
||||
}
|
||||
if overlay.Python.PyprojectTOML != "" {
|
||||
src["python.pyproject_toml"] = "config file"
|
||||
}
|
||||
if len(overlay.Python.PyprojectTOMLs) > 0 {
|
||||
src["python.pyproject_tomls"] = "config file"
|
||||
}
|
||||
if overlay.GitLab.URL != "" {
|
||||
src["gitlab.url"] = "config file"
|
||||
}
|
||||
|
||||
@@ -338,6 +338,49 @@ func TestLoadGradleBuildFilesSources(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPythonEffectivePaths(t *testing.T) {
|
||||
if got := (PythonConfig{}).EffectivePaths(); got != nil {
|
||||
t.Errorf("empty config: got %v, want nil", got)
|
||||
}
|
||||
if got := (PythonConfig{PyprojectTOML: "pyproject.toml"}).EffectivePaths(); len(got) != 1 || got[0] != "pyproject.toml" {
|
||||
t.Errorf("single path: got %v", got)
|
||||
}
|
||||
p := PythonConfig{PyprojectTOML: "pyproject.toml", PyprojectTOMLs: []string{"a/pyproject.toml", "b/pyproject.toml"}}
|
||||
if got := p.EffectivePaths(); len(got) != 2 || got[0] != "a/pyproject.toml" {
|
||||
t.Errorf("multi-path priority: got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadPythonSources(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
content := "python:\n pyproject_toml: \"pyproject.toml\"\n"
|
||||
if err := os.WriteFile(filepath.Join(dir, filename), []byte(content), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, src, err := LoadWithSources(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if src["python.pyproject_toml"] != "config file" {
|
||||
t.Errorf("src[python.pyproject_toml] = %q, want %q", src["python.pyproject_toml"], "config file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadPythonPathsSources(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
content := "python:\n pyproject_tomls:\n - \"a/pyproject.toml\"\n - \"b/pyproject.toml\"\n"
|
||||
if err := os.WriteFile(filepath.Join(dir, filename), []byte(content), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, src, err := LoadWithSources(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if src["python.pyproject_tomls"] != "config file" {
|
||||
t.Errorf("src[python.pyproject_tomls] = %q, want %q", src["python.pyproject_tomls"], "config file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadPartialOverride(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
// Only override tag_prefix — commit_message should keep its default
|
||||
|
||||
Reference in New Issue
Block a user