From 1add88c423ab746b83662f074756b4bfb0db334c Mon Sep 17 00:00:00 2001 From: Scot Wells Date: Tue, 30 Jun 2026 18:37:21 -0500 Subject: [PATCH 1/4] Add release tooling to publish the milo-ipam plugin Tagged releases now build and publish the milo-ipam datumctl plugin as per-platform archives plus a checksums.txt, attached as GitHub release assets. - .goreleaser.yaml builds milo-ipam from ./cmd/milo-ipam for linux/darwin/windows on amd64/arm64. The archive name_template renders OS title-cased and amd64 as x86_64, producing the exact asset names the datumctl plugin catalog expects: milo-ipam_Linux_x86_64.tar.gz milo-ipam_Linux_arm64.tar.gz milo-ipam_Darwin_x86_64.tar.gz milo-ipam_Darwin_arm64.tar.gz milo-ipam_Windows_x86_64.zip milo-ipam_Windows_arm64.zip plus checksums.txt covering all archives. The binary inside each archive is milo-ipam (milo-ipam.exe on Windows). - release.yml gains a publish-plugin job that runs goreleaser on version tags only, leaving the existing container-image and kustomize-bundle publishing jobs untouched. - dist/ is gitignored. --- .github/workflows/release.yml | 33 +++++++++++++++++++ .gitignore | 3 ++ .goreleaser.yaml | 60 +++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 .goreleaser.yaml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3cea552..71e649c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,3 +43,36 @@ jobs: image-overlays: config/base image-name: ghcr.io/milo-os/ipam secrets: inherit + + # Build and publish the milo-ipam datumctl plugin as per-platform archives + + # checksums.txt, attached as GitHub release assets. Only runs on version tags + # (vX.Y.Z); independent of the container/kustomize jobs above. The produced + # asset names are consumed by the datumctl plugin catalog entry in + # milo-os/cli-plugins (plugins/ipam.yaml). + publish-plugin: + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Install Syft CLI + run: curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo sh -s -- -b /usr/local/bin + + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version-file: go.mod + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + distribution: goreleaser + version: "~> v2" + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index d42d45f..553fd62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Compiled binary /ipam +# GoReleaser build output +/dist/ + # Local test infrastructure (kind cluster, kind managed by task test-infra:cluster-up) /.test-infra/ diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..de9da92 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,60 @@ +# GoReleaser config for the milo-ipam datumctl plugin. +# +# Release a version by pushing a semver tag (vX.Y.Z). The Release workflow runs +# goreleaser, which builds the plugin for each supported platform and publishes +# per-platform archives + checksums.txt as GitHub release assets. The datumctl +# plugin catalog entry (milo-os/cli-plugins, plugins/ipam.yaml) references these +# exact asset names, so the archive name_template below must not change casually. +# +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +version: 2 + +project_name: milo-ipam + +before: + hooks: + - go mod tidy + +builds: + - id: milo-ipam + main: ./cmd/milo-ipam + binary: milo-ipam + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + +archives: + - id: milo-ipam + # name template renders OS title-cased (Linux/Darwin/Windows) and amd64 as + # x86_64, matching goreleaser's common convention and the datumctl plugin + # catalog entry (milo-ipam_Darwin_arm64, milo-ipam_Linux_x86_64, ...). + name_template: >- + {{ .ProjectName }}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + formats: [tar.gz] + format_overrides: + - goos: windows + formats: [zip] + +checksum: + name_template: checksums.txt + +sboms: + - artifacts: archive + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + - "^chore:" From d755e5e131655bca26546c5d26a7409484d81153 Mon Sep 17 00:00:00 2001 From: Scot Wells Date: Tue, 30 Jun 2026 18:39:54 -0500 Subject: [PATCH 2/4] Update IPAM plugin description Match the plugin's --plugin-manifest description to the catalog entry: 'Manage IP address space (pools and prefixes) across the platform'. --- cmd/milo-ipam/manifest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/milo-ipam/manifest.go b/cmd/milo-ipam/manifest.go index d0e3386..2d8f1f1 100644 --- a/cmd/milo-ipam/manifest.go +++ b/cmd/milo-ipam/manifest.go @@ -13,7 +13,7 @@ import ( const ( pluginName = "ipam" pluginVersion = "0.1.0" - pluginDescription = "Manage IP address space (pools and prefixes) on Datum" + pluginDescription = "Manage IP address space (pools and prefixes) across the platform" // pluginAPIVersion is the version of the datumctl <-> plugin contract this // binary speaks, not the IPAM API version. pluginAPIVersion = 1 From 85df6f561508ad60d1af9651ea0dc6bb828f7396 Mon Sep 17 00:00:00 2001 From: Scot Wells Date: Tue, 30 Jun 2026 18:48:01 -0500 Subject: [PATCH 3/4] Wire the plugin version through from the release tag Make pluginVersion an ldflags-overridable var and have goreleaser inject the release version (-X main.pluginVersion={{ .Version }}) at build time, so a published milo-ipam reports the version it was released under instead of a hardcoded constant. Local/dev builds keep the in-source default. --- .goreleaser.yaml | 6 ++++++ cmd/milo-ipam/manifest.go | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index de9da92..5786fe9 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -28,6 +28,12 @@ builds: goarch: - amd64 - arm64 + # Inject the release version (the git tag without its leading "v") so the + # published binary's --plugin-manifest and `milo-ipam --version` report the + # version it was released under, rather than the in-source default. + ldflags: + - -s -w + - -X main.pluginVersion={{ .Version }} archives: - id: milo-ipam diff --git a/cmd/milo-ipam/manifest.go b/cmd/milo-ipam/manifest.go index 2d8f1f1..0473e26 100644 --- a/cmd/milo-ipam/manifest.go +++ b/cmd/milo-ipam/manifest.go @@ -12,7 +12,6 @@ import ( const ( pluginName = "ipam" - pluginVersion = "0.1.0" pluginDescription = "Manage IP address space (pools and prefixes) across the platform" // pluginAPIVersion is the version of the datumctl <-> plugin contract this // binary speaks, not the IPAM API version. @@ -24,6 +23,13 @@ const ( minAPIVersion = "ipam.miloapis.com/v1alpha1" ) +// pluginVersion is the plugin's release version. It defaults to a development +// value for local builds and is overridden at release time by goreleaser via +// -ldflags "-X main.pluginVersion=" (the git tag without its leading +// "v"), so a published binary reports the version it was released under. It is +// a var (not a const) precisely so the linker can set it. +var pluginVersion = "0.1.0" + // pluginManifest is the document emitted in response to --plugin-manifest. type pluginManifest struct { Name string `json:"name"` From a9c5045eb46b581f0752567d0f2534d01c0732ee Mon Sep 17 00:00:00 2001 From: Scot Wells Date: Tue, 30 Jun 2026 18:50:24 -0500 Subject: [PATCH 4/4] Default the plugin version to 0.0.0 for unreleased builds A plain 'go build' previously reported 0.1.0, making a local build indistinguishable from the released 0.1.0. Default to 0.0.0 so an unreleased build is unambiguous; release builds still get the real tag injected via ldflags. --- cmd/milo-ipam/manifest.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/milo-ipam/manifest.go b/cmd/milo-ipam/manifest.go index 0473e26..f9d8b9e 100644 --- a/cmd/milo-ipam/manifest.go +++ b/cmd/milo-ipam/manifest.go @@ -23,12 +23,12 @@ const ( minAPIVersion = "ipam.miloapis.com/v1alpha1" ) -// pluginVersion is the plugin's release version. It defaults to a development -// value for local builds and is overridden at release time by goreleaser via +// pluginVersion is the plugin's release version. It defaults to "0.0.0" to mark +// an unreleased local build and is overridden at release time by goreleaser via // -ldflags "-X main.pluginVersion=" (the git tag without its leading // "v"), so a published binary reports the version it was released under. It is // a var (not a const) precisely so the linker can set it. -var pluginVersion = "0.1.0" +var pluginVersion = "0.0.0" // pluginManifest is the document emitted in response to --plugin-manifest. type pluginManifest struct {