Github actions and required checks in a monorepo (using paths to limit execution)

I have a workflow defined like this:

name: Api Lint

on:
  push:
    branches:
    - master
    paths:
    - api/**
  pull_request:
    paths:
    - api/**

jobs:
  api-lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Use Node.js 12.x
      uses: actions/setup-node@v1
      with:
        node-version: 12.x
    - run: yarn install
    - name: api lint
      working-directory: ./api
      env:
        CI: true
      run: |
        yarn lint

You’ll notice this job only runs when the pull_request changes a file under the api directory. I’d like to make this a required check using the “Require status checks to pass before merging” setting, but when I make a change that does not touch the api directory the check does not run, so does not pass and I can’t merge my change with that enforcement in place.

Any ideas? Thanks!

6 Likes

I used a hack to achieve what you want:
I created another workflow with dummy jobs that have the same names with those required jobs that are not always triggered.
In case the job is triggered and failed, it still still be push blocking according to required check. If it’s not triggered, then the dummy job will always succeed and unblocks the push.
I hope GitHub can build some native solution for this.

5 Likes

That’s a wild hack, lol. Would you mind sharing what your dummy job looks like? Thanks! For example, does it still start the container and have all of that overhead?

Something like

name: Dummy
on: push

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Do nothing
        run: exit 0
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Do nothing
        run: exit 0
3 Likes

I would not really call such hack a sane solution, but would rather see native implementation skipping checks for pull requests that do not touch paths defined for the action pull request event.

5 Likes

Yes, can we re-open this so Github can make a real solution?

EDIT: created https://github.community/t5/GitHub-Actions/Feature-request-conditional-required-checks/m-p/36938#M2735

2 Likes

It may be dicey, but as it stands @samchou19815’s method of always triggering the dummy jobs that are named the same as the real jobs appears necessary to enable requiring different checks for different code paths. For example, requiring some tests to pass for changes to one service, but a different set of tests or no tests at all for another service or updates to the docs.

When there are multiple checks registered on the pull request with the same name, they all have to pass to fulfill the requirement. Also, the dummy job and the real job both start up at about the same time, so there’s no real window where the dummy has a chance to finish and allow merging before the real job starts up.

I call my dummy “automerge”

name: Automerge
on:
  pull_request:
    branches:
      - master
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Exit with success
        run: exit 0

For anyone wondering, you can do this with the paths-filter action. It runs a job to check which path changed (checkout not needed for this job, which is a plus), then the following jobs will conditionally run or skip. Then you can mark them all as required.

I understand it’s quite an old ticket, but we have actually created a new GitHub Action for this use case.

Merge Gatekeeper is still in its early days, but it comes with a simple mindset that all jobs that ran should be in a success state. Merge Gatekeeper’s job is to wait and check other job status, and only becomes successful when all other jobs ran to completion and in a success state.

With that simple logic, you will only need to add a new Action setup using Merge Gatekeeper to your monorepo, and set it as the only required job - no other jobs need to be marked as required. As mentioned, the assumption is that no job should be in failed state, but this works nicely without any complex Action definitions.

If you need more granular control and ignore some failed state, it may be better handled with the solution @cscleison has referenced above, which looks great for some paths based branching :+1: