-
Notifications
You must be signed in to change notification settings - Fork 80
202 lines (181 loc) · 8.2 KB
/
Copy pathrelease.yml
File metadata and controls
202 lines (181 loc) · 8.2 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
# Cuts tagged releases for the public code-interpreter repo. Like ci.yml this
# file is inert inside the monorepo — GitHub only runs workflows from the repo
# root — and becomes a root workflow in the published repo.
#
# Three entry points feed one job:
#
# * successful CI on main — automatically releases deployable changes. The
# next repository version follows Conventional Commit intent; changes that
# only touch docs, workflows, or tests do not cut a release.
#
# * workflow_dispatch — pick a version in the Actions UI. The chart is
# packaged before the tag is created, so a packaging failure aborts while
# the release is still un-cut and the version is still free to reuse.
# * push of a v* tag — for tags cut locally with `git tag -a … && git push`.
# Tags this workflow pushes itself carry GITHUB_TOKEN, and GitHub does not
# re-trigger workflows for those, so the two paths never double-publish.
#
# `main` accepts no direct pushes (see CONTRIBUTING.md), but the branch
# ruleset does not cover tags, so the job can create them. GITHUB_TOKEN
# defaults to read-only in this repository; the explicit `contents: write`
# below is what lets the tag push and the release upload through.
name: Release
on:
workflow_run:
workflows: ['CI']
branches: [main]
types: [completed]
workflow_dispatch:
inputs:
version:
description: 'Repository version to release, e.g. v1.0.0 or v1.1.0-rc1.'
required: true
type: string
draft:
description: 'Publish as a draft so the notes can be edited before going public'
type: boolean
default: false
push:
tags:
- 'v*'
permissions:
contents: write
concurrency:
# Automatic runs serialize against one another. If main advances before an
# older run starts, version resolution skips the stale SHA and the newest
# successful run releases the full range instead.
group: release-${{ github.event_name == 'workflow_run' && 'main' || github.event.inputs.version || github.ref_name }}
cancel-in-progress: false
jobs:
release:
name: Tag and publish
if: >-
github.event_name != 'workflow_run' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main')
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
# `workflow_run` can be rerun for a commit older than this resolver. Save
# the helper from the revision that supplied this workflow before the
# release checkout replaces the working tree with that historical SHA.
- name: Checkout release workflow
if: github.event_name == 'workflow_run'
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 1
ref: ${{ github.workflow_sha }}
- name: Preserve release resolver
if: github.event_name == 'workflow_run'
run: install -m 755 .github/scripts/resolve-release-version.sh "$RUNNER_TEMP/resolve-release-version.sh"
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
# Full history and tags: resolving whether this release is the newest
# stable one compares it against every other tag in the repository.
fetch-depth: 0
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.ref }}
- name: Resolve and validate version
id: version
env:
EVENT_NAME: ${{ github.event_name }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
INPUT_VERSION: ${{ github.event.inputs.version }}
INPUT_DRAFT: ${{ github.event.inputs.draft }}
REF_NAME: ${{ github.ref_name }}
REF_TYPE: ${{ github.ref_type }}
GH_TOKEN: ${{ github.token }}
RESOLVER_PATH: ${{ github.event_name == 'workflow_run' && format('{0}/resolve-release-version.sh', runner.temp) || '.github/scripts/resolve-release-version.sh' }}
# The resolution itself lives in a script so that every path through it
# — automatic release, resumed release, dispatch, pushed tag, and the
# runs that must skip or fail — is covered by
# tests/release-version-resolution.sh in CI.
run: "$RESOLVER_PATH"
# helm is preinstalled on ubuntu-latest, the same way the chart tests in
# ci.yml depend on it.
- name: Package Helm chart
id: chart
if: steps.version.outputs.skip != 'true'
run: |
set -euo pipefail
# Subcharts resolve through the Bitnami OCI mirror on Docker Hub,
# which rate-limits anonymous pulls. A transient 429 should cost a
# retry, not the release.
for attempt in 1 2 3; do
if helm dependency update helm/codeapi; then
break
fi
if [ "$attempt" = 3 ]; then
echo "::error::helm dependency update failed after 3 attempts"
exit 1
fi
sleep $(( attempt * 15 ))
done
helm package helm/codeapi --destination dist
CHART_PATH="$(ls dist/codeapi-*.tgz)"
{
echo "path=$CHART_PATH"
echo "name=$(basename "$CHART_PATH")"
} >> "$GITHUB_OUTPUT"
- name: Create tag
if: steps.version.outputs.skip != 'true' && github.event_name != 'push'
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
if ! git rev-parse -q --verify "refs/tags/$VERSION" >/dev/null; then
git tag -a "$VERSION" -m "$VERSION"
git push origin "refs/tags/$VERSION"
fi
- name: Publish release
if: steps.version.outputs.skip != 'true'
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.version.outputs.version }}
APP_VERSION: ${{ steps.version.outputs.app_version }}
CHART_VERSION: ${{ steps.version.outputs.chart_version }}
CHART_PATH: ${{ steps.chart.outputs.path }}
CHART_NAME: ${{ steps.chart.outputs.name }}
PRERELEASE: ${{ steps.version.outputs.prerelease }}
LATEST: ${{ steps.version.outputs.latest }}
DRAFT: ${{ steps.version.outputs.draft }}
REPO_URL: ${{ github.server_url }}/${{ github.repository }}
run: |
set -euo pipefail
if gh release view "$VERSION" >/dev/null 2>&1; then
echo "::error::Release $VERSION already exists"
exit 1
fi
# Quoted heredoc so the markdown backticks stay literal; the
# placeholders are filled in afterwards.
cat > release-notes.md <<'NOTES'
Pin deployments to this tag instead of tracking `main`:
```bash
git clone --branch __VERSION__ --depth 1 __REPO_URL__.git
```
The attached `__CHART_NAME__` is the packaged Helm chart (chart `__CHART_VERSION__`, appVersion `__APP_VERSION__`) with its Redis and MinIO subcharts vendored, so it installs without adding any chart repositories:
```bash
helm install codeapi ./__CHART_NAME__ -f my-values.yaml
```
Chart configuration is documented in [helm/codeapi/README.md](__REPO_URL__/blob/__VERSION__/helm/codeapi/README.md).
NOTES
sed -i \
-e "s|__VERSION__|$VERSION|g" \
-e "s|__REPO_URL__|$REPO_URL|g" \
-e "s|__CHART_NAME__|$CHART_NAME|g" \
-e "s|__CHART_VERSION__|$CHART_VERSION|g" \
-e "s|__APP_VERSION__|$APP_VERSION|g" \
release-notes.md
# --generate-notes appends the merged-pull-request changelog below
# the body from --notes-file, categorised per .github/release.yml.
gh release create "$VERSION" \
--title "$VERSION" \
--notes-file release-notes.md \
--generate-notes \
--verify-tag \
--prerelease="$PRERELEASE" \
--latest="$LATEST" \
--draft="$DRAFT" \
"$CHART_PATH#Helm chart ($CHART_NAME)"