-
Notifications
You must be signed in to change notification settings - Fork 2
218 lines (181 loc) · 8.68 KB
/
merge-from-milestone.yml
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: Create Pre-Release PR from Milestone
permissions:
contents: write
pull-requests: write
issues: write
on:
workflow_dispatch:
inputs:
milestone_name:
description: 'Milestone name to collect closed PRs from'
required: true
default: 'v3.8.2'
target_branch:
description: 'Target branch to merge the consolidated PR'
required: true
default: 'pre-release-v3.8.2'
schedule:
- cron: '0 10 * * 0'
env:
MILESTONE_NAME: ${{ github.event.inputs.milestone_name || 'v3.8.2' }}
TARGET_BRANCH: ${{ github.event.inputs.target_branch || 'pre-release-v3.8.2' }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
LABEL_NAME: cherry-picked
jobs:
cherry_pick_milestone_prs:
runs-on: ubuntu-latest
steps:
# Step 1: Checkout repository
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.BOT_TOKEN }}
# Step 2: Setup Git User for OpenIM-Robot
- name: Setup Git User for OpenIM-Robot
run: |
git config --global user.email "[email protected]"
git config --global user.name "OpenIM-Robot"
# Step 3: Fetch Milestone ID and Filter PR Numbers
- name: Fetch Milestone ID and Filter PR Numbers
env:
MILESTONE_NAME: ${{ env.MILESTONE_NAME }}
run: |
# Fetch milestones
milestones=$(curl -s -H "Authorization: token $BOT_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/milestones")
milestone_id=$(echo "$milestones" | grep -B3 "\"title\": \"$MILESTONE_NAME\"" | grep '"number":' | head -n1 | grep -o '[0-9]\+')
if [ -z "$milestone_id" ]; then
echo "Milestone '$MILESTONE_NAME' not found. Exiting."
exit 1
fi
echo "Milestone ID: $milestone_id"
echo "MILESTONE_ID=$milestone_id" >> $GITHUB_ENV
# Fetch all issues for the milestone
issues=$(curl -s -H "Authorization: token $BOT_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/issues?milestone=$milestone_id&state=closed&per_page=100")
> pr_numbers.txt
# Use for loop to filter PRs that do not have the 'cherry-picked' label
for pr_number in $(echo "$issues" | jq -r '.[] | select(.pull_request != null) | .number'); do
labels=$(curl -s -H "Authorization: token $BOT_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels" | jq -r '.[].name')
if ! echo "$labels" | grep -q "${LABEL_NAME}"; then
echo "PR #$pr_number does not have the 'cherry-picked' label. Adding to the list."
echo "$pr_number" >> pr_numbers.txt
else
echo "PR #$pr_number already has the 'cherry-picked' label. Skipping."
fi
done
echo "Filtered PR numbers:"
cat pr_numbers.txt || echo "No closed PR numbers found for milestone."
# Sort PR numbers
sort -n pr_numbers.txt -o pr_numbers.txt
echo "Sorted PR numbers:"
cat pr_numbers.txt
# Step 4: Fetch Merge Commits for PRs and Generate Title and Body
- name: Fetch Merge Commits for PRs and Generate Title and Body
run: |
> commit_hashes.txt
> pr_title.txt
> pr_body.txt
# Add Description to pr_body.txt
echo "### Description:" >> pr_body.txt
echo "Merging PRs from milestone \`$MILESTONE_NAME\` into target branch \`$TARGET_BRANCH\`." >> pr_body.txt
echo "" >> pr_body.txt
echo "### Need Merge PRs:" >> pr_body.txt
pr_numbers_in_title="" # Variable to store PR numbers for the title
for pr_number in $(cat pr_numbers.txt); do
echo "Processing PR #$pr_number"
pr_details=$(curl -s -H "Authorization: token $BOT_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/pulls/$pr_number")
pr_title=$(echo "$pr_details" | jq -r '.title')
merge_commit=$(echo "$pr_details" | jq -r '.merge_commit_sha')
short_commit_hash=$(echo "$merge_commit" | cut -c 1-7)
# Writing the formatted PR information into pr_body.txt
echo "- $pr_title: (#$pr_number) ($short_commit_hash)" >> pr_body.txt
if [ "$merge_commit" != "null" ];then
echo "$merge_commit" >> commit_hashes.txt
# Append PR number to pr_title.txt and pr_numbers_in_title
echo "#$pr_number" >> pr_title.txt
pr_numbers_in_title="$pr_numbers_in_title #$pr_number"
fi
done
commit_hashes=$(cat commit_hashes.txt | tr '\n' ' ')
first_commit_hash=$(head -n 1 commit_hashes.txt)
cherry_pick_branch="cherry-pick-${first_commit_hash:0:7}"
echo "COMMIT_HASHES=$commit_hashes" >> $GITHUB_ENV
echo "CHERRY_PICK_BRANCH=$cherry_pick_branch" >> $GITHUB_ENV
echo "pr_numbers_in_title=$pr_numbers_in_title" >> $GITHUB_ENV
# Step 5: Pull and Cherry-pick Commits, Then Push (Handle Only Modified Files)
- name: Pull and Cherry-pick Commits, Then Push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
run: |
# Fetch and pull the latest changes from the target branch
git fetch origin
git checkout $TARGET_BRANCH
git pull origin $TARGET_BRANCH
# Create a new branch for cherry-picking
git checkout -b $CHERRY_PICK_BRANCH
# Cherry-pick the commits
for commit_hash in $COMMIT_HASHES; do
echo "Attempting to cherry-pick commit $commit_hash"
if ! git cherry-pick "$commit_hash" --strategy=recursive -X theirs; then
echo "Conflict detected during cherry-pick for $commit_hash."
# Resolve conflict by adding only modified and deleted files
modified_files=$(git diff --name-only --diff-filter=AM) # Track added and modified files
deleted_files=$(git diff --name-only --diff-filter=D) # Track deleted files
if [ -n "$modified_files" ]; then
echo "Staging modified files: $modified_files"
git add $modified_files
fi
if [ -n "$deleted_files" ]; then
echo "Staging deleted files: $deleted_files"
git rm $deleted_files
fi
# Continue cherry-pick after resolving conflict
git cherry-pick --continue || git cherry-pick --skip
echo "Conflicts resolved. Continuing with cherry-pick."
else
echo "Cherry-pick successful for commit $commit_hash."
fi
# Add a small delay to avoid issues
sleep 2
done
# Configure remote URL with BOT_TOKEN for authentication
git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git"
git push origin $CHERRY_PICK_BRANCH --force
# Step 6: Create Pull Request
- name: Create Pull Request
run: |
pr_title="deps: Merge ${{ env.pr_numbers_in_title }} PRs into $TARGET_BRANCH"
pr_body=$(cat pr_body.txt)
echo "Prepared PR title:"
echo "$pr_title"
echo "Prepared PR body:"
echo "$pr_body"
# Create the Pull Request
response=$(curl -s -X POST -H "Authorization: token $BOT_TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/repos/${{ github.repository }}/pulls \
-d "$(jq -n --arg title "$pr_title" \
--arg head "$CHERRY_PICK_BRANCH" \
--arg base "$TARGET_BRANCH" \
--arg body "$pr_body" \
'{title: $title, head: $head, base: $base, body: $body}')")
# Extract the PR number from the response
pr_number=$(echo "$response" | jq -r '.number')
echo "Created PR #$pr_number"
# Step 7: Add Label to Created Pull Request
- name: Add Label to Created Pull Request
run: |
curl -s -X POST -H "Authorization: token $BOT_TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels \
-d "$(jq -n --arg label "milestone-merge" '{labels: [$label]}')"