-
Notifications
You must be signed in to change notification settings - Fork 0
158 lines (143 loc) · 6.21 KB
/
Copy pathstlc-promote.yml
File metadata and controls
158 lines (143 loc) · 6.21 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
name: Promote SDK changes
# Staging is the generator's integration history. Production `next` is the
# developer-facing queue for the next release. This workflow combines the
# latest released state with validated staging changes, then advances `next`.
# Release automation maintains the single versioned PR from `next` to `main`.
on:
push:
branches: [main]
workflow_dispatch: {}
permissions:
contents: read
jobs:
promote:
if: github.repository == 'kernel/hypeman-python-staging'
runs-on: ${{ vars.STLC_RUNNER || 'ubuntu-latest' }}
concurrency:
group: stlc-promote
cancel-in-progress: true
steps:
- name: Check out staging
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Mint production token
id: production-token
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1
with:
app-id: ${{ secrets.ADMIN_APP_ID }}
private-key: ${{ secrets.ADMIN_APP_PRIVATE_KEY }}
owner: kernel
repositories: hypeman-python
permission-contents: write
permission-pull-requests: write
permission-workflows: write
- name: Fetch production branches
id: production
env:
GH_TOKEN: ${{ steps.production-token.outputs.token }}
PRODUCTION_REPO: kernel/hypeman-python
run: |
set -euo pipefail
git remote add production \
"https://x-access-token:${GH_TOKEN}@github.com/${PRODUCTION_REPO}.git"
if git ls-remote --exit-code --heads production main >/dev/null 2>&1; then
git fetch production main
echo "has_main=true" >> "$GITHUB_OUTPUT"
else
echo "has_main=false" >> "$GITHUB_OUTPUT"
fi
if git ls-remote --exit-code --heads production next >/dev/null 2>&1; then
git fetch production next
echo "has_next=true" >> "$GITHUB_OUTPUT"
else
echo "has_next=false" >> "$GITHUB_OUTPUT"
fi
- name: Prepare the next release branch
env:
APP_SLUG: ${{ steps.production-token.outputs.app-slug }}
GH_TOKEN: ${{ steps.production-token.outputs.token }}
HAS_MAIN: ${{ steps.production.outputs.has_main }}
HAS_NEXT: ${{ steps.production.outputs.has_next }}
PRODUCTION_REPO: kernel/hypeman-python
run: |
set -euo pipefail
bot_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id)
git config user.name "${APP_SLUG}[bot]"
git config user.email "${bot_id}+${APP_SLUG}[bot]@users.noreply.github.com"
open_conflict_pr() {
source_ref=$1
source_name=$2
advance_next=$3
conflict_branch=stlc/promotion-conflict
git merge --abort
existing=$(gh pr list --repo "$PRODUCTION_REPO" --base next \
--head "$conflict_branch" --state open --json url --jq '.[0].url // ""')
if [ -n "$existing" ]; then
echo "::error title=SDK promotion blocked::Resolve the existing recovery PR: $existing"
exit 1
fi
if [ "$advance_next" = "true" ]; then
git push production HEAD:refs/heads/next
fi
git push production "$source_ref:refs/heads/$conflict_branch" --force
body=$(mktemp)
printf '%s\n' \
'## SDK promotion conflict' \
'' \
"The automated promotion could not merge $source_name into the pending next release." \
'' \
'Resolve the conflicts on this branch, validate the SDK, mark this PR ready, and merge it with a merge commit.' \
'' \
'After merging, rerun the staging Promote SDK changes workflow to include any newer generated changes.' \
> "$body"
recovery_url=$(gh pr create --repo "$PRODUCTION_REPO" --draft \
--base next --head "$conflict_branch" \
--title 'chore: resolve SDK promotion conflict' --body-file "$body")
echo "::error title=SDK promotion conflict::Resolve the recovery PR: $recovery_url"
exit 1
}
if [ "$HAS_MAIN" != "true" ]; then
# The Python production repository started empty. Seed a minimal
# default branch so release-please can open the first next -> main
# release PR while preserving staging as a parent of that release.
git checkout --orphan stlc/bootstrap-main
git rm -rf .
git checkout origin/main -- \
.github/workflows/release-please.yml \
.release-please-manifest.json \
release-please-config.json
git commit -m 'chore: initialize SDK release history'
git push production HEAD:refs/heads/main
git fetch production main
fi
if [ "$HAS_NEXT" = "true" ]; then
git checkout -B stlc/promote-next production/next
else
git checkout -B stlc/promote-next production/main
fi
if ! git merge-base --is-ancestor production/main HEAD; then
if ! git merge --no-edit production/main; then
open_conflict_pr production/main 'production main' false
fi
fi
if ! git merge-base --is-ancestor origin/main HEAD; then
merge_args=(--no-edit)
if ! git merge-base production/main origin/main >/dev/null 2>&1; then
merge_args+=(--allow-unrelated-histories)
fi
if ! git merge "${merge_args[@]}" origin/main; then
open_conflict_pr origin/main 'validated staging changes' true
fi
fi
if [ "$HAS_NEXT" = "true" ]; then
git merge-base --is-ancestor production/next HEAD
fi
- name: Update the pending release
env:
GH_TOKEN: ${{ steps.production-token.outputs.token }}
run: |
set -euo pipefail
git push production HEAD:refs/heads/next
echo "Updated production next; the versioned release PR will be opened or refreshed."