jonelantha: Blog


Create your own local js GitHub Action with just two files

Here's a handy shortcut if you've got an npm based project and you're looking for a quick way to create your own GitHub Action in the same repo with very little overhead.

Create your own node.js action with just a couple of files, it turns out there's no need to create a nested package.json file or commit a nested node_modules to your repo (as suggested in the official method).

Why would I even want to do this?

Here's a few reasons why this might make sense for you:

  • you have some complexity in your workflow yml file which you'd like to refactor out (in the spirit of clean code we should try and keep our workflow file as a high level overview of the pipeline, preferably not cluttered with implementation details).
  • you have a non-trivial action which you'd like to share between more than one workflow yml file.
  • you're not yet at the point where it makes sense to define your action in its own repo (sure that would be nice, but most of the time YAGNI).

TL;DR

Here's a brief overview of what's involved (there's a step by step example later on):

  1. Your project should be javascript based using npm.
  2. Your custom GitHub Action cannot be executed before the npm ci / npm install step in your workflow.
  3. You can add the GitHub Toolkit packages your action needs to your root package.json file, there's no need to create a separate package.json file and no need to commit the contents of a nested node_modules directory to your repo.
  4. You'll create your action.yml and action.js files in their own directory somewhere inside your project, the code inside the action will be able to require the GitHub Toolkit packages from your root node_modules folder.
  5. You then execute your new local GitHub action from your workflow yml file.

Step by step example

Let's have a look at a simple 'hello world' example. Our example will console.log out a parameter sent in from the workflow yml file and will execute the date shell command, sending the output to the workflow log.

(the completed example can be found at https://github.com/jonelantha/helloworld-github-action)

  1. Firstly you'll need an npm based repo checked into GitHub. For the purposes of this walkthrough, just a barebones package.json file created from npm init will be fine.

  2. Create the following four level directory structure at the root of your project:

    .github
      workflows
        actions
          helloworld
  3. Create the action metadata file for the new action:
    .github/workflows/actions/helloworld/action.yml

    name: "Hello World"
    description: "Simple example action"
    inputs:
      example-param:
        description: "An example parameter"
    runs:
      using: "node12"
      main: "action.js"

    For more info on the syntax here, see the Metadata syntax for GitHub Actions documention.

  4. Create the main js action file:
    .github/workflows/actions/helloworld/action.js

    const core = require("@actions/core");
    const { exec } = require("@actions/exec");
    
    async function exampleAction() {
      const exampleParam = core.getInput("example-param");
      console.log(`Here's the example param: '${exampleParam}'`);
    
      console.log("And now let's run the system 'date' command:"); 
      await exec("date");
    }
    
    exampleAction()
      .catch(error => core.setFailed(error.message));

    To find out more about the packages being used here, see the GitHub Actions Toolkit repo.

  5. Add the two GitHub Actions Toolkit packages to your node_modules folder by typing the following into a terminal window:

    npm i @actions/core
    npm i @actions/exec
  6. Create a simple workflow yml file which will activate the action everytime a push occurs: .github/workflows/helloworld-workflow.yml

    name: HelloWorld
    
    on:
      push:
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
    
        steps:
          - name: Checkout
            uses: actions/checkout@v1
          - name: Install npm packages
            run: npm ci
          - name: Hello World
            uses: ./.github/workflows/actions/helloworld
            with:
              example-param: Hello World
  7. Commit the files and push your changes up to GitHub. After a minute or two your workflow should've run, check the output in the actions tab and you should see something like this:

    Here's the example param: 'Hello World'
    And now let's run the system 'date' command:
    /bin/date
    Sat Feb 15 18:03:14 UTC 2020
  8. That's it!

You want more actions?

You can add more actions just by repeating the steps above, however there's one slight restriction; GitHub always expects the manifest file to be called action.yml - this means multiple actions can't live in the same directory as each other. All you need to do is create a new directory alongside the helloworld directory and put your new action.yml and action.js files in there.

Final thoughts

You've created a GitHub Action inside your repo by adding only two files, a nice lightweight solution if all you want to do is a little bit of workflow refactoring.

However, there may come a time when you outgrow this setup, perhaps you want to share your action between multiple repos or perhaps you want to share it with the wider world. When that time comes then you should move the action to its own repo, for more details, see the official GitHub actions instructions.


© 2003-2023 jonelantha