Skip to content

Commit

Permalink
Modernize the Cherry-Picker script (pantsbuild#19230)
Browse files Browse the repository at this point in the history
Modernizes our Cherry-Pick script by making it much more "talkative".
Mainly:
- Will comment on success with PR links (and remove label)
- Will comment on cherry-pick failure with helpful instructions
- Adds new "auto-cherry-pick-failed" label

Additionally, the code leverages `actions/github-script` and calls into
an in-repo file so we can test it (which found several bugs, yay).
Lastly, the cherry-pick script is gone, since the comment instructs on
how to reproduce (a new `make_pr.sh` was created though to handle the PR
creation aspect

---------

Co-authored-by: Tobias Nilsson <[email protected]>
Co-authored-by: Huon Wilson <[email protected]>
  • Loading branch information
3 people authored Jun 13, 2023
1 parent f9df772 commit d6f6373
Show file tree
Hide file tree
Showing 12 changed files with 6,735 additions and 146 deletions.
14 changes: 13 additions & 1 deletion .github/workflows/BUILD
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

files(sources=["*.yaml"])
files(
sources=["*.yaml"],
overrides={
"auto-cherry-picker.yaml": {
"dependencies": [
"//build-support/cherry_pick/package.json:support_files",
"//build-support/cherry_pick/package-lock.json:support_files",
"//build-support/cherry_pick/helper.js:support_files",
"//build-support/cherry_pick/make_pr.sh:support_files",
]
}
},
)
81 changes: 73 additions & 8 deletions .github/workflows/auto-cherry-picker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,88 @@ on:
required: true

jobs:
picker:
prerequisites:
name: Gather Prerequisites
if: (github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'needs-cherrypick') ) || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
outputs:
pr_num: ${{ steps.get-prereqs.outputs.pr_num }}
merge_commit: ${{ steps.get-prereqs.outputs.merge_commit }}
matrix: ${{ steps.get-prereqs.outputs.matrix }}
steps:
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Check out code
uses: actions/checkout@v3
- run: npm install ./build-support/cherry_pick
- id: get-prereqs
name: Get Cherry-Pick prerequisites
# NB: See https://github.com/actions/github-script/pull/397
uses: thejcannon/github-script@7ed0cc648959192a3868f0de9862110d7922b7cc
with:
# Always checkout the latest commit of main, for latest changes to the script
ref: "main"
# NB: we're usually cherrypicking the HEAD of main, and we need its parent commit to diff
# for the cherry-pick, so we can save an extra round-trip by just getting that parent now
fetch-depth: 2
github-token: ${{ secrets.WORKER_PANTS_CHERRY_PICK_PAT }}
allow-empty-token: true
script: |
const Helper = require('./build-support/cherry_pick/helper.js');
const helper = new Helper({octokit: github, context, core});
const prereqs = await helper.get_prereqs();
if (prereqs !== null) {
core.setOutput("pr_num", prereqs.pr_num);
core.setOutput("merge_commit", prereqs.merge_commit);
core.setOutput("matrix", prereqs.milestones.map(
milestone => {return {
milestone,
branch_name: `cherry-pick-${prereqs.pr_num}-to-${milestone}`,
}}
));
}
- name: Cherry-Pick
cherry_picker:
name: Cherry-Pick
needs: prerequisites
runs-on: ubuntu-latest
strategy:
matrix:
include: ${{ fromJSON(needs.prerequisites.outputs.matrix) }}
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Prepare cherry-pick branch
if: ${{ !env.ACT }}
run: |
git config --local user.email "[email protected]"
git config --local user.name "Worker Pants (Pantsbuild GitHub Automation Bot)"
bash -x build-support/bin/cherry_pick.sh ${{ github.event.pull_request.number || inputs.PR_number }} origin
git fetch --depth=2 origin "${{ needs.prerequisites.outputs.merge_commit }}"
# NB: If this fetch fails, we assume that means the milestone branch hasn't been created yet
git fetch --depth 1 origin "${{ matrix.milestone }}" || exit 0
git checkout -b "${{ matrix.branch_name }}" FETCH_HEAD
git cherry-pick "${{ needs.prerequisites.outputs.merge_commit }}"
git push -u origin "${{ matrix.branch_name }}"
- name: Create Cherry-Pick Branch
env:
GH_TOKEN: ${{ secrets.WORKER_PANTS_CHERRY_PICK_PAT }}
run: |
bash build-support/cherry_pick/make_pr.sh "${{ needs.prerequisites.outputs.pr_num }}" "${{ matrix.milestone }}"
post_pick:
name: Post-Pick Actions
needs: [cherry_picker, prerequisites]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check out code
uses: actions/checkout@v3
- run: npm install ./build-support/cherry_pick
- name: Run Script
# NB: See https://github.com/actions/github-script/pull/397
uses: thejcannon/github-script@7ed0cc648959192a3868f0de9862110d7922b7cc
with:
github-token: ${{ secrets.WORKER_PANTS_CHERRY_PICK_PAT }}
allow-empty-token: true
script: |
const Helper = require('./build-support/cherry_pick/helper.js');
const helper = new Helper({octokit: github, context, core});
await helper.cherry_pick_finished("${{ needs.prerequisites.outputs.merge_commit }}", ${{ needs.prerequisites.outputs.matrix }});
11 changes: 3 additions & 8 deletions .github/workflows/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@
# These aren't meant to be comprehensive, as they can be quite expensive to run. However, they are
# still useful as they can expose bugs before the action is run in "prod".

experimental_test_shell_command(
name="Test workflow_dispatch dryrun",
command="./act workflow_dispatch --dryrun",
execution_dependencies=[
"//build-support/bin/act:act-at-root",
".github/workflows:workflows",
],
workdir="/",
python_tests(
name="tests",
dependencies=["//build-support/bin/act:act-at-root"],
timeout=120,
)
76 changes: 76 additions & 0 deletions .github/workflows/tests/auto_cherry_picker_smoke_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
import subprocess
from textwrap import dedent

import pytest


@pytest.fixture(scope="session", autouse=True)
def stub_make_pr():
with open("build-support/cherry_pick/make_pr.sh", "w") as f:
f.write(
dedent(
"""\
#!/usr/bin/env bash
set -euo pipefail
echo "make_pr.sh $@"
# We exit 1 to test we still call the finish job
exit 1
"""
)
)


@pytest.fixture(scope="session", autouse=True)
def stub_helper():
with open("build-support/cherry_pick/helper.js", "w") as f:
f.write(
dedent(
"""\
class CherryPickHelper {
constructor({ octokit, context, core }) {}
async get_prereqs() {
return {
pr_num: 12345,
merge_commit: "ABCDEF12345",
milestones: ["2.16.x", "2.17.x"],
};
}
async cherry_pick_finished(merge_commit_sha, matrix_info) {
console.log(`cherry_picked_finished: ${merge_commit_sha} ${JSON.stringify(matrix_info)}`);
}
};
module.exports = CherryPickHelper;
"""
)
)


def test_auto_cherry_pick():
result = subprocess.run(
[
"./act",
"workflow_dispatch",
"-W",
".github/workflows/auto-cherry-picker.yaml",
"--input",
"PR_number=17295",
"--env",
"GITHUB_REPOSITORY=pantsbuild/pants",
],
text=True,
capture_output=True,
check=False,
)
stdout = result.stdout
print(stdout)
assert "make_pr.sh 12345 2.16.x" in stdout
assert "make_pr.sh 12345 2.17.x" in stdout
assert (
'cherry_picked_finished: ABCDEF12345 [{"milestone":"2.16.x","branch_name":"cherry-pick-12345-to-2.16.x"},{"milestone":"2.17.x","branch_name":"cherry-pick-12345-to-2.17.x"}]'
in stdout
)
116 changes: 0 additions & 116 deletions build-support/bin/cherry_pick.sh

This file was deleted.

11 changes: 11 additions & 0 deletions build-support/cherry_pick/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

package_json(name="package.json")

javascript_sources()
javascript_tests(name="tests")

shell_sources(name="shell")

files(name="support_files", sources=["*"])
Loading

0 comments on commit d6f6373

Please sign in to comment.