feat(gradle): release v1.6.0 — Gradle build file version bump
ci / vet, staticcheck, test, build (push) Failing after 3m1s
release / Build and publish release (push) Successful in 5m1s

Add internal/gradle package with ReadVersion and WriteVersion for
build.gradle (Groovy DSL, single-quoted) and build.gradle.kts (Kotlin
DSL, double-quoted). Quote style is preserved on write. regexp.QuoteMeta
ensures version strings with dots or special characters are safe.

Config follows the established multi-value pattern:
- gradle.build_file: single path (opt-in, no default)
- gradle.build_files: list for multi-module projects (overrides build_file)
- --gradle flag overrides build_file and clears build_files

100% per-package statement coverage maintained across all 13 packages;
FuzzReadVersion and FuzzWriteVersion added per fuzzing guidelines.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 17:59:13 +02:00
parent e2d4214405
commit dfdf2b019a
14 changed files with 558 additions and 21 deletions
+26
View File
@@ -17,6 +17,7 @@ type Config struct {
Git GitConfig `yaml:"git"`
Maven MavenConfig `yaml:"maven"`
Node NodeConfig `yaml:"node"`
Gradle GradleConfig `yaml:"gradle"`
GitLab GitLabConfig `yaml:"gitlab"`
GitHub GitHubConfig `yaml:"github"`
}
@@ -73,6 +74,23 @@ func (n NodeConfig) EffectivePaths() []string {
return nil
}
type GradleConfig struct {
BuildFile string `yaml:"build_file"` // single path (opt-in, no default)
BuildFiles []string `yaml:"build_files"` // multiple paths; overrides BuildFile
}
// EffectiveBuildFiles returns the list of Gradle build file paths to process.
// Returns nil when no gradle paths are configured (gradle processing is opt-in).
func (g GradleConfig) EffectiveBuildFiles() []string {
if len(g.BuildFiles) > 0 {
return g.BuildFiles
}
if g.BuildFile != "" {
return []string{g.BuildFile}
}
return nil
}
type GitLabConfig struct {
URL string `yaml:"url"`
Token string `yaml:"token"`
@@ -117,6 +135,8 @@ 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",
"gitlab.token": "default",
"gitlab.project": "default",
@@ -193,6 +213,12 @@ func LoadWithSources(dir string) (Config, Sources, error) {
if len(overlay.Node.PackageJSONs) > 0 {
src["node.package_jsons"] = "config file"
}
if overlay.Gradle.BuildFile != "" {
src["gradle.build_file"] = "config file"
}
if len(overlay.Gradle.BuildFiles) > 0 {
src["gradle.build_files"] = "config file"
}
if overlay.GitLab.URL != "" {
src["gitlab.url"] = "config file"
}
+46
View File
@@ -292,6 +292,52 @@ func TestApplyEnvWithSourcesCIServerURL(t *testing.T) {
}
}
func TestGradleEffectiveBuildFiles(t *testing.T) {
// Neither set → nil (opt-in)
if got := (GradleConfig{}).EffectiveBuildFiles(); got != nil {
t.Errorf("empty config: got %v, want nil", got)
}
// BuildFile only
if got := (GradleConfig{BuildFile: "build.gradle"}).EffectiveBuildFiles(); len(got) != 1 || got[0] != "build.gradle" {
t.Errorf("BuildFile only: got %v", got)
}
// BuildFiles wins over BuildFile
g := GradleConfig{BuildFile: "build.gradle", BuildFiles: []string{"a/build.gradle", "b/build.gradle"}}
if got := g.EffectiveBuildFiles(); len(got) != 2 || got[0] != "a/build.gradle" {
t.Errorf("BuildFiles priority: got %v", got)
}
}
func TestLoadGradleSources(t *testing.T) {
dir := t.TempDir()
content := "gradle:\n build_file: \"build.gradle\"\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["gradle.build_file"] != "config file" {
t.Errorf("src[gradle.build_file] = %q, want %q", src["gradle.build_file"], "config file")
}
}
func TestLoadGradleBuildFilesSources(t *testing.T) {
dir := t.TempDir()
content := "gradle:\n build_files:\n - \"a/build.gradle\"\n - \"b/build.gradle\"\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["gradle.build_files"] != "config file" {
t.Errorf("src[gradle.build_files] = %q, want %q", src["gradle.build_files"], "config file")
}
}
func TestLoadPartialOverride(t *testing.T) {
dir := t.TempDir()
// Only override tag_prefix — commit_message should keep its default