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
83 changes: 16 additions & 67 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
name: Release

# A successful CI run on the current main commit is the only release path.
# VERSION sets the next deliberate baseline; later releases increment patch.
on:
workflow_run:
workflows: [CI]
Expand All @@ -10,75 +8,26 @@ on:

permissions:
contents: write
id-token: write
attestations: write
artifact-metadata: write

concurrency:
group: release
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}

steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
ref: ${{ github.event.workflow_run.head_sha }}

- name: Compute release version
id: version
run: |
git fetch origin main --tags
if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]; then
echo "A newer main commit superseded this CI run; nothing to release."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if git describe --tags --exact-match --match 'v*.*.*' HEAD >/dev/null 2>&1; then
echo "HEAD is already tagged; nothing to release."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi

BASE_VERSION=$(tr -d '[:space:]' < VERSION)
if ! echo "$BASE_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "VERSION must contain a semantic version without a leading v." >&2
exit 1
fi
BASE_TAG="v$BASE_VERSION"
LATEST=$(git tag --list 'v*.*.*' | sort -V | tail -n 1)
if [ -z "$LATEST" ]; then
TAG="$BASE_TAG"
elif [ "$LATEST" != "$BASE_TAG" ] && [ "$(printf '%s\n%s\n' "$LATEST" "$BASE_TAG" | sort -V | tail -n 1)" = "$BASE_TAG" ]; then
TAG="$BASE_TAG"
else
TAG=$(echo "$LATEST" | awk -F '[v.]' '{printf "v%d.%d.%d", $2, $3, $4 + 1}')
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"

- name: Create and push tag
if: ${{ steps.version.outputs.skip != 'true' }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "${{ steps.version.outputs.tag }}"
git push origin "${{ steps.version.outputs.tag }}"

- name: Set up Go
if: ${{ steps.version.outputs.skip != 'true' }}
uses: actions/setup-go@v7
with:
go-version: 1.26.x
check-latest: true

- name: Run goreleaser
if: ${{ steps.version.outputs.skip != 'true' }}
uses: goreleaser/goreleaser-action@v7
with:
distribution: goreleaser
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: >-
${{
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_repository.full_name == github.repository
}}
uses: open-ships/ci/.github/workflows/release-go.yaml@v1.1.0
with:
commit-sha: ${{ github.event.workflow_run.head_sha }}
project-name: n2k-cli
distribution: goreleaser
go-version: 1.26.5
release-title-with-date: true
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,10 @@ just secure

Releases follow semantic versioning. [`VERSION`](VERSION) declares the release
baseline, and fully green release automation publishes the tag and prebuilt
binaries.
binaries. GoReleaser builds remain project-owned, while the exact-version-tagged
shared Open Ships release policy publishes checksums, an SBOM, toolchain
evidence, and separate build-provenance and SBOM attestations for the platform
archives.

## License

Expand Down