-
Notifications
You must be signed in to change notification settings - Fork 4
233 lines (215 loc) · 9.11 KB
/
Copy pathbinary-release.yml
File metadata and controls
233 lines (215 loc) · 9.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
name: Binary Release
# Auto Release creates the vX.Y.Z tag/release with GITHUB_TOKEN, and a tag
# pushed by GITHUB_TOKEN cannot start a `push: tags` workflow. So this chains
# off Auto Release's completion: it builds the alcatraz CLI (cmd/alcatraz)
# for darwin/linux, uploads the archives and checksums to that release, and
# publishes the Homebrew formula to hoophq/homebrew-tap (the shared tap), so
# users can `brew install hoophq/tap/alcatraz`.
#
# The manual trigger re-publishes binaries for an existing tag — the recovery
# path when a release was cut while this workflow was broken or the tap push
# failed.
on:
workflow_run:
workflows: ["Auto Release"]
types: [completed]
workflow_dispatch:
inputs:
version:
description: "Existing release tag to (re)publish binaries for, without the leading v (e.g. 0.5.0)"
required: true
type: string
permissions:
contents: write
# Serialize runs: back-to-back releases would otherwise race on pushing the
# formula commit to the tap.
concurrency:
group: binary-release
cancel-in-progress: false
jobs:
resolve:
name: Resolve release tag
runs-on: ubuntu-latest
# Auto Release runs on every push to main; act only on successful runs.
# Manual dispatches name their tag explicitly and always proceed.
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
outputs:
publish: ${{ steps.dispatch.outputs.publish || steps.tag.outputs.publish }}
version: ${{ steps.dispatch.outputs.version || steps.tag.outputs.version }}
ref: ${{ steps.dispatch.outputs.ref || steps.tag.outputs.ref }}
steps:
- name: Use the dispatched tag
id: dispatch
if: ${{ github.event_name == 'workflow_dispatch' }}
env:
RAW: ${{ inputs.version }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
# This job has write permissions: refuse to build/upload for a
# malformed version or a tag that has no release.
VERSION="${RAW#v}"
if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::'${RAW}' is not a semver version (want X.Y.Z)"
exit 1
fi
if ! gh release view "v${VERSION}" --repo "${{ github.repository }}" >/dev/null 2>&1; then
echo "::error::release v${VERSION} does not exist in ${{ github.repository }} — create the release first, this workflow only attaches binaries"
exit 1
fi
{
echo "publish=true"
echo "version=${VERSION}"
echo "ref=v${VERSION}"
} >> "$GITHUB_OUTPUT"
echo "Publishing v${VERSION} (manual dispatch)"
- uses: actions/checkout@v4
if: ${{ github.event_name == 'workflow_run' }}
with:
# The exact commit Auto Release ran on. fetch-depth: 0 brings the
# tags so we can read the version tag it created at that commit.
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
- name: Find the release tag at this commit
id: tag
if: ${{ github.event_name == 'workflow_run' }}
run: |
set -euo pipefail
# Auto Release tags the released commit vX.Y.Z, or tags nothing for
# a skip-release PR or a direct push. Bind the published version to
# that tag so source and version always match; skip when absent.
TAG=$(git tag --points-at HEAD | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1 || true)
if [ -z "$TAG" ]; then
echo "No release tag at ${{ github.event.workflow_run.head_sha }}; nothing to publish."
echo "publish=false" >> "$GITHUB_OUTPUT"
else
echo "publish=true" >> "$GITHUB_OUTPUT"
echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
echo "ref=${{ github.event.workflow_run.head_sha }}" >> "$GITHUB_OUTPUT"
echo "Publishing ${TAG}"
fi
binaries:
name: Build archives & update tap
needs: resolve
if: ${{ needs.resolve.outputs.publish == 'true' }}
runs-on: ubuntu-latest
env:
# The secrets context is not allowed in step `if:` expressions, so the
# tap-publish gate is hoisted into job env here.
HAS_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN != '' }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.resolve.outputs.ref }}
- uses: actions/setup-go@v5
with:
go-version: "1.26"
- name: Cross-compile and package archives
env:
VERSION: ${{ needs.resolve.outputs.version }}
run: |
set -euo pipefail
mkdir -p dist
for os in darwin linux; do
for arch in amd64 arm64; do
stage="dist/stage_${os}_${arch}"
mkdir -p "$stage"
CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \
go build -trimpath -ldflags "-s -w -X main.version=v${VERSION}" \
-o "$stage/alcatraz" ./cmd/alcatraz
cp README.md LICENSE "$stage/"
tar -czf "dist/alcatraz_${VERSION}_${os}_${arch}.tar.gz" \
-C "$stage" alcatraz README.md LICENSE
done
done
# Bare globs (no ./ prefix): installers grep checksums.txt for the
# exact archive name.
(cd dist && sha256sum -- *.tar.gz > checksums.txt && cat checksums.txt)
- name: Attach archives to the release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: v${{ needs.resolve.outputs.version }}
run: |
set -euo pipefail
# --clobber lets a re-run replace assets instead of failing on
# "asset already exists". checksums.txt is consumed by installers.
gh release upload "$TAG" dist/*.tar.gz dist/checksums.txt \
--clobber --repo "${{ github.repository }}"
- name: Render the Homebrew formula
env:
VERSION: ${{ needs.resolve.outputs.version }}
run: |
set -euo pipefail
sha() { grep "alcatraz_${VERSION}_$1.tar.gz" dist/checksums.txt | awk '{print $1}'; }
base="https://github.com/${{ github.repository }}/releases/download/v${VERSION}"
cat > dist/alcatraz.rb <<EOF
class Alcatraz < Formula
desc "Known-pattern PII detection CLI - in-process, no service, no network"
homepage "https://github.com/hoophq/alcatraz"
version "${VERSION}"
license "MIT"
on_macos do
on_arm do
url "${base}/alcatraz_${VERSION}_darwin_arm64.tar.gz"
sha256 "$(sha darwin_arm64)"
end
on_intel do
url "${base}/alcatraz_${VERSION}_darwin_amd64.tar.gz"
sha256 "$(sha darwin_amd64)"
end
end
on_linux do
on_arm do
url "${base}/alcatraz_${VERSION}_linux_arm64.tar.gz"
sha256 "$(sha linux_arm64)"
end
on_intel do
url "${base}/alcatraz_${VERSION}_linux_amd64.tar.gz"
sha256 "$(sha linux_amd64)"
end
end
def install
bin.install "alcatraz"
end
test do
assert_match version.to_s, shell_output("#{bin}/alcatraz version")
end
end
EOF
cat dist/alcatraz.rb
- name: Tap publish skipped (no HOMEBREW_TAP_TOKEN)
if: ${{ env.HAS_TAP_TOKEN != 'true' }}
run: echo "::warning::HOMEBREW_TAP_TOKEN is not set — release assets are published, but Formula/alcatraz.rb was not pushed to hoophq/homebrew-tap."
- name: Check out the tap
if: ${{ env.HAS_TAP_TOKEN == 'true' }}
uses: actions/checkout@v4
with:
# A cross-repo push needs a token with write access to the tap; the
# default GITHUB_TOKEN is scoped to this repo only. Same secret the
# other hoop tools use for their tap publishes.
repository: hoophq/homebrew-tap
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: tap
- name: Update and push the formula
if: ${{ env.HAS_TAP_TOKEN == 'true' }}
env:
VERSION: ${{ needs.resolve.outputs.version }}
run: |
set -euo pipefail
mkdir -p tap/Formula
cp dist/alcatraz.rb tap/Formula/alcatraz.rb
cd tap
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/alcatraz.rb
# A re-run produces identical archives and checksums, so there may
# be nothing to commit.
if git diff --cached --quiet; then
echo "Formula already up to date for v${VERSION}; nothing to push."
else
git commit -m "alcatraz ${VERSION}"
# The tap may have moved since checkout (another tool releasing);
# rebase our formula commit on top instead of failing.
git pull --rebase origin main
git push origin main
fi