When working on CICD, we want to execute a variety of scripts and commands in different languages and shells in a single Action and map those outputs to the GitHub Actions workflow.
We also want to reuse parts of our workflows into other workflows.
Those 2 things are historically very difficult to do in GitHub actions. Well, despair not, today I'm showing you how to do just that, using a new GitHub Actions type that has just been released: composite run steps.
About Composite Run Steps Actions
So, first things first: What is a composite run steps action?
A composite run steps action allows you to combine multiple workflow run steps within one action. For example, you can use this feature to bundle together multiple run commands into an action, and then have a workflow that executes the bundled commands a single step using that action.
In simple words, it is a feature that enables you to nest actions within actions.
Why would you want to do it?
The most common reason is that you create a sort of template action and then you can reuse it anywhere you need. Another very common one is when you have multiple project and all of them need to follow the same steps in the CICD workflow.
Using the Composite Run Steps you can now write that part once, save it somewhere and use it in any of your actions. And if you need to change that, maybe adding a new step or changing some parameters, you'll change it once in the central location and the change will apply to all the workflows that use it.
The Video
If you are a visual learner, simply prefer to watch and listen instead of reading, or you want to see this in action, here you have the video with the whole explanation.
I'd encourage you to watch it because, to be fair, it is much more complete than this post.
If you rather prefer reading, well... let's just continue :)
Supported Properties
For each run step in a composite action, these are the properties that are currently supported:
name
id
run
env
shell
working-directory
In addition, mapping input and outputs throughout the action are also supported.
The metadata
First of all, you need to create a metadata file.
I prefer creating a new repository to host my composite run steps action, because I like to keep things organized and this also optimize the reusability.
But you can save the composited actions also in the local repository and reference them from there.
You have to create a file named action.yml or action.yaml. Other file names are not supported.
The file could look like this:
name: 'File Copy'
description: 'Pretends to copy some files and return the number of files copied'
inputs:
destinationFolder: # path
description: 'The folder to copy the files to'
required: true
default: '~'
outputs:
copied-files:
description: "Number of files copied"
value: ${{ steps.random-number-generator.outputs.filesNo }}
runs:
using: "composite"
steps:
- run: ${{ github.action_path }}/ExecuteSomething.sh
shell: bash
- id: random-number-generator
run: echo "::set-output name=filesNo::$(echo $RANDOM)"
shell: bash
- run: ${{ github.action_path }}/CopyFiles.sh
shell: bash
In this file, the properties name, description, and runs are mandatory.
The input and outputs sections, instead, are optional and are the way we can mut input and outputs from and to the using workflow.
The YAML is quite self explanatory, I just want to point out the using: "composite"
part because it's what makes this work.
Check the video with the full explanation to understand what all the parts in the YAML mean.
Save, commit, and push to the repo.
Tag time
Before we can use this "snippet" into our actions, we need to create a Tag and a Release for our repo.
You can use whatever tag you like, but this is what will identify your Composite Run Steps, so choose something meaningful.
For this example I'd go with v1
Ok, now we have everything we need. Let's create a composite action.
Use it in the Composite Run Steps Action
Let's go to Actions, and create a new workflow. Something like this:
# This is an example of using Composite Run Steps Actions
name: Composite Example
on: [workflow_dispatch]
jobs:
copy_files_job:
runs-on: ubuntu-latest
name: A job that copy files
steps:
- uses: actions/checkout@v2
- id: myCompositeAction
uses: n3wt0n/CompositeActionsArchive@v1
with:
destinationFolder: '/whatever/folder'
- run: echo Files copied ${{ steps.myCompositeAction.outputs.copied-files }}
shell: bash
As you can see, this is a normal GitHub action. I'm using a manual trigger (check this video if you are not familiar with Manually Triggering GH Actions), but it can use any trigger you want.
The interesting part is the one in the middle:
- id: myCompositeAction
uses: n3wt0n/CompositeActionsArchive@v1
with:
destinationFolder: '/whatever/folder'
As you can see, we are using our metadata file referencing it with the syntax "account/repo@tag"
.
More or less what you would do when using an Action from the Marketplace.
We are also passing some params as input (using the with: clause) and we are getting the output out of it (with the usual context, in the form steps.YOUR_STEP_ID.outputs.YOUR_PARAM_NAME
)
Once again, check the video with the full explanation to understand what all the parts in the YAML mean.
And you're basically done!
Not bad right? Making slices of GitHub Actions workflows reusable is a real game changer.
Unsupported features
Some notes.
Since at the time of writing this feature has been released very recently, there are few things which are not yet supported. Those include setting conditionals, continue-on-error, timeouts and uses. Although the team is already working on most of those features.
Another thing that is not supported is using secrets on individual steps within a composite action.
Of course, you can still use all of those attributes in workflows that use a composite run steps action.
Conclusion
Alright, that's it for today. I will have another post and another video when the composite run steps actions will be more mature and gain more of the missing features, so subscribe to my YouTube channel and stay tuned so you'll not miss them.
Let me know in the comment section below what you think about this new feature, and if you have any question about it.
References and Links
- Video with the full explanation about GitHub Composite Actions
- GitHub Actions Showcase
- Video on GitHub Actions for .Net Framework
Like, share and follow me 🚀 for more content:
📽 YouTube
☕ Buy me a coffee
💖 Patreon
🌐 CoderDave.io Website
👕 Merch
👦🏻 Facebook page
🐱💻 GitHub
👲🏻 Twitter
👴🏻 LinkedIn
🔉 Podcast
Top comments (10)
One thing that caught me out was that you can’t reference other actions from within your composite action. Both the name “composite action” and the fact this post talks about “nesting actions within actions” led me astray for a while.
The crucial bit is that right now “uses” is not supported in a composite action. You can basically only use it to create a new action from several shell commands.
Just popping this here so others don’t go down that path of trying to refactor their workflows.
You are right, I should probably ass that to the article.
The reason why I haven't ephatsized that much is because the support for
uses
was to be added soon at the time I wrote the article and made the video. However, apparently the team's backlog has shifted and it's still not supported -_-'Can now use other actions:
github.blog/changelog/2021-08-25-g...
Yes, I’ve already made an article and a video about this new feature : dev.to/n3wt0n/create-github-action...
I've just double checked and in fact I do mention that in the "Unsupported Features" section :)
Ah yeah I see it now. 👍 I guess the name makes more sense if their plan was to add support for “uses”. It’s a shame they’ve not been able to implement it yet though, it would be a nice feature.
What do you think of this new feature?
looks great, I've finally found a way to achieve some DRY when moving from Travis CI similar to its import config feature
you have not used the input parameter which you are accepting in your composite file :)
hehe yes that was just a dummy example on how to require and pass parameters :)