Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
39 changes: 39 additions & 0 deletions dagger/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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) {
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(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").
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
}
12 changes: 9 additions & 3 deletions dagger/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,18 @@ func (r *Replicated) GenerateDocs(
}

// Generate CLI new docs
goModCache := dag.CacheVolume("replicated-go-mod-122")
goBuildCache := dag.CacheVolume("replicated-go-build-121")
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.24").
From(image).
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source).
WithWorkdir("/go/src/github.com/replicatedhq/replicated").
WithMountedCache("/go/pkg/mod", goModCache).
Expand Down
47 changes: 47 additions & 0 deletions dagger/exec_utils.go
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
14 changes: 10 additions & 4 deletions dagger/functionality.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@ func validateFunctionality(
// +defaultPath="./"
source *dagger.Directory,
) error {
goModCache := dag.CacheVolume("replicated-go-mod-122")
goBuildCache := dag.CacheVolume("replicated-go-build-121")
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.24").
From(image).
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source).
WithWorkdir("/go/src/github.com/replicatedhq/replicated").
WithMountedCache("/go/pkg/mod", goModCache).
Expand All @@ -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
}
Expand Down
12 changes: 9 additions & 3 deletions dagger/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -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-122")
goBuildCache := dag.CacheVolume("replicated-go-build-121")
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.24").
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").
Expand Down
8 changes: 5 additions & 3 deletions dagger/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ func validateSecurity(
// +defaultPath="./"
source *dagger.Directory,
) error {
goModCache := dag.CacheVolume("replicated-go-mod-122")
goBuildCache := dag.CacheVolume("replicated-go-build-121")
goModCache, goBuildCache, err := goCacheVolumes(ctx, source)
if err != nil {
return err
}

// run semgrep
semgrep := dag.Container().
Expand All @@ -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
}
Expand Down
Loading