-
Notifications
You must be signed in to change notification settings - Fork 1
139 lines (115 loc) · 5.27 KB
/
cherry-pick.yml
File metadata and controls
139 lines (115 loc) · 5.27 KB
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
name: Cherry Pick
on:
pull_request_target:
types: [closed, labeled]
permissions:
contents: write
pull-requests: write
jobs:
cherry-pick:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cherry Pick
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
MERGE_COMMIT_SHA: ${{ github.event.pull_request.merge_commit_sha }}
run: |
# Function to post comment
post_comment() {
gh pr comment "$PR_NUMBER" --body "$1"
}
# Configure git for the original author
echo "Fetching author info for $PR_AUTHOR..."
AUTHOR_INFO=$(gh api "/users/$PR_AUTHOR" --jq '{email: .email, name: .name}')
AUTHOR_EMAIL=$(echo "$AUTHOR_INFO" | jq -r '.email')
AUTHOR_NAME=$(echo "$AUTHOR_INFO" | jq -r '.name')
if [ "$AUTHOR_EMAIL" = "null" ] || [ -z "$AUTHOR_EMAIL" ]; then
AUTHOR_EMAIL="${PR_AUTHOR}@users.noreply.github.com"
echo "Author email not found, using default: $AUTHOR_EMAIL"
fi
if [ "$AUTHOR_NAME" = "null" ] || [ -z "$AUTHOR_NAME" ]; then
AUTHOR_NAME="${PR_AUTHOR}"
echo "Author name not found, using username: $AUTHOR_NAME"
fi
git config user.name "$AUTHOR_NAME"
git config user.email "$AUTHOR_EMAIL"
# Capture current SHA to return to later
ORIGINAL_HEAD_SHA=$(git rev-parse HEAD)
# Get labels
LABELS=$(gh pr view "$PR_NUMBER" --json labels --jq '.labels[].name')
if [ -z "$LABELS" ]; then
echo "No labels found."
exit 0
fi
# Loop through labels
echo "$LABELS" | while read -r label; do
if [[ "$label" == cherry-pick:* ]]; then
TARGET_BRANCH=$(echo "${label#cherry-pick:}" | xargs)
if [ -z "$TARGET_BRANCH" ]; then
echo "Empty target branch for label '$label', skipping."
continue
fi
echo "Processing cherry-pick to $TARGET_BRANCH"
# Check if target branch exists on remote
if ! git ls-remote --exit-code --heads origin "$TARGET_BRANCH"; then
echo "Target branch $TARGET_BRANCH does not exist."
post_comment "❌ Cherry-pick failed: Target branch \`$TARGET_BRANCH\` does not exist."
continue
fi
# Create a new branch for the cherry-pick
NEW_BRANCH="cherry-pick/$PR_NUMBER/$TARGET_BRANCH"
# Clean up local branch if it exists (from previous run)
if git show-ref --verify --quiet "refs/heads/$NEW_BRANCH"; then
git branch -D "$NEW_BRANCH"
fi
# Fetch the target branch and checkout a new branch from it
git fetch origin "$TARGET_BRANCH"
git checkout -b "$NEW_BRANCH" "origin/$TARGET_BRANCH"
# Cherry pick
# Try standard cherry-pick first (for squash merges or single commits)
if git cherry-pick "$MERGE_COMMIT_SHA"; then
echo "Cherry-pick successful."
else
echo "Standard cherry-pick failed, trying with -m 1 (for merge commits)..."
git cherry-pick --abort
if git cherry-pick -m 1 "$MERGE_COMMIT_SHA"; then
echo "Cherry-pick with -m 1 successful."
else
echo "Cherry-pick failed."
git cherry-pick --abort
post_comment "❌ Cherry-pick failed: Conflicts detected when cherry-picking to \`$TARGET_BRANCH\`. Please resolve manually."
# Cleanup
git checkout "$ORIGINAL_HEAD_SHA"
git branch -D "$NEW_BRANCH"
continue
fi
fi
# Push
# Check if remote branch already exists, if so, force push? Or maybe fail?
# Force push is better to update the PR if we are re-running.
git push origin "$NEW_BRANCH" --force
# Create PR
NEW_TITLE="[$TARGET_BRANCH] $PR_TITLE"
# Check if PR already exists
EXISTING_PR=$(gh pr list --base "$TARGET_BRANCH" --head "$NEW_BRANCH" --json url --jq '.[0].url')
if [ -n "$EXISTING_PR" ]; then
echo "PR already exists: $EXISTING_PR"
post_comment "ℹ️ Cherry-pick PR already exists: $EXISTING_PR"
else
CREATED_PR_URL=$(gh pr create --base "$TARGET_BRANCH" --head "$NEW_BRANCH" --title "$NEW_TITLE" --body "Cherry-pick of #$PR_NUMBER" --reviewer "$PR_AUTHOR")
echo "Created PR: $CREATED_PR_URL"
post_comment "✅ Cherry-pick successful! Created PR: $CREATED_PR_URL"
fi
# Cleanup for next loop
git checkout "$ORIGINAL_HEAD_SHA"
git branch -D "$NEW_BRANCH"
fi
done