I've been using different build systems for years, but after playing with github actions quite a bit there was still some things that I was only managing based on trial and error. I've written this guide to try and fill in those gaps. If you've been through theQuickstart for GitHub Actions andUnderstanding GitHub Actions documentation but still have some questions I'm hoping this post will answer some of them.
First some definitions:
- Workflows are combinations of jobs
- Jobs are combinations of steps that are run on a virtual machine, they can even be a workflow of their own
- Steps are either actions or shell commands
Sharing data in your workflow
This was one of the bits that I felt the documentation didn't explain clearly enough. All the information is there, but spread across multiple pages and can take quite a while to put it all together.
Environment variable types
It's worth baring in mind that because most of what follows uses environment variables under the hood it is astring
, so even though the value could be'true'
or'false'
you would need an expression that explicitly compares it to those values. e.g.if: env.isTag == 'true'
would work, butif: env.isTag
alone would not.
Inputs to workflows however can bestring
,number
orboolean
types.
Sharing data between steps in a job
If one of your steps has an output that you need in a later step within the same job you can set it as an environment variable. This is done by sending a statement setting it to the$GITHUB_ENV
file. A minimal demonstration of this is:
steps:-name:Set myValuerun:echo "myValue=wibble" >> $GITHUB_ENV-name:Echo myValuerun:echo "$myValue"
Ofcourse the above isn't that useful, thewibble
part would usually be a calculated value. You would usually use some of the calculate the value from some other environment variables. You can either calculate your value in the bash script, e.g.
env:wibble:wibblesteps:-name:Set myValuerun:echo "myValue=$GITHUB_REF_NAME-$wibble" >> $GITHUB_ENV
or you can use the javascript context${{ }}
and any of theexpressions orcontexts to calculate your value, e.g.
env:wibble:wibblesteps:-name:Set myValuerun:echo "myValue=${{ github.ref_name + "-" + env.wibble }} >> $GITHUB_ENV
These two blocks should be equivalent, but theexpressions mean I generally use the JS version.
The key bit is that it is sent to the$GITHUB_ENV
file. This is what will make it available as an environment variable to the steps that follow it. But only within that job. What if you want to share that value with different jobs?
Sharing data between jobs within a workflow
In the above you used the$GITHUB_ENV
file to make a value available to later steps, but if you want to share a value to a different job you need to use the$GITHUB_OUTPUTS
file instead. But that would be too easy. In addition you also need to declare it as an output.
Within your job you will need to add anoutputs
section that uses the JS context to access the value you will output. You do this by accessing thesteps
context object. The step that you use will now need anid
so that you can access it throughsteps.<stepId>
.
For example, if you want a job that outputs a value that says if this build was triggered by a tag:
jobs:isTagJob:runs-on:ubuntu-latestoutputs:isTag:${{ steps.set_istag.outputs.isTag }}steps:-id:set_istag# step id used to find the output abovename:Set isTag# name that will appear in the logging for this sectionrun:echo "isTag=${{ startsWith(github.ref, 'refs/tags/') }}" >> $GITHUB_OUTPUT
This will make theisTag
value available to any jobs dependant on this one through theneeds context. The format isneeds.<jobId>.outputs.<outputName>
so the above would beneeds.isTagJob.outputs.isTag
. For example the following will only run theannounce_tag
step ifisTag
is'true'
.
...announceTag:runs-on:ubuntu-latestneeds:[isTagJob]# This makes it dependent on the `isTagJob` job abovesteps:-id:announce_tagname:Announce tagif:needs.isTag.outputs.isTag == 'true'run:echo ::notice::This build is for a tag
Sharing data to reusable workflows
Workflows that are called by other workflows useworkflow_call
as theiron
trigger. You can pass values to these workflows by defininginputs
in that workflow and passing the values in usingwith
in the calling workflow.
For example the file.github/workflows/build-dotnet.yml
shown below takes two inputsprojectDir
andisTag
and then uses them in it's jobs.
name:Build Dotneton:workflow_call:inputs:projectDir:required:truetype:stringisTag:required:truetype:booleanjobs:build-code:runs-on:ubuntu-lateststeps:-id:buildname:"Build${{inputs.projectDir}}"run:dotnet build ${{ inputs.projectDir}}-id:push_artifactname:"Push${{inputs.projectDir}}artifact"if:inputs.isTag# the input is a boolean so don't need to compare to `'true'` like with env vars.uses:actions/upload-artifact@v3with:name:${{ inputs.projectDir }}path:./temp/${{ inputs.projectDir}}/**/*
The calling workflow will need to ensure it provides the values correctly so that this workflow can use them. The calling workflow code could look like:
name:Buildon:push:jobs:isTagJob:runs-on:ubuntu-latestoutputs:isTag:${{ steps.set_istag.outputs.isTag }}steps:-id:set_istag# step id used to find the output abovename:Set isTag# name that will appear in the logging for this sectionrun:echo "isTag=${{ startsWith(github.ref, 'refs/tags/') }}" >> $GITHUB_OUTPUTbuild-dotnet-proj-a:needs:[isTagJob]uses:./.github/workflows/build-dotnet.ymlwith:projectDir:projects/projectAisTag:${{needs.isTagJob.outputs.isTag == 'true'}}build-dotnet-proj-b:needs:[isTagJob]uses:./.github/workflows/build-dotnet.ymlwith:projectDir:projects/projectBisTag:${{needs.isTagJob.outputs.isTag == 'true'}}
The same syntax for inputs in reusable workflows is also used actions.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse