Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add conditional execution of action steps #834

Closed
igagis opened this issue Nov 29, 2020 · 46 comments
Closed

add conditional execution of action steps #834

igagis opened this issue Nov 29, 2020 · 46 comments
Labels
enhancement New feature or request

Comments

@igagis
Copy link

igagis commented Nov 29, 2020

Describe the enhancement
Add possibility to use if: option for action steps of composite actions.

Code Snippet

inputs:
  echo-bla:
    description: 'echo bla-bla-bla if not empty'
    required: true
runs:
  using: "composite"
  steps:
    - run: echo "start"
      shell: bash
    - run: echo "bla bla bla"
      shell: bash
      if: ${{ inputs.echo-bla }}
    - run: echo "stop"
      shell: bash
@igagis igagis added the enhancement New feature or request label Nov 29, 2020
@louisgv
Copy link

louisgv commented Feb 2, 2021

The specific case described in the ticket can be done with plain shell script. Something like the example below:

      run: |
        npm install
        [[ "${{ inputs.package }}" = true ]] && npm run package || true

More complex - well we shall wait for #646

@igagis
Copy link
Author

igagis commented Feb 2, 2021

@louisgv Well, ok, actually, I want the if: in composite actions to avoid running in shell which are not present in the system. So that I could make universal actions which would run in linux images, as well as windows ones (i.e. bash/powershell).
So, implementing check in bash is not an option for me since bash can be absent.

@dcharles-godaddy
Copy link

I'd like to have an action that does different things depending upon cancelled(), failure(), or success(), and these functions do not appear to be available inside of a run:

The workflow is not valid. .github/workflows/success.yaml (Line: 8, Col: 14): Unrecognized function: 'success'. Located at position 1 within expression: success()

@tahirmt
Copy link

tahirmt commented Aug 18, 2021

Is there any plan to add if conditionals to composite actions now that they support uses

@potatoqualitee
Copy link

lol, didn't even realize i needed an if conditional as well. I'm basically building a wrapper for actions/cache@v2 which requires if: steps.cacher.outputs.cache-hit != 'true' within my composite action. looking forward to this implementation!

make-github-pseudonymous-again added a commit to infoderm/patients that referenced this issue Aug 19, 2021
Still waiting for actions/runner#834 to make
`if`'s legal.
webknjaz added a commit to ansible-community/ansible-test-gh-action that referenced this issue Aug 24, 2021
webknjaz added a commit to ansible-community/ansible-test-gh-action that referenced this issue Aug 24, 2021
@smokedlinq
Copy link

Also have a need for this. It's the last thing keeping me from using composites similar to Azure DevOps pipeline templates...

@sondrelg
Copy link

actions/cache@v2 which requires if: steps.cacher.outputs.cache-hit != 'true' within my composite action

I came here looking for an answer to this - and with some inspiration from @louisgv I think I might have been able to come up with a temporary workaround until ifs are fully supported. Posting it here just in case anyone finds it useful:

Instead of this:

- uses: actions/cache@v2
  id: cache-venv
  with:
    path: .venv
    key: some-key-0
- run: poetry install --no-interaction --no-root
  if: steps.cache-venv.outputs.cache-hit != 'true'

It looks like this would also work

- uses: actions/cache@v2
  id: cache-venv
  with:
    path: .venv
    key: some-key-${{ inputs.pip-cache-key }}
- run: |
    if echo ${{ steps.cache-venv.outputs.cache-hit }} | grep -c "true"
    then
      echo "Cache hit - skipping dependency installation"
    else
      poetry install --no-interaction --no-root
    fi
  shell: bash

Here is a full example workflow. Here is an example of a project using the remote workflow with a cold cache, and here with a warm cache 👍

It seems to work the same at least 🤞

@potatoqualitee
Copy link

super cool interim solution, thanks for sharing, @sondrelg !

@sebastianluszczek
Copy link

sebastianluszczek commented Aug 27, 2021

@sondrelg would like to use your result but have a little different problem

I got some input (not required)

inputs:
    test:
        description: "Test command to run"
        required: false
runs:
    using: "composite"
    steps:
        - id: install
          run: |
              npm ci
          shell: bash
        - id: test
          run: |
              if [ -z "${{ inputs.test }}" ]
              then
                echo -e "test exist: ${{ inputs.test }}"
                "${{ inputs.test }}"
              else
                echo -e "\nno test specified"
              fi
          shell: bash
        - id: build
          run: |
              mkdir dist
              npm run build
          shell: bash

but it always get into first block even if I not specify test while using action

@sondrelg
Copy link

I had some trouble with missing values as well @sebastianluszczek - perhaps it would help to set a default value for your input, and check against that, rather than using -z?

zmughal added a commit to PDLPorters/devops that referenced this issue Aug 27, 2021
This uses a composite action with conditionals, but these will not yet
work per <actions/runner#834>.

This commit is just to show the start of the action before transforming
it using a shell script workaround. If simpler, that transformation can
be reverted to this version when support for conditionals in composite
actions is added.
@zmughal
Copy link

zmughal commented Sep 1, 2021

A more robust workaround is to use the construction:

if ${{ toJSON(
         fromJSON( «input that is either 'true' or 'false'» )
         ... «rest of boolean expression»
       ) }}; then
  « commands... »;
fi

as the value of the run: key. This works because the output of toJSON() in that case is either 'true' or 'false' which are the same as the shell script built-ins.

A benefit of this approach is that when if: support is added, the contents of the expression inside of toJSON() can be copied out from the value in run: into the value of if:

If you want to have a fallback value in case the input is left empty, then use || 'false' is to make sure that fromJSON() gets a value that can be parsed as a boolean when the argument is an empty string:

fromJSON(inputs.test-enable-coverage || 'false')

A couple full example steps would be:

inputs:
  target-all:
    required: true
    default: false
  target-test:
    required: true
    default: false
  test-enable-coverage:
    required: true
    default: false
  target-notifications:
    required: true
    default: false
runs:
  using: "composite"
  steps:
    # Target: target-test
    - name: target-test (no coverage)
      shell: bash
      env:
        HARNESS_OPTIONS: ${{ inputs.test-harness-options }}
      run: |
          if ${{ toJSON(
                (  fromJSON(inputs.target-all)
                || fromJSON(inputs.target-test)
                )
                && ! fromJSON(inputs.test-enable-coverage || 'false')
              ) }}; then
            echo "::group::test (no coverage)"
            if [ -f Makefile.PL ]; then
              $MYPERL Makefile.PL && make test
            else
              echo "No file Makefile.PL" >&2
            fi
            echo "::endgroup::"
          fi
    # Target: target-notifications
    - name: irc push (build messages)
      shell: bash
      run: |
          if ${{ toJSON(
                      fromJSON(inputs.target-notifications)
                   && github.event_name == 'push'
                   && github.repository == inputs.repository
                 ) }}; then
            echo "commitmsg="$( git show -s --oneline ${{ join(github.event.commits.*.id, ' ') }} ) >> $GITHUB_ENV
          fi

@dkirrane
Copy link

dkirrane commented Sep 2, 2021

Does this issue include support for continue-on-error & timeout-minutes on steps in a composite action?

@ccolella-mdc
Copy link

I also need this functionality. I am trying to run another action based on an if: . Using bash/powershell will not work in this case.

@finolacahill
Copy link

Big +1 on this functionality. I have a number of composite actions that are stored centrally and checked in and used by a variety of different repos for CI checks. This is to avoid massive amounts of repeated code. Currently each composite action has a final step whereby it uploads essential logs/reports as an artifact. Given that in composite actions one can neither if: always nor continue-on-error (and continue on error still frustratingly results in the job appearing as a success overall), all actions that error out have no error logs uploaded as an artifact.
Composite actions are so close to being the solution to enforcing DRY principles on CI checks here, but it's failing at the last hurdle. All my artifact-upload steps have to be copy and pasted over and over into the individual workflows in the individual repos in order to be able to use an if conditional. Why?

@ivanmarquescepsa
Copy link

+1

@solarmosaic-kflorence
Copy link

solarmosaic-kflorence commented Nov 10, 2021

@fhammerl will https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions be updated to denote runs.steps[*].if?

EDIT: it is being tracked here github/docs#12378

marten-seemann added a commit to protocol/.github that referenced this issue Nov 12, 2021
GitHub Actions finally fixed the issue, see actions/runner#834 (comment).
This reverts #202.
marten-seemann added a commit to protocol/.github that referenced this issue Nov 12, 2021
GitHub Actions finally fixed the issue, see actions/runner#834 (comment).
This reverts #202.
TheDome added a commit to neohelden/actions-library that referenced this issue Nov 17, 2021
phantomjinx added a commit to phantomjinx/camel-k that referenced this issue Nov 19, 2021
* If conditional not part of composite actions:
  see actions/runner#834

* Replace action outputs with global environment variables
 * Easier to debug as printed in logs
 * If actions are if-conditioned to not execute, if already run, then
   their outputs will not exist whereas global env vars will. This makes
   it possible to retain the env vars while skipping repeated executions
   of the same actions
phantomjinx added a commit to phantomjinx/camel-k that referenced this issue Nov 19, 2021
* If conditional not part of composite actions:
  see actions/runner#834

* Replace action outputs with global environment variables
 * Easier to debug as printed in logs
 * If actions are if-conditioned to not execute, if already run, then
   their outputs will not exist whereas global env vars will. This makes
   it possible to retain the env vars while skipping repeated executions
   of the same actions
phantomjinx added a commit to phantomjinx/camel-k that referenced this issue Nov 19, 2021
* If conditional not part of composite actions:
  see actions/runner#834

* Replace action outputs with global environment variables
 * Easier to debug as printed in logs
 * If actions are if-conditioned to not execute, if already run, then
   their outputs will not exist whereas global env vars will. This makes
   it possible to retain the env vars while skipping repeated executions
   of the same actions
phantomjinx added a commit to phantomjinx/camel-k that referenced this issue Nov 19, 2021
* If conditional not part of composite actions:
  see actions/runner#834

* Replace action outputs with global environment variables
 * Easier to debug as printed in logs
 * If actions are if-conditioned to not execute, if already run, then
   their outputs will not exist whereas global env vars will. This makes
   it possible to retain the env vars while skipping repeated executions
   of the same actions
phantomjinx added a commit to phantomjinx/camel-k that referenced this issue Nov 22, 2021
* If conditional not part of composite actions:
  see actions/runner#834

* Replace action outputs with global environment variables
 * Easier to debug as printed in logs
 * If actions are if-conditioned to not execute, if already run, then
   their outputs will not exist whereas global env vars will. This makes
   it possible to retain the env vars while skipping repeated executions
   of the same actions
phantomjinx added a commit to phantomjinx/camel-k that referenced this issue Nov 22, 2021
* If conditional not part of composite actions:
  see actions/runner#834

* Replace action outputs with global environment variables
 * Easier to debug as printed in logs
 * If actions are if-conditioned to not execute, if already run, then
   their outputs will not exist whereas global env vars will. This makes
   it possible to retain the env vars while skipping repeated executions
   of the same actions
@electriquo
Copy link

why do one need to find this thread and not read it in the original documentation?! :(

@solarmosaic-kflorence
Copy link

@foolioo it is being tracked here now github/docs#12378

gaborcsardi pushed a commit to r-lib/actions that referenced this issue Dec 3, 2021
…e action

Now that [composite actions support conditionals](actions/runner#834 (comment))
we can consolidate more of the logic into the composite action
galargh pushed a commit to protocol/.github that referenced this issue Dec 8, 2021
GitHub Actions finally fixed the issue, see actions/runner#834 (comment).
This reverts #202.
galargh pushed a commit to protocol/.github that referenced this issue Dec 8, 2021
GitHub Actions finally fixed the issue, see actions/runner#834 (comment).
This reverts #202.
@AlexDCraig
Copy link

Does the if conditional not work for outputs of previous steps?

For example:

    - name: Apply Tag of Commit Hash to Master
      id: tag_master_with_commit
      if: ${{ steps.tag_check.outputs.tag_exists }} != true
      uses: mathieudutour/github-tag-action@v5.6
      with:
        github_token: ${{ inputs.github_token }}
        custom_tag: ${{ steps.short_sha.outputs.short_sha }}
        tag_prefix: 'master-'

This doesn't appear to actually run a conditional statement against the previous step's output and thus always runs.

@solarmosaic-kflorence
Copy link

solarmosaic-kflorence commented Dec 10, 2021

@AlexDHoffer it does work, although I have also had problems with matching on boolean true. I have solved it by ensuring that the output is always cast as a string (e.g. "true"), and then matching instead on the string value, like steps.tag_check.outputs.tag_exists != 'true'. I feel like this might be a bug.

EDIT: I think it's this one #1483

@ghost
Copy link

ghost commented Feb 7, 2022

I found the following works:

if: ${{ steps.approvals.outputs.VALUE  == 'integration' }}

While the below does not:

if: ${{ steps.approvals.outputs.VALUE  }} == 'integration'

Is this the expected behavior?

@ccolella-mdc
Copy link

I found the following works:

if: ${{ steps.approvals.outputs.VALUE  == 'integration' }}

While the below does not:

if: ${{ steps.approvals.outputs.VALUE  }} == 'integration'

Is this the expected behavior?

yes. This should also work.

if: steps.approvals.outputs.VALUE  == 'integration'

Raboo added a commit to deltaprojects/action-ci-cd that referenced this issue Feb 23, 2022
Raboo added a commit to deltaprojects/action-ci-cd that referenced this issue Feb 23, 2022
Raboo added a commit to deltaprojects/action-ci-cd that referenced this issue Feb 23, 2022
Raboo added a commit to deltaprojects/action-ci-cd that referenced this issue Feb 23, 2022
@albert-k-nylas
Copy link

albert-k-nylas commented May 4, 2022

Is it expected that secrets are not available inside a conditional step? I'm running the following and it gives me the result below. Notice that credentials were not passed (no *** printed)
Screen Shot 2022-05-04 at 1 26 33 PM

- name: Set up Cloud SDK to access cluster ${{ env.GKE_STAGING_CLUSTER_NAME }}
        if: ${{ inputs.cluster == 'staging' }}
        uses: google-github-actions/get-gke-credentials@fb08709ba27618c31c09e014e1d8364b02e5042e #v0.2.1
        with:
          project_id: ${{ env.PROJECT_ID }}
          cluster_name: ${{ env.GKE_STAGING_CLUSTER_NAME }}
          location: ${{ env.LOCATION }}
          credentials: ${{ secrets.GKE_STAGING_SECRET }}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests