1name: Cherry Pick
2
3on:
4 issue_comment:
5 types: [created]
6 pull_request_target:
7 types: [closed]
8
9jobs:
10 cherry-pick:
11 # This job will run when a PR is merged with a specific comment,
12 # or when a comment is added to an already merged PR.
13 runs-on: ubuntu-latest
14 # Use pull_request_target so that we can add comments back to the PR
15 # if the cherry-pick fails.
16 permissions:
17 pull-requests: write
18 contents: write
19 issues: write
20
21 steps:
22 - name: Checkout
23 uses: actions/checkout@v4
24 with:
25 fetch-depth: 0 # Required to get all history for cherry-picking
26
27 - name: Extract info and determine trigger
28 id: info
29 run: |
30 # Default to failure unless a valid trigger is found
31 echo "valid=false" >> $GITHUB_OUTPUT
32
33 if [[ "${{ github.event_name }}" == "pull_request_target" && "${{ github.event.pull_request.merged }}" == "true" ]]; then
34 echo "Triggered by PR merge"
35 PR_NUMBER="${{ github.event.pull_request.number }}"
36
37 # Check PR body first, then fall back to comments
38 TEXT_TO_SEARCH="${{ github.event.pull_request.body }}"
39 if [[ ! "$TEXT_TO_SEARCH" =~ /cherry-pick[[:space:]]+(stable|preview) ]]; then
40 echo "Command not found in PR body. Checking comments..."
41 TEXT_TO_SEARCH=$(gh pr view $PR_NUMBER --json comments -q '.comments[].body' | tail -n 100)
42 fi
43
44 if [[ "$TEXT_TO_SEARCH" =~ /cherry-pick[[:space:]]+(stable|preview) ]]; then
45 echo "Found cherry-pick command."
46 MERGE_SHA="${{ github.event.pull_request.merge_commit_sha }}"
47 # Get the last matching command in the text
48 CHANNEL=$(echo "$TEXT_TO_SEARCH" | grep -oP '/cherry-pick[[:space:]]+\K(stable|preview)' | tail -n1)
49
50 echo "valid=true" >> $GITHUB_OUTPUT
51 echo "merge_sha=$MERGE_SHA" >> $GITHUB_OUTPUT
52 echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
53 echo "channel=$CHANNEL" >> $GITHUB_OUTPUT
54 else
55 echo "No cherry-pick command found in PR body or recent comments. Exiting."
56 exit 0
57 fi
58
59 elif [[ "${{ github.event_name }}" == "issue_comment" && "${{ github.event.issue.pull_request }}" != "" ]]; then
60 echo "Triggered by issue comment"
61 COMMENT_BODY="${{ github.event.comment.body }}"
62 if [[ ! "$COMMENT_BODY" =~ /cherry-pick[[:space:]]+(stable|preview) ]]; then
63 echo "Comment does not contain cherry-pick command. Exiting."
64 exit 0
65 fi
66
67 PR_NUMBER="${{ github.event.issue.number }}"
68
69 # Check if the PR is merged
70 MERGE_SHA=$(gh pr view $PR_NUMBER --json mergeCommit -q .mergeCommit.oid)
71 if [[ -z "$MERGE_SHA" ]]; then
72 echo "PR #$PR_NUMBER is not merged. Exiting."
73 exit 0
74 fi
75
76 CHANNEL=$(echo "$COMMENT_BODY" | grep -oP '/cherry-pick[[:space:]]+\K(stable|preview)' | head -n1)
77
78 echo "valid=true" >> $GITHUB_OUTPUT
79 echo "merge_sha=$MERGE_SHA" >> $GITHUB_OUTPUT
80 echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
81 echo "channel=$CHANNEL" >> $GITHUB_OUTPUT
82 fi
83 env:
84 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
85
86 - name: Cherry-pick
87 if: steps.info.outputs.valid == 'true'
88 run: |
89 set -e
90
91 CHANNEL="${{ steps.info.outputs.channel }}"
92 MERGE_SHA="${{ steps.info.outputs.merge_sha }}"
93 PR_NUMBER="${{ steps.info.outputs.pr_number }}"
94
95 # Get the latest version for the channel
96 echo "Fetching latest version for '$CHANNEL' channel..."
97 query=""
98 case $CHANNEL in
99 stable)
100 ;;
101 preview)
102 query="&preview=1"
103 ;;
104 *)
105 echo "Invalid channel: $CHANNEL" >&2
106 exit 1
107 ;;
108 esac
109 LATEST_VERSION=$(curl -s "https://zed.dev/api/releases/latest?asset=zed&os=macos&arch=aarch64$query" | jq -r .version)
110
111 if [[ -z "$LATEST_VERSION" ]]; then
112 echo "Could not fetch latest version for channel '$CHANNEL'"
113 gh pr comment $PR_NUMBER --body "Could not fetch latest version for channel '$CHANNEL' from zed.dev API."
114 exit 1
115 fi
116 echo "Latest version is $LATEST_VERSION"
117
118 # Construct target branch name (e.g., v0.85.4 -> v0.85.x)
119 TARGET_BRANCH=$(echo "$LATEST_VERSION" | sed -E 's/v([0-9]+\.[0-9]+)\..*/v\1.x/')
120 echo "Target branch is $TARGET_BRANCH"
121
122 # Configure git
123 git config user.name "github-actions[bot]"
124 git config user.email "github-actions[bot]@users.noreply.github.com"
125
126 # Create and push the cherry-pick branch
127 NEW_BRANCH="cherry-pick/pr-${PR_NUMBER}-to-${TARGET_BRANCH}"
128
129 git fetch origin $TARGET_BRANCH
130 git checkout -b $NEW_BRANCH "origin/$TARGET_BRANCH"
131
132 echo "Attempting to cherry-pick $MERGE_SHA..."
133 if ! git cherry-pick $MERGE_SHA; then
134 echo "Cherry-pick failed. Please resolve conflicts manually."
135 gh pr comment $PR_NUMBER --body "Automated cherry-pick to \`$TARGET_BRANCH\` failed due to conflicts. Please resolve them manually."
136 exit 1
137 fi
138
139 echo "Pushing new branch $NEW_BRANCH..."
140 git push -u origin $NEW_BRANCH
141
142 # Create the pull request
143 echo "Creating pull request..."
144 gh pr create \
145 --title "Cherry-pick PR #${PR_NUMBER} to ${TARGET_BRANCH}" \
146 --body "This PR cherry-picks the changes from #${PR_NUMBER} to the \`$TARGET_BRANCH\` branch." \
147 --base $TARGET_BRANCH \
148 --head $NEW_BRANCH \
149 --reviewer "${{ github.actor }}"
150 env:
151 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}