From 9f198425b193a0a39b17222e3276bb844b8f87fa Mon Sep 17 00:00:00 2001 From: Andrew Lavery Date: Thu, 26 Mar 2026 15:31:26 -0400 Subject: [PATCH 1/2] update to use go 1.26 within dagger for builds --- .github/workflows/main.yaml | 9 +++++++++ Makefile | 4 ++++ dagger/build.go | 33 +++++++++++++++++++++++++++++++++ dagger/docs.go | 6 +++--- dagger/functionality.go | 6 +++--- dagger/release.go | 6 +++--- dagger/security.go | 4 ++-- 7 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 dagger/build.go diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 42230189b..0e80884bd 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -89,3 +89,12 @@ jobs: ${{ runner.os }}-go- - name: make build run: make build + + dagger-build: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: Install Dagger + run: curl -fsSL https://dl.dagger.io/dagger/install.sh | sudo BIN_DIR=/usr/local/bin sh + - name: Dagger build + run: make dagger-build diff --git a/Makefile b/Makefile index c77db3ddc..94a45ca10 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,10 @@ build: -o bin/replicated \ cli/main.go +.PHONY: dagger-build +dagger-build: + dagger call build --progress plain export --path bin/replicated + .PHONY: release release: dagger call release \ diff --git a/dagger/build.go b/dagger/build.go new file mode 100644 index 000000000..953557bfa --- /dev/null +++ b/dagger/build.go @@ -0,0 +1,33 @@ +package main + +import ( + "context" + "dagger/replicated/internal/dagger" +) + +// Build compiles the replicated CLI binary. +func (r *Replicated) Build( + ctx context.Context, + + // +defaultPath="./" + source *dagger.Directory, +) (*dagger.File, error) { + goModCache := dag.CacheVolume("replicated-go-mod-126") + goBuildCache := dag.CacheVolume("replicated-go-build-126") + + binary := dag.Container(dagger.ContainerOpts{ + Platform: "linux/amd64", + }). + From("golang:1.26"). + WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source). + WithoutFile("/go/src/github.com/replicatedhq/replicated/bin/replicated"). + WithWorkdir("/go/src/github.com/replicatedhq/replicated"). + WithMountedCache("/go/pkg/mod", goModCache). + WithEnvVariable("GOMODCACHE", "/go/pkg/mod"). + WithMountedCache("/go/build-cache", goBuildCache). + WithEnvVariable("GOCACHE", "/go/build-cache"). + With(CacheBustingExec([]string{"make", "build"})). + File("/go/src/github.com/replicatedhq/replicated/bin/replicated") + + return binary, nil +} diff --git a/dagger/docs.go b/dagger/docs.go index 35d248606..2268d3261 100644 --- a/dagger/docs.go +++ b/dagger/docs.go @@ -61,12 +61,12 @@ func (r *Replicated) GenerateDocs( } // Generate CLI new docs - goModCache := dag.CacheVolume("replicated-go-mod-122") - goBuildCache := dag.CacheVolume("replicated-go-build-121") + goModCache := dag.CacheVolume("replicated-go-mod-126") + goBuildCache := dag.CacheVolume("replicated-go-build-126") // generate the docs from this current commit docs := dag.Container(). - From("golang:1.24"). + From("golang:1.26"). WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source). WithWorkdir("/go/src/github.com/replicatedhq/replicated"). WithMountedCache("/go/pkg/mod", goModCache). diff --git a/dagger/functionality.go b/dagger/functionality.go index 3e7946616..a29b1cca3 100644 --- a/dagger/functionality.go +++ b/dagger/functionality.go @@ -11,12 +11,12 @@ func validateFunctionality( // +defaultPath="./" source *dagger.Directory, ) error { - goModCache := dag.CacheVolume("replicated-go-mod-122") - goBuildCache := dag.CacheVolume("replicated-go-build-121") + goModCache := dag.CacheVolume("replicated-go-mod-126") + goBuildCache := dag.CacheVolume("replicated-go-build-126") // unit tests unitTest := dag.Container(). - From("golang:1.24"). + From("golang:1.26"). WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source). WithWorkdir("/go/src/github.com/replicatedhq/replicated"). WithMountedCache("/go/pkg/mod", goModCache). diff --git a/dagger/release.go b/dagger/release.go index f0df52780..86956544f 100644 --- a/dagger/release.go +++ b/dagger/release.go @@ -105,13 +105,13 @@ func (r *Replicated) Release( // copy the source that has the tag included in it updatedSource = tagContainer.Directory("/go/src/github.com/replicatedhq/replicated") - goModCache := dag.CacheVolume("replicated-go-mod-122") - goBuildCache := dag.CacheVolume("replicated-go-build-121") + goModCache := dag.CacheVolume("replicated-go-mod-126") + goBuildCache := dag.CacheVolume("replicated-go-build-126") replicatedBinary := dag.Container(dagger.ContainerOpts{ Platform: "linux/amd64", }). - From("golang:1.24"). + From("golang:1.26"). WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", updatedSource). WithoutFile("/go/src/github.com/replicatedhq/replicated/bin/replicated"). WithWorkdir("/go/src/github.com/replicatedhq/replicated"). diff --git a/dagger/security.go b/dagger/security.go index 55cdd06c3..7a50a680f 100644 --- a/dagger/security.go +++ b/dagger/security.go @@ -11,8 +11,8 @@ func validateSecurity( // +defaultPath="./" source *dagger.Directory, ) error { - goModCache := dag.CacheVolume("replicated-go-mod-122") - goBuildCache := dag.CacheVolume("replicated-go-build-121") + goModCache := dag.CacheVolume("replicated-go-mod-126") + goBuildCache := dag.CacheVolume("replicated-go-build-126") // run semgrep semgrep := dag.Container(). From 663073b4b3e0fe94b4fe9cc00c42e887479ca878 Mon Sep 17 00:00:00 2001 From: Andrew Lavery Date: Thu, 26 Mar 2026 15:37:48 -0400 Subject: [PATCH 2/2] detect go version from go.mod, don't hardcode in dagger --- dagger/build.go | 12 ++++++++--- dagger/docs.go | 12 ++++++++--- dagger/exec_utils.go | 47 +++++++++++++++++++++++++++++++++++++++++ dagger/functionality.go | 14 ++++++++---- dagger/release.go | 12 ++++++++--- dagger/security.go | 8 ++++--- 6 files changed, 89 insertions(+), 16 deletions(-) diff --git a/dagger/build.go b/dagger/build.go index 953557bfa..bc848269a 100644 --- a/dagger/build.go +++ b/dagger/build.go @@ -12,13 +12,19 @@ func (r *Replicated) Build( // +defaultPath="./" source *dagger.Directory, ) (*dagger.File, error) { - goModCache := dag.CacheVolume("replicated-go-mod-126") - goBuildCache := dag.CacheVolume("replicated-go-build-126") + image, err := goImage(ctx, source) + if err != nil { + return nil, err + } + goModCache, goBuildCache, err := goCacheVolumes(ctx, source) + if err != nil { + return nil, err + } binary := dag.Container(dagger.ContainerOpts{ Platform: "linux/amd64", }). - From("golang:1.26"). + From(image). WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source). WithoutFile("/go/src/github.com/replicatedhq/replicated/bin/replicated"). WithWorkdir("/go/src/github.com/replicatedhq/replicated"). diff --git a/dagger/docs.go b/dagger/docs.go index 2268d3261..13459ff83 100644 --- a/dagger/docs.go +++ b/dagger/docs.go @@ -61,12 +61,18 @@ func (r *Replicated) GenerateDocs( } // Generate CLI new docs - goModCache := dag.CacheVolume("replicated-go-mod-126") - goBuildCache := dag.CacheVolume("replicated-go-build-126") + image, err := goImage(ctx, source) + if err != nil { + return errors.Wrap(err, "failed to detect go version") + } + goModCache, goBuildCache, err := goCacheVolumes(ctx, source) + if err != nil { + return errors.Wrap(err, "failed to create cache volumes") + } // generate the docs from this current commit docs := dag.Container(). - From("golang:1.26"). + From(image). WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source). WithWorkdir("/go/src/github.com/replicatedhq/replicated"). WithMountedCache("/go/pkg/mod", goModCache). diff --git a/dagger/exec_utils.go b/dagger/exec_utils.go index c03069979..f8d21c797 100644 --- a/dagger/exec_utils.go +++ b/dagger/exec_utils.go @@ -1,10 +1,57 @@ package main import ( + "context" "dagger/replicated/internal/dagger" + "fmt" + "strings" "time" ) +// goVersion reads the go directive from go.mod in the source directory and +// returns the major.minor version (e.g. "1.26" from "go 1.26.1"). +func goVersion(ctx context.Context, source *dagger.Directory) (string, error) { + contents, err := source.File("go.mod").Contents(ctx) + if err != nil { + return "", fmt.Errorf("failed to read go.mod: %w", err) + } + for _, line := range strings.Split(contents, "\n") { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, "go ") { + version := strings.TrimPrefix(line, "go ") + // strip patch version if present (e.g. "1.26.1" -> "1.26") + parts := strings.SplitN(version, ".", 3) + if len(parts) >= 2 { + return parts[0] + "." + parts[1], nil + } + return version, nil + } + } + return "", fmt.Errorf("go directive not found in go.mod") +} + +// goImage returns the golang Docker image tag for the version in go.mod. +func goImage(ctx context.Context, source *dagger.Directory) (string, error) { + v, err := goVersion(ctx, source) + if err != nil { + return "", err + } + return "golang:" + v, nil +} + +// goCacheVolumes returns the mod and build cache volumes keyed by the Go version. +func goCacheVolumes(ctx context.Context, source *dagger.Directory) (*dagger.CacheVolume, *dagger.CacheVolume, error) { + v, err := goVersion(ctx, source) + if err != nil { + return nil, nil, err + } + // replace dots for a clean cache key suffix (e.g. "126" from "1.26") + suffix := strings.ReplaceAll(v, ".", "") + modCache := dag.CacheVolume("replicated-go-mod-" + suffix) + buildCache := dag.CacheVolume("replicated-go-build-" + suffix) + return modCache, buildCache, nil +} + // CacheBustingExec is a helper function that will add a cache busting env var automatically // to the container. This is useful when Exec target is a dynamic event acting on an entity outside // of the container that you absolutely want to re-run every time. diff --git a/dagger/functionality.go b/dagger/functionality.go index a29b1cca3..a56d69f32 100644 --- a/dagger/functionality.go +++ b/dagger/functionality.go @@ -11,12 +11,18 @@ func validateFunctionality( // +defaultPath="./" source *dagger.Directory, ) error { - goModCache := dag.CacheVolume("replicated-go-mod-126") - goBuildCache := dag.CacheVolume("replicated-go-build-126") + image, err := goImage(ctx, source) + if err != nil { + return err + } + goModCache, goBuildCache, err := goCacheVolumes(ctx, source) + if err != nil { + return err + } // unit tests unitTest := dag.Container(). - From("golang:1.26"). + From(image). WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source). WithWorkdir("/go/src/github.com/replicatedhq/replicated"). WithMountedCache("/go/pkg/mod", goModCache). @@ -25,7 +31,7 @@ func validateFunctionality( WithEnvVariable("GOCACHE", "/go/build-cache"). With(CacheBustingExec([]string{"make", "test-unit"})) - _, err := unitTest.Stderr(ctx) + _, err = unitTest.Stderr(ctx) if err != nil { return err } diff --git a/dagger/release.go b/dagger/release.go index 86956544f..3bf76aafc 100644 --- a/dagger/release.go +++ b/dagger/release.go @@ -105,13 +105,19 @@ func (r *Replicated) Release( // copy the source that has the tag included in it updatedSource = tagContainer.Directory("/go/src/github.com/replicatedhq/replicated") - goModCache := dag.CacheVolume("replicated-go-mod-126") - goBuildCache := dag.CacheVolume("replicated-go-build-126") + image, err := goImage(ctx, updatedSource) + if err != nil { + return errors.Wrap(err, "failed to detect go version") + } + goModCache, goBuildCache, err := goCacheVolumes(ctx, updatedSource) + if err != nil { + return errors.Wrap(err, "failed to create cache volumes") + } replicatedBinary := dag.Container(dagger.ContainerOpts{ Platform: "linux/amd64", }). - From("golang:1.26"). + From(image). WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", updatedSource). WithoutFile("/go/src/github.com/replicatedhq/replicated/bin/replicated"). WithWorkdir("/go/src/github.com/replicatedhq/replicated"). diff --git a/dagger/security.go b/dagger/security.go index 7a50a680f..34a265505 100644 --- a/dagger/security.go +++ b/dagger/security.go @@ -11,8 +11,10 @@ func validateSecurity( // +defaultPath="./" source *dagger.Directory, ) error { - goModCache := dag.CacheVolume("replicated-go-mod-126") - goBuildCache := dag.CacheVolume("replicated-go-build-126") + goModCache, goBuildCache, err := goCacheVolumes(ctx, source) + if err != nil { + return err + } // run semgrep semgrep := dag.Container(). @@ -25,7 +27,7 @@ func validateSecurity( WithEnvVariable("GOCACHE", "/go/build-cache"). With(CacheBustingExec([]string{"semgrep", "scan", "--config=p/golang", "."})) - _, err := semgrep.Stderr(ctx) + _, err = semgrep.Stderr(ctx) if err != nil { return err }