Maxim
Maxim

Reputation: 743

Github Actions: check steps status

I have in my job for CI some steps which can throw an error. I don't want restart workflow on every step with error and want to go to the last step that checks those steps and complete this job as fail. But I can't get status info previously steps.

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: <any> 
        continue-on-error: true
      - name: Step 2
        id: world
        run: <any> 
        continue-on-error: true
      - name: Check on failures
        if: job.steps.hello.status == failure() || job.steps.world.status == failure()
        run: exit 1

When I use next constructions in "if" or "run" then will get: steps -> {}, job.steps -> null.

How can I get status information?

Upvotes: 64

Views: 77973

Answers (5)

syl.fabre
syl.fabre

Reputation: 746

I encountered the same issue today and solved by using a condition:

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: <any> 
        if: ${{ failure() ||  success() }}
      - name: Step 2
        id: world
        run: <any> 
        if: ${{ failure() ||  success() }}

In the end:

  • All steps are executed
  • The job myjob will fail if any step fails

This is similar to Azure DevOps succeededOrFailed() condition.

Happy workflowing!

Upvotes: 1

peterevans
peterevans

Reputation: 41920

Update: The steps context now contains detail about the execution of each step by default. Using the outcome property of each step we can check the result of its execution.

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: <any> 
        continue-on-error: true
      - name: Step 2
        id: world
        run: <any> 
        continue-on-error: true
      - name: Check on failures
        if: steps.hello.outcome != 'success' || steps.world.outcome != 'success'
        run: exit 1

Original answer Looking at the documentation for the steps context, it doesn't look like it contains any information about the step other than outputs. These must be explicitly defined by steps. That is why the steps context is empty {}.

https://help.github.com/en/articles/contexts-and-expression-syntax-for-github-actions#steps-context

Unfortunately, as far as I can tell, there is no default status for a step that can be accessed. The solution involves manually defining a status output variable from each step.

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: echo ::set-output name=status::failure
        continue-on-error: true
      - name: Step 2
        id: world
        run: echo ::set-output name=status::success
        continue-on-error: true
      - name: Dump steps context
        env:
          STEPS_CONTEXT: ${{ toJson(steps) }}
        run: echo "$STEPS_CONTEXT"
      - name: Check on failures
        if: steps.hello.outputs.status == 'failure' || steps.world.outputs.status == 'failure'
        run: exit 1

This creates the following context output and the job fails.

{
  "hello": {
    "outputs": {
      "status": "failure"
    }
  },
  "world": {
     "outputs": {
      "status": "success"
    }
  }
}

https://help.github.com/en/articles/metadata-syntax-for-github-actions#outputs https://help.github.com/en/articles/development-tools-for-github-actions#set-an-output-parameter-set-output

Upvotes: 91

张馆长
张馆长

Reputation: 1839

jobs:
  build:
    name: Build
    env:
      DOCKER_PASS: ${{ secrets.DOCKER_PASS }} 
    runs-on: ubuntu-latest
    steps:

    - name: script
      id: test1
      continue-on-error: true
      run: |
        ls -l sadasd
        
    - name: script
      id: sync
      continue-on-error: true
      run: |
        ls -l
    - name: Dump steps context
      env:
        STEPS_CONTEXT: ${{ toJson(steps) }}
      run: echo "$STEPS_CONTEXT"

the output

Run echo "$STEPS_CONTEXT"
{
  "test1": {
    "outputs": {},
    "outcome": "failure",
    "conclusion": "success"
  },
  "sync": {
    "outputs": {},
    "outcome": "success",
    "conclusion": "success"
  }
}

so could use step:

    - name: sync run
      id: sync
      continue-on-error: true
      run: |
        .....
    - name: after_success
      run: |
        ...
      if: steps.sync.outcome  == 'success'
    - name: after_failure
      run: |
        ...
      if: steps.sync.outcome != 'success'

Upvotes: 4

Nicolas Vuillamy
Nicolas Vuillamy

Reputation: 690

You can get status using setps.STEPNAME.outcome property, associated to a check of success() or failure()

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: <any> 
        continue-on-error: true
      - name: Step 2
        id: world
        run: <any> 
        continue-on-error: true
      - name: Check on failures
        if: (${{ success() }} || ${{ failure() }}) && (${{ steps.hello.outcome }} == 'failure' || ${{ steps.world.outcome }} == 'failure')
        run: exit 1

Upvotes: 10

Junaid
Junaid

Reputation: 3945

I'm using somewhat similar to @peterevans suggested earlier but leveraging the shell exit for a command and set +e flag:

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: |
          set +e
          ./my-script.sh
          echo ::set-output name=exit_status::failure
      - name: Step 2
        id: world
        run:
          set +e
          python3 ./my-script.py
          echo ::set-output name=exit_status::$?
      - name: Check on failures
        if: steps.hello.outputs.exit_status != 0 | steps.world.outputs.exit_status != 0
        run: exit 1

Upvotes: 2

Related Questions