Github Actions: check steps status - github-actions

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?

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

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

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'

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

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!

Related

Is it possible to access step outputs from another Github actions job?

Given the following sample workflow
name: My workflow
on:
push:
branches:
- 'main'
jobs:
job_1:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout#v3
with:
fetch-depth: 0
- name: Get next version
id: get_next_version
uses: thenativeweb/get-next-version#2.5.0
- name: Echo for new version
if: ${{ steps.get_next_version.outputs.hasNextVersion == 'true' }}
run: echo there is a new version
- name: Echo for no new version
if: ${{ steps.get_next_version.outputs.hasNextVersion != 'true' }}
run: echo there is no new version
job_2:
needs: job_1
if: needs.job_1.steps.get_next_version.outputs.hasNextVersion == 'true'
runs-on: ubuntu-latest
steps:
- name: First step
run: echo job_2 is running
The action get-next-version analyzes my commit and calculates a new version. As you can see in job_1 I can access the calculated result.
job_2 depends on job_1 and should only run if there would be a new version. I tried to access the result in the if statement of job_2 but it seems that didn't work, I might be using the wrong syntax.
I get the echo
there is a new version
but job_2 was skipped. Is there a way to get access to the data of get_next_version.outputs ( I want the fields hasNextVersion and version )?
Yes - it's possible.
Each job can define its output as an output of one of its steps.
The related documentation can be found here
name: My workflow
on:
push:
branches:
- 'main'
jobs:
job_1:
runs-on: ubuntu-latest
# define output for first job forwarding output of hasNextVersionOutput job
outputs:
hasNextVersion: ${{ steps.hasNextVersionOutput.outputs.hasNextVersion }}
steps:
- name: Checkout repository
uses: actions/checkout#v3
with:
fetch-depth: 0
- name: Get next version
id: get_next_version
uses: thenativeweb/get-next-version#2.5.0
# add a step to generate the output that will be read by the job
- name: Generate output
run: echo "hasNextVersion=${{
steps.get_next_version.outputs.hasNextVersion }}" >> $GITHUB_OUTPUT
- name: Echo for new version
if: ${{ steps.get_next_version.outputs.hasNextVersion == 'true' }}
run: echo there is a new version
- name: Echo for no new version
if: ${{ steps.get_next_version.outputs.hasNextVersion != 'true' }}
run: echo there is no new version
job_2:
needs: job_1
# read output directly from job (you cannot access its steps
if: needs.job_1.outputs.hasNextVersion == 'true'
runs-on: ubuntu-latest
steps:
- name: First step
run: echo job_2 is running

how to run Github Actions Jobs in parallel using matrix?

I've really struggled here doing this for the first time and having no background in development.
We have an action that checks the status of several services running on different envs (DEV, TEST, PROD) and sends notifications to Microsoft Teams Channel.
At the moment there is a dedicated action for each env and the goal is to combine them in one.
the action itself:
name: Services Health Check
on:
workflow_dispatch:
schedule:
- cron: '*/30 * * * *'
env:
DEV: https://app.dev.contoso.com
TEST: https://app.test.contoso.com
PROD: https://app.contoso.com
TEAMS_TOKEN_DEV: ${{ secrets.HEALTH_CHECK_TEAMS_WEB_HOOK_URL_DEV }}
TEAMS_TOKEN_TEST: ${{ secrets.HEALTH_CHECK_TEAMS_WEB_HOOK_URL_TEST }}
TEAMS_TOKEN_PROD: ${{ secrets.HEALTH_CHECK_TEAMS_WEB_HOOK_URL_PROD }}
jobs:
#here I want to create a matrix as a JSON array to look like this, but Im not sure if I do it right (I am also not sure if I correctly escape the characters and which one should I escape):
#[
# { dev : https://app.dev.contoso.com, webhook : ${{ secrets.WEB_HOOK_URL_DEV }} },
# {test : https://app.test.contoso.com, webhook : ${{ secrets.WEB_HOOK_URL_TEST }} },
# {prod : https://app.contoso.com, webhook : ${{ secrets.WEB_HOOK_URL_TEST }} }
#]
env-matrix:
name: Setup ENV Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.env }}
steps:
- id: matrix-env
run: |
echo '::set-output name=env::[\{\"env\"\:\"$DEV\", \"webhook\"\:\"$TEAMS_TOKEN_DEV\"\}, \{\"env\"\:\"$DEMO\", \"webhook\"\:\"$TEAMS_TOKEN_DEMO\"\}, \{\"env\"\:\"$TEST\", \"webhook\"\:\"$TEAMS_TOKEN_TEST\"\}, \{\"env\"\:\"$POC\", \"webhook\"\:\"$TEAMS_TOKEN_POC\"\}, \{\"env\"\:\"$PRE\", \"webhook\"\:\"$TEAMS_TOKEN_PRE\"\}, \{\"env\"\:\"$PROD\", \"webhook\"\:\"$TEAMS_TOKEN_PROD\"\}]'
#and the healthcheck job itself
healthcheck:
needs: env-matrix
name: Health Check
runs-on: ubuntu-18.04
strategy:
matrix:
value: ${{ fromJson(needs.env-matrix.outputs.matrix-env)}}
steps:
- name: service1
uses: repo/action
continue-on-error: true
with:
url: '${{ matrix.value.env }}/service1/q/health/ready'
teamsWebHookURL: '${{ matrix.value.webhook }}'
- name: service2
uses: repo/action
continue-on-error: true
with:
url: '${{ matrix.value.env }}/service2/q/health/ready'
teamsWebHookURL: '${{ matrix.value.webhook }}'
so the job must run on DEV with TEAMS_TOKEN_DEV, on TEST with TEAMS_TOKEN_TEST, but I don't know the way to access an array item, so the steps are incorrect.
Any help will be appreciated. If you know a simpler solution pls share.
Thanks for your time and help
Another way of rewriting your workflow is to define the name of the secrets in the matrix and then using Array notation to fetch the actual value of the secrets. Below is a way of doing this and it is not a clone of your workflow. But this should give you an idea.
name: Services Health Check
on:
workflow_dispatch:
jobs:
healthcheck:
name: Health Check
runs-on: ubuntu-18.04
strategy:
matrix:
environment: [dev, test, prod]
include:
- environment: dev
url: https://app.dev.contoso.com
webhook: HEALTH_CHECK_TEAMS_WEB_HOOK_URL_DEV
- environment: test
url: https://app.test.contoso.com
webhook: HEALTH_CHECK_TEAMS_WEB_HOOK_URL_TEST
- environment: prod
url: https://app.prod.contoso.com
webhook: HEALTH_CHECK_TEAMS_WEB_HOOK_URL_PROD
steps:
- name: test_1
run: |
echo ${{ format('{0}{1}', matrix.url, '/service1/q/health/ready') }}
echo ${{secrets[matrix.webhook]}}
- name: test_2
run: |
echo ${{ format('{0}{1}', matrix.url, '/service2/q/health/ready') }}
echo ${{secrets[matrix.webhook]}}

Github Actions workflow_dispatch choice not working

So, i have tried different versions of this, but i still cannot get it right.
I have a github actions pipeline where i would like to insert a choice so people don't have to look for it in documentation:
name: Echo message
on:
workflow_dispatch:
inputs:
hubAddressGroupObject:
type: choice
description: 'Enter the name of the hub where the entry is added'
required: true
default: 'AZURE-EUW-XXXXX'
options:
- 'AZURE-EUW-XXXXX'
- 'AZURE-FRC-XXXXX'
- 'AZURE-USE-XXXXX'
- 'AZURE-FRC-XXXXX'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: WriteMessage
shell: pwsh
run: |
Test-script.ps1 -message "${{ github.event.inputs.hubAddressGroupObject }}"
The 'Test-script.p1' can look like this:
param (
[string] $message
)
Write-Host ('{0}' -f $message)
The output is still a normal workflow_dispatch with no choice.
What am i doing wrong?
Also, i have merged the current branch into main (default).
your code seems to be correct, you have space issue's with "jobs",
shift-tab it and it should work:
name: Echo message
on:
workflow_dispatch:
inputs:
hubAddressGroupObject:
type: choice
description: 'Enter the name of the hub where the entry is added'
required: true
default: 'AZURE-EUW-XXXXX'
options:
- 'AZURE-EUW-XXXXX'
- 'AZURE-FRC-XXXXX'
- 'AZURE-USE-XXXXX'
- 'AZURE-FRC-XXXXX'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: WriteMessage
run: |
echo "${{ github.event.inputs.hubAddressGroupObject }}"

How to make GitHub Workflow status as skipped if a particular job skips

In my GitHub workflow I had to add a Pre-CI job to get the commit message of the PR which I use in if condition of my main-job. Now the issue here as pre_ci job always runs, I'll get workflow status as success whether main-job runs or skips.
pre_ci:
name: Check Build Condition
if: ${{ github.event_name == 'pull_request' }}
runs-on: ubuntu-latest
steps:
- name: Checkout Project
uses: actions/checkout#v2
with:
fetch-depth: 2
- name: "[Pull Request] Get commit message"
id: pr_get_commit_message
run: echo ::set-output name=pr_commit_message::$(git log --format=%B -n 1 HEAD^2)
outputs:
commit_message: ${{ steps.pr_get_commit_message.outputs.pr_commit_message }}
main-job:
runs-on: ubuntu-latest
timeout-minutes: 10
needs: pre_ci
if: ${{ (github.event_name == 'pull_request' && !contains(needs.pre_ci.outputs.commit_message, '#skipCI')) }}
steps:
- name: echo
run: |
echo "Main job executed"
Is there a way I can set the workflow status a skip if main-job skips
P.S screenshot of skipped workflow

How can I use a Github action's output in a workflow?

Let's take this example composite action found on Github's documentation:
name: 'Hello World'
description: 'Greet someone'
inputs:
who-to-greet: # id of input
description: 'Who to greet'
required: true
default: 'World'
outputs:
random-number:
description: "Random number"
value: ${{ steps.random-number-generator.outputs.random-id }}
runs:
using: "composite"
steps:
- run: echo Hello ${{ inputs.who-to-greet }}.
shell: bash
- id: random-number-generator
run: echo "::set-output name=random-id::$(echo $RANDOM)"
shell: bash
- run: ${{ github.action_path }}/goodbye.sh
shell: bash
How can we use that specific output random-number in an external workflow that calls this action? I tried the following snippet but currently it seems the workflow cannot read the output variable from the action as it just comes out empty - 'Output - '
jobs:
test-job:
runs-on: self-hosted
steps:
- name: Call Hello World
id: hello-world
uses: actions/hello-world-action#v1
- name: Comment
if: ${{ github.event_name == 'pull_request' }}
uses: actions/github-script#v3
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Output - ${{ steps.hello-world.outputs.random-number.value }}'
})
It seems my attempt was correct with the exception of one detail:
Instead of:
${{ steps.hello-world.outputs.random-number.value }}
It should be referenced without the .value:
${{ steps.hello-world.outputs.random-number}}
Now it works.