Skip to content

Commit

Permalink
Cleanup from first release with dagger (#440)
Browse files Browse the repository at this point in the history
  • Loading branch information
marccampbell authored Oct 18, 2024
1 parent 73811c8 commit 4f9a108
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 306 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '^1.20'
go-version: '^1.22'
- uses: replicatedhq/action-install-pact@v1
- run: make test
- if: github.event_name == 'push' || ( github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository )
Expand All @@ -31,6 +31,6 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '^1.20'
go-version: '^1.22'
- name: make build
run: make build
4 changes: 2 additions & 2 deletions .github/workflows/working.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '^1.20'
go-version: '^1.22'
- uses: replicatedhq/action-install-pact@v1
- name: make test
run: make test
Expand All @@ -27,6 +27,6 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '^1.20'
go-version: '^1.22'
- name: make build
run: make build
53 changes: 0 additions & 53 deletions .goreleaser-nodocker.yaml

This file was deleted.

8 changes: 1 addition & 7 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,4 @@ archives:
- CHANGELOG*
snapshot:
version_template: SNAPSHOT-{{ .Commit }}
dockers:
- dockerfile: deploy/Dockerfile
image_templates:
- "replicated/vendor-cli:latest"
- "replicated/vendor-cli:{{ .Major }}"
- "replicated/vendor-cli:{{ .Major }}.{{ .Minor }}"
- "replicated/vendor-cli:{{ .Major }}.{{ .Minor }}.{{ .Patch }}"

35 changes: 6 additions & 29 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,37 +1,10 @@
API_PKGS=apps channels releases

VERSION=$(shell git describe)
ABBREV_VERSION=$(shell git describe --abbrev=0)
VERSION_PACKAGE = github.com/replicatedhq/replicated/pkg/version
DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"`
BUILDTAGS = containers_image_ostree_stub exclude_graphdriver_devicemapper exclude_graphdriver_btrfs containers_image_openpgp

export GO111MODULE=on

GIT_TREE = $(shell git rev-parse --is-inside-work-tree 2>/dev/null)
ifneq "$(GIT_TREE)" ""
define GIT_UPDATE_INDEX_CMD
git update-index --assume-unchanged
endef
define GIT_SHA
`git rev-parse HEAD`
endef
else
define GIT_UPDATE_INDEX_CMD
echo "Not a git repo, skipping git update-index"
endef
define GIT_SHA
""
endef
endif

define LDFLAGS
-ldflags "\
-X ${VERSION_PACKAGE}.version=${VERSION} \
-X ${VERSION_PACKAGE}.gitSHA=${GIT_SHA} \
-X ${VERSION_PACKAGE}.buildTime=${DATE} \
"
endef
export CGO_ENABLED=0

.PHONY: test-unit
test-unit:
Expand Down Expand Up @@ -138,4 +111,8 @@ docs:

.PHONE: release
release:
dagger call release --one-password-service-account env:OP_SERVICE_ACCOUNT_PRODUCTION --version $(version)
dagger call release \
--one-password-service-account-production env:OP_SERVICE_ACCOUNT_PRODUCTION \
--version $(version) \
--github-token env:GITHUB_TOKEN \
--progress plain
167 changes: 147 additions & 20 deletions dagger/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"context"
"dagger/replicated/internal/dagger"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"

"github.com/Masterminds/semver"
)
Expand All @@ -27,32 +29,86 @@ func (r *Replicated) Release(
clean bool,

onePasswordServiceAccountProduction *dagger.Secret,

githubToken *dagger.Secret,
) error {
gitTreeOK, err := checkGitTree(ctx, source)
gitTreeOK, err := checkGitTree(ctx, source, githubToken)
if err != nil {
return err
}
if !gitTreeOK {
return fmt.Errorf("git tree is not clean")
return fmt.Errorf("Your git tree is not clean. You cannot release what's not commited.")
}

latestVersion, err := getLatestVersion(ctx)
if err != nil {
return err
}

major, minor, patch, err := parseVersion(ctx, version)
major, minor, patch, err := parseVersion(ctx, latestVersion, version)
if err != nil {
return err
}

_ = dag.Container().
fmt.Printf("Releasing as version %d.%d.%d\n", major, minor, patch)

// replace the version in the Makefile
buildFileContent, err := source.File("./pkg/version/build.go").Contents(ctx)
if err != nil {
return err
}
buildFileContent = strings.ReplaceAll(buildFileContent, "const version = \"unknown\"", fmt.Sprintf("const version = \"%d.%d.%d\"", major, minor, patch))
updatedSource := source.WithNewFile("./pkg/version/build.go", buildFileContent)

// mount that and commit the updated build.go to git (don't push)
// so that goreleaser won't have a dirty git tree error
gitCommitContainer := dag.Container().
From("alpine/git:latest").
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source).
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", updatedSource).
WithWorkdir("/go/src/github.com/replicatedhq/replicated").
WithExec([]string{"git", "config", "user.email", "[email protected]"}).
WithExec([]string{"git", "config", "user.name", "Replicated Release Pipeline"}).
WithExec([]string{"git", "add", "pkg/version/build.go"}).
WithExec([]string{"git", "commit", "-m", fmt.Sprintf("Set version to %d.%d.%d", major, minor, patch)})
_, err = gitCommitContainer.Stdout(ctx)
if err != nil {
return err
}
updatedSource = gitCommitContainer.Directory("/go/src/github.com/replicatedhq/replicated")

githubTokenPlaintext, err := githubToken.Plaintext(ctx)
if err != nil {
return err
}
tagContainer := dag.Container().
From("alpine/git:latest").
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", updatedSource).
WithWorkdir("/go/src/github.com/replicatedhq/replicated").
WithExec([]string{"git", "tag", fmt.Sprintf("v%d.%d.%d", major, minor, patch)}).
WithExec([]string{"git", "push", "origin", fmt.Sprintf("v%d.%d.%d", major, minor, patch)})
WithExec([]string{"git", "remote", "add", "tag", fmt.Sprintf("https://%[email protected]/replicatedhq/replicated.git", githubTokenPlaintext)}).
With(CacheBustingExec([]string{"git", "tag", fmt.Sprintf("v%d.%d.%d", major, minor, patch)})).
With(CacheBustingExec([]string{"git", "push", "tag", fmt.Sprintf("v%d.%d.%d", major, minor, patch)}))
_, err = tagContainer.Stdout(ctx)
if err != nil {
return err
}

replicatedBinary := dag.Container().
// 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")

replicatedBinary := dag.Container(dagger.ContainerOpts{
Platform: "linux/amd64",
}).
From("golang:1.22").
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source).
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", updatedSource).
WithWorkdir("/go/src/github.com/replicatedhq/replicated").
WithExec([]string{"make", "build"}).
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")

dockerContainer := dag.Container().
Expand All @@ -65,6 +121,10 @@ func (r *Replicated) Release(
WithWorkdir("/out").
WithEntrypoint([]string{"/replicated"}).
WithFile("/replicated", replicatedBinary)
_, err = dockerContainer.Stdout(ctx)
if err != nil {
return err
}

username, err := dag.Onepassword().FindSecret(
onePasswordServiceAccountProduction,
Expand Down Expand Up @@ -96,12 +156,17 @@ func (r *Replicated) Release(
panic(err)
}

goreleaserContainer := dag.Goreleaser(dagger.GoreleaserOpts{
Version: goreleaserVersion,
}).Ctr().WithSecretVariable("GITHUB_TOKEN", githubToken)

if snapshot {
_, err := dag.
Goreleaser(dagger.GoreleaserOpts{
Version: goreleaserVersion,
Ctr: goreleaserContainer,
}).
WithSource(source).
WithSource(updatedSource).
Snapshot(ctx, dagger.GoreleaserSnapshotOpts{
Clean: clean,
})
Expand All @@ -112,8 +177,9 @@ func (r *Replicated) Release(
_, err := dag.
Goreleaser(dagger.GoreleaserOpts{
Version: goreleaserVersion,
Ctr: goreleaserContainer,
}).
WithSource(source).
WithSource(updatedSource).
Release(ctx, dagger.GoreleaserReleaseOpts{
Clean: clean,
})
Expand All @@ -125,11 +191,7 @@ func (r *Replicated) Release(
return nil
}

func parseVersion(ctx context.Context, version string) (int64, int64, int64, error) {
latestVersion, err := getLatestVersion(ctx)
if err != nil {
return 0, 0, 0, err
}
func parseVersion(ctx context.Context, latestVersion string, version string) (int64, int64, int64, error) {
parsedLatestVersion, err := semver.NewVersion(latestVersion)
if err != nil {
return 0, 0, 0, err
Expand Down Expand Up @@ -168,8 +230,14 @@ func getLatestVersion(ctx context.Context) (string, error) {
return release.TagName, nil
}

var (
ErrGitTreeNotClean = errors.New("Your git tree is not clean. You cannot release what's not commited.")
ErrMainBranch = errors.New("You must be on the main branch to release")
ErrCommitNotInGitHub = errors.New("You must merge your changes into the main branch before releasing")
)

// checkGitTree will return true if the local git tree is clean
func checkGitTree(ctx context.Context, source *dagger.Directory) (bool, error) {
func checkGitTree(ctx context.Context, source *dagger.Directory, githubToken *dagger.Secret) (bool, error) {
container := dag.Container().
From("alpine/git:latest").
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source).
Expand All @@ -181,8 +249,67 @@ func checkGitTree(ctx context.Context, source *dagger.Directory) (bool, error) {
return false, err
}

if len(output) == 0 {
return true, nil
if len(output) > 0 {
return false, ErrGitTreeNotClean
}

container = dag.Container().
From("alpine/git:latest").
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source).
WithWorkdir("/go/src/github.com/replicatedhq/replicated").
WithExec([]string{"git", "branch"})

output, err = container.Stdout(ctx)
if err != nil {
return false, err
}

if !strings.Contains(output, "* main") {
return false, ErrMainBranch
}

container = dag.Container().
From("alpine/git:latest").
WithMountedDirectory("/go/src/github.com/replicatedhq/replicated", source).
WithWorkdir("/go/src/github.com/replicatedhq/replicated").
WithExec([]string{"git", "rev-parse", "HEAD"})

commit, err := container.Stdout(ctx)
if err != nil {
return false, err
}

req, err := http.NewRequest("GET", fmt.Sprintf("https://api.github.com/repos/replicatedhq/replicated/commits/%s", commit), nil)
if err != nil {
return false, err
}

githubTokenPlaintext, err := githubToken.Plaintext(ctx)
if err != nil {
return false, err
}

req.Header.Set("Authorization", fmt.Sprintf("token %s", githubTokenPlaintext))

resp, err := http.DefaultClient.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()

type GitHubResponse struct {
SHA string `json:"sha"`
NodeID string `json:"node_id"`
Status string `json:"status"`
}

var ghResp GitHubResponse
if err := json.NewDecoder(resp.Body).Decode(&ghResp); err != nil {
return false, err
}

if ghResp.Status == "422" {
return false, ErrCommitNotInGitHub
}

return false, nil
Expand Down
Loading

0 comments on commit 4f9a108

Please sign in to comment.