-
Notifications
You must be signed in to change notification settings - Fork 2
209 lines (181 loc) · 8.57 KB
/
release-tag.yml
File metadata and controls
209 lines (181 loc) · 8.57 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
name: Release Tag - Create Version Tag
on:
workflow_call:
inputs:
version:
description: 'Release version (e.g., vX.Y.Z). Must start with "v".'
required: true
type: string
outputs:
release_name:
description: 'The release name without "v" prefix (e.g., X.Y.Z)'
value: ${{ jobs.create-tag.outputs.release_name }}
tag_sha:
description: 'The commit SHA that the tag points to'
value: ${{ jobs.create-tag.outputs.tag_sha }}
version:
description: 'The full version string with "v" prefix (e.g., vX.Y.Z)'
value: ${{ jobs.create-tag.outputs.version }}
# Note: This workflow is called exclusively via workflow_call from release.yml.
# It does NOT have a workflow_dispatch trigger to keep release.yml as the single
# entry point for all release operations.
permissions:
contents: read
jobs:
create-tag:
name: Create Version Tag
runs-on: ubuntu-latest
environment: release-tag
permissions:
contents: write
outputs:
release_name: ${{ steps.version.outputs.release_name }}
tag_sha: ${{ steps.final-sha.outputs.tag_sha }}
version: ${{ steps.version.outputs.version }}
steps:
- name: Tag - Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
fetch-tags: true
- name: Tag - Validate and parse version
id: version
run: |
VERSION="${{ inputs.version }}"
# Validate version starts with 'v'
if [[ ! "${VERSION}" =~ ^v ]]; then
echo "::error::Version '${VERSION}' must start with 'v'"
exit 1
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "release_name=${VERSION#v}" >> $GITHUB_OUTPUT
- name: Tag - Check if tag already exists
id: check-tag
run: |
TAG="${{ steps.version.outputs.version }}"
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
if git rev-parse "refs/tags/${TAG}" >/dev/null 2>&1; then
TAG_SHA=$(git rev-parse "refs/tags/${TAG}^{commit}" 2>/dev/null || git rev-parse "refs/tags/${TAG}")
echo "ℹ️ Tag ${TAG} already exists at commit ${TAG_SHA:0:8}"
# Verify version-bearing files at the tagged commit match the release
TAG_SERVER_VERSION=$(git show "${TAG_SHA}:server/package.json" \
| grep -m1 '"version"' \
| sed 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
if [[ "${TAG_SERVER_VERSION}" == "${RELEASE_NAME}" ]]; then
echo "tag_exists=true" >> $GITHUB_OUTPUT
echo "tag_sha=${TAG_SHA}" >> $GITHUB_OUTPUT
echo "✅ Existing tag ${TAG} has correct version (${RELEASE_NAME})"
else
echo "⚠️ Version mismatch at tag ${TAG}: found ${TAG_SERVER_VERSION}, expected ${RELEASE_NAME}"
echo " Removing stale tag to recreate with correct versions..."
git tag -d "${TAG}" 2>/dev/null || true
git push origin ":refs/tags/${TAG}" 2>/dev/null || true
echo "tag_exists=false" >> $GITHUB_OUTPUT
echo "ℹ️ Stale tag ${TAG} removed — will recreate with updated versions"
fi
else
echo "tag_exists=false" >> $GITHUB_OUTPUT
echo "ℹ️ Tag ${TAG} does not exist yet"
fi
- name: Tag - Setup CodeQL environment
if: steps.check-tag.outputs.tag_exists != 'true'
uses: ./.github/actions/setup-codeql-environment
with:
add-to-path: true
install-language-runtimes: false
- name: Tag - Setup Node.js
if: steps.check-tag.outputs.tag_exists != 'true'
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
cache: 'npm'
node-version-file: '.node-version'
- name: Tag - Update release version
if: steps.check-tag.outputs.tag_exists != 'true'
run: |
TAG_VERSION="${{ steps.version.outputs.release_name }}"
echo "Updating all version-bearing files to '${TAG_VERSION}'..."
./server/scripts/update-release-version.sh "${TAG_VERSION}"
- name: Tag - Install dependencies
if: steps.check-tag.outputs.tag_exists != 'true'
run: npm install --include=optional --ignore-scripts
- name: Tag - Install CodeQL pack dependencies
if: steps.check-tag.outputs.tag_exists != 'true'
run: server/scripts/install-packs.sh
- name: Tag - Tidy (lint and format)
if: steps.check-tag.outputs.tag_exists != 'true'
run: npm run tidy
- name: Tag - Build server
if: steps.check-tag.outputs.tag_exists != 'true'
run: npm run build -w server
- name: Tag - Run tests
if: steps.check-tag.outputs.tag_exists != 'true'
run: npm run test:server
- name: Tag - Commit version changes and create tag
id: create-tag
if: steps.check-tag.outputs.tag_exists != 'true'
run: |
TAG="${{ steps.version.outputs.version }}"
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
# Configure git
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# workflow_call checkouts may leave us in detached HEAD when the
# caller is triggered from a tag ref. Create a temporary local
# branch so that `git commit` and `git tag` work correctly.
TEMP_BRANCH="tmp/release-${TAG}"
git checkout -B "${TEMP_BRANCH}"
# Stage version-bearing files and lockfile changes
git add -A
# Ensure CodeQL-generated artifacts are not staged for commit
git restore --staged .codeql 2>/dev/null || true
git restore --staged '*.qlx' 2>/dev/null || true
# Check if there are changes to commit
if git diff --cached --quiet; then
echo "ℹ️ No changes to commit (versions already up to date)"
CURRENT_SHA=$(git rev-parse HEAD)
else
git commit -m "Release ${TAG}: update versions to ${RELEASE_NAME}"
CURRENT_SHA=$(git rev-parse HEAD)
echo "✅ Committed version changes at ${CURRENT_SHA:0:8}"
fi
# Create the annotated tag on the (possibly new) commit and push
# it. We intentionally do NOT push the commit to main because
# branch protection rules require PRs and status checks. The
# tagged commit is reachable via the tag ref and is used by all
# downstream release jobs to build artifacts.
git tag -a "${TAG}" -m "Release ${TAG}" "${CURRENT_SHA}"
git push origin "refs/tags/${TAG}"
echo "✅ Created and pushed tag ${TAG} at commit ${CURRENT_SHA:0:8}"
echo "tag_sha=${CURRENT_SHA}" >> $GITHUB_OUTPUT
- name: Tag - Output existing tag SHA
id: existing-tag
if: steps.check-tag.outputs.tag_exists == 'true'
run: |
echo "tag_sha=${{ steps.check-tag.outputs.tag_sha }}" >> $GITHUB_OUTPUT
- name: Tag - Set final tag SHA output
id: final-sha
run: |
if [ "${{ steps.check-tag.outputs.tag_exists }}" == "true" ]; then
SHA="${{ steps.check-tag.outputs.tag_sha }}"
else
SHA="${{ steps.create-tag.outputs.tag_sha }}"
fi
echo "tag_sha=${SHA}" >> $GITHUB_OUTPUT
- name: Tag - Summary
run: |
TAG="${{ steps.version.outputs.version }}"
echo "## Release Tag Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.check-tag.outputs.tag_exists }}" == "true" ]; then
echo "ℹ️ Tag \`${TAG}\` already existed at \`${{ steps.check-tag.outputs.tag_sha }}\`" >> $GITHUB_STEP_SUMMARY
else
echo "✅ Created tag \`${TAG}\` at \`${{ steps.create-tag.outputs.tag_sha }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Step | Status |" >> $GITHUB_STEP_SUMMARY
echo "| ---- | ------ |" >> $GITHUB_STEP_SUMMARY
echo "| Version update | ✅ All files updated to ${{ steps.version.outputs.release_name }} |" >> $GITHUB_STEP_SUMMARY
echo "| Tidy (lint + format) | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
echo "| Build | ✅ Success |" >> $GITHUB_STEP_SUMMARY
echo "| Tests | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
echo "| Tag creation | ✅ ${TAG} |" >> $GITHUB_STEP_SUMMARY
fi