-
Notifications
You must be signed in to change notification settings - Fork 4
260 lines (232 loc) · 10.8 KB
/
release-tag.yml
File metadata and controls
260 lines (232 loc) · 10.8 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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
name: Release Tag - Create Version Tag
on:
workflow_call:
inputs:
version:
description: 'Release version (e.g., vX.Y.Z or vX.Y.Z-suffix). Must start with "v".'
required: true
type: string
outputs:
release_name:
description: 'The release name without "v" prefix (e.g., X.Y.Z or X.Y.Z-alpha)'
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 or vX.Y.Z-alpha)'
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 }}"
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_exists=true" >> $GITHUB_OUTPUT
echo "tag_sha=${TAG_SHA}" >> $GITHUB_OUTPUT
echo "ℹ️ Tag ${TAG} already exists at commit ${TAG_SHA:0:8}"
else
echo "tag_exists=false" >> $GITHUB_OUTPUT
echo "ℹ️ Tag ${TAG} does not exist yet"
fi
- name: Tag - Validate existing tag versions
id: validate-existing
if: steps.check-tag.outputs.tag_exists == 'true'
run: |
TAG="${{ steps.version.outputs.version }}"
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
echo "Validating versions on existing tag ${TAG}..."
git checkout "refs/tags/${TAG}" --quiet
chmod +x ./scripts/update-release-version.sh
if ./scripts/update-release-version.sh --check "${RELEASE_NAME}"; then
echo "✅ Existing tag ${TAG} has correct versions"
echo "versions_valid=true" >> $GITHUB_OUTPUT
else
echo ""
echo "⚠️ Existing tag ${TAG} has incorrect versions — will delete and recreate"
git checkout - --quiet
git tag -d "${TAG}" 2>/dev/null || true
git push origin --delete "${TAG}" 2>/dev/null || true
echo "versions_valid=false" >> $GITHUB_OUTPUT
fi
- name: Tag - Determine if tag creation is needed
id: needs-creation
run: |
if [ "${{ steps.check-tag.outputs.tag_exists }}" != "true" ]; then
echo "needed=true" >> $GITHUB_OUTPUT
echo "ℹ️ Tag does not exist — creation needed"
elif [ "${{ steps.validate-existing.outputs.versions_valid }}" != "true" ]; then
echo "needed=true" >> $GITHUB_OUTPUT
echo "ℹ️ Existing tag had wrong versions — recreation needed"
else
echo "needed=false" >> $GITHUB_OUTPUT
echo "ℹ️ Existing tag is valid — no creation needed"
fi
- name: Tag - Update release version
if: steps.needs-creation.outputs.needed == 'true'
run: |
TAG_VERSION="${{ steps.version.outputs.release_name }}"
echo "Updating all version-bearing files to '${TAG_VERSION}'..."
chmod +x ./scripts/update-release-version.sh
./scripts/update-release-version.sh "${TAG_VERSION}"
- name: Tag - Install CodeQL via GitHub CLI
if: steps.needs-creation.outputs.needed == 'true'
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
CODEQL_VERSION=$(jq -r .CodeQLCLI qlt.conf.json)
echo "Installing CodeQL CLI ${CODEQL_VERSION} via gh-codeql..."
gh extension install github/gh-codeql
gh codeql set-version "${CODEQL_VERSION}"
STUB_DIR="$HOME/.local/bin"
mkdir -p "${STUB_DIR}"
gh codeql install-stub "${STUB_DIR}/"
echo "${STUB_DIR}" >> "$GITHUB_PATH"
export PATH="${STUB_DIR}:${PATH}"
echo "CodeQL version: $(codeql version --format=terse)"
- name: Tag - Upgrade CodeQL pack lock files
if: steps.needs-creation.outputs.needed == 'true'
shell: bash
run: |
echo "Upgrading CodeQL pack lock files"
find . -name "qlpack.yml" -type f | sort | while read -r qlpack_file; do
pack_dir=$(dirname "$qlpack_file")
echo "Upgrading pack in directory: $pack_dir"
cd "$pack_dir"
codeql pack upgrade
cd - > /dev/null
done
echo "Finished upgrading all CodeQL pack lock files"
- name: Tag - Setup Node.js for CDS compilation
if: steps.needs-creation.outputs.needed == 'true'
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: 'extractors/cds/tools/package-lock.json'
- name: Tag - Compile CAP CDS files
if: steps.needs-creation.outputs.needed == 'true'
run: |
chmod +x ./extractors/cds/tools/workflow/cds-compilation-for-actions.sh
./extractors/cds/tools/workflow/cds-compilation-for-actions.sh
- name: Tag - Run CodeQL unit tests
if: steps.needs-creation.outputs.needed == 'true'
env:
LGTM_INDEX_XML_MODE: all
LGTM_INDEX_FILETYPES: ".json:JSON\n.cds:JSON"
shell: bash
run: |
echo "Running CodeQL unit tests to validate release..."
codeql test run \
--threads=0 \
--strict-test-discovery \
--additional-packs="${GITHUB_WORKSPACE}" \
-- javascript/
- name: Tag - Validate version consistency
if: steps.needs-creation.outputs.needed == 'true'
run: |
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
echo "Validating all version-bearing files match ${RELEASE_NAME}..."
./scripts/update-release-version.sh --check "${RELEASE_NAME}"
- name: Tag - Commit version changes and create tag
id: create-tag
if: steps.needs-creation.outputs.needed == '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"
# Detach HEAD so we never push to a protected branch.
# The version-update commit will only be reachable via the tag.
git checkout --detach HEAD
# Stage version-bearing files and lockfile changes
git add -A
# Ensure generated artifacts (CodeQL, CAP compilation) are not staged
git restore --staged .codeql 2>/dev/null || true
git restore --staged '*.qlx' 2>/dev/null || true
git restore --staged 'javascript/frameworks/cap/test/**/model.cds.json' 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 "✅ Created version commit at ${CURRENT_SHA:0:8}"
fi
# Push only the tag — never the branch
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.needs-creation.outputs.needed == 'false'
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.needs-creation.outputs.needed }}" == "false" ]; 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.needs-creation.outputs.needed }}" == "false" ]; then
echo "ℹ️ Tag \`${TAG}\` already existed at \`${{ steps.check-tag.outputs.tag_sha }}\` with correct versions" >> $GITHUB_STEP_SUMMARY
else
echo "✅ Created tag \`${TAG}\` at \`${{ steps.create-tag.outputs.tag_sha }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.check-tag.outputs.tag_exists }}" == "true" ]; then
echo "⚠️ Previous tag had incorrect versions and was replaced" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
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 "| Pack lock upgrade | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
echo "| CodeQL unit tests | ✅ Passed |" >> $GITHUB_STEP_SUMMARY
echo "| Version consistency | ✅ All files match |" >> $GITHUB_STEP_SUMMARY
echo "| Tag creation | ✅ ${TAG} |" >> $GITHUB_STEP_SUMMARY
fi