-
Notifications
You must be signed in to change notification settings - Fork 292
120 lines (106 loc) · 4.76 KB
/
Copy pathrelease-notes-assemble.yaml
File metadata and controls
120 lines (106 loc) · 4.76 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
name: Assemble Release Notes on Tag
on:
push:
tags:
- 'v*'
jobs:
assemble:
# RC tags are pre-release; only assemble notes for final releases.
if: ${{ !contains(github.ref_name, '-rc') }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- name: Generate App token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.RELEASE_NOTES_APP_ID }}
private-key: ${{ secrets.RELEASE_NOTES_APP_PRIVATE_KEY }}
- name: Get App user id
id: app-user
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
run: |
echo "user-id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
- name: Checkout tagged commit
# Check out the tagged commit (not main HEAD) so a fragment merged
# into main between the tag push and this workflow's run is not
# accidentally rolled into the wrong release.
uses: actions/checkout@v7
with:
ref: ${{ github.sha }}
token: ${{ steps.app-token.outputs.token }}
- name: Assemble fragments and open PR
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
APP_USER_ID: ${{ steps.app-user.outputs.user-id }}
TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
# ── Phase 1: read fragments from the tagged commit ──────────
# The checkout step landed us on the tagged commit so that
# fragments merged into main *after* the tag are excluded.
shopt -s nullglob
fragments=( release-notes.d/unreleased/*.md )
if [[ ${#fragments[@]} -eq 0 ]]; then
echo "No fragments to assemble for ${TAG}; exiting."
exit 0
fi
tmp=$(mktemp)
for f in "${fragments[@]}"; do
pr=$(sed -n 's/^pr: *//p' "$f" | head -1)
url=$(sed -n 's/^url: *//p' "$f" | head -1)
date=$(sed -n 's/^date: *//p' "$f" | head -1)
note=$(awk 'p {print; next} /^---$/ {if (++c == 2) p = 1}' "$f" | sed '/^[[:space:]]*$/d' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
if [[ -z "$pr" || -z "$url" || -z "$date" || -z "$note" ]]; then
echo "Malformed fragment: $f" >&2
exit 1
fi
printf '%s\t%s\t%s\t%s\n' "$date" "$pr" "$url" "$note" >> "$tmp"
done
sort -k1,1 -k2,2n "$tmp" -o "$tmp"
today=$(date -u +%Y-%m-%d)
new_section=$(mktemp)
printf 'RELEASE %s %s\n' "$TAG" "$today" > "$new_section"
while IFS=$'\t' read -r date pr url note; do
printf '%s %s %s\n' "$date" "$url" "$note" >> "$new_section"
done < "$tmp"
printf '\n' >> "$new_section"
# ── Phase 2: branch from main so the PR contains only
# release-notes changes, not unrelated diffs between
# the tagged commit and main HEAD ─────────────────────
git fetch origin main
BRANCH="release-notes/assemble-${TAG}"
git config user.name "${APP_SLUG}[bot]"
git config user.email "${APP_USER_ID}+${APP_SLUG}[bot]@users.noreply.github.com"
git checkout -b "$BRANCH" origin/main
# ── Phase 3: apply release-notes changes on top of main ─
touch RELEASE-NOTES.md
cat "$new_section" RELEASE-NOTES.md > RELEASE-NOTES.md.new
mv RELEASE-NOTES.md.new RELEASE-NOTES.md
git add RELEASE-NOTES.md
# Remove only the fragments captured from the tagged commit,
# not the current main glob which may include post-tag fragments.
# The -f guard skips fragments already absent from main.
for f in "${fragments[@]}"; do
if [[ -f "$f" ]]; then
git rm -- "$f"
fi
done
git commit -s -m "docs: assemble release notes for ${TAG}"
# Force-push so a re-run (re-tag, manual workflow re-run) overwrites
# the prior branch rather than failing non-fast-forward.
git push -f origin "$BRANCH"
if gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number' | grep -q .; then
echo "Assembly PR already open for $BRANCH; pushed update."
else
gh pr create \
--title "docs: assemble release notes for ${TAG}" \
--body "Assembles staged release-note fragments into RELEASE-NOTES.md for ${TAG} and removes the fragments." \
--base main \
--head "$BRANCH"
fi