Create a GitHub Action using actions-toolkit

19 May 2019 in Tech

In this post we're going to create a GitHub action that outputs an emoji when triggered by a release. It'll output ๐ŸŽ‰ if a release is created, โ˜ ๏ธ if it's deleted and โš ๏ธ if it's any other action.

We'll be using node to create this action as it allows me to make use of the excellent actions-toolkit.

Initialise your action

Instead of creating a Dockerfile manually and bootstrapping an application ourselves, we're going to use actions-toolkit to run an interactive bootstrap process.

If you're interested in how it works, there is a post on creating a GitHub Action with Docker

bash
npx actions-toolkit release-reaction

This will ask you for an action name, description, icon and colour:

bash
โ˜… Welcome to actions-toolkit! Let's get started creating an action.
โ„น Creating folder /private/tmp/release-reaction...
โœ” What is the name of your action? ยท Release Reaction
โœ” What is a short description of your action? ยท Output an emoji in the log, depending on if a release was published/unpublished/other
โœ” Choose an icon for your action. Visit https://feathericons.com for a visual reference. ยท bell
โœ” Choose a background color background color used in the visual workflow editor for your action. ยท blue
------------------------------------
โ„น Creating package.json...
โ„น Creating Dockerfile...
โ„น Creating index.js...
โ„น Creating index.test.js...
------------------------------------
โœ” Done! Enjoy building your GitHub Action!
โ„น Get started with:
cd release-reaction && npm install

Follow the instructions and change directory in to your new folder and run npm install.

Once that completes, edit index.js replace the existing contents with the following.

javascript
const { Toolkit } = require("actions-toolkit");
Toolkit.run(
async (tools) => {
// Add code here
},
{
event: ["release"],
}
);

We require the actions-toolkit package and create a new instance of it to use in our action.

The event: ['release'] entry tells Toolkit that we're expecting to be triggered on a release action and to exit with an error if we're not. This prevents people from using incorrectly configured workflows.

GitHub provide an event.json file containing information about the event that triggered an action run. This file can be used to find out more information about the release, including the event action (created, deleted, published etc).

This information is made available by Toolkit in tools.context.payload. As we're going to be checking the action a few times, let's save it to a variable:

javascript
const action = tools.context.payload.action;

Our first error case is if action is not set. If this is the case, we want the action to exit with a failure. To do this, we can use the tools.exit.failure method which logs a message and then ends the process with an error code of 1.

javascript
if (!action) {
tools.exit.failure("๐Ÿ˜ข No action found in the payload");
}

We'll check for a success next. If the action is created then we'll use the tools.exit.success method which logs and exits with an error code of 0 (no error):

javascript
if (action == "created") {
tools.exit.success("๐ŸŽ‰ New Release Created");
}

We also want to explicitly check for an action of deleted. We also use tools.exit.success here as although deletion is a negative action, it's expected and we should acknowledge that:

javascript
if (action == "deleted") {
tools.exit.success("โ˜ ๏ธ Release Deleted");
}

Then finally, we handle any other actions that we don't explicitly look for. In version 1 of GitHub Actions we could use tools.exit.neutral in this instance as it's not a failure and it's not a success, it's just something we're not interested in. Here's how it used to work:

Using neutral behaved the same as failure - it stopped all running actions and did not run any future actions in the current workflow. However, so long as there are no explicit failures then the workflow will be seen as successful.

However, as of version 2 of GitHub Actions the neutral concept no longer exists. With this in mind, let's log a warning using tools.log.warn and allow the action to exit successfully.

javascript
tools.log.warn("โš ๏ธ Unknown action: " + action);

If we wanted to conditionally execute the next step, we could set an output in this action and use an if statement in the next step to check if it has been set.

Putting it all together, our action looks like the following:

javascript
const { Toolkit } = require("actions-toolkit");
Toolkit.run(
async (tools) => {
const action = tools.context.payload.action;
if (!action) {
tools.exit.failure("๐Ÿ˜ข No action found in the payload");
}
if (action == "created") {
tools.exit.success("๐ŸŽ‰ New Release Created");
}
if (action == "deleted") {
tools.exit.success("โ˜ ๏ธ Release Deleted");
}
tools.log.warn("โš ๏ธ Unknown action: " + action);
},
{
event: ["release"],
}
);

Testing

You can test this workflow by creating GitHub releases, but there is an easier way thanks to act. Go and have a read of this post and continue reading once act is installed.

We're going to be testing an action on our action itself, so we need to make sure it has a workflow defined in .github/workflows/release.yml with the following contents:

yaml
name: Release Status
on: release
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Show Release Status
uses: ./

Once that's done, create a file at /tmp/event.json with the following data:

javascript
{
"action": "created",
"release": {
"name": "1.2.3",
"body": "This is a test",
"html_url": "https://example.com"
},
"repository": {
"name": "Testing"
}
}

This is a stripped down version of the release event JSON that GitHub provide (see complete example).

Run act release -e /tmp/event.json to trigger a release event using the fake event JSON payload that we've provided.

bash
$ act release -e /tmp/event.json
[Release Status] docker build -t release-reaction:latest /tmp/release-reaction
[Release Status] docker run image=release-reaction:latest entrypoint=[] cmd=[]
โœ” success ๐ŸŽ‰ New Release Created

Congratulations! You just created and tested your first GitHub action using actions-toolkit.