-
Notifications
You must be signed in to change notification settings - Fork 0
303 lines (257 loc) · 13 KB
/
release.yaml
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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
name: Release Pipeline
on:
workflow_dispatch:
inputs:
version:
description: "Release version tag (required format: v[mayor].[minor].[bugfix], e.g. v1.3.0)"
type: string
required: true
draft:
description: Should a release draft be created? (Otherwise the release will be published immediately)
type: boolean
default: true
required: true
artifact:
description: Add artifacts to the release. All files from /docs are added to the release.
type: boolean
default: true
required: false
force:
description: "If force is true, already published releases can be overwritten. Caution: This action deletes already published releases and can **not** be undone!"
type: boolean
required: false
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Check user permission
id: permission_check
run: |
if [[ "${{ github.actor }}" != "msacrea" && "${{ github.actor }}" != "micmuell" && "${{ github.actor }}" != "dkoeni" && "${{ github.actor }}" != "juergen-petry" ]]; then
echo "You have no permissons to start the release action."
exit 1
fi
- name: Validate input parameters
id: param_check
run: |
VERSION_REGEX="^v[0-9]+\.[0-9]+\.[0-9]+$"
version=${{ github.event.inputs.version }}
if [[ ! "$version" =~ $VERSION_REGEX ]]; then
echo "Invalid version format: $version . Please provide a version matching the pattern 'v[number].[number].[number]'."
exit 1
fi
- name: Checkout repository
uses: actions/checkout@v4
- name: Checkout Wiki
uses: actions/checkout@v4
with:
repository: ${{github.repository}}.wiki
path: wiki
- name: Extract variables for Release # Adjust names only here
id: var
run: |
version=$(echo ${{ github.event.inputs.version }} | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') # alternative: '[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]'
repo_name=$( echo ${{ github.repository }} | sed -E "s/^.*\///" )
echo "VERSION"=$version >> $GITHUB_OUTPUT
echo "RELEASE_NAME=$repo_name Release $version" >> $GITHUB_OUTPUT
echo "RELEASE_TAG=v$version" >> $GITHUB_OUTPUT
echo "RELEASE_BRANCH=main" >> $GITHUB_OUTPUT
echo "RELEASE_NOTES=RELEASE.md" >> $GITHUB_OUTPUT
echo "RELEASE_ASSETS_FOLDER=docs/" >> $GITHUB_OUTPUT
echo "RELEASE_ASSETS_NAME=artifact" >> $GITHUB_OUTPUT
- name: Get release note content from wiki
id: release_note_body
run: |
regex="### Release ${{ steps.var.outputs.RELEASE_TAG }}[[:space:]]*[[:print:]]*[[:cntrl:]]{2}([[:print:]]+[[:space:]])*"
content=$(grep -ozE "$regex" wiki/Roadmap.md | tr "\0" "\n" | tail -n +3)
# abort if content is empty --> wiki page must be present before release
if [ -z "$content" ]; then
echo "Found no data for ${{ steps.var.outputs.RELEASE_NAME }} at wiki/Roadmap (${{ github.repository }}). Please create a section <<Release ${{ steps.var.outputs.RELEASE_TAG }}>> and fill in details for the release by following the instructions at the .github Wiki. A template can be found at https://github.com/swissfintechinnovations/.github/wiki/Roadmap-Example."
exit 1
fi
body="$content"$'\n\n# \n\n'
echo "BODY=${body//$'\n'/'\n'}" >> $GITHUB_OUTPUT
- name: Check file version
id: check_version
run: |
BASE_BRANCH="${{ steps.var.outputs.RELEASE_BRANCH }}"
git checkout -q origin/$BASE_BRANCH
release_version=${{ steps.var.outputs.VERSION }}
versions=$(grep -Eo 'version: [0-9]+\.[0-9]+\.[0-9]+' *.yaml | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+')
versions_outdated='false'
for version in $versions; do
if [[ $version != $release_version ]]; then
versions_outdated='true'
break
fi
done
echo "VERSIONS_OUTDATED=$versions_outdated" >> $GITHUB_OUTPUT
- name: Switch to release branch
id: create_release_branch
if: steps.check_version.outputs.VERSIONS_OUTDATED == 'true'
run: |
BASE_BRANCH="${{ steps.var.outputs.RELEASE_BRANCH }}"
BRANCH_NAME="release/${{ steps.var.outputs.VERSION }}"
git config --global user.name "sfti bot"
git config --global user.email "github-bot@common-api.ch"
git checkout -q origin/$BASE_BRANCH
git checkout $BRANCH_NAME 2>/dev/null || git checkout -b $BRANCH_NAME # checkout branch or create new one if not exists
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT
- name: Update version in files
id: update_version
if: steps.check_version.outputs.VERSIONS_OUTDATED == 'true'
run: |
VERSION="${{ steps.var.outputs.VERSION }}"
RELEASE_NAME="${{ steps.var.outputs.RELEASE_NAME }}"
BRANCH_NAME="${{ steps.create_release_branch.outputs.BRANCH_NAME }}"
echo "Prepare Release $RELEASE_NAME: update version number in yaml files"
sed -E -i "s/version: [0-9]+\.[0-9]+\.[0-9]+/version: $VERSION/" *.yaml
git add -u .
# commit only if there was changes in the yaml files
git diff --staged --quiet || git commit -m "Automated version update"
# git commit --quiet --allow-empty -m '[skip-workflow]'
git push --quiet --set-upstream origin $BRANCH_NAME
- name: "Rollback: Delete Branch"
if: failure() && steps.update_version.outcome == 'failure'
run: |
git checkout -q main
git branch -D ${{ steps.create_release_branch.outputs.BRANCH_NAME }}
git push origin --delete ${{ steps.create_release_branch.outputs.BRANCH_NAME }}
- name: Create and merge Pull Request
id: create_pr
if: steps.check_version.outputs.VERSIONS_OUTDATED == 'true'
run: |
BASE_BRANCH=${{ steps.var.outputs.RELEASE_BRANCH }}
response=$(gh pr create -B $BASE_BRANCH -H ${{ steps.create_release_branch.outputs.BRANCH_NAME }} --title 'Automated version update to version ${{ steps.var.outputs.VERSION }}' --body 'Created by Github action (release workflow)')
number=$(echo "$response" | grep -oE '[0-9]+$') # parse GitHub PR link to extract PR number
echo "PR_NUMBER=$number" >> $GITHUB_OUTPUT
sleep 2
# gh pr review $number --approve # can not approve own PR
gh pr merge $number --admin --merge --delete-branch --body "Automated version update" # force merge since PR is not approved (--admin flag)
git checkout $BASE_BRANCH
env:
GITHUB_TOKEN: ${{ secrets.SFTI_BOT_TOKEN }}
- name: "Rollback: Delete PR"
if: failure() && steps.create_pr.outcome == 'failure'
run: |
gh pr close ${{ steps.create_pr.outputs.PR_NUMBER }} -c "Couldn't merge PR automatically" --delete-branch
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Delete release (draft) if already exists
id: delete_release_draft
run: |
ACCESS_TOKEN=${{ secrets.GITHUB_TOKEN }}
REPO_NAME=${{ github.repository }}
TAG=${{ steps.var.outputs.RELEASE_TAG }}
RELEASE_NAME="${{ steps.var.outputs.RELEASE_NAME }}"
# Get the release ID belonging to the release tag
RELEASE_ID=$(curl -sS -X GET -H "Authorization: Bearer $ACCESS_TOKEN" "https://api.github.com/repos/$REPO_NAME/releases" | jq -r ".[] | select(.name == \"$RELEASE_NAME\") | .id")
# RELEASE_ID var contains 0 or 1 IDs
if [[ ! $RELEASE_ID =~ ^[0-9]*$ ]]; then
echo "Found more than one release with name \"$RELEASE_ID\"."
exit 1
fi
is_draft=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/$REPO_NAME/releases/$RELEASE_ID | jq '.draft')
if [[ "$is_draft" == 'false' ]]; then
echo "Release is published."
if [[ ${{ github.event.inputs.force }} == true ]]; then
commit_id=$(git rev-list -n 1 "refs/tags/$TAG")
echo $commit_id
git tag -d $TAG
git push origin ":refs/tags/$TAG"
echo "Force Flag is set! Deleted tag $TAG at commit ID $commit_id."
fi
if [[ ${{ github.event.inputs.force }} == false ]]; then
echo "Release $TAG already exists. Please verify that the version entered is correct. Set the force flag to overwrite the release."
exit 1
fi
fi
if [[ -n "$RELEASE_ID" ]]; then
# Delete the existing release draft
curl -sS -X DELETE -H "Authorization: Bearer $ACCESS_TOKEN" "https://api.github.com/repos/$REPO_NAME/releases/$RELEASE_ID"
echo "Deleted release \"$RELEASE_ID\" with ID $RELEASE_ID"
fi
- name: Create release draft
id: create_release_draft
run: |
ACCESS_TOKEN=${{ secrets.GITHUB_TOKEN }}
REPO_NAME=${{ github.repository }}
RESPONSE=$(curl -sS -i -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/$REPO_NAME/releases" \
-d '{
"tag_name": "'"${{ steps.var.outputs.RELEASE_TAG }}"'",
"target_commitish": "'"${{ steps.var.outputs.RELEASE_BRANCH }}"'",
"name": "'"${{ steps.var.outputs.RELEASE_NAME }}"'",
"name": "'"${{ steps.var.outputs.RELEASE_NAME }}"'",
"body": "'"${{ steps.release_note_body.outputs.BODY }}"'",
"generate_release_notes": true,
"draft": true
}')
if [[ $(echo $RESPONSE | head -n 1 | cut -d$' ' -f2 ) -ne 201 ]]; then
echo "Failed to create release draft. Received response from GitHub API:"
echo ""
echo "$RESPONSE"
exit 1
fi
echo "RELEASE_ID=$(echo $RESPONSE | grep -o -z '\{.*\}' | jq -r '.id')" >> $GITHUB_OUTPUT
- name: Upload artifacts
id: upload_artifact
# ensure assert folder exsits and not empty otherwise skip step
if: github.event.inputs.artifact == 'true' && (hashFiles(steps.var.outputs.RELEASE_ASSETS_FOLDER) != '')
run: |
ACCESS_TOKEN=${{ secrets.GITHUB_TOKEN }}
REPO_NAME=${{ github.repository }}
RELEASE_ID=${{ steps.create_release_draft.outputs.RELEASE_ID }}
RELEASE_ASSETS_FOLDER=${{ steps.var.outputs.RELEASE_ASSETS_FOLDER }}
RELEASE_ASSETS_NAME=${{ steps.var.outputs.RELEASE_ASSETS_NAME }}
RELEASE_ASSETS_ZIP=$RELEASE_ASSETS_NAME.zip
RELEASE_ASSETS_TARGZ=$RELEASE_ASSETS_NAME.tar.gz
zip -qr $RELEASE_ASSETS_ZIP $RELEASE_ASSETS_FOLDER
RESPONSE=$(curl -sS -i -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/octet-stream" \
"https://uploads.github.com/repos/$REPO_NAME/releases/$RELEASE_ID/assets?name=$RELEASE_ASSETS_ZIP" \
--data-binary "@$RELEASE_ASSETS_ZIP" )
if [[ $(echo $RESPONSE | head -n 1 | cut -d$' ' -f2 ) -ne 201 ]]; then
echo "Failed to upload release asset $RELEASE_ASSETS_ZIP. Received response from GitHub API:"
echo ""
echo "$RESPONSE"
exit 1
fi
tar -czf $RELEASE_ASSETS_TARGZ $RELEASE_ASSETS_FOLDER
RESPONSE=$(curl -sS -i -X POST -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/octet-stream" \
--data-binary "@$RELEASE_ASSETS_TARGZ" \
"https://uploads.github.com/repos/$REPO_NAME/releases/$RELEASE_ID/assets?name=$RELEASE_ASSETS_TARGZ")
if [[ $(echo $RESPONSE | head -n 1 | cut -d$' ' -f2 ) -ne 201 ]]; then
echo "Failed to upload release asset $RELEASE_ASSETS_TARGZ. Received response from GitHub API:"
echo ""
echo "$RESPONSE"
exit 1
fi
- name: Publish release
if: github.event.inputs.draft == 'false'
id: publish_release
run: |
ACCESS_TOKEN=${{ secrets.GITHUB_TOKEN }}
REPO_NAME=${{ github.repository }}
RELEASE_ID=${{ steps.create_release_draft.outputs.RELEASE_ID }}
RESPONSE=$(curl -sS -i -X PATCH \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/$REPO_NAME/releases/$RELEASE_ID" \
-d '{
"prerelease": false,
"draft": false,
"make_latest": "true"
}')
if [[ $(echo $RESPONSE | head -n 1 | cut -d$' ' -f2 ) -ne 200 ]]; then
echo "Failed to publish release. Received response from GitHub API:"
echo ""
echo "$RESPONSE"
exit 1
fi