-
Notifications
You must be signed in to change notification settings - Fork 16
218 lines (212 loc) · 10.4 KB
/
auto-cherrypick.yaml
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
name: Auto CherryPick PR
permissions: write-all
env:
PR_LABEL_PREFIX_CHERRYPICK: "cherrypick-"
CHERRYPICK_LABEL: "robot-cherrypick"
DEFAULT_REVIEWER: "weizhoublue"
on:
push:
branches:
- 'release-*'
- 'main'
workflow_dispatch:
inputs:
prNumber:
description: 'pr number'
required: true
destBranch:
description: 'dest branch, if empty, follow the pr label'
required: false
jobs:
cherry_pick:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true
# ${{ secrets.GITHUB_TOKEN }} is forbidden to create or approve pull requests
- name: cherry pick
env:
GITHUB_TOKEN: ${{ secrets.WELAN_PAT}}
JSON: ${{ toJSON(github) }}
run: |
set -x
echo "============ print var ======== "
if ${{ github.event_name == 'workflow_dispatch' }}; then
PR_NUMBER=${{ github.event.inputs.prNumber }}
else
grep -Eio "Merge pull request #[0-9]+ " <<< "${JSON}" || true
echo "try to get PR from commit"
COMMIT=` echo "${JSON}" | jq '.event.commits[0].id' | tr -d '"' ` || true
if [ -n "${COMMIT}" ]; then
PR_NUMBER=`curl -s -H "Accept: application/vnd.github.groot-preview+json" https://api.github.com/repos/${{ github.repository }}/commits/${COMMIT}/pulls | jq -r '.[].number' `
else
echo "error, failed to get any commit ID"
fi
if [ -z "${PR_NUMBER}" ] ; then
PR_NUMBER=` grep -Eio "Merge pull request #[0-9]+ " <<< "${JSON}" | grep -Eo "[0-9]+" | uniq ` || true
fi
if [ -z "${PR_NUMBER}" ] ; then
echo "error, failed to get PR NUMBER"
exit 1
fi
# grep -Ei "https://github.com/.*/commit" <<< "${JSON}"
#PR_COMMITS=` grep -Ei "https://github.com/.*/commit" <<< "${JSON}" | awk -F'"' '{print $4}' | uniq -c | awk '{ if ($1 == 1 ) print $2}' | awk -F'/' '{print $NF}' | tr '\n' ' ' `
# grep '"username":' <<< "${JSON}"
#PR_AUTHOR=` grep '"username":' <<< "${JSON}" | awk -F'"' '{print $4}' | sort | uniq | grep -v "web-flow" | head -1 | tr -d '\n' `
# [ -n "${PR_AUTHOR}" ] || { echo "no PR_AUTHOR, ignore" ; }
#
fi
RP_API_BODY=` curl https://api.github.com/repos/${{ github.repository }}/pulls/${PR_NUMBER} -s -H "Accept: application/vnd.github.groot-preview+json" `
PR_COMMITS=` echo "${RP_API_BODY}" | jq ' .merge_commit_sha ' | tr -d '"' `
PR_AUTHOR=` echo "${RP_API_BODY}" | jq ' .user.login ' | tr -d '"' `
PR_URL="https://github.com/${{ github.repository }}/pull/${PR_NUMBER}"
ACTION_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
#gh pr view ${PR_NUMBER} || { echo "failed to get pr ${PR_NUMBER}" ; exit 1 ; }
#PR_LABEL=` gh pr view ${PR_NUMBER} | grep -i "^labels:" | tr ',' ' ' | tr -s ' ' | sed 's/labels://g' `
# [ -n "${PR_LABEL}" ] || { echo "no PR_LABEL, ignore" ; }
PR_LABEL=` echo "${RP_API_BODY}" | jq ' .labels[].name ' | tr -d '"' | tr '\n' ' ' `
#PR_TITLE=`gh pr view ${PR_NUMBER} | sed -n '1 p' `
# [ -n "${PR_TITLE}" ] || { echo "error, no PR_TITLE " ; exit 1 ; }
PR_TITLE=` echo "${RP_API_BODY}" | jq ' .title ' | tr -d '"' `
#
if [ -z "${PR_COMMITS}" ]; then
echo "error, failed to get pr commits"
fi
echo "number: ${PR_NUMBER}"
echo "action url: ${ACTION_URL}"
echo "PR_COMMITS: ${PR_COMMITS}"
echo "author: ${PR_AUTHOR}"
echo "url: ${PR_URL}"
echo "PR_LABEL: ${PR_LABEL}"
echo "PR_TITLE: ${PR_TITLE}"
#
#
echo "=============================== get dest branch from labels ======== "
WANT_MERGE_BRANCH_LIST=""
INITIAL_LABEL=""
if ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.destBranch != '' }}; then
WANT_MERGE_BRANCH_LIST=${{ github.event.inputs.destBranch }}
else
for LABEL in ${PR_LABEL} ; do
echo "checking label $LABEL "
PREFIX="${{ env.PR_LABEL_PREFIX_CHERRYPICK }}"
if ! grep -E "^${PREFIX}" <<< "${LABEL}" &>/dev/null; then
INITIAL_LABEL+="${LABEL},"
continue
fi
BRANCH_NAME=` sed 's?'"${PREFIX}"'??' <<< "$LABEL" `
WANT_MERGE_BRANCH_LIST+=" $BRANCH_NAME "
done
fi
[ -z "$WANT_MERGE_BRANCH_LIST" ] && echo "no branch to cherry pick" && exit 0
echo "cherry pick to $WANT_MERGE_BRANCH_LIST "
INITIAL_LABEL="${INITIAL_LABEL%,}"
echo "INITIAL_LABEL: ${INITIAL_LABEL}"
#
#
echo "============ begin to cherry pick ============ "
FINAL_FAILURE=false
git branch
git config user.email "[email protected]"
git config user.name "robot"
gh label create ${{ env.CHERRYPICK_LABEL }} || true
for BRANCH in $WANT_MERGE_BRANCH_LIST ; do
echo "************** cherry for branch ${BRANCH}"
if ! git ls-remote --exit-code --heads origin ${BRANCH} ; then
# todo: create issue
echo "error, branch $BRANCH does not exist"
gh issue create \
--body "reason: the branch $BRANCH does not exist. PR <${PR_URL}> , action <${ACTION_URL}> " \
--title "failed to auto cherry pick PR ${PR_NUMBER} to branch ${BRANCH}" \
--label "${{ env.CHERRYPICK_LABEL }}" \
--assignee "${PR_AUTHOR},${{ env.DEFAULT_REVIEWER }}"
if (($?!=0)) ; then
echo "!!!! error, failed to create issue"
FINAL_FAILURE=true
fi
continue
fi
git fetch origin ${BRANCH}:${BRANCH} || true
if ! git checkout ${BRANCH} ; then
echo "error, failed to checkout to branch $BRANCH"
gh issue create \
--body "reason: failed to get the branch $BRANCH. PR <${PR_URL}> , action <${ACTION_URL}> " \
--title "failed to auto cherry pick PR ${PR_NUMBER} to branch ${BRANCH}" \
--label "${{ env.CHERRYPICK_LABEL }}" \
--assignee "${PR_AUTHOR},${{ env.DEFAULT_REVIEWER }}"
if (($?!=0)) ; then
echo "!!!! error, failed to create issue"
FINAL_FAILURE=true
fi
continue
fi
PR_BRANCH=robot/cherrypick/pr${PR_NUMBER}/${BRANCH}
git checkout -b ${PR_BRANCH}
git branch --show-current
FAIL=false
UPDATE=false
ERROR_MESSAGE=""
for COMMIT in $PR_COMMITS; do
if ! ERROR_MESSAGE=`git cherry-pick -m 1 $COMMIT 2>&1` ; then
echo ">>>>>>>>>>>> fail when cherry pick $COMMIT to branch $BRANCH "
echo "$ERROR_MESSAGE"
echo "---- failure detail"
git status
git diff
echo "<<<<<<<<<<<<<"
if git diff --exit-code --quiet ; then
echo "no changes happen, ignore cherry pick $COMMIT "
git cherry-pick --abort || true
git reset --hard HEAD || true
continue
else
FAIL=true
echo "error, failed to cherry pick $COMMIT "
git cherry-pick --abort || true
git reset --hard HEAD || true
break
fi
else
UPDATE=true
echo "succeed to cherry pick $COMMIT to branch $BRANCH "
fi
done
if [ "$FAIL" == "true" ] ; then
echo "failed to cherry pick to branch $BRANCH "
FINAL_FAILURE=true
echo -e "commits $PR_COMMITS conflict when merging to branch $BRANCH, please manually cherry pick it by yourself. \n PR <${PR_URL}> , action <${ACTION_URL}> \n\n \`\`\`\n${ERROR_MESSAGE}\n\`\`\` " | \
gh issue create \
--title "failed to auto cherry pick PR ${PR_NUMBER} to branch ${BRANCH}" \
--label "${{ env.CHERRYPICK_LABEL }}" \
--assignee "${PR_AUTHOR},${{ env.DEFAULT_REVIEWER }}" \
--body-file -
fi
if [ "$UPDATE" == "true" ] ; then
echo "succeeded to cherry pick to branch $BRANCH "
# create a pr
git commit -s -S --amend --no-edit
git push origin ${PR_BRANCH}:${PR_BRANCH} -f
gh pr create --title "${PR_TITLE}" \
--assignee "${PR_AUTHOR},${{ env.DEFAULT_REVIEWER }}" \
--label "${{ env.CHERRYPICK_LABEL }},${INITIAL_LABEL}" \
--body "robot cherry pick pr <${PR_URL}> to branch ${BRANCH}, action <${ACTION_URL}> , commits $PR_COMMITS " \
--base ${BRANCH}
else
echo "no changes happened for commits $PR_COMMITS, ignore create pr"
fi
done
echo "=========== check result ============"
if [ "$FINAL_FAILURE" == "true" ] ; then
# if failed to create issue or pr, fails
echo "error, failure happened"
else
echo "all done"
fi