Create Pre-Release PR from Milestone #36
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
TEMP_DIR: "./temp" # Temporary directory for storing PR number and other info | |
jobs: | |
cherry_pick_milestone_prs: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Setup temp directory | |
run: mkdir -p ${{ env.TEMP_DIR }} | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
token: ${{ secrets.BOT_TOKEN }} | |
- name: Setup Git User for OpenIM-Robot | |
run: | | |
git config --global user.email "[email protected]" | |
git config --global user.name "OpenIM-Robot" | |
- name: Fetch Milestone ID and Filter PR Numbers | |
env: | |
MILESTONE_NAME: ${{ env.MILESTONE_NAME }} | |
run: | | |
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 | |
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") | |
> ${{ env.TEMP_DIR }}/pr_numbers.txt | |
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" >> ${{ env.TEMP_DIR }}/pr_numbers.txt | |
else | |
echo "PR #$pr_number already has the 'cherry-picked' label. Skipping." | |
fi | |
done | |
echo "Filtered PR numbers:" | |
cat ${{ env.TEMP_DIR }}/pr_numbers.txt || echo "No closed PR numbers found for milestone." | |
- name: Fetch Merge Commits for PRs and Generate Title and Body | |
run: | | |
> ${{ env.TEMP_DIR }}/commit_hashes.txt | |
> ${{ env.TEMP_DIR }}/pr_title.txt | |
> ${{ env.TEMP_DIR }}/pr_body.txt | |
echo "### Description:" >> ${{ env.TEMP_DIR }}/pr_body.txt | |
echo "Merging PRs from milestone \`$MILESTONE_NAME\` into target branch \`$TARGET_BRANCH\`." >> ${{ env.TEMP_DIR }}/pr_body.txt | |
echo "" >> ${{ env.TEMP_DIR }}/pr_body.txt | |
echo "### Need Merge PRs:" >> ${{ env.TEMP_DIR }}/pr_body.txt | |
pr_numbers_in_title="" # Variable to store PR numbers for the title | |
for pr_number in $(cat ${{ env.TEMP_DIR }}/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) | |
echo "- $pr_title: (#$pr_number) ($short_commit_hash)" >> ${{ env.TEMP_DIR }}/pr_body.txt | |
if [ "$merge_commit" != "null" ]; then | |
echo "$merge_commit" >> ${{ env.TEMP_DIR }}/commit_hashes.txt | |
echo "#$pr_number" >> ${{ env.TEMP_DIR }}/pr_title.txt | |
pr_numbers_in_title="$pr_numbers_in_title #$pr_number" | |
fi | |
done | |
commit_hashes=$(cat ${{ env.TEMP_DIR }}/commit_hashes.txt | tr '\n' ' ') | |
first_commit_hash=$(head -n 1 ${{ env.TEMP_DIR }}/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 | |
- name: Pull and Cherry-pick Commits, Then Push | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
BOT_TOKEN: ${{ secrets.BOT_TOKEN }} | |
run: | | |
git fetch origin | |
git checkout $TARGET_BRANCH | |
git pull origin $TARGET_BRANCH | |
git checkout -b $CHERRY_PICK_BRANCH | |
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 for $commit_hash. Resolving with incoming changes." | |
# Get the list of conflicting files | |
conflict_files=$(git diff --name-only --diff-filter=U) | |
echo "Conflicting files:" | |
echo "$conflict_files" | |
# Resolve conflicts for each conflicting file | |
for file in $conflict_files; do | |
if [ -f "$file" ]; then | |
echo "Resolving conflict for $file" | |
git add "$file" | |
else | |
echo "File $file has been deleted. Skipping." | |
git rm "$file" | |
fi | |
done | |
echo "Conflicts resolved. Continuing cherry-pick." | |
git cherry-pick --continue | |
else | |
echo "Cherry-pick successful for commit $commit_hash." | |
fi | |
done | |
git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git" | |
git push origin $CHERRY_PICK_BRANCH --force | |
- name: Create Pull Request | |
run: | | |
pr_title="deps: Merge ${{ env.pr_numbers_in_title }} PRs into $TARGET_BRANCH" | |
pr_body=$(cat ${{ env.TEMP_DIR }}/pr_body.txt) | |
echo "Prepared PR title:" | |
echo "$pr_title" | |
echo "Prepared PR body:" | |
echo "$pr_body" | |
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}')") | |
pr_number=$(echo "$response" | jq -r '.number') | |
echo "$pr_number" > ${{ env.TEMP_DIR }}/pr_number.txt | |
- name: Add Label to Created Pull Request | |
run: | | |
pr_number=$(cat ${{ env.TEMP_DIR }}/pr_number.txt) | |
echo "Adding 'milestone-merge' label to PR #$pr_number" | |
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]}')" | |