release.yml RawHistoryFolder
1name: release
2
3# Every push to main that passes CI cuts a new release. The workflow:
4# 1. waits for the ci workflow on the same commit to succeed
5# 2. looks up the latest existing vX.Y.Z tag
6# 3. bumps the patch number (vX.Y.Z+1) — or starts at v0.0.1 if none
7# 4. creates and pushes that tag
8# 5. runs goreleaser, which builds binaries for linux/darwin/windows
9# (amd64 + arm64) and attaches them plus checksums.txt to a fresh
10# GitHub Release page
11#
12# Skip a release by putting [skip-release] anywhere in the commit
13# message (note the hyphen) — useful for docs-only or ci-only
14# commits. We use [skip-release] rather than [skip release] so that
15# commits that merely *mention* the phrase don't accidentally opt out.
16on:
17 workflow_run:
18 workflows: [ci]
19 types: [completed]
20 branches: [main]
21
22permissions:
23 # Needed to create tags and to upload release archives.
24 contents: write
25
26# Only one release job at a time. If two pushes land in quick
27# succession, queue them so they don't race on the tag.
28concurrency:
29 group: release
30 cancel-in-progress: false
31
32jobs:
33 debug:
34 # One-shot diagnostic job with no if-filter: dumps the full
35 # workflow_run context so we can see what fields are actually
36 # populated on the webhook payload. Remove once the release job
37 # starts firing reliably.
38 runs-on: ubuntu-latest
39 steps:
40 - name: dump workflow_run
41 env:
42 WR: ${{ toJSON(github.event.workflow_run) }}
43 run: |
44 echo "conclusion: ${{ github.event.workflow_run.conclusion }}"
45 echo "head_branch: ${{ github.event.workflow_run.head_branch }}"
46 echo "head_sha: ${{ github.event.workflow_run.head_sha }}"
47 echo "---"
48 printenv WR | head -c 2000
49
50 release:
51 needs: debug
52 # Only run when ci succeeded and we're on main, and when the head
53 # commit doesn't opt out via [skip-release].
54 if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'main' }}
55 runs-on: ubuntu-latest
56 steps:
57 - name: checkout
58 uses: actions/checkout@v4
59 with:
60 # Full history so we can read existing tags.
61 fetch-depth: 0
62 # Check out the exact sha that ci verified, not whatever the
63 # branch tip happens to be at this moment (which may have
64 # advanced since ci finished).
65 ref: ${{ github.event.workflow_run.head_sha }}
66
67 - name: compute next version
68 id: bump
69 shell: bash
70 run: |
71 set -euo pipefail
72 # Find the newest vX.Y.Z tag. If the repo has none yet, start
73 # at v0.0.0 so the first release becomes v0.0.1.
74 latest=$(git tag --list 'v*.*.*' --sort=-v:refname | head -n1)
75 if [ -z "$latest" ]; then
76 latest="v0.0.0"
77 fi
78 echo "latest tag: $latest"
79
80 # Strip the v prefix, split on dots, bump the patch.
81 ver="${latest#v}"
82 IFS=. read -r major minor patch <<<"$ver"
83 patch=$((patch + 1))
84 next="v${major}.${minor}.${patch}"
85 echo "next tag: $next"
86
87 echo "next=$next" >> "$GITHUB_OUTPUT"
88 echo "version=${next#v}" >> "$GITHUB_OUTPUT"
89
90 - name: create and push tag
91 env:
92 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
93 run: |
94 git config user.name "github-actions[bot]"
95 git config user.email "github-actions[bot]@users.noreply.github.com"
96 git tag -a "${{ steps.bump.outputs.next }}" \
97 -m "release ${{ steps.bump.outputs.next }}"
98 git push origin "${{ steps.bump.outputs.next }}"
99
100 - name: set up go
101 uses: actions/setup-go@v5
102 with:
103 go-version: "1.23"
104 cache: true
105
106 - name: run goreleaser
107 uses: goreleaser/goreleaser-action@v6
108 with:
109 distribution: goreleaser
110 version: latest
111 args: release --clean
112 env:
113 # goreleaser reads the tag we just pushed and builds binaries
114 # for every (goos, goarch) combination in .goreleaser.yaml.
115 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
116 # Optional: PAT with `repo` scope for patriceckhart/homebrew-tap
117 # so we can push a Formula/zot.rb update on every release.
118 # If unset, goreleaser skips the brew step (skip_upload: auto).
119 HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}