2

A common pattern in GitHub action workflows is to run something like this:

  - name: Install and Build 
    run: |
      npm ci
      npm run build

Clearly the intention is to run the second command only if the first command succeeds.

When running on Linux, the question becomes if the shell runs with set -e semantics. This answer suggests that set -e semantics are the default.

I'm trying to find that information in the documentation, but I'm a bit confused how it is specified. The section on exit codes contains the following for shell/sh shells:

Fail-fast behavior using set -eo pipefail: This option is set when shell: bash is explicitly specified. It is not applied by default.

This seems to contradict the other answer (and question!), and would mean that the above pattern actually is invalid, because the second line would be executed even if the first line fails.

Am I just misreading the documentation, or is it really necessary to either always specify set -e manually or add the shell: bash explicitly to get the desired behavior?

bluenote10
  • 23,414
  • 14
  • 122
  • 178
  • Relevant: https://stackoverflow.com/a/75401626/7670262 – Azeem Feb 11 '23 at 10:42
  • What adds to the confusion: The documentation of the [`shell`](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell) settings says that `bash` is the default if it is available. So, if `shell` is unspecified, it actually uses `bash`, but since it wasn't "specified explicitly" it has different semantics regarding error handling? That's unexpected. – bluenote10 Feb 11 '23 at 10:49
  • The part "**It is not applied by default.**" sure is contradictory. – Azeem Feb 11 '23 at 11:11
  • 1
    Just tested [here](https://github.com/iamazeem/test/actions/runs/4151180961) to verify for unspecified, sh, and bash. Result: with unspecified (`shell: /usr/bin/bash -e {0}`), with sh (`shell: /usr/bin/sh -e {0}`), and with bash (`shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}`). In all cases, the `set -e` semantics are there. The docs surely need to be updated to avoid confusion. – Azeem Feb 11 '23 at 11:51
  • @Azeem I see, thanks for the clarification! I missed that the `-e` itself is also included in the `sh` variant of the command. So the "is not applied by default" only refers to the `-o pipefail` part. – bluenote10 Feb 11 '23 at 11:56
  • Sure thing. Yes, that applies only to `-o pipefail` part and could have been more explicit. – Azeem Feb 11 '23 at 12:06
  • 1
    Issue created on the GH docs repo: https://github.com/github/docs/issues/23853 – Azeem Feb 11 '23 at 13:04

1 Answers1

3

Does a GitHub action step use set -e semantics by default?

Yes, it does.

According to jobs.<job_id>.steps[*].shell, the sh and bash invocations do include -e whether specified or unspecified.

  • unspecified: bash -e {0}
  • with shell: bash: bash --noprofile --norc -eo pipefail {0}
  • with shell: sh: sh -e {0}

However, this section specified under Exit codes and error action preference:

bash/sh: Fail-fast behavior using set -eo pipefail: This option is set when shell: bash is explicitly specified. It is not applied by default.

applies to the -o pipefail part for Bash only. It could have been more explicit though.

An issue has been created on the GitHub docs repo to revise this: https://github.com/github/docs/issues/23853

Azeem
  • 11,148
  • 4
  • 27
  • 40