Multiple PR's get created at once, causes actions to stomp on one another

In my repo, I have a devel/test/prod branch. If a PR is opened to prod, I have it so actions copies/opens a new PR’s to devel/test. If test passes, it then unlocks the PR to prod to let a human merge it.

The problem is each of those PR’s all have the same commit, so they all run their suite of actions on that commit at once. (If test starts running it’s suite, it’s possible for devel to start it’s after, and the test PR will show devel’s workflow instead of it’s own. This is especially annoying when some actions get overridden with the ‘skipped’ workflow from a completely different PR.).

Is this a known/unknown bug? Or more than likely, am I missing a way to separate them? If this is a bug, could someone point me to a place to better report this? Maybe this is a known limitation, and I have to open each PR one at a time?

Workflow that triggers on merge TO prod:

name: Auto merge PR's

on:
  pull_request:
    types:
      - opened
      - reopened
      - labeled
      - unlabeled
      - edited
      - synchronize

jobs:
  automerge:
    name: Automerge [prod]
    if: >
      github.event.pull_request.base.ref == 'prod' &&
      contains(github.event.pull_request.labels.*.name, 'auto merge')
    runs-on: ubuntu-latest
    strategy:
      matrix:
        merge_to_branch: [devel, test]
    steps:

      # Setup Git:
      - uses: actions/checkout@v2
        with:
          ref: ${{ matrix.merge_to_branch }}

      # Change what is in the PR
      - name: Reset branch to ${head_of_pr}
        run: |
          git fetch origin ${head_of_pr}:${head_of_pr}
          git reset --hard ${head_of_pr}
        env:
          head_of_pr: ${{ github.event.pull_request.head.ref }}

      # Open PR to target branch:
      - name: "Open PR to ${{ matrix.merge_to_branch }}"
        uses: peter-evans/create-pull-request@v3.8.2
        with:
          # Let bot open the PR, so auto merge can trigger
          token: ${{ secrets.BOT_TOKEN }}
          labels: 'auto merge, dependancies'
          # Open from wherever the PR was from, to each base branch:
          branch: ${{ github.event.pull_request.head.ref }}
          base: ${{ matrix.merge_to_branch }}
          title: "Automatic merge triggered from ${{ github.event.pull_request.head.ref }} to ${{ matrix.merge_to_branch }}"

      - if: matrix.merge_to_branch == 'test'
        name: 'Wait for action suite'
        uses: "WyriHaximus/github-action-wait-for-status@v1.3"
        id: waitforstatuschecks
        with:
          checkInterval: 10
          # Ignore the action, with the right matrix label:
          ignoreActions: "Automerge [prod] (${{ matrix.merge_to_branch }})"
        env:
          GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

      - if: matrix.merge_to_branch == 'test'
        name: 'Check success of action suite'  
        run: "[[ \"${{ steps.waitforstatuschecks.outputs.status }}\" == 'success' ]]"

      # PR should now be good to merge. TODO: Take off the 'auto merge' label, and assign reviewers

Hi @Cameronsplaze :wave:
Thanks for making your first post! You have come to the right place. I am going to move this to our Actions category for better visibility.

Good to hear! And thanks for moving this too.

1 Like

I know it would be duplicating some steps, but why not get rid of the matrix, and then sequentially push to DEV, the TEST, then back to PROD?

I won’t be able to try this out til tomorrow, but I think it would work… I just really hate duplicated code lol. I probably should just bite the bullet on this one though.
Any idea if how these PR’s are currently acting, are intended? With new PR’s overriding the runs of different PR’s I mean. I’m worried it just isn’t possible to separate the different actions to their separate PR’s.

I’ll be honest I’ll have to try it out some to really grok the interactions. Is your repo public where I could look at some stuff and poke around?

In theory the PRs shouldn’t be overwriting each other, but I’m thinking this is a race condition (aka timing issue) with the matrix command and the spawning of multiple jobs that run in parallel.

My first step would be to break it into a bunch of sequential steps and see if you can get it working that way. that should work no problem.

1 Like

I think I see what you mean. My guess is if I break it out into two jobs, and let those go in parallel, it’ll still act like being in a matrix. I’m definitely down to try it tomorrow, I’m just on a different team today. I agree though, running everything in sequential first is a good first step.

The repo I’m working on is here, feel free to poke around!

It might be hard to see what’s going on though, the actions in the pr itself get overridden, and the commits have a ton of jobs tied to them. Feel free to ask if you have any questions!

yes, you may be right. I’ll have to think on this some.

If I understand your outline, you PR to Dev and Test. It doesn’t matter what happens in DEV, it only matters what happens in test.

I’ll see if I can find some time later today/tonight to play with it.

1 Like

No rush! Thanks a ton for looking into this too.

And you’re exactly right. Devel is the wild west, but if test fails, we want it to block the prod PR from merging.

So why do you PR into different branches like that? Why not just use environments, and deploy directly to DEV/TEST/PROD? I’m gonna try and figure it out how you are doing it, but I may want to try and convince you to try something else :slight_smile:

@Cameronsplaze

I think I know why you are seeing the DEVEL and TEST workflow runs show up on both the PRs to DEVEL and TEST. I’m gonna try and explain it here, but I’m also happy to hop on a Zoom call with you for about 15 minutes this week to talk through it as well.

The problem is the logic in your auto-merge-nonprod.yml file.

on:
  pull_request:
    types:
      - opened
      - reopened
      - labeled
      - unlabeled
      - edited
      - synchronize

jobs:
  automerge-nonprod:
    name: Automerge [non-prod]
    if: >
      github.event.pull_request.base.ref != 'prod' &&
      contains(github.event.pull_request.labels.*.name, 'auto merge')

Your trigger is any type of pull request, and then you have an if statement to confirm that it isn’t a pull request to the prod branch. Well, you are automatically creating two new pull requests, one for DEVEL and one for TEST. So the workflow that is triggered for both applies to both. I’m not doing a good job of explaining it, but it ultimately is the logic here.

I think the solution would be to create two auto-merge-nonprod.yml, one for DEVREL and one for TEST. You would then need to modify your if statement appropriately.

Hi @mickeygousset,

I finally get to spend the day on this, thank you for being patient!

This is the first I’ve heard of environments, but I’m having a hard time seeing how they move code between branches. Sorry if this is part obvious, but we have other features we push to devel, then manually move up to test, then prod. The reason I open the original PR to prod, then copy to devel/test, is to not bring the other commits up the chain with these security updates. Maybe there’s a route with cherry picking I can do instead, and start the PR’s from devel with only merging that one change?

(Edited) I see what you mean with spitting it apart now. That’s why it’s creating the workflow and skipping it, instead of just ignoring it exists! I’m about to try to separate them, but I’m confused what to use instead of the ‘if’. The 'on: branches: ’ checks if the pr is opened from a branch, and I want to check if the pr is open to a branch. Is there a key I’m missing maybe?

Wouldn’t you just say:

github.event.pull_request.base.ref == ‘devel’ &&
contains(github.event.pull_request.labels.*.name, ‘auto merge’)

or

github.event.pull_request.base.ref == ‘test’ &&
contains(github.event.pull_request.labels.*.name, ‘auto merge’)

Instead of checking that you aren’t on PROD, in each individual file, you check to make sure you ARE on the branch for that particular file?

Oh, I don’t think I understand your comment before this one then. I’d love to jump in a zoom call sometime!

I was thinking you meant if we could get the condition check inside the ‘on’ block, instead of the ‘jobs: if’, it wouldn’t create the skipped job that override the existing one running. (Since it wouldn’t even trigger the action).

There was a bug in how I was waiting (it would just hang before), so I got that worked out and switched the prod only to NOT be a matrix now (first devel runs, then test). It’s still hitting the problem where, since the prod PR is opened first, when dev and/or test run, the “skipped” prod-only action those produce overrides the original one. If I separate out the nonprod action, they’re still on the same commit and running after the prod PR, so it’ll still get overridden I think?

Is pr’s affecting one another like this if they’re on the same commit intentional? Maybe I can submit a feature request keep actions separated based on target branch of PR?

Pinning the exact commit I’m on, for if future people are interested: