Skip to content
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: Create the Pull Request using peter-evans/create-pull-request action
- name: Create Pull Request using Action
uses: peter-evans/[email protected]
with:

Check failure on line 155 in .github/workflows/merge-from-milestone.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/merge-from-milestone.yml

Invalid workflow file

You have an error in your yaml syntax on line 155
token: ${{ secrets.BOT_TOKEN }}
branch: ${{ env.CHERRY_PICK_BRANCH }}
base: $TARGET_BRANCH
title: "deps: Merge $(cat pr_title.txt | paste -sd " ") PRs into $TARGET_BRANCH"
body: |
$(cat pr_body.txt)
# 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