How do I set a github branch protection rule based on the success or failure of an entire github actions workflow? - github

I'm trying to set a github branch protection rule based on the success or failure of a github actions workflow.
You can see the workflow here:
https://github.com/apostrophecms/apostrophe/blob/main/.github/workflows/main.yml
The workflow passes, and I even have a working badge for it, but I am unable to set a branch protection rule requiring that it pass as a status check.
I can set a branch protection rule based on any one of the individual builds in the matrix, but I don't want to set all of them individually and keep track of that as my matrix rule changes.
As you can see from the screenshots, I am unable to pick "build", the name of the job (although I can pick any of the sub-builds), and I am also unable to pick "tests", the name of the workflow as a whole (it does not change if I use an uppercase t).
What am I missing? Thanks for your help!
Screenshot one: I can pick a sub-build but not the entire build job.
Screenshot two: I can't pick the name of the overall "Tests" workflow at all.

There's a trick to add one step to the workflow to collect all jobs from the matrix to one check:
tests:
runs-on: ubuntu-latest
needs: build
if: always()
steps:
- name: All tests ok
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Some tests failed
if: ${{ contains(needs.*.result, 'failure') }}
run: exit 1
if: always() is obligatory to collect failed tasks, otherwise PR will never get a proper status check. Also, this is an additional step for you to pay (if you use paid plans).

In this case, you have a single job with a matrix. That means you'll end with 9 possibilities (3 node options × 3 MongoDB options). Each of those is considered a separate status check and can be enabled or disabled as mandatory individually. This is so that you can add new options without making them mandatory up front.
If you want every one of those jobs to pass, then you need to choose every one of the 9 jobs and mark them as required.

Related

Skip a GitHub Action workflow that is run on successful completion of previous workflow, when the initial trigger was a pull request containing 'WIP'

Background / Context
We have two GitHub Action workflows 1. "Build, Test & Package" and 2. "Deploy to UAT".
Workflow (1) is triggered based on:
# runs on pull request (change or push) or tag (for release)
on:
pull_request:
release:
And builds our software, runs unit tests etc and packages up docker containers ready to be run in an environment.
Workflow (2) is then triggered on successful completion of workflow (1):
on:
# when the build workflow finished (not necessarily succeeded - that needs the IF below)
# NOTE: this *always* runs as if from the master branch
workflow_run:
workflows: ["Build, Test & Package"]
types:
- completed
# or manually
# NOTE: this *always* runs as if from the master branch
workflow_dispatch:
inputs:
PACKAGE_VERSION:
description: "PACKAGE_VERSION"
required: false
Which also needs an 'if' on the first step in the workflow to exclude running for unsuccessful executions of workflow (1).
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
Question
What I'd like to do, is EXCLUDE running the deployment workflow (2) when the initial pull request that kicks off the whole pipeline starting with (1) has "WIP" in its name somewhere.
Basically this is to avoid polluting our UAT environment with any build other than a current nominated 'current' PR, whilst still allowing our CI pipeline to run to verify tests etc for ALL pull requests even if they are 'WIP'.
Is this possible?

Configuration of GitHub Actions: Avoid running CI twice when merging PR into main

I am using GitHub a
ctions to manage my CI and the following events trigger my workflow:
on:
pull_request:
branches: main
push:
branches: main
I observed the following "problem":
When I create a PR, the CI is run. If the test passes and I merge it into main, the tests are run again (which I don'
t want in specific cases). How can I setup my workflow such that the CI is not triggered when merging a PR, where the CI already passed for the PR?
Thanks in advance!
You might consider an if conditional in your case:
jobs.<job_id>.if
You can use the jobs.<job_id>.if conditional to prevent a job from running unless a condition is met. You can use any supported context and expression to create a conditional.
When you use expressions in an if conditional, you may omit the expression syntax (${{ }}) because GitHub automatically evaluates the if conditional as an expression. For more information, see "Expressions".
jobs:
build:
if: github.event.pull_request.merged == false
. . .
That would still trigger the workflow, but it can skip the jobs in the workflow.
Alternatives exist in this thread, which deals with the opposite requirements ("Trigger workflow only on pull request merge"): it can be adapted to do what you need (not trigger a workflow, or at least do the same job twice, on PR merge)

Only run GitHub Actions manually while blocking Pull Request

I have a set of GitHub Actions configured to block pull requests from being merged until the Actions complete successfully. However, every time a new commit is pushed to a PR, the Actions are run again, which can be very wasteful if the author is not yet ready to merge, and intends to make future changes. Is there any way to have a GitHub Action still block a PR being merged but also not run the Action automatically?
With this recent update you can now convert pull requests back to draft status. So you could do that when you need to make changes and disable the CI for drafts. Then convert the draft to a pull request after the changes are complete to rerun CI.
on: pull_request
jobs:
build:
if: github.event.pull_request.draft == 'false'
runs-on: ubuntu-latest
steps:
...
One workaroound would be for the Action to look for a specific comment (for example: "[TO MERGE]: this commit is about ...), and:
return immediately if '[TO MERGE]' is not found, minimizing the action overhead on each commit
go on with checks, if '[TO MERGE]' is found.

Can I filter a GitHub action step based on the commit message?

I've recently added a static analysis step to my GitHub actions. However, it is somewhat expensive so I'm trying to reduce the number of times that this step is run. I've already added an appropriate filter so that it only runs on one OS and so that it only runs on my "feature" branches. However, I would like to also filter out any checkins that include "WIP" in their commit message. (The theory being that there is no point in performing the full analysis until it is no longer a "Work In Progress".)
I've searched through the docs, expecting I would find an object I could use as part of the github context object, but to no avail.
Any ideas on how I can accomplish this goal?
If you want to see exactly what I'm doing, the action Yaml is as follows. I'm hoping to find some change I can make to the if statement on the Static Analysis item that would accomplish my goal.
name: On Push
on: [push]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout#v1
- name: Build
run: |
./configure
make -j 4
- name: Run tests
run: |
make -j 4 check
- name: Static Analysis
if: runner.os == 'macOS' && startsWith(github.ref, 'refs/heads/feature/')
run: |
make analyze
You can make use of the event property on the github context to access the push payload.
Add the following to the step that does the analysis:
if: !startsWith(github.event.head_commit.message, 'WIP')
Related to your issue, you now (Feb. 2021) have:
GitHub Actions: Skip pull request and push workflows
with [skip ci]
GitHub Actions now supports skipping push and pull_request workflows by looking for some common keywords in your commit message.
If any commit message in your push or the HEAD commit of your PR contains the strings [skip ci], [ci skip], [no ci], [skip actions], or [actions skip] workflows triggered on the push or pull_request events will be skipped.
This is not as flexible as a custom commit message (like your "WIP"), but it still can help.
if: ${{ !startsWith(github.event.head_commit.message, '#NORUN') }}
Syntax should be like this

How to trigger a GitHub Action workflow for every successful commit

I want to run a GitHub Actions workflow for every successful commit (e.g. after all check suites have ran successfully).
It seems like the check_suite events will be fired for each individual check suite, and contain no information about the other suites. I want to wait for all registered check suites.
The status event seems to be exactly what I want:
Statuses can include a context to indicate what service is providing that status. For example, you may have your continuous integration service push statuses with a context of ci, and a security audit tool push statuses with a context of security. You can then use the combined status endpoint to retrieve the whole status for a commit.
But the status lives completely unrelated to the check_suites events, and most CI services now uses the check_suites (including GitHub Actions itself), and not status.
How can I, with a GitHub Actions workflow, check that all check_suites finished and the commit has successfully passed all checks and tests?
You can use the GitHub API to list the check suites belonging to a ref: https://octokit.github.io/rest.js/#octokit-routes-checks-list-suites-for-ref.
So, within your action (triggered by check_suite), you can list all the suites for the current ref, check they're all successful and then run your code.
If you're building a javascript action it could look like this:
import * as github from "#actions/github";
const response = await client.checks.listSuitesForRef({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
ref: sha
});
const passes = response.data.check_suites.every(...)
if (passes) { ... }
The major drawback of this approach is that this very action is itself a check suite belonging to the current commit, so it will appear in response.data.check_suites (and will never be successful at this point ... because it's still running!). I don't have a solution for this part yet...
It looks like you are now able to trigger actions based on commit status (reference).
on:
status
jobs:
if_error_or_failure:
runs-on: ubuntu-latest
if: >-
github.event.state == 'error' ||
github.event.state == 'failure'
steps:
- env:
DESCRIPTION: ${{ github.event.description }}
run: |
echo The status is error or failed: $DESCRIPTION