-
Notifications
You must be signed in to change notification settings - Fork 0
180 lines (158 loc) · 6.44 KB
/
release.yml
File metadata and controls
180 lines (158 loc) · 6.44 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
name: Release
on:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
dry_run:
description: 'Dry run (skip tag push, release creation, and proxy trigger)'
required: false
type: boolean
default: false
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
fetch-tags: true
- name: Authorize release actor
run: |
ACTOR="${{ github.actor }}"
ALLOWED=""
if [ -f CODEOWNERS ]; then
ALLOWED="$ALLOWED $(grep -oP '@\K[\w-]+' CODEOWNERS | sort -u)"
fi
if [ -f RELEASERS ]; then
ALLOWED="$ALLOWED $(grep -vE '^\s*(#|$)' RELEASERS | tr -s '[:space:]' ' ')"
fi
for user in $ALLOWED; do
if [ "$ACTOR" = "$user" ]; then
echo "Authorized: $ACTOR is in CODEOWNERS or RELEASERS"
exit 0
fi
done
echo "::error::$ACTOR is not authorized to create releases. Only users listed in CODEOWNERS or RELEASERS may trigger this workflow."
exit 1
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
- name: Determine next version
id: version
run: |
LATEST=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
if [ -z "$LATEST" ]; then
LATEST="v0.0.0"
fi
echo "current=$LATEST" >> "$GITHUB_OUTPUT"
MAJOR=$(echo "$LATEST" | sed 's/^v//' | cut -d. -f1)
MINOR=$(echo "$LATEST" | sed 's/^v//' | cut -d. -f2)
PATCH=$(echo "$LATEST" | sed 's/^v//' | cut -d. -f3)
case "${{ inputs.bump }}" in
major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;;
minor) MINOR=$((MINOR + 1)); PATCH=0 ;;
patch) PATCH=$((PATCH + 1)) ;;
esac
NEXT="v${MAJOR}.${MINOR}.${PATCH}"
echo "next=$NEXT" >> "$GITHUB_OUTPUT"
echo "### Version bump: $LATEST → $NEXT (${{ inputs.bump }})" >> "$GITHUB_STEP_SUMMARY"
- name: Verify CI passed on HEAD
run: |
HEAD_SHA=$(git rev-parse HEAD)
echo "Checking CI status for $HEAD_SHA..."
CONCLUSION=$(gh run list --commit "$HEAD_SHA" --workflow ci.yml --json conclusion --jq '.[0].conclusion // "none"')
if [ "$CONCLUSION" != "success" ]; then
echo "::error::CI has not passed on HEAD ($HEAD_SHA). Latest conclusion: $CONCLUSION"
exit 1
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify CHANGELOG has entry for next version
run: |
NEXT="${{ steps.version.outputs.next }}"
if ! grep -q "## $NEXT" CHANGELOG.md; then
echo "::error::CHANGELOG.md does not contain an entry for $NEXT. Add the changelog entry before releasing."
exit 1
fi
- name: Build and test
run: |
make build
make test-race
- name: Extract changelog for release notes
id: notes
run: |
NEXT="${{ steps.version.outputs.next }}"
NOTES=$(awk "/^## $NEXT/{flag=1; next} /^## v[0-9]/{flag=0} flag" CHANGELOG.md)
{
echo "body<<RELEASE_NOTES_EOF"
echo "$NOTES"
echo "RELEASE_NOTES_EOF"
} >> "$GITHUB_OUTPUT"
- name: Create annotated tag
if: ${{ !inputs.dry_run }}
run: |
NEXT="${{ steps.version.outputs.next }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag -a "$NEXT" -m "$NEXT"
git push origin "$NEXT"
- name: Create GitHub release
if: ${{ !inputs.dry_run }}
run: |
NEXT="${{ steps.version.outputs.next }}"
gh release create "$NEXT" \
--title "$NEXT" \
--notes "$RELEASE_NOTES" \
--verify-tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_NOTES: ${{ steps.notes.outputs.body }}
- name: Trigger Go module proxy indexing
if: ${{ !inputs.dry_run }}
run: |
NEXT="${{ steps.version.outputs.next }}"
MODULE=$(head -1 go.mod | awk '{print $2}')
echo "Requesting proxy indexing for ${MODULE}@${NEXT}..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://proxy.golang.org/${MODULE}/@v/${NEXT}.info")
echo "Proxy response: $HTTP_CODE"
if [ "$HTTP_CODE" -ge 400 ]; then
echo "::warning::Go module proxy returned $HTTP_CODE — indexing may be delayed"
fi
- name: Verify pkg.go.dev availability
if: ${{ !inputs.dry_run }}
run: |
NEXT="${{ steps.version.outputs.next }}"
MODULE=$(head -1 go.mod | awk '{print $2}')
echo "Waiting for pkg.go.dev to index ${MODULE}@${NEXT}..."
for i in 1 2 3 4 5; do
sleep 15
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://pkg.go.dev/${MODULE}@${NEXT}")
echo "Attempt $i: HTTP $HTTP_CODE"
if [ "$HTTP_CODE" -eq 200 ]; then
echo "pkg.go.dev is serving ${MODULE}@${NEXT}"
echo "### pkg.go.dev: [${MODULE}@${NEXT}](https://pkg.go.dev/${MODULE}@${NEXT})" >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
done
echo "::warning::pkg.go.dev has not indexed ${NEXT} yet — check manually at https://pkg.go.dev/${MODULE}@${NEXT}"
- name: Summary
run: |
NEXT="${{ steps.version.outputs.next }}"
CURRENT="${{ steps.version.outputs.current }}"
if [ "${{ inputs.dry_run }}" = "true" ]; then
echo "### Dry run complete" >> "$GITHUB_STEP_SUMMARY"
echo "Would have tagged **$NEXT** (from $CURRENT, ${{ inputs.bump }} bump)" >> "$GITHUB_STEP_SUMMARY"
else
echo "### Release $NEXT published" >> "$GITHUB_STEP_SUMMARY"
echo "- Tag: [$NEXT](https://github.com/${{ github.repository }}/releases/tag/$NEXT)" >> "$GITHUB_STEP_SUMMARY"
echo "- Bump: $CURRENT → $NEXT (${{ inputs.bump }})" >> "$GITHUB_STEP_SUMMARY"
fi