GitHub/Workflow: Difference between revisions
| (14 intermediate revisions by the same user not shown) | |||
| Line 29: | Line 29: | ||
steps: | steps: | ||
- run: hostname | - run: hostname | ||
</pre> | |||
== workflow dispatch limits == | |||
https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch | |||
Limits: | |||
* The maximum number of top-level properties for inputs is 10. | |||
* The maximum payload for inputs is 65,535 characters. | |||
== Don't Immediately Fail on Non Zero Return Code == | |||
# exit on error temporarily | |||
set -e | |||
# disable exitting on error temporarily | |||
set +e | |||
== Change Run Name with Input == | |||
<pre> | |||
name: Nodecheck | |||
run-name: Nodecheck for ${{ inputs.RUNNER_LABEL }} | |||
on: | |||
workflow_dispatch: | |||
inputs: | |||
RUNNER_LABEL: | |||
description: Name of runner to target | |||
required: true | |||
type: string | |||
workflow_call: | |||
inputs: | |||
RUNNER_LABEL: | |||
required: true | |||
type: string | |||
description: Name of runner to target | |||
jobs: | |||
run: | |||
uses: some-org/some-repo/.github/workflows/nodecheck.yaml@latest | |||
with: | |||
RUNNER_LABEL: ${{ inputs.RUNNER_LABEL }} | |||
secrets: inherit | |||
... | |||
</pre> | </pre> | ||
| Line 132: | Line 176: | ||
ref: Defining outputs for jobs - GitHub Enterprise Cloud Docs - https://docs.github.com/en/enterprise-cloud@latest/actions/using-jobs/defining-outputs-for-jobs | ref: Defining outputs for jobs - GitHub Enterprise Cloud Docs - https://docs.github.com/en/enterprise-cloud@latest/actions/using-jobs/defining-outputs-for-jobs | ||
Multi-line output: <ref>https://github.com/github/docs/issues/21529</ref> | |||
<pre> | |||
run: | | |||
echo 'JSON_RESPONSE<<EOF' >> $GITHUB_OUTPUT | |||
curl https://example.lab >> $GITHUB_OUTPUT | |||
echo 'EOF' >> $GITHUB_OUTPUT | |||
</pre> | |||
=== Python version job output === | === Python version job output === | ||
| Line 139: | Line 191: | ||
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh: | with open(os.environ['GITHUB_OUTPUT'], 'a') as fh: | ||
print(f'{SOME}={THING}', file=fh) | print(f'{SOME}={THING}', file=fh) | ||
</pre | </pre> | ||
Function version: | |||
<pre> | |||
def set_output(name, value): | |||
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh: | |||
print(f'{name}={value}', file=fh) | |||
</pre> | |||
Multi lined version: | Multi lined version: | ||
| Line 151: | Line 210: | ||
print(value, file=fh) | print(value, file=fh) | ||
print(delimiter, file=fh) | print(delimiter, file=fh) | ||
# call example: | |||
set_multiline_output("value", my_multiline_string) | |||
</pre> | </pre> | ||
| Line 207: | Line 269: | ||
* How to Dynamically assign the runs-on value in the github actions - Stack Overflow - https://stackoverflow.com/questions/73241812/how-to-dynamically-assign-the-runs-on-value-in-the-github-actions | * How to Dynamically assign the runs-on value in the github actions - Stack Overflow - https://stackoverflow.com/questions/73241812/how-to-dynamically-assign-the-runs-on-value-in-the-github-actions | ||
* Github Actions: How use strategy/matrix with script - Stack Overflow - https://stackoverflow.com/questions/59977364/github-actions-how-use-strategy-matrix-with-script | * Github Actions: How use strategy/matrix with script - Stack Overflow - https://stackoverflow.com/questions/59977364/github-actions-how-use-strategy-matrix-with-script | ||
--- todo --- | |||
ideas: | |||
runs-on: ${{ fromJson(format('[{0}]', github.event.inputs.LABELS)) }} | |||
this will work if labels is a string of quoted labels: "a","b" | |||
Sadness - if the actions expressions supported a "replace()" function, could have the comma replace with a "," | |||
== Dynamic Jobs == | == Dynamic Jobs == | ||
| Line 246: | Line 318: | ||
- run: echo ${{ matrix.runson }} | - run: echo ${{ matrix.runson }} | ||
- run: echo ${{ matrix.task }} | - run: echo ${{ matrix.task }} | ||
</pre> | |||
== Official Dynamic Job Examples == | |||
Reference: https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object | |||
<pre> | |||
name: build | |||
on: push | |||
jobs: | |||
job1: | |||
runs-on: ubuntu-latest | |||
outputs: | |||
matrix: ${{ steps.set-matrix.outputs.matrix }} | |||
steps: | |||
- id: set-matrix | |||
run: echo "matrix={\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}" >> $GITHUB_OUTPUT | |||
job2: | |||
needs: job1 | |||
runs-on: ubuntu-latest | |||
strategy: | |||
matrix: ${{ fromJSON(needs.job1.outputs.matrix) }} | |||
steps: | |||
- run: echo "Matrix - Project ${{ matrix.project }}, Config ${{ matrix.config }}" | |||
</pre> | |||
and | |||
<pre> | |||
jobs: | |||
example_matrix: | |||
strategy: | |||
matrix: | |||
os: [ubuntu-22.04, ubuntu-20.04] | |||
version: [10, 12, 14] | |||
runs-on: ${{ matrix.os }} | |||
steps: | |||
- uses: actions/setup-node@v4 | |||
with: | |||
node-version: ${{ matrix.version }} | |||
</pre> | </pre> | ||
| Line 358: | Line 470: | ||
Expressions - GitHub Docs | Expressions - GitHub Docs | ||
https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions | https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions | ||
How to run a github-actions step, even if the previous step fails, while still failing the job - Stack Overflow | |||
https://stackoverflow.com/questions/58858429/how-to-run-a-github-actions-step-even-if-the-previous-step-fails-while-still-f | |||
=== success === | === success === | ||
| Line 395: | Line 510: | ||
if: ${{ always() }} | if: ${{ always() }} | ||
</pre> | </pre> | ||
if: always() | |||
=== cancelled === | === cancelled === | ||
Latest revision as of 05:21, 28 May 2025
Starter Workflows
Quickstart for GitHub Actions - GitHub Docs https://docs.github.com/en/actions/quickstart
actions/starter-workflows: Accelerating new GitHub Actions workflows https://github.com/actions/starter-workflows
GitHub Marketplace - Actions https://github.com/marketplace?category=&query=&type=actions&verification=
Manual Run
manual.yaml:
name: Manual Run
run-name: Test
on:
workflow_dispatch:
inputs:
LABEL:
required: true
type: string
description: label
jobs:
run:
runs-on: ${{ inputs.LABEL }}
steps:
- run: hostname
workflow dispatch limits
Limits:
- The maximum number of top-level properties for inputs is 10.
- The maximum payload for inputs is 65,535 characters.
Don't Immediately Fail on Non Zero Return Code
# exit on error temporarily set -e
# disable exitting on error temporarily set +e
Change Run Name with Input
name: Nodecheck
run-name: Nodecheck for ${{ inputs.RUNNER_LABEL }}
on:
workflow_dispatch:
inputs:
RUNNER_LABEL:
description: Name of runner to target
required: true
type: string
workflow_call:
inputs:
RUNNER_LABEL:
required: true
type: string
description: Name of runner to target
jobs:
run:
uses: some-org/some-repo/.github/workflows/nodecheck.yaml@latest
with:
RUNNER_LABEL: ${{ inputs.RUNNER_LABEL }}
secrets: inherit
...
On Pull Request
name: On Pull Request
on:
pull_request:
types: [opened, reopened]
jobs:
test:
runs-on: [ubuntu-latest]
steps:
- name: do something
shell: bash
run: |
echo "hi"
On Label Change
Note: Must have event in
name: On Label
on:
pull_request:
types:
- labeled
jobs:
label-job:
if: "github.event.label.name == 'run-mylabel'"
uses: myorg/myrepo/.github/workflows/dolabel.yaml@v2
with:
VAR1: VAR1
secrets: inherit
Basic Workflow
name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push]
jobs:
Explore-GitHub-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v3
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
ref: https://docs.github.com/en/actions/quickstart
Using Job Output
if you want to export the job output from the workflow:
name: CI Precommit Automation Pipeline - Get Builds
on:
workflow_call:
inputs:
...
outputs:
output1: ${{ jobs.job1.outputs.output1 }}
job outputs:
jobs:
job1:
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
output1: ${{ steps.step1.outputs.test }}
output2: ${{ steps.step2.outputs.test }}
steps:
- id: step1
run: echo "test=hello" >> "$GITHUB_OUTPUT"
- id: step2
run: echo "test=world" >> "$GITHUB_OUTPUT"
- id: step3
run: echo "I see step1: ${{ steps.step1.outputs.test }}
job2:
runs-on: ubuntu-latest
needs: job1
steps:
- env:
OUTPUT1: ${{needs.job1.outputs.output1}}
OUTPUT2: ${{needs.job1.outputs.output2}}
run: echo "$OUTPUT1 $OUTPUT2"
ref: Defining outputs for jobs - GitHub Enterprise Cloud Docs - https://docs.github.com/en/enterprise-cloud@latest/actions/using-jobs/defining-outputs-for-jobs
Multi-line output: [1]
run: |
echo 'JSON_RESPONSE<<EOF' >> $GITHUB_OUTPUT
curl https://example.lab >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
Python version job output
Python version: [2]
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh:
print(f'{SOME}={THING}', file=fh)
Function version:
def set_output(name, value):
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh:
print(f'{name}={value}', file=fh)
Multi lined version:
import uuid
def set_multiline_output(name, value):
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh:
delimiter = uuid.uuid1()
print(f'{name}<<{delimiter}', file=fh)
print(value, file=fh)
print(delimiter, file=fh)
# call example:
set_multiline_output("value", my_multiline_string)
Dynamic Runs-on
Dynamic from Input:
name: Dynamic Labels
run-name: Dynamic Labels
on:
workflow_dispatch:
inputs:
LABELS:
required: false
type: string
jobs:
run:
# runs-on: ${{ fromJSON( '["CI"]' ) }} # This works
# runs-on: ${{ fromJSON( '["CI", "MORE"]' ) }} # This works
runs-on: ${{ fromJSON( inputs.LABELS ) }} # This works if formatted like: ["CI", "MORE"]
# runs-on: ${{ inputs.LABELS }} # this works for single label
# runs-on: [ CI, MORE ] # this works
steps:
- run: hostname
Dynamic from script:
name: Dynamic Script
run-name: Test
on:
workflow_dispatch:
inputs:
Go:
required: false
type: string
jobs:
job1:
runs-on: ubuntu-latest
outputs:
RUNS: ${{ steps.set-RUNS.outputs.RUNS }}
steps:
- id: set-RUNS
run: echo "RUNS=[\"CI\",\"MORE\"]" >> $GITHUB_OUTPUT
job2:
needs: job1
runs-on: ${{fromJSON(needs.job1.outputs.RUNS)}}
steps:
- run: hostname
ref:
- How to Dynamically assign the runs-on value in the github actions - Stack Overflow - https://stackoverflow.com/questions/73241812/how-to-dynamically-assign-the-runs-on-value-in-the-github-actions
- Github Actions: How use strategy/matrix with script - Stack Overflow - https://stackoverflow.com/questions/59977364/github-actions-how-use-strategy-matrix-with-script
--- todo ---
ideas:
runs-on: ${{ fromJson(format('[{0}]', github.event.inputs.LABELS)) }}
this will work if labels is a string of quoted labels: "a","b"
Sadness - if the actions expressions supported a "replace()" function, could have the comma replace with a ","
Dynamic Jobs
{ "include": [
{"runson": ["CI", "MORE"],
"task": "joe"},
{"runson": ["CI", "LESS"],
"task": "bob"}
]
}
name: Dynamic Jobs
run-name: Test
on:
workflow_dispatch:
inputs:
Go:
required: false
type: string
jobs:
generate:
runs-on: ubuntu-latest
outputs:
MATRIX: ${{ steps.set-MATRIX.outputs.MATRIX }}
steps:
- id: set-MATRIX
run: echo "MATRIX={\"include\":[{\"runson\":[\"CI\",\"MORE\"],\"task\":\"joe\"},{\"runson\":[\"CI\",\"LESS\"],\"task\":\"bob\"}]}" >> $GITHUB_OUTPUT
jober:
needs: generate
runs-on: ${{ matrix.runson }}
strategy:
matrix: ${{fromJson(needs.generate.outputs.matrix)}}
steps:
- run: hostname
- run: echo ${{ matrix.runson }}
- run: echo ${{ matrix.task }}
Official Dynamic Job Examples
Reference: https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object
name: build
on: push
jobs:
job1:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
run: echo "matrix={\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}" >> $GITHUB_OUTPUT
job2:
needs: job1
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJSON(needs.job1.outputs.matrix) }}
steps:
- run: echo "Matrix - Project ${{ matrix.project }}, Config ${{ matrix.config }}"
and
jobs:
example_matrix:
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
version: [10, 12, 14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.version }}
Remotely Trigger Workflow - repository_dispatch
on: repository_dispatch:
---
on:
repository_dispatch:
types: [some_event_type]
curl -X POST https://api.github.com/repos/OWNER/REPO/dispatches -H "Authorization: Bearer ${GH_TOKEN}" -d '{"event_type":"some_event_type"}'
---
curl -X POST https://api.github.com/repos/ORG/REPO/dispatches -d '{"event_type":"some_event_type"}' # -d or --data, -X or --request # -H "Accept: application/vnd.github.v3+json" # -H "Accept: application/vnd.github+json" # You will most likely need to also pass along auth: (unless you are silly and on a publicly executable workflow?) # -H "Authorization: Bearer $GITHUB_TOKEN"
curl -L \ -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer <YOUR-TOKEN>" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/OWNER/REPO/dispatches \ -d '{"event_type":"on-demand-test","client_payload":{"unit":false,"integration":true}}'
---
if you want to trigger from some other branch:
{...,'ref':'other_branch_or_ref'},...}
---
repository_dispatch - Events that trigger workflows - GitHub Docs https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#repository_dispatch
repository_dispatch - Repositories - GitHub Docs https://docs.github.com/rest/repos/repos#create-a-repository-dispatch-event
---
If you pass this payload through, you can limit the workflow, and access it in the workflow:
{
"event_type": "test_result",
"client_payload": {
"passed": false,
"message": "Error: timeout"
}
}
workflow:
on:
repository_dispatch:
types: [test_result]
jobs:
run_if_failure:
if: ${{ !github.event.client_payload.passed }}
runs-on: ubuntu-latest
steps:
- env:
MESSAGE: ${{ github.event.client_payload.message }}
run: echo $MESSAGE
Job Timeout
Workflow syntax - jobs - timeout-minutes https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes
my-job: runs-on: ubuntu-latest timeout-minutes: 30
jobs.<job_id>.timeout-minutes The maximum number of minutes to let a job run before GitHub automatically cancels it. Default: 360
If the timeout exceeds the job execution time limit for the runner, the job will be canceled when the execution time limit is met instead. For more information about job execution time limits, see "Usage limits, billing, and administration" for GitHub-hosted runners and "About self-hosted runners" for self-hosted runner usage limits.
Usage Limits:
There are some limits on GitHub Actions usage when using GitHub-hosted runners. These limits are subject to change. [3]
- Job execution time - Each job in a workflow can run for up to 6 hours of execution time. If a job reaches this limit, the job is terminated and fails to complete.
There are some limits on GitHub Actions usage when using self-hosted runners. These limits are subject to change. [4]
- Job execution time - Each job in a workflow can run for up to 5 days of execution time. If a job reaches this limit, the job is terminated and fails to complete.
Step Timeout
jobs.<job_id>.steps[*].timeout-minutes The maximum number of minutes to run the step before killing the process.
Status Check Functions
Expressions - GitHub Docs https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions
How to run a github-actions step, even if the previous step fails, while still failing the job - Stack Overflow https://stackoverflow.com/questions/58858429/how-to-run-a-github-actions-step-even-if-the-previous-step-fails-while-still-f
success
steps:
...
- name: The job has succeeded
if: ${{ success() }}
failure
Returns true when any previous step of a job fails.
steps:
...
- name: The job has failed
if: ${{ failure() }}
with step conclusion check:
steps:
...
- name: Failing step
id: demo
run: exit 1
- name: The demo step has failed
if: ${{ failure() && steps.demo.conclusion == 'failure' }}
always
Causes the step to always execute, and returns true, even when canceled. The always expression is best used at the step level or on tasks that you expect to run even when a job is canceled.
if: ${{ always() }}
if: always()
cancelled
Returns true if the workflow was canceled.
if: ${{ cancelled() }}
Pass Status to Step
Use:
steps.<id>.outcome != 'success'
- name: Check status step
id: check-step
if: success()
shell: bash
run: |
echo "Workflow successful"
- name: The step to call the action
if: always()
uses: ./path/to/action
with:
some-token: ${{ inputs.some-token }}
some-value: ${{ inputs.some-value }}
workflow-status: ${{ steps.check-step.outcome }}
keywords
- ↑ https://github.com/github/docs/issues/21529
- ↑ https://github.com/orgs/community/discussions/28146
- ↑ https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits
- ↑ https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#usage-limits