Skip to content

NeverUseAlways

Using always() is discouraged.

Defined by ImplicitStatusCheckRule which supports workflows, actions in the "Default" ruleset along with NegativeStatusCheck.

Description

always() does not mean what you might think it means.

always() == success() || failure() || cancelled()

Most of the time, we just want to use if: success() || failure(), for example to upload test reports, when tests failed.

Implying cancelled() via always() is risky when the step affects something external. If someone manually cancels a workflow run, they explicitly expressed they don't want its effects to happen, but always() will still execute the steps.

References:

Compliant examples

Compliant example #1

Step is explicitly defining to run on failure in addition to the default success().

example.yml

on: push
jobs:
  example:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Something that could fail."

      - uses: actions/upload-artifact@v0
        if: ${{ success() || failure() }}

Compliant example #2

Step is well-specified when to execute with if:.

example.yml

on: push
jobs:
  example:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Something that could fail."

      - uses: actions/upload-artifact@v0
        if: ${{ success() || failure() || cancelled() }}

Non-compliant example

always() used in an if: condition.

example.yml

on: push
jobs:
  example:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Something that could fail."

      - uses: actions/upload-artifact@v0
        if: ${{ always() }}

  • Line 8: Step[actions/upload-artifact@v0] in Job[example] uses the always() condition.