From b44452c105eee16e090c91df9b1749b9e9e2158c Mon Sep 17 00:00:00 2001 From: Marek Aufart Date: Thu, 8 Oct 2026 14:45:16 +0200 Subject: [PATCH] Set plugin version during build and release Replace the hard-coded plugin version with a development default that release builds override through Go linker flags. This keeps local builds identifiable as devel and makes the binary metadata match the release selected from the plugin index. Replace the release workflow with a verified, immutable release process. It validates the requested version, refuses to reuse existing tags, checks module tidiness, runs unit tests, and builds binaries for Linux, macOS, and Windows. The workflow checks that every generated binary contains the requested version and verifies the version reported by the Linux plugin metadata endpoint before publishing artifacts and checksums. Remove automatic updates to crane-plugins from the release workflow. Add an index entry only after the release artifacts have passed all checks. Update the README with the local development version behavior and a linker-flag build example. Fixes: https://github.com/migtools/crane-plugin-openshift/issues/35 Signed-off-by: Marek Aufart --- .github/workflows/release.yml | 133 +++++++++++++++++++++------------- README.md | 10 +++ openshift/plugin.go | 4 +- openshift/plugin_test.go | 11 +++ 4 files changed, 106 insertions(+), 52 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5e591b0..6671485 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,82 +1,113 @@ -name: Releases +name: Release + on: workflow_dispatch: inputs: version: - description: Bump Version - default: v0.1.0 + description: "Version to release, for example v0.11.1" required: true + +permissions: + contents: write + jobs: - build: + release: + name: Build and publish plugin binaries runs-on: ubuntu-latest steps: - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: "1.25.0" + - name: Check the version + env: + VERSION: ${{ inputs.version }} + run: | + if ! printf '%s' "$VERSION" | grep -Eq '^v0\.[0-9]+\.[0-9]+(-[0-9A-Za-z][0-9A-Za-z.]*)?$'; then + echo "version must be v0.MINOR.PATCH with an optional pre-release suffix, got '$VERSION'" + exit 1 + fi - name: Check out source code uses: actions/checkout@v4 with: + fetch-depth: 0 persist-credentials: false - - name: Tidy - env: - GOPROXY: "https://proxy.golang.org" - run: go mod tidy && git diff --quiet HEAD + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version-file: go.mod - - name: Ensure artifact directory exists - run: mkdir -p bin + - name: Refuse to reuse a tag + env: + VERSION: ${{ inputs.version }} + run: | + if git rev-parse -q --verify "refs/tags/$VERSION" >/dev/null || git ls-remote --exit-code --refs origin "refs/tags/$VERSION" >/dev/null; then + echo "tag $VERSION already exists. Pick a new version." + exit 1 + fi - - name: Build openshift plugin linux amd64 + - name: Verify go.mod is tidy env: GOPROXY: "https://proxy.golang.org" - run: GOOS=linux GOARCH=amd64 go build -o bin/amd64-linux-openshiftplugin-${{ github.event.inputs.version }} . + run: | + go mod tidy + git diff --exit-code go.mod go.sum - - name: Build openshift plugin darwin amd64 + - name: Run unit tests env: GOPROXY: "https://proxy.golang.org" - run: GOOS=darwin GOARCH=amd64 go build -o bin/amd64-darwin-openshiftplugin-${{ github.event.inputs.version }} . + run: go test ./... -count=1 - - name: Build openshift plugin darwin arm64 + - name: Build and verify plugin binaries env: GOPROXY: "https://proxy.golang.org" - run: GOOS=darwin GOARCH=arm64 go build -o bin/arm64-darwin-openshiftplugin-${{ github.event.inputs.version }} . + VERSION: ${{ inputs.version }} + CGO_ENABLED: "0" + run: | + mkdir -p bin + ldflags="-X github.com/migtools/crane-plugin-openshift/openshift.PluginVersion=${VERSION}" - - name: release - uses: ncipollo/release-action@v1 - with: - artifacts: "bin/*" - allowUpdates: true - token: ${{ secrets.GITHUB_TOKEN }} - tag: ${{ github.event.inputs.version }} + while read -r os arch; do + out="bin/${arch}-${os}-openshiftplugin-${VERSION}" + if [ "$os" = "windows" ]; then + out="${out}.exe" + fi + echo "building $out" + GOOS="$os" GOARCH="$arch" go build -trimpath -ldflags "$ldflags" -o "$out" . - - name: Checkout crane-plugins - uses: actions/checkout@v4 - with: - repository: ${{ github.repository_owner }}/crane-plugins - token: ${{ secrets.PLUGIN_RELEASE }} - path: crane-plugins + # A stale -X package path leaves the development version in the binary. + if ! strings "$out" | grep -Fq "$VERSION"; then + echo "$out does not carry $VERSION. Check the -X path against openshift.PluginVersion." + exit 1 + fi + done <<'PLATFORMS' + linux amd64 + linux arm64 + darwin amd64 + darwin arm64 + windows amd64 + PLATFORMS - - name: setup python - uses: actions/setup-python@v5 - with: - python-version: "3.12" + metadata=$(printf '{}' | "bin/amd64-linux-openshiftplugin-${VERSION}") + if ! printf '%s' "$metadata" | jq -e --arg version "$VERSION" '.version == $version' >/dev/null; then + echo "linux amd64 plugin metadata does not report $VERSION: $metadata" + exit 1 + fi - - name: Updating index file and adding manifest - shell: bash + - name: Write checksums run: | - pip install pyyaml - cd crane-plugins - python $GITHUB_WORKSPACE/.github/workflows/script.py "${{ github.event.inputs.version }}" "${{ github.repository_owner }}" "${{ github.repository }}" + cd bin + sha256sum * > checksums.txt + cat checksums.txt - - name: Create Pull Request against crane-plugins - uses: peter-evans/create-pull-request@v6 + - name: Publish the release + uses: softprops/action-gh-release@v2 with: - token: ${{ secrets.PLUGIN_RELEASE }} - commit-message: Updating index and adding manifest from openshift plugin release - title: Adding openshift plugin from release ${{ github.event.inputs.version }} - body: Update index and add manifest to include version ${{ github.event.inputs.version }} of openshift plugin - branch: OpenShiftPlugin - base: main - path: crane-plugins + tag_name: ${{ inputs.version }} + target_commitish: ${{ github.sha }} + name: ${{ inputs.version }} + fail_on_unmatched_files: true + files: | + bin/* + body: | + Plugin binaries for crane plugin-manager. + + Add this version to the crane plugin index only after this release completes successfully. diff --git a/README.md b/README.md index eff4d3b..483f13c 100644 --- a/README.md +++ b/README.md @@ -131,3 +131,13 @@ go test ./... ```bash go build -o crane-plugin-openshift . ``` + +Locally built binaries report the version `devel`. The release workflow sets the +published plugin version at link time and verifies it before publishing release +artifacts. Add a release to `crane-plugins` only after that workflow succeeds. + +For example, to build a binary that reports `v0.11.1`: + +```bash +go build -ldflags "-X github.com/migtools/crane-plugin-openshift/openshift.PluginVersion=v0.11.1" -o crane-plugin-openshift . +``` diff --git a/openshift/plugin.go b/openshift/plugin.go index c2aae8e..50d83cd 100644 --- a/openshift/plugin.go +++ b/openshift/plugin.go @@ -10,7 +10,9 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -const PluginVersion = "v0.1.0" +// PluginVersion is reported to crane in plugin metadata. Release builds set it +// with -ldflags; locally built binaries remain identifiable as development builds. +var PluginVersion = "devel" const ( StripDefaultRBACFlag = "strip-default-rbac" diff --git a/openshift/plugin_test.go b/openshift/plugin_test.go index 368c185..439c515 100644 --- a/openshift/plugin_test.go +++ b/openshift/plugin_test.go @@ -11,6 +11,17 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) +func TestMetadataVersion(t *testing.T) { + metadata := (&OpenShiftTransformPlugin{}).Metadata() + + if metadata.Version != PluginVersion { + t.Errorf("metadata version = %q, want %q", metadata.Version, PluginVersion) + } + if PluginVersion != "devel" { + t.Errorf("default plugin version = %q, want %q", PluginVersion, "devel") + } +} + func TestImageStreamDetection(t *testing.T) { tests := []struct { name string