From a76a4be6c890cc468bc9d2f99720305efff6395e Mon Sep 17 00:00:00 2001 From: tetrapod00 <145553014+tetrapod00@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:09:28 -0800 Subject: [PATCH 1/3] Add GitHub Action to automatically create cherrypick PRs Uses peter-evans/create-pull-request and actions/checkout, both of which are already dependencies. When merging a PR with a cherrypick label, which only contains a single commit, attempt to cherrypick the single commit into a new branch, then create a PR. Fails if there are multiple commits (to catch squash and merge). Fails if the cherrypick does not apply cleanly. Does not attempt to merge the new PR. Does not attempt to update stable. --- .github/workflows/cherrypick.yml | 70 ++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/cherrypick.yml diff --git a/.github/workflows/cherrypick.yml b/.github/workflows/cherrypick.yml new file mode 100644 index 00000000000..9868c35a16e --- /dev/null +++ b/.github/workflows/cherrypick.yml @@ -0,0 +1,70 @@ +name: Create Cherrypick PR + +on: + pull_request: + types: + - closed + branches: + # TODO extract this to an env variable? + - 'master' + +env: + # TODO add a way to handle multiple potential cherrypick targets. + TARGET_BRANCH: '4.3' + USERNAME: 'Godot Organization' + EMAIL: 'noreply@godotengine.org' + +jobs: + Create-cherrypick-PR: + # Only attempt to cherrypick PRs with a single commit. + # PRs with multiple commits are merged with "Squash and merge" and are structured differently. + # The cherrypick label is hardcoded because contains() doesn't seem to be able to use an environment variable as a second argument. + if: ${{ github.event.pull_request.merged == true && github.event.pull_request.commits == 1 && contains( github.event.pull_request.labels.*.name, 'cherrypick:4.3' ) }} + runs-on: ubuntu-latest + env: + # In the typical case of a PR with a single commit, merged with a merge commit, + # this will be the commit to cherrypick. + COMMIT_HASH: ${{ github.event.pull_request.head.sha }} + PR_NUMBER: ${{ github.event.number }} + + steps: + + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ env.TARGET_BRANCH }} + + - name: Cherrypick Commit + id: cherrypick_commit + continue-on-error: true + # TODO maybe only fetch some branches? + run: | + git config user.name "${{ env.USERNAME }}" + git config user.email "${{ env.EMAIL }}" + git fetch + git cherry-pick -m 1 ${{ env.COMMIT_HASH }} + + - name: Create Pull Request + if: steps.cherrypick_commit.outcome == 'success' + uses: peter-evans/create-pull-request@v7 + with: + commit-message: 'Cherrypick to ${{ env.TARGET_BRANCH }}' + branch: 'cherrypick-${{ env.PR_NUMBER }}-${{ env.TARGET_BRANCH }}' + delete-branch: true + + # Configure the commit author. + author: '${{ env.USERNAME }} <${{ env.EMAIL }}>' + committer: '${{ env.USERNAME }} <${{ env.EMAIL }}>' + + # Configure the pull request. + title: 'Cherrypick ${{ env.PR_NUMBER }} to ${{ env.TARGET_BRANCH }}' + body: 'Cherrypick #${{ env.PR_NUMBER }} to ${{ env.TARGET_BRANCH }}.' + # TODO only add the bug or enhancement label, depending on which the original PR uses. + labels: 'bug,enhancement' + + - name: Handle failure + if: steps.cherrypick_commit.outcome == 'failure' + run: | + echo "Can't automatically cherrypick. Potential causes:" + echo "- PR has multiple commits. Did you squash and merge?" + echo "- Cherrypick did not apply cleanly and can't be auto-merged." From 666ac9e28bde265199101ded0cb6135a7b37117d Mon Sep 17 00:00:00 2001 From: tetrapod00 <145553014+tetrapod00@users.noreply.github.com> Date: Tue, 3 Dec 2024 00:40:44 -0800 Subject: [PATCH 2/3] Handle squash and merge --- .github/workflows/cherrypick.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cherrypick.yml b/.github/workflows/cherrypick.yml index 9868c35a16e..901845dc34b 100644 --- a/.github/workflows/cherrypick.yml +++ b/.github/workflows/cherrypick.yml @@ -16,15 +16,16 @@ env: jobs: Create-cherrypick-PR: - # Only attempt to cherrypick PRs with a single commit. - # PRs with multiple commits are merged with "Squash and merge" and are structured differently. # The cherrypick label is hardcoded because contains() doesn't seem to be able to use an environment variable as a second argument. - if: ${{ github.event.pull_request.merged == true && github.event.pull_request.commits == 1 && contains( github.event.pull_request.labels.*.name, 'cherrypick:4.3' ) }} + if: ${{ github.event.pull_request.merged == true && contains( github.event.pull_request.labels.*.name, 'cherrypick:4.3' ) }} runs-on: ubuntu-latest env: - # In the typical case of a PR with a single commit, merged with a merge commit, - # this will be the commit to cherrypick. - COMMIT_HASH: ${{ github.event.pull_request.head.sha }} + # "Ternary" hack featured in the official docs. + # When using "Squash and merge", the commit hash is the last merge commit of the pull request merge branch. + # When using "Merge", the commit hash is the last commit to the head branch of the pull request. + # This is mildly error-prone, since in theory we could merge multiple commits without squashing. + # We are relying on human review of the generated PRs to catch that. + COMMIT_HASH: ${{ github.event.pull_request.commits > 1 && github.sha || github.event.pull_request.head.sha }} PR_NUMBER: ${{ github.event.number }} steps: From b0c0eeb49adf2157d8af18186a3d30e02b3dea1d Mon Sep 17 00:00:00 2001 From: tetrapod <145553014+tetrapod00@users.noreply.github.com> Date: Tue, 24 Dec 2024 08:09:59 -0800 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Thaddeus Crews --- .github/workflows/cherrypick.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cherrypick.yml b/.github/workflows/cherrypick.yml index 901845dc34b..f8777d6785a 100644 --- a/.github/workflows/cherrypick.yml +++ b/.github/workflows/cherrypick.yml @@ -5,24 +5,24 @@ on: types: - closed branches: - # TODO extract this to an env variable? + # TODO: Extract this to an env variable? - 'master' env: - # TODO add a way to handle multiple potential cherrypick targets. + # TODO: Add a way to handle multiple potential cherrypick targets. TARGET_BRANCH: '4.3' USERNAME: 'Godot Organization' EMAIL: 'noreply@godotengine.org' jobs: Create-cherrypick-PR: - # The cherrypick label is hardcoded because contains() doesn't seem to be able to use an environment variable as a second argument. + # The cherrypick label is hardcoded because `contains()` doesn't seem to be able to use an environment variable as a second argument. if: ${{ github.event.pull_request.merged == true && contains( github.event.pull_request.labels.*.name, 'cherrypick:4.3' ) }} runs-on: ubuntu-latest env: # "Ternary" hack featured in the official docs. # When using "Squash and merge", the commit hash is the last merge commit of the pull request merge branch. - # When using "Merge", the commit hash is the last commit to the head branch of the pull request. + # When using "Merge", the commit hash is the last commit to the head branch of the pull request. # This is mildly error-prone, since in theory we could merge multiple commits without squashing. # We are relying on human review of the generated PRs to catch that. COMMIT_HASH: ${{ github.event.pull_request.commits > 1 && github.sha || github.event.pull_request.head.sha }} @@ -38,7 +38,7 @@ jobs: - name: Cherrypick Commit id: cherrypick_commit continue-on-error: true - # TODO maybe only fetch some branches? + # TODO: Maybe only fetch some branches? run: | git config user.name "${{ env.USERNAME }}" git config user.email "${{ env.EMAIL }}" @@ -60,7 +60,7 @@ jobs: # Configure the pull request. title: 'Cherrypick ${{ env.PR_NUMBER }} to ${{ env.TARGET_BRANCH }}' body: 'Cherrypick #${{ env.PR_NUMBER }} to ${{ env.TARGET_BRANCH }}.' - # TODO only add the bug or enhancement label, depending on which the original PR uses. + # TODO: Only add the bug or enhancement label, depending on which the original PR uses. labels: 'bug,enhancement' - name: Handle failure