42

With Travis CI, we can skip the build for a particular commit with adding a suffix to a commit. This is described at Travis CI. I find this feature practical when I only edit README.md which is not code-related and the pre-flight build doesn't need to be triggered.

[skip ci]

How do I skip the jobs trigged on: push events using GitHub Actions?

name: Maven Build
on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - name: Check-out project
      uses: actions/checkout@v1
    - name: Set up JDK 11.0.3
      uses: actions/setup-java@v1
      with:
        java-version: 11.0.3
    - name: Build with Maven
      run: mvn -B package --file pom.xml

Answers summary:

Big thanks to all the answerers providing various ways to achieve it. I bet everybody would need something a little bit different regarding to the origin of their problem and the CI approach. Here are the answers listed for a quick navigation:

All the answers deserve upvote! If you like my question, you should double-like the answers.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • 1
    Related to: [How to skip all steps at once?](https://github.community/t5/GitHub-Actions/How-to-skip-all-steps-at-once/m-p/56422) – Evandro Coan Apr 30 '20 at 23:51
  • https://github.com/fkirc/skip-duplicate-actions is a simple third party solution that helps in the case that GitHub's native solutions are not sufficiently powerful or flexible – Mike76 Dec 15 '20 at 21:57
  • 2
    The new (Feb. 2021) `[skip ci]` commit message policy is also interesting: https://stackoverflow.com/a/66114678/6309 – VonC Feb 09 '21 at 07:31
  • @VonC: That's a great feature! You could have answered it here. I have linked your answer in the summary of my question since I find it very helpful. Thanks! – Nikolas Charalambidis Feb 09 '21 at 08:31
  • @NikolasCharalambidis No: it is based on commit-message, while your question was more file-based, if I am not mistaken. – VonC Feb 09 '21 at 08:32
  • It's a mix-up. With Travis-CI, I used the commit-based approach (I didn't find a better one) to skip the CI on the `README.md` file commit. That's why I find your answer relevant there. – Nikolas Charalambidis Feb 09 '21 at 09:08

4 Answers4

61

UPDATE: Please see Helmisek anwser, which points out that Github has the functionality built-in now.

My answer only makes sense, if you want to skip just some jobs/steps.


You can give the following a try:

name: Maven Build
on: [push]

jobs:
  build:
    if: "!contains(github.event.commits[0].message, '[skip ci]')"
    runs-on: ubuntu-latest

    steps:
    - name: Check-out project
      uses: actions/checkout@v1
    - name: Set up JDK 11.0.3
      uses: actions/setup-java@v1
      with:
        java-version: 11.0.3
    - name: Build with Maven
      run: mvn -B package --file pom.xml
General Grievance
  • 4,555
  • 31
  • 31
  • 45
scthi
  • 2,205
  • 1
  • 18
  • 14
43

As of now (Feb, 2021) GitHub actions do support this behavior by default. No more parsing etc. for the default cases.

See:

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.

Link: Github Actions Changelog, February 2021

Helmisek
  • 1,209
  • 11
  • 12
  • 4
    I've just tried it out and it works okay. For example `chore: build script update [skip ci]` and it's skipped. – Helmisek Jul 06 '21 at 11:21
39

Also, for files and directories you want ignored on all pushes you can configure the workflow itself:

on:
  push:
    paths-ignore:
    - 'README.md'
oliverbarnes
  • 2,111
  • 1
  • 20
  • 31
  • `I sense great power coming from that box. I must know about these powers, I want to see it.` git commit -m "update workflow.yml to skip running on readme changes [skip ci]" – mts Sep 23 '22 at 00:18
2

Git 2.27 (Q2 2020) illustrates another approach: Instead of always building all branches at GitHub via Actions, users can specify which branches to build.

See commit e76eec3 (07 May 2020) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit dd4a287, 13 May 2020)

ci: allow per-branch config for GitHub Actions

Signed-off-by: Jeff King

Depending on the workflows of individual developers, it can either be convenient or annoying that our GitHub Actions CI jobs are run on every branch.

As an example of annoying: if you carry many half-finished work-in-progress branches and rebase them frequently against master, you'd get tons of failure reports that aren't interesting (not to mention the wasted CPU).

This commit adds a new job which checks a special branch within the repository for CI config, and then runs a shell script it finds there to decide whether to skip the rest of the tests.

The default will continue to run tests for all refs if that branch or script is missing.

There have been a few alternatives discussed:

One option is to carry information in the commit itself about whether it should be tested, either in the tree itself (changing the workflow YAML file) or in the commit message (a "[skip ci]" flag or similar). But these are frustrating and error-prone to use:

  • you have to manually apply them to each branch that you want to mark
  • it's easy for them to leak into other workflows, like emailing patches

We could likewise try to get some information from the branch name. But that leads to debates about whether the default should be "off" or "on", and overriding still ends up somewhat awkward.
If we default to "on", you have to remember to name your branches appropriately to skip CI.
And if "off", you end up having to contort your branch names or duplicate your pushes with an extra refspec.

By comparison, this commit's solution lets you specify your config once and forget about it, and all of the data is off in its own ref, where it can be changed by individual forks without touching the main tree.

There were a few design decisions that came out of on-list discussion. I'll summarize here:

  • we could use GitHub's API to retrieve the config ref, rather than a real checkout (and then just operate on it via some javascript).
    We still have to spin up a VM and contact GitHub over the network from it either way, so it ends up not being much faster.
    I opted to go with shell to keep things similar to our other tools (and really could implement allow-refs in any language you want). This also makes it easy to test your script locally, and to modify it within the context of a normal git.git tree.

  • we could keep the well-known refname out of refs/heads/ to avoid cluttering the branch namespace. But that makes it awkward to manipulate.
    By contrast, you can just "git checkout ci-config" to make changes.

  • we could assume the ci-config ref has nothing in it except config (i.e., a branch unrelated to the rest of git.git).
    But dealing with orphan branches is awkward. Instead, we'll do our best to efficiently check out only the ci/config directory using a shallow partial clone, which allows your ci-config branch to be just a normal branch, with your config changes on top.

  • we could provide a simpler interface, like a static list of ref patterns.
    But we can't get out of spinning up a whole VM anyway, so we might as well use that feature to make the config as flexible as possible.
    If we add more config, we should be able to reuse our partial-clone to set more outputs.

So the script is ci/config/allow-refs.sample:

#!/bin/sh
#
# Sample script for enabling/disabling GitHub Actions CI runs on
# particular refs. By default, CI is run for all branches pushed to
# GitHub. You can override this by dropping the ".sample" from the script,
# editing it, committing, and pushing the result to the "ci-config" branch of
# your repository:
#
#   git checkout -b ci-config
#   cp allow-refs.sample allow-refs
#   $EDITOR allow-refs
#   git commit -am "implement my ci preferences"
#   git push
#
# This script will then be run when any refs are pushed to that repository. It
# gets the fully qualified refname as the first argument, and should exit with
# success only for refs for which you want to run CI.

case "$1" in
# allow one-off tests by pushing to "for-ci" or "for-ci/mybranch"
refs/heads/for-ci*) true ;;
# always build your integration branch
refs/heads/my-integration-branch) true ;;
# don't build any other branches or tags
*) false ;;
esac

All the action .github/workflows has to do is

  • Checkout the special branch and the special script in it:

That is:

git -c protocol.version=2 clone \
  --no-tags \
  --single-branch \
  -b ci-config \
  --depth 1 \
  --no-checkout \
  --filter=blob:none \
  https://github.com/${{ github.repository }} config-repo \
&& \
cd config-repo \
&& \
git checkout HEAD -- ci/config
  • Check if the pushed branch is authorized:

Which is:

enabled=yes
if test -x config-repo/ci/config/allow-ref &&
         ! config-repo/ci/config/allow-ref '${{ github.ref }}'
then
  enabled=no
fi
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250