Create Pre-Release PR from Milestone #2
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: Merge PRs 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 with full history | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
token: ${{ secrets.BOT_TOKEN }} | |
# Step 2: Setup Git user configuration for the bot | |
- 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 without the 'cherry-picked' label | |
- name: Fetch Milestone ID and Filter PR Numbers | |
env: | |
MILESTONE_NAME: ${{ env.MILESTONE_NAME }} | |
run: | | |
# Fetch all milestones and find the one with the specified name | |
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]\+') | |
echo "Milestone ID: $milestone_id" | |
# Fetch all issues for the milestone and filter out PRs without the 'cherry-picked' label | |
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 | |
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') | |
# Only include PRs that do not have the 'cherry-picked' label | |
if ! echo "$labels" | grep -q "${LABEL_NAME}"; then | |
echo "$pr_number" >> pr_numbers.txt | |
fi | |
done | |
echo "Filtered PR numbers:" | |
cat pr_numbers.txt | |
# Sort PR numbers in ascending order | |
sort -n pr_numbers.txt -o pr_numbers.txt | |
echo "Sorted PR numbers:" | |
cat pr_numbers.txt | |
# Step 4: Fetch merge commit SHA for each filtered PR and prepare PR title and body | |
- name: Fetch Merge Commits for PRs and Prepare PR Title and Body | |
run: | | |
> commit_hashes.txt | |
> pr_title.txt | |
> pr_body.txt | |
# Collect PR details and format the title and body for the new PR | |
for pr_number in $(cat pr_numbers.txt); do | |
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) | |
commit_url="https://github.com/${{ github.repository }}/commit/$merge_commit" | |
pr_url="https://github.com/${{ github.repository }}/pull/$pr_number" | |
# Prepare PR title | |
echo "#$pr_number" >> pr_title.txt | |
# Prepare PR body | |
echo "* **$pr_title**: ([#$pr_number]($pr_url)) ([\`$short_commit_hash\`]($commit_url))" >> pr_body.txt | |
done | |
# Collect commit hashes and prepare the branch name for cherry-picking | |
pr_numbers_in_title=$(paste -sd " " pr_title.txt) | |
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 | |
# Step 5: Cherry-pick commits and push to remote | |
- name: Cherry-pick Commits and 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 and resolve conflicts by taking the incoming changes | |
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 | |
if git diff --cached --quiet; then | |
echo "Empty commit, continuing..." | |
git cherry-pick --continue --allow-empty | |
else | |
echo "Conflict resolved with incoming content" | |
git cherry-pick --continue | |
fi | |
fi | |
done | |
# Push the new branch with cherry-picked commits | |
git push origin $CHERRY_PICK_BRANCH | |
# Step 6: Use curl to create the Pull Request | |
- name: Create Pull Request using curl | |
run: | | |
pr_title="deps: Merge $(cat pr_title.txt | paste -sd " ") 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 using curl | |
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}')" | |
# Step 7: Label PRs as cherry-picked after success | |
- name: Label Successfully Cherry-Picked PRs | |
if: ${{ success() }} | |
run: | | |
for pr_number in $(cat pr_numbers.txt); do | |
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 "${LABEL_NAME}" '{labels: [$label]}')" | |
done |