korthout / backport-action

Fast and flexible GitHub action to cherry-pick merged pull requests to selected branches
MIT License
61 stars 26 forks source link

Feature request : backport to all open feature branches #343

Closed RupertBarrow closed 1 year ago

RupertBarrow commented 1 year ago

It would be nice to be able to backport to all feature branches currently open named eg 'feature/*'. The configuration would be something like:

This would create a PR on each feature/* branch.

korthout commented 1 year ago

Hi @RupertBarrow 👋 That's a great request!

✅ You can use the target_branches input for this, since v1.3.0.

Note that the target_branches input requires space-delimited branches, so finding these requires a checkout with a deep fetch and an extra step in your workflow.

name: Backport to all feature branches
on:
  pull_request_target:
    types: [closed]
permissions:
  contents: write # so it can comment
  pull-requests: write # so it can create pull requests
jobs:
  backport:
    name: Open backport pull requests
    runs-on: ubuntu-latest
    # Don't run on closed unmerged pull requests
    if: github.event.pull_request.merged
    steps:
      - uses: actions/checkout@v3
        with:
          # Fetch all branches
          fetch-depth: 0

      - id: branches
        shell: bash
        # list all banches, filtering for 'feature/*', and cutting off remotes/origin/
        # then finally substitute newlines for spaces
        run: |
          branches=$(git branch --list --all | grep 'origin/feature/' | cut -c 18- )
          space_delimited=${branches//$'\n'/ }
          echo "BRANCHES=${space_delimited}" >> $GITHUB_OUTPUT

      - uses: korthout/backport-action@v1
        with:
          # now you can use the branches output in the backport-action
          target_branches: ${{ steps.branches.outputs.BRANCHES }}
Tested with an example workflow

[Example run](https://github.com/korthout/zeebe/actions/runs/5134971757/jobs/9239736633), using workflow: ```yml name: Space delimit branches on: workflow_dispatch: {} jobs: branches: name: Space delimited branches runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - id: branches shell: bash run: | branches=$(git branch --list --all | grep 'origin/stable/' | cut -c 18- ) space_delimited=${branches//$'\n'/ } echo "BRANCHES=${space_delimited}" >> $GITHUB_OUTPUT - run: echo "${{ steps.branches.outputs.BRANCHES }}" ```

RupertBarrow commented 1 year ago

Wow, thanks for the quick turnaround and the detailed response ! It would be great if "target_branches" accepted a regex. If that is difficult, you could create a specific "target_branches_regex" parameter just for that.

Thanks for the solution : I will try it out and tell you how it goes !

RupertBarrow commented 1 year ago

Hi @korthout , Unfortunately the backport did not go as well as expected in Github Actions : feature branches are found correctly but I have 3 issues:

  1. backport is trying to merge into the feature branch which triggered the packport Github Action : we need to find a way of excluding that branch from the target_branches
  2. more severe : the cherry picking is failing for an unknown reason, the same on each target branch (see attached log)
  3. moreover, when the cherry-picking fails, it does not make the workflow fail : unless you look in the logs, it looks like the workflow succeeded

backport.log.zip

korthout commented 1 year ago

Hi @RupertBarrow Thanks for sharing the logs, it helps a lot in troubleshooting this.

🏗️ Let's see if we can get it to work as you expect.

  1. 🔧 There are a few ways you could avoid backporting to the merged branch:
    • make sure that the branch is deleted before the workflow executes
    • remove the branch from the target branches, using inverted grep | grep -v ${merged_branch_name}, which will require you to figure out the name of the merged branch. This may be available under the pull_request_target's payload pull_request, e.g. github.event.pull_request.head.ref or github.event.pull_request.head.label, but you may have to strip parts of the ref away.
  2. ❌ The actions failed backporting to:
    • the merged branch, because the cherry-pick results in an empty commit which is not supported by this action (yet).
    • the other branches, because there is a merge conflict. There is only so much automation can achieve, the action cannot decide how to resolve conflicts. In that case, it comments on the pull request with instructions how to attempt the cherry-pick locally, so a human can attempt to resolve the conflicts. Try to backport pull requests with changes that won't conflict on the other branches.
  3. ✅ The workflow succeeded because the error is reported as comments on the pull request. The idea is that the workflow should only fail when misconfigured, e.g. missing required permissions to comment. If you wish to change this behavior you can use the action's outputs to fail the workflow ❌
RupertBarrow commented 1 year ago

Thanks, again, for your quick answers.

  1. of course, best answer. But I don't always (yet) want to automatically deleted merged branches, often because I could make fixes on the same branch after QA (not best practice but ... well ...)
  2. so your Github Action attempts the merge itself, immediately ? I thought it would be more respectful of developers working on those branches to propose them a PR : up to them to merge the PR when they prefer, and when they are ready. Can your workflow not generate a PR, rather than merging itself immediately ?
  3. I understand your point of view.
korthout commented 1 year ago

I'm happy to try and get this working for you 👍 I'm convinced we can.

    • As a counter argument, when GitHub deletes the branch it keeps a hidden reference so you can always recover it (there's even a button in the bottom of the pull request for this after deleting the branch). In addition, since git is decentralised the branch still exists on your local machine and you can easily push it to GitHub again with your new commits.
    • If it really is no option to delete the branch, then please follow the instructions I gave on removing the branch name from the target_branches input. This will require some additional bash instructions in the branches step of the workflow above. If you need help with this, please let me know.
  1. The action creates a pull request (see step 3 in How it works). It does not automatically merge the created pull request. However, in step 2 it cherry-picks the commits from the original pull request onto the target branch. There can be conflicts on cherry-picking the changes, which is the case in the logs you've shared. If you want the action to succeed, you need to backport changes that don't conflict with the branches they are backported to.

Here you can see the cherry-pick not being able to apply the changes due to a conflict:

2023-05-31T17:36:48.1661328Z Switched to a new branch 'backport-135-to-feature/42-epic-run-rapido-companion-as-an-lwr-application' 2023-05-31T17:36:48.1679969Z git cherry-pick -x 8ac6904b5a994e454d3671ba79b29f56636641f3 2023-05-31T17:36:48.3866870Z error: could not apply 8ac6904... ci: added backport from "main" to feature branches 2023-05-31T17:36:48.3868445Z hint: After resolving the conflicts, mark them with 2023-05-31T17:36:48.3868952Z hint: "git add/rm ", then run 2023-05-31T17:36:48.3869713Z hint: "git cherry-pick --continue". 2023-05-31T17:36:48.3870396Z hint: You can instead skip this commit with "git cherry-pick --skip". 2023-05-31T17:36:48.3871099Z hint: To abort and get back to the state before "git cherry-pick", 2023-05-31T17:36:48.3871672Z hint: run "git cherry-pick --abort". 2023-05-31T17:36:48.3888843Z git cherry-pick --abort 2023-05-31T17:36:48.5223614Z Backport failed for feature/42-epic-run-rapido-companion-as-an-lwr-application, because it was unable to cherry-pick the commit(s).

Hope this helps 🙇

korthout commented 1 year ago

I thought a bit more about the problem you're facing, and I see two ways the action can help support this better:

I'll re-open this issue to track this.

korthout commented 1 year ago
  • exclude original pull request's branch name (head) from the target branches (can also be considered a bug on target_branches input
  • allow glob patterns in target_branches input, with a documentation note that this requires a deep checkout using fetch-depth: 0

@RupertBarrow I've resolved the first of these two with #344, which is now available on versions v1.3.1, v1.3 and v1 (as well as v1.next-preview). If you have the chance, please give it another try.

To support glob patterns in target_branches input, I'll open a separate issue.