-
Notifications
You must be signed in to change notification settings - Fork 0
148 lines (138 loc) · 6.22 KB
/
Copy pathpublish-release.yml
File metadata and controls
148 lines (138 loc) · 6.22 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
name: Publish Release
on:
pull_request_target:
branches: [main]
types: [closed]
workflow_dispatch:
inputs:
release_pr:
description: 'Merged release PR number to recover or republish'
required: true
type: number
concurrency:
group: publish-release-${{ inputs.release_pr || github.event.pull_request.number }}
cancel-in-progress: false
jobs:
publish-release:
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'chore/release-v') &&
endsWith(github.event.pull_request.user.login, '[bot]'))
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: read
packages: write
steps:
- name: Generate bot token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ secrets.BOT_CLIENT_ID }}
private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }}
- name: Resolve and verify release PR
id: release-pr
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_NUMBER: ${{ inputs.release_pr || github.event.pull_request.number }}
run: |
set -euo pipefail
PR=$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json author,headRefName,mergedAt,mergeCommit)
IS_BOT=$(jq -r '.author.is_bot // false' <<<"$PR")
HEAD_REF=$(jq -r '.headRefName' <<<"$PR")
MERGED_AT=$(jq -r '.mergedAt // empty' <<<"$PR")
MERGE_SHA=$(jq -r '.mergeCommit.oid // empty' <<<"$PR")
if [ -z "$MERGED_AT" ] || [ -z "$MERGE_SHA" ] || [ "$IS_BOT" != "true" ] || [[ "$HEAD_REF" != chore/release-v* ]]; then
echo "PR #$PR_NUMBER is not a merged bot-authored release PR"
exit 1
fi
FILES=$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json files --jq '.files[].path' | sort)
EXPECTED=$'package-lock.json\npackage.json'
if [ "$FILES" != "$EXPECTED" ]; then
echo "Release PR changed unexpected files:"
echo "$FILES"
exit 1
fi
echo "merge_sha=$MERGE_SHA" >> "$GITHUB_OUTPUT"
- name: Checkout merged release
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ steps.release-pr.outputs.merge_sha }}
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Resolve and validate release metadata
id: release
env:
PR_BODY: ${{ github.event.pull_request.body }}
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_NUMBER: ${{ inputs.release_pr || github.event.pull_request.number }}
run: |
set -euo pipefail
VERSION=$(jq -r .version package.json)
LOCK_VERSION=$(jq -r .version package-lock.json)
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$ ]] || [ "$LOCK_VERSION" != "$VERSION" ]; then
echo "Version files do not contain matching semver values"
exit 1
fi
if [ -z "$PR_BODY" ]; then
PR_BODY=$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json body --jq .body)
fi
NOTES=$(printf '%s\n' "$PR_BODY" | sed -n '/<!-- release-notes -->/,$p' | tail -n +2)
if [ -z "${NOTES//[[:space:]]/}" ]; then
echo "Release notes are missing from the release PR"
exit 1
fi
printf '%s\n' "$NOTES" > "$RUNNER_TEMP/release-notes.md"
echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"
- name: Create tag at merge commit
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
MERGE_SHA: ${{ steps.release-pr.outputs.merge_sha }}
TAG: ${{ steps.release.outputs.tag }}
run: |
set -euo pipefail
if EXISTING_SHA=$(gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/$TAG" --jq .object.sha 2>/dev/null); then
if [ "$EXISTING_SHA" != "$MERGE_SHA" ]; then
echo "Tag $TAG already points to $EXISTING_SHA"
exit 1
fi
else
gh api --method POST "repos/$GITHUB_REPOSITORY/git/refs" -f ref="refs/tags/$TAG" -f sha="$MERGE_SHA" >/dev/null
fi
- name: Create GitHub release
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
TAG: ${{ steps.release.outputs.tag }}
run: |
set -euo pipefail
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "Release $TAG already exists"
else
gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --title "$TAG" --notes-file "$RUNNER_TEMP/release-notes.md"
fi
- name: Setup Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
with:
version: v4.2.3
- name: Package and push Helm chart to OCI registry
env:
# The Actions token (not the app token): GHCR package creation is
# scoped to the repo's own token — the app token 403s on the first
# push of a new package (ghcr.io/misospace/charts/dispatch).
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.release.outputs.tag }}
run: |
set -euo pipefail
CHART_VERSION="${VERSION#v}"
# Stamp Chart.yaml with the release version (runner-preinstalled
# mikefarah yq — do NOT pip-install the python jq-wrapper yq, its
# flags differ and it shadows the good one on PATH).
yq -i ".version = \"${CHART_VERSION}\"" charts/dispatch/Chart.yaml
yq -i ".appVersion = \"${CHART_VERSION}\"" charts/dispatch/Chart.yaml
helm repo add bjw-s-labs https://bjw-s-labs.github.io/helm-charts
helm dependency build charts/dispatch
helm package charts/dispatch --destination /tmp/charts
# Native OCI push (helm >= 3.8) — no chartmuseum plugin needed.
helm registry login ghcr.io --username "${GITHUB_ACTOR}" --password-stdin <<< "${GH_TOKEN}"
helm push "/tmp/charts/dispatch-${CHART_VERSION}.tgz" oci://ghcr.io/misospace/charts