From e0354ac41a64ac465e71f32f1b5412841752be67 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 25 Jun 2025 12:09:54 +0200 Subject: [PATCH 1/2] fix: unique version per custom build --- pkg/commands/internal/builder.go | 10 ++++++++-- pkg/commands/internal/builder_test.go | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/commands/internal/builder.go b/pkg/commands/internal/builder.go index c008f1930ff6..25837d8ce742 100644 --- a/pkg/commands/internal/builder.go +++ b/pkg/commands/internal/builder.go @@ -173,12 +173,14 @@ func (b Builder) goModTidy(ctx context.Context) error { } func (b Builder) goBuild(ctx context.Context, binaryName string) error { + now := time.Now().UTC() + //nolint:gosec // the variable is sanitized. cmd := exec.CommandContext(ctx, "go", "build", "-ldflags", fmt.Sprintf( - "-s -w -X 'main.version=%s-custom-gcl' -X 'main.date=%s'", - sanitizeVersion(b.cfg.Version), time.Now().UTC().String(), + "-s -w -X 'main.version=%s' -X 'main.date=%s'", + createVersion(b.cfg.Version, now), now.String(), ), "-o", binaryName, "./cmd/golangci-lint", @@ -241,6 +243,10 @@ func (b Builder) getBinaryName() string { return name } +func createVersion(orig string, now time.Time) string { + return fmt.Sprintf("%s-custom-gcl-%d", sanitizeVersion(orig), now.UnixNano()) +} + func sanitizeVersion(v string) string { fn := func(c rune) bool { return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '/' diff --git a/pkg/commands/internal/builder_test.go b/pkg/commands/internal/builder_test.go index 99a1cad0e0c1..327a86123202 100644 --- a/pkg/commands/internal/builder_test.go +++ b/pkg/commands/internal/builder_test.go @@ -2,8 +2,10 @@ package internal import ( "testing" + "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_sanitizeVersion(t *testing.T) { @@ -54,3 +56,12 @@ func Test_sanitizeVersion(t *testing.T) { }) } } + +func Test_createVersion(t *testing.T) { + parse, err := time.Parse(time.RFC3339Nano, "2010-02-04T21:00:57.123456789+08:00") + require.NoError(t, err) + + version := createVersion("1.2.3", parse) + + assert.Equal(t, "1.2.3-custom-gcl-1265288457123456789", version) +} From a7cafef698128334a9b55f483787e39006e10db4 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 25 Jun 2025 14:58:24 +0200 Subject: [PATCH 2/2] fix: hash local module replacement --- pkg/commands/internal/builder.go | 40 ++++++++++++++++++++++----- pkg/commands/internal/builder_test.go | 11 -------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/pkg/commands/internal/builder.go b/pkg/commands/internal/builder.go index 25837d8ce742..5bb9b472fac2 100644 --- a/pkg/commands/internal/builder.go +++ b/pkg/commands/internal/builder.go @@ -2,6 +2,8 @@ package internal import ( "context" + "crypto/sha256" + "encoding/base64" "fmt" "io" "os" @@ -12,6 +14,8 @@ import ( "time" "unicode" + "golang.org/x/mod/sumdb/dirhash" + "github.com/golangci/golangci-lint/v2/pkg/logutils" ) @@ -173,15 +177,17 @@ func (b Builder) goModTidy(ctx context.Context) error { } func (b Builder) goBuild(ctx context.Context, binaryName string) error { - now := time.Now().UTC() + version, err := b.createVersion(b.cfg.Version) + if err != nil { + return fmt.Errorf("custom version: %w", err) + } + + b.log.Infof("version: %s", version) //nolint:gosec // the variable is sanitized. cmd := exec.CommandContext(ctx, "go", "build", "-ldflags", - fmt.Sprintf( - "-s -w -X 'main.version=%s' -X 'main.date=%s'", - createVersion(b.cfg.Version, now), now.String(), - ), + fmt.Sprintf("-s -w -X 'main.version=%s' -X 'main.date=%s'", version, time.Now().UTC().String()), "-o", binaryName, "./cmd/golangci-lint", ) @@ -243,8 +249,28 @@ func (b Builder) getBinaryName() string { return name } -func createVersion(orig string, now time.Time) string { - return fmt.Sprintf("%s-custom-gcl-%d", sanitizeVersion(orig), now.UnixNano()) +func (b Builder) createVersion(orig string) (string, error) { + hash := sha256.New() + + for _, plugin := range b.cfg.Plugins { + if plugin.Path == "" { + continue + } + + dh, err := dirhash.HashDir(plugin.Path, "", dirhash.DefaultHash) + if err != nil { + return "", fmt.Errorf("hash plugin directory: %w", err) + } + + b.log.Infof("%s: %s", plugin.Path, dh) + + hash.Write([]byte(dh)) + } + + return fmt.Sprintf("%s-custom-gcl-%s", + sanitizeVersion(orig), + sanitizeVersion(base64.URLEncoding.EncodeToString(hash.Sum(nil))), + ), nil } func sanitizeVersion(v string) string { diff --git a/pkg/commands/internal/builder_test.go b/pkg/commands/internal/builder_test.go index 327a86123202..99a1cad0e0c1 100644 --- a/pkg/commands/internal/builder_test.go +++ b/pkg/commands/internal/builder_test.go @@ -2,10 +2,8 @@ package internal import ( "testing" - "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_sanitizeVersion(t *testing.T) { @@ -56,12 +54,3 @@ func Test_sanitizeVersion(t *testing.T) { }) } } - -func Test_createVersion(t *testing.T) { - parse, err := time.Parse(time.RFC3339Nano, "2010-02-04T21:00:57.123456789+08:00") - require.NoError(t, err) - - version := createVersion("1.2.3", parse) - - assert.Equal(t, "1.2.3-custom-gcl-1265288457123456789", version) -}