diff --git a/.aqua/aqua.yaml b/.aqua/aqua.yaml index cb149ad..520f324 100644 --- a/.aqua/aqua.yaml +++ b/.aqua/aqua.yaml @@ -6,41 +6,42 @@ checksum: require_checksum: false registries: - type: standard - ref: v4.118.0 # renovate: depName=aquaproj/aqua-registry + ref: v4.190.0 # renovate: depName=aquaproj/aqua-registry - name: local type: local path: registry.yaml packages: - - name: miniscruff/changie@v1.17.0 + - name: miniscruff/changie@v1.19.0 tags: ['release'] - - name: golang/go@go1.21.6 + - name: golang/go@go1.22.4 tags: ['first', 'release', 'test', 'scan', 'lint'] - - name: direnv/direnv@v2.33.0 + - name: direnv/direnv@v2.34.0 - name: magefile/mage@v1.15.0 tags: ['release', 'test', 'scan', 'lint'] - name: charmbracelet/glow@v1.5.1 - - name: goreleaser/goreleaser@v1.23.0 + - name: goreleaser/goreleaser@v2.0.0 tags: ['release'] - - name: mvdan/gofumpt@v0.5.0 - - name: anchore/syft@v0.100.0 + - name: mvdan/gofumpt@v0.6.0 + - name: anchore/syft@v1.5.0 tags: ['release'] - - name: norwoodj/helm-docs@v1.12.0 - - name: gotestyourself/gotestsum@v1.11.0 + - name: norwoodj/helm-docs@v1.13.1 + - name: gotestyourself/gotestsum@v1.12.0 tags: ['test'] - name: c-bata/kube-prompt@v1.0.11 - - name: kubernetes-sigs/kind@v0.20.0 + - name: kubernetes-sigs/kind@v0.23.0 - name: kubernetes/kubectl version: v1.25.2 - - name: helm/helm@v3.13.3 - - name: kubernetes/minikube@v1.32.0 + - name: helm/helm@v3.15.1 + - name: kubernetes/minikube@v1.33.1 tags: ['ci'] - - name: stern/stern@v1.28.0 - - name: tilt-dev/tilt@v0.33.10 - - name: golangci/golangci-lint@v1.55.2 + - name: stern/stern@v1.30.0 + - name: tilt-dev/tilt@v0.33.16 + - name: golangci/golangci-lint@v1.59.0 tags: ['lint'] - name: mage-select version: v1.4.2 registry: local tags: ['goinstall'] - - name: DelineaXPM/dsv-cli@v1.40.5 - - name: gitleaks/gitleaks@v8.18.1 + - name: DelineaXPM/dsv-cli@v1.41.1 + - name: gitleaks/gitleaks@v8.18.3 + - name: charmbracelet/gum@v0.14.1 diff --git "a/.changes/unreleased/\360\237\244\226 CI & Build-20240608-002754.yaml" "b/.changes/unreleased/\360\237\244\226 CI & Build-20240608-002754.yaml" new file mode 100644 index 0000000..bc906f7 --- /dev/null +++ "b/.changes/unreleased/\360\237\244\226 CI & Build-20240608-002754.yaml" @@ -0,0 +1,3 @@ +kind: "\U0001F916 CI & Build" +body: Add a buildName metadata to binary so easy to see if caching issue with container loading. Handle `dev.local/dsv-k8s` as standard image name to better reflect standard approach I've been using. Improve validation checks. Goreleaser upgrade schema and more. Lots of quality of life improvements for dev, and aqua updates. +time: 2024-06-08T00:27:54.636538807Z diff --git a/.gitignore b/.gitignore index 12ab598..db6faf4 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,5 @@ packages-* vendor/**/*.png -Tiltfile.local \ No newline at end of file +Tiltfile.local +.env diff --git a/.goreleaser.yaml b/.goreleaser.yaml index aab4ebf..68bafd2 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -1,4 +1,5 @@ --- +version: 2 project_name: dsv-k8s dist: .artifacts/goreleaser env: @@ -7,6 +8,7 @@ env: - GITEA_TOKEN='' - LOCAL_DEBUGGING=false # set to make this quick and bypass extra effort builds like archiving zip - CGO_ENABLED=0 + - BUILD_NAME='{{ if index .Env "BUILD_NAME" }}{{ .Env.BUILD_NAME }}{{else}}""{{end}}' before: hooks: - go mod download @@ -22,6 +24,7 @@ builds: - -X main.commit={{ .FullCommit }} - -X main.date={{ .Now.Format "2006-01-02T15:04:05Z07:00" }} #RFC3339 - -X main.builtBy=goreleaser + - -X main.buildName={{ .Env.BUILD_NAME }} goos: [linux] goarch: - amd64 @@ -49,7 +52,7 @@ checksum: snapshot: name_template: '{{ incpatch .Version }}-next' changelog: - skip: false + disable: true sort: asc use: github groups: @@ -97,8 +100,8 @@ dockers: - id: local-docker-images goos: linux image_templates: - - '{{ .ProjectName }}:{{ .Tag }}' - - '{{ .ProjectName }}:latest' # This one is for dev usage so latest version, no tagged semver required in docker compose or local testing + - 'dev.local/{{ .ProjectName }}:{{ .Tag }}' + - 'dev.local/{{ .ProjectName }}:latest' # This one is for dev usage so latest version, no tagged semver required in docker compose or local testing skip_push: true dockerfile: ./docker/Dockerfile.distroless use: buildx @@ -108,7 +111,6 @@ dockers: - --label=org.opencontainers.image.title={{ .ProjectName }} - --label=org.opencontainers.image.revision={{ .FullCommit }} - --label=org.opencontainers.image.version={{.Version}} - - --label=org.opencontainers.image.version="{{ .Tag }}" announce: slack: enabled: true diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 17e44f1..151d42c 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -2,7 +2,7 @@ version: 0.1 plugins: sources: - id: trunk - ref: v1.4.2 + ref: v1.5.0 uri: https://github.com/trunk-io/plugins actions: enabled: @@ -39,7 +39,7 @@ runtimes: - node@18.12.1 - python@3.10.8 cli: - version: 1.19.0 + version: 1.22.1 lint: threshold: - linters: [gitleaks] @@ -48,35 +48,35 @@ lint: - cspell - gofmt enabled: - - checkov@3.2.19 + - checkov@3.2.128 - gokart@0.5.1 - - osv-scanner@1.6.2 - - terrascan@1.18.11 - - trivy@0.49.1 - - trufflehog@3.67.5 + - osv-scanner@1.7.4 + - terrascan@1.19.1 + - trivy@0.52.0 + - trufflehog@3.78.0 - gofumpt@0.5.0 - - renovate@37.180.0 + - renovate@37.396.1 - golangci-lint@SYSTEM - git-diff-check - taplo@0.8.1 - - markdownlint@0.39.0 - - prettier@3.2.5 - - actionlint@1.6.26 + - markdownlint@0.41.0 + - prettier@3.3.1 + - actionlint@1.7.1 - hadolint@2.12.0 - - gitleaks@8.18.2 - - shellcheck@0.9.0 + - gitleaks@8.18.3 + - shellcheck@0.10.0 - shfmt@3.6.0 - - yamllint@1.34.0 - - svgo@3.2.0 + - yamllint@1.35.1 + - svgo@3.3.2 - prettier@2.8.3 - git-diff-check - taplo@0.8.1 - yamllint@1.29.0 - - actionlint@1.6.26 + - actionlint@1.7.1 - gitleaks@8.15.3 - hadolint@2.12.0 - - markdownlint@0.39.0 - - shellcheck@0.9.0 + - markdownlint@0.41.0 + - shellcheck@0.10.0 - shfmt@3.6.0 ignore: diff --git a/Tiltfile b/Tiltfile index 0fba16e..a7df962 100644 --- a/Tiltfile +++ b/Tiltfile @@ -117,7 +117,7 @@ local_resource( cmd="zsh -l -c \"mage -f -l\"", trigger_mode=TRIGGER_MODE_AUTO, auto_init=True, - deps=['magefiles/*.go'], + deps=['magefiles/**/*.go'], labels=["startup"] ) local_resource( @@ -216,5 +216,29 @@ local_resource( auto_init=False, labels=["setup"], ) +local_resource( + "minikube:listimages", + cmd="mage minikube:listimages", + trigger_mode=TRIGGER_MODE_MANUAL, + deps=[], + auto_init=False, + labels=["setup"], +) +local_resource( + "minikube:removeimages", + cmd="mage minikube:removeimages", + trigger_mode=TRIGGER_MODE_MANUAL, + deps=[], + auto_init=False, + labels=["setup"], +) +local_resource( + "minikube:loadimages", + cmd="mage minikube:loadimages", + trigger_mode=TRIGGER_MODE_MANUAL, + deps=[], + auto_init=False, + labels=["setup"], +) # k8s_resource('injector', resource_deps='minikube:init', pod_readiness='ignore') diff --git a/cmd/injector/main.go b/cmd/injector/main.go index d19fd00..02b7eca 100644 --- a/cmd/injector/main.go +++ b/cmd/injector/main.go @@ -38,9 +38,11 @@ var ( commit = "none" // Date is the date the binary was produced. date = "unknown" + // buildName is the build name for easier confirmation on local builds that a build has changed. + buildName = "unknown" ) -// main is the entry point for the injector; creates an HTTPS listener and listing for v1.AdmissionReview requests +// main is the entry point for the injector. It creates an HTTPS listener and listing for v1.AdmissionReview requests func main() { if err := Run(os.Args); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) @@ -56,6 +58,7 @@ func Run(args []string) error { //nolint:funlen,cyclop // ok for Run Str("version", version). Str("commit", commit). Str("date", date). + Str("buildName", buildName). Msg("injector version information") // Config is the configuration for the injector. diff --git a/cmd/syncer/main.go b/cmd/syncer/main.go index 5651c4c..cf04f5a 100644 --- a/cmd/syncer/main.go +++ b/cmd/syncer/main.go @@ -41,6 +41,8 @@ var ( commit = "none" // Date is the date the binary was produced. date = "unknown" + // buildName is the build name for easier confirmation on local builds that a build has changed. + buildName = "unknown" ) // Run contains the actual invocation code for the syncer and is public to allow running integration tests with it. @@ -50,6 +52,7 @@ func Run(args []string) error { //nolint:funlen // ok for Run Str("version", version). Str("commit", commit). Str("date", date). + Str("buildName", buildName). Msg("syncer version information") // Config is the configuration for the syncer. diff --git a/go.mod b/go.mod index 0871ee6..4582528 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( atomicgo.dev/keyboard v0.2.9 // indirect atomicgo.dev/schedule v0.1.0 // indirect github.com/aws/aws-sdk-go v1.44.119 // indirect + github.com/brianvoe/gofakeit/v6 v6.28.0 // indirect github.com/containerd/console v1.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect diff --git a/go.sum b/go.sum index 5632b98..1e09a59 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/aws/aws-sdk-go v1.44.119 h1:TPkpDsanBMcZaF5wHwpKhjkapRV/b7d2qdC+a+IPb github.com/aws/aws-sdk-go v1.44.119/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/bitfield/script v0.22.0 h1:LA7QHuEsXMPD52YLtxWrlqCCy+9FOpzNYfsRHC5Gsrc= github.com/bitfield/script v0.22.0/go.mod h1:ms4w+9B8f2/W0mbsgWDVTtl7K94bYuZc3AunnJC4Ebs= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II= github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= diff --git a/magefiles/constants/constants.mage.go b/magefiles/constants/constants.mage.go index 04a152e..de5a517 100644 --- a/magefiles/constants/constants.mage.go +++ b/magefiles/constants/constants.mage.go @@ -43,7 +43,7 @@ const ( // DockerImageQualified is the qualified path of the image in Docker Hub. DockerImageQualified = "docker.io/delineaxpm/dsv-k8s" // DockerImageNameLocal is the name of the built image to run locally and load with minikube/kind. - DockerImageNameLocal = "dsv-k8s" + DockerImageNameLocal = "dev.local/dsv-k8s" ) const ( diff --git a/magefiles/goreleaser.mage.go b/magefiles/goreleaser.mage.go index 29e0687..a50fcd7 100644 --- a/magefiles/goreleaser.mage.go +++ b/magefiles/goreleaser.mage.go @@ -2,16 +2,47 @@ package main import ( "fmt" + "hash" + "hash/fnv" "os" "path/filepath" "strings" + "time" + "github.com/brianvoe/gofakeit/v6" "github.com/magefile/mage/sh" "github.com/pterm/pterm" "github.com/sheldonhull/magetools/pkg/magetoolsutils" "github.com/sheldonhull/magetools/pkg/req" ) +// FNV64a hashes using fnv64a algorithm +// +// Sourced from: https://github.com/shomali11/util/blob/master/xhashes/xhashes.go +func FNV64a(text string) uint64 { + algorithm := fnv.New64a() + return uint64Hasher(algorithm, text) +} + +// uint64Hasher returns a uint64 +// +// Sourced from: https://github.com/shomali11/util/blob/master/xhashes/xhashes.go +func uint64Hasher(algorithm hash.Hash64, text string) uint64 { + algorithm.Write([]byte(text)) + return algorithm.Sum64() +} + +func randomBuildName() (petname string) { + v := time.Now().Unix() + gofakeit.Seed(v) + animal := gofakeit.Animal() + adjective := gofakeit.AdjectiveDescriptive() + petname = strings.ToLower(strings.Join([]string{adjective, animal}, "-")) + pterm.Info.Printfln("Random Pet Calculated at Runtime: %s\n", petname) + + return petname +} + func checkEnvVar(envVar string, required bool) (string, error) { envVarValue := os.Getenv(envVar) if envVarValue == "" && required { @@ -47,7 +78,11 @@ func Build() error { } pterm.Debug.Printfln("goreleaser: %+v", releaserArgs) - return sh.RunV(binary, releaserArgs...) // "--skip-announce",. + return sh.RunWithV( + map[string]string{ + "BUILD_NAME": randomBuildName(), + }, + binary, releaserArgs...) // "--skip-announce",. } // 🔨 BuildAll builds all the binaries defined in the project, for all platforms. This includes Docker image generation but skips publish. @@ -63,10 +98,14 @@ func BuildAll() error { "release", "--snapshot", "--clean", - "--skip-publish", + "--skip", "publish,sbom", } pterm.Debug.Printfln("goreleaser: %+v", releaserArgs) - return sh.RunV(binary, releaserArgs...) + _ = os.Setenv("BUILD_NAME", randomBuildName()) + return sh.RunWithV( + map[string]string{ + "BUILD_NAME": randomBuildName(), + }, binary, releaserArgs...) // To pass in explicit version mapping, you can do this. I'm not using at this time. // Return sh.RunWithV(map[string]string{ // "GORELEASER_CURRENT_TAG": "latest", @@ -108,9 +147,11 @@ func Release() error { } pterm.Debug.Printfln("goreleaser: %+v", releaserArgs) - return sh.RunWithV(map[string]string{ - "GORELEASER_CURRENT_TAG": cleanVersion, - }, + return sh.RunWithV( + map[string]string{ + "GORELEASER_CURRENT_TAG": cleanVersion, + "BUILD_NAME": randomBuildName(), + }, binary, releaserArgs..., ) diff --git a/magefiles/helm/helm.mage.go b/magefiles/helm/helm.mage.go index 84897d7..b07443a 100644 --- a/magefiles/helm/helm.mage.go +++ b/magefiles/helm/helm.mage.go @@ -209,15 +209,16 @@ func Checkfile(file string) error { pterm.Error.Printfln("❌ Error reading file %q %v", file, err) return err } - re := regexp.MustCompile(`repository:\s+dsv-k8s`) //nolint:varnamelen // standard prefix, can update golangcilint config + escapedRepositoryMatch := regexp.QuoteMeta(constants.DockerImageNameLocal) + re := regexp.MustCompile(fmt.Sprintf(`repository:\s+%s`, escapedRepositoryMatch)) //nolint:varnamelen // standard prefix, can update golangcilint config match := re.Find(b) if match != nil { - pterm.Success.Printfln("✅ %s is configured to use local image", file) + pterm.Success.Printfln("✅ %s is configured to use local image [expected: %s]", file, constants.DockerImageNameLocal) } else { re = regexp.MustCompile(`repository:\s+[^\n]*`) match = re.Find(b) if match != nil { - pterm.Warning.Printfln("❌ %s: not configured to use local image: %q (this is fine if you are't building as a developer with changes)", file, match) + pterm.Warning.Printfln("❌ %s: not configured to use local image: %q [expected: %s] (this is fine if you are't building as a developer with changes)", file, match, escapedRepositoryMatch) } else { pterm.Warning.Printfln("❌ %s: not configured to use local image: repository not found", file) } @@ -226,7 +227,7 @@ func Checkfile(file string) error { re = regexp.MustCompile(`pullPolicy:\s+Never`) match = re.Find(b) if match != nil { - pterm.Success.Printfln("✅ %s is configured with pullPolicy of Never", file) + pterm.Success.Printfln("✅ %s is configured with pullPolicy of Never [expected: Never]", file) } else { re = regexp.MustCompile(`pullPolicy:\s+\w*`) match = re.Find(b) @@ -239,7 +240,7 @@ func Checkfile(file string) error { re = regexp.MustCompile(`tag:\s+[']?latest[']?`) match = re.Find(b) if match != nil { - pterm.Success.Printfln("✅ %s is configured with pullPolicy of Never", file) + pterm.Success.Printfln("✅ %s is configured with tag of %s [expected: latest]", file, match) } else { re = regexp.MustCompile(`tag:\s+[']?.*[']?`) match = re.Find(b) diff --git a/magefiles/jobs.mage.go b/magefiles/jobs.mage.go index fbbae44..c64a27f 100644 --- a/magefiles/jobs.mage.go +++ b/magefiles/jobs.mage.go @@ -29,11 +29,16 @@ func (Job) Init() { // Redeploy removes k8s resources, helm uninstall, and then runs k8s apply and helm install. func (Job) Redeploy() { pterm.DefaultSection.Println("(Job) Redeploy()") - mg.SerialDeps( - minikube.Minikube{}.LoadImages, // just be sure in case forget to load local images that the latest is always used + + mg.Deps( helm.Helm{}.Uninstall, mg.F(k8s.K8s{}.Delete, constants.CacheManifestDirectory), - helm.Helm{}.Install, // this should take place first so the creation of the manifests can benefit from the resulting injector/syncer + ) + + mg.SerialDeps( + minikube.Minikube{}.RemoveImages, + minikube.Minikube{}.LoadImages, // just be sure in case forget to load local images that the latest is always used + helm.Helm{}.Install, // this should take place first so the creation of the manifests can benefit from the resulting injector/syncer mg.F(k8s.K8s{}.Apply, constants.CacheManifestDirectory), // k8s.K8s{}.Logs, // use chained command ) diff --git a/magefiles/minikube/minikube.mage.go b/magefiles/minikube/minikube.mage.go index 57b8491..2fc8252 100644 --- a/magefiles/minikube/minikube.mage.go +++ b/magefiles/minikube/minikube.mage.go @@ -160,13 +160,14 @@ func (Minikube) RemoveImages() { pterm.Error.Printfln("image not rm from minikube: %v", err) } // Check if the output contains the image name - if !strings.Contains(output, "docker.io/library/dsv-k8s:latest") { + if !strings.Contains(output, constants.DockerImageNameLocal) || + strings.Contains(output, fmt.Sprintf("No such image: %s", constants.DockerImageNameLocal)) { pterm.Success.Printfln("image unloaded") break } // If the image is still being unloaded, print a progress message - pterm.Info.Printf("Still waiting for image to unload (elapsed time: %s)\n", elapsed.Round(time.Second)) + pterm.Info.Printf("Still waiting for image [%s] to unload (elapsed time: %s)\n", constants.DockerImageNameLocal, elapsed.Round(time.Second)) // Wait for 3 seconds before trying again time.Sleep(3 * time.Second) //nolint:gomnd // no need to make a constant @@ -176,10 +177,10 @@ func (Minikube) RemoveImages() { // for _, chart := range constants.HelmChartsList { // Load image into minikube // debug output "--logtostderr", - - if err := sh.Run("minikube", "image", "rm", "--profile", constants.KindClusterName, constants.DockerImageQualified); err != nil { - pterm.Warning.Printfln("image not rm from minikube: %v", err) - } + // NOTE: removed this as we don't need to remove those images regularly as it's an upstream version infrequently changed and causes confusing output. + // if err := sh.Run("minikube", "image", "rm", "--profile", constants.KindClusterName, constants.DockerImageQualified); err != nil { + // pterm.Warning.Printfln("image not rm from minikube: %v", err) + // } pterm.Success.Printfln("image removed from minikube: %s", constants.DockerImageNameLocal) // } }