-
Notifications
You must be signed in to change notification settings - Fork 4.1k
190 lines (151 loc) · 7.08 KB
/
blathers-backport.yml
File metadata and controls
190 lines (151 loc) · 7.08 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
name: Blathers Backport
on:
repository_dispatch:
types: [backport]
jobs:
backport:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
pull-requests: write
issues: write
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.BLATHERS_APP_ID }}
private-key: ${{ secrets.BLATHERS_PRIVATE_KEY }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Configure git identity
run: |
git config user.name "blathers-crl[bot]"
git config user.email "blathers-crl[bot]@users.noreply.github.com"
- name: Backport PR
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_NUMBER: ${{ github.event.client_payload.pr_number }}
BRANCHES: ${{ github.event.client_payload.branches }}
PR_AUTHOR: ${{ github.event.client_payload.pr_author }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
# Fetch PR title and body for use in backport PRs.
PR_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title')
PR_BODY=$(gh pr view "$PR_NUMBER" --json body --jq '.body')
# Get commit SHAs from the merged PR.
COMMIT_SHAS=$(gh pr view "$PR_NUMBER" --json commits --jq '.commits[].oid')
COMMIT_COUNT=$(echo "$COMMIT_SHAS" | wc -l | tr -d ' ')
# Collect reviewers from the original PR.
REVIEWERS=$(gh pr view "$PR_NUMBER" --json reviews --jq '[.reviews[].author.login] | unique | join(",")')
FAILED_BRANCHES=""
SUCCEEDED_BRANCHES=""
for BRANCH in $BRANCHES; do
echo "=== Backporting to $BRANCH ==="
# Normalize branch name: try as-is first, then with release- prefix.
# Also strip .x suffix (backport labels use e.g. "24.1.x").
TARGET_BRANCH="${BRANCH%.x}"
if ! git rev-parse --verify "origin/$TARGET_BRANCH" >/dev/null 2>&1; then
TARGET_BRANCH="release-$TARGET_BRANCH"
if ! git rev-parse --verify "origin/$TARGET_BRANCH" >/dev/null 2>&1; then
echo "::error::Branch $BRANCH not found (tried $BRANCH and release-${BRANCH%.x})"
FAILED_BRANCHES="$FAILED_BRANCHES $BRANCH"
continue
fi
fi
BACKPORT_BRANCH="blathers/backport-${TARGET_BRANCH}-${PR_NUMBER}"
# Clean up any existing backport branch.
git branch -D "$BACKPORT_BRANCH" 2>/dev/null || true
git push origin --delete "$BACKPORT_BRANCH" 2>/dev/null || true
# Create backport branch from target.
git checkout -b "$BACKPORT_BRANCH" "origin/$TARGET_BRANCH"
# Cherry-pick all commits from the PR.
CHERRY_PICK_FAILED=false
for SHA in $COMMIT_SHAS; do
if ! git cherry-pick "$SHA"; then
echo "::error::Cherry-pick of $SHA failed on branch $TARGET_BRANCH"
git cherry-pick --abort 2>/dev/null || true
CHERRY_PICK_FAILED=true
break
fi
done
if [ "$CHERRY_PICK_FAILED" = "true" ]; then
FAILED_BRANCHES="$FAILED_BRANCHES $BRANCH"
git checkout -f HEAD 2>/dev/null || true
continue
fi
# Push the backport branch.
if ! git push origin "$BACKPORT_BRANCH"; then
echo "::error::Failed to push branch $BACKPORT_BRANCH"
FAILED_BRANCHES="$FAILED_BRANCHES $BRANCH"
continue
fi
# Transform version-specific closing keywords.
# e.g. "Fixes-26.1 #159676" -> "Fixes #159676" when targeting release-26.1.
VERSION="${TARGET_BRANCH#release-}"
ESCAPED_VERSION=$(echo "$VERSION" | sed 's/\./\\./g')
TRANSFORMED_BODY=$(echo "$PR_BODY" | sed -E "s/(Fixes|Closes|Resolves|Addresses)-${ESCAPED_VERSION}:?[[:space:]]+/\1 /gi")
# Create backport PR.
BACKPORT_PR_URL=$(gh pr create \
--base "$TARGET_BRANCH" \
--head "$BACKPORT_BRANCH" \
--title "${TARGET_BRANCH}: ${PR_TITLE}" \
--body "$(cat <<EOF
Backport ${COMMIT_COUNT}/${COMMIT_COUNT} commits from #${PR_NUMBER} on behalf of @${PR_AUTHOR}.
----
${TRANSFORMED_BODY}
----
Release justification:
EOF
)")
if [ -z "$BACKPORT_PR_URL" ]; then
echo "::error::Failed to create PR for branch $TARGET_BRANCH"
FAILED_BRANCHES="$FAILED_BRANCHES $BRANCH"
continue
fi
BACKPORT_PR_NUMBER=$(echo "$BACKPORT_PR_URL" | grep -oE '[0-9]+$')
# Add labels.
gh pr edit "$BACKPORT_PR_NUMBER" --add-label "O-robot,blathers-backport"
# Remove "backport-failed" label if it was previously added by a failed attempt.
gh pr edit "$PR_NUMBER" --remove-label "backport-failed" || true
# Add assignee (original PR author).
gh pr edit "$BACKPORT_PR_NUMBER" --add-assignee "$PR_AUTHOR" || true
# Request reviewers from the original PR.
if [ -n "$REVIEWERS" ]; then
gh pr edit "$BACKPORT_PR_NUMBER" --add-reviewer "$REVIEWERS" || true
fi
SUCCEEDED_BRANCHES="$SUCCEEDED_BRANCHES $BRANCH"
echo "=== Successfully created backport PR: $BACKPORT_PR_URL ==="
done
# Post results on the original PR.
if [ -n "$(echo "$SUCCEEDED_BRANCHES" | xargs)" ]; then
SUCCESS_MSG="Successfully created backport PRs for:$SUCCEEDED_BRANCHES"
if [ -n "$(echo "$FAILED_BRANCHES" | xargs)" ]; then
SUCCESS_MSG="$SUCCESS_MSG
Failed to backport to:$FAILED_BRANCHES
Please create these backports manually using the [backport tool](https://github.com/cockroachdb/backport).
[See action run for details]($RUN_URL)."
fi
gh pr comment "$PR_NUMBER" --body "$SUCCESS_MSG"
fi
if [ -n "$(echo "$FAILED_BRANCHES" | xargs)" ]; then
if [ -z "$(echo "$SUCCEEDED_BRANCHES" | xargs)" ]; then
gh pr comment "$PR_NUMBER" --body "$(cat <<EOF
Encountered an error creating backports. Some common things that can go wrong:
1. The backport branch might have already existed.
2. There was a merge conflict.
3. The backport branch contained merge commits.
You might need to create your backport manually using the [backport](https://github.com/cockroachdb/backport) tool.
[See action run for details]($RUN_URL).
----
Failed branches:$FAILED_BRANCHES
EOF
)"
fi
gh issue edit "$PR_NUMBER" --add-label "backport-failed" || true
exit 1
fi