Composite actions
Cardinal
Posted on December 7, 2021
In this part we will start with implementing composite actions, the base building blocks that are used in the workflows.
We save all created actions locally in the repo in .github/workflows/actions
directory. Every action has own named directory and a single action.yml file in it.
build-test-pack action
.github/workflows/actions/build-test-pack/action.yml :
name: "Build, test and pack WebExtension"
description: "Builds, tests, and packs extension dir into zip file"
inputs:
doNotPackZip:
description: 'Set `true` to omit pack step'
required: false
runs:
using: "composite"
steps:
# Add additional build and test steps here
- name: Validate manifest.json of the extension
uses: cardinalby/schema-validator-action@v1
with:
file: ${{ env.EXTENSION_DIR }}manifest.json
schema: 'https://json.schemastore.org/webextension.json'
- name: Pack directory to zip
if: inputs.doNotPackZip != 'true'
uses: cardinalby/webext-buildtools-pack-extension-dir-action@v1
with:
extensionDir: ${{ env.EXTENSION_DIR }}
zipFilePath: ${{ env.ZIP_FILE_PATH }}
- It can pack or not pack zip depending on the input.
- My extension doesn't have any build and test steps, so I put manifest.json schema validation instead of actual build and test steps. This post doesn't cover the topic of building and testing WebExtensions. But it's the place where these steps should be.
- The action needs ZIP_FILE_PATH and EXTENSION_DIR environment variables to be set in the workflow.
get-zip-asset action
The next composite action we are going to create will be used in publish-on-chrome-webstore and publish-on-firefox-addons workflows. These workflows can be triggered:
- Manually on any tag or branch (a release may not exist)
- Or by dispatching from publish-release-on-tag workflow. In this case a release with packed zip file exists.
Both "Firefox" and "Chrome" workflows should handle these cases and download zip file from a release (if any) or build it on the spot. That is the duplicated logic that we extract to the composite action.
.github/workflows/actions/get-zip-asset/action.yml :
name: "Obtain extension.zip asset"
description: "Downloads or builds zip asset"
inputs:
githubToken:
description: GitHub token
required: true
outputs:
releaseUploadUrl:
description: Release upload url, if exists
value: ${{ steps.getRelease.outputs.upload_url }}
runs:
using: "composite"
steps:
- name: Get release
id: getRelease
if: github.ref_type == 'tag'
uses: cardinalby/git-get-release-action@v1
env:
GITHUB_TOKEN: ${{ inputs.githubToken }}
with:
tag: ${{ github.ref_name }}
doNotFailIfNotFound: true
- name: Find out zip asset id from assets JSON
if: steps.getRelease.outputs.assets
id: readAssetIdFromRelease
uses: cardinalby/js-eval-action@v1
env:
ASSETS_JSON: ${{ steps.getRelease.outputs.assets }}
ASSET_NAME: ${{ env.ZIP_ASSET_NAME }}
with:
expression: |
JSON.parse(env.ASSETS_JSON)
.find(asset => asset.name == env.ZIP_ASSET_NAME)
?.id || ''
- name: Download found zip release asset
id: downloadZipAsset
if: steps.readAssetIdFromRelease.outputs.result
uses: cardinalby/download-release-asset-action@v1
with:
token: ${{ inputs.githubToken }}
assetId: ${{ steps.readAssetIdFromRelease.outputs.result }}
targetPath: ${{ env.ZIP_FILE_PATH }}
- name: Build and pack zip
id: buildZip
if: steps.downloadZipAsset.outcome != 'success'
uses: ./.github/workflows/actions/build-test-pack
- name: Upload zip file artifact
if: steps.buildZip.outcome == 'success'
uses: actions/upload-artifact@v2
with:
name: ${{ env.ZIP_FILE_NAME }}
path: ${{ env.ZIP_FILE_PATH }}
- githubToken input is needed because composite actions don't have access to secrets, and we have to pass them manually via inputs.
- releaseUploadUrl output is filled if release exists. It can be used in a calling workflow to upload release assets.
- Searching for a release makes sense only if a workflow was triggered with
tag
ref. PassingdoNotFailIfNotFound: true
to cardinalby/git-get-release-action prevents the step from failing the entire job if a release not found. - I use js-eval-action (that is generic JS interpreter action) to find zip asset in the release.
- We build zip (calling the composite action we have just created) only if
steps.downloadZipAsset.outcome != 'success'
, i.e. in the case if ref is nottag
, or release not found, or the release doesn't have zip asset.
Not a composite action
We have one more piece of code that will be duplicated around all jobs and workflows. I'm talking about these steps we will add at the beginning of each job:
- uses: actions/checkout@v2
- uses: cardinalby/export-env-action@v1
with:
envFile: './.github/workflows/constants.env'
expand: true
This code:
- Checks out the repo.
- Exports env variables from ./.github/workflows/constants.env file (you can find its contents in the first post) to the job environment using export-env-action.
Unfortunately, we can't extract checkout step to a local composite action because to call local composite actions you need first checkout the repo with the composite actions 🙂. Thus, I decided that extracting the single export-env-action step doesn't make a big sense and left it as it is. In the following parts I will not draw attention to these steps at the beginning of each workflow.
Posted on December 7, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.