• Stars
    star
    928
  • Rank 49,232 (Top 1.0 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 6 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐Ÿ›  A toolkit for building GitHub Actions in Node.js

GitHub Actions Toolkit

An opinionated toolkit for building GitHub Actions in Node.js
Usage โ€ข API โ€ข How to test your Action โ€ข FAQ

GitHub Actions status Codecov

This toolkit is an opinionated alternative to (and wrapper around) the official toolkit. actions/toolkit makes many features optional in the interest of performance, so you may prefer to use it instead of this library.

Usage

Installation

$ npm install actions-toolkit
const { Toolkit } = require('actions-toolkit')
const tools = new Toolkit()

Bootstrap a new action

$ npx actions-toolkit my-cool-action

This will create a new folder my-cool-action with the following files:

โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ action.yml
โ”œโ”€โ”€ index.js
โ”œโ”€โ”€ index.test.js
โ””โ”€โ”€ package.json

API

Toolkit options

event (optional)

An optional list of events that this action works with. If omitted, the action will run for any event - if present, the action will exit with a failing status code for any event that is not allowed.

const tools = new Toolkit({
  event: ['issues', 'pull_requests']
})

You can also pass a single string:

const tools = new Toolkit({
  event: 'issues'
})

And/or strings that include an action (what actually happened to trigger this event) for even more specificity:

const tools = new Toolkit({
  event: ['issues.opened']
})

secrets (optional)

You can choose to pass a list of secrets that must be included in the workflow that runs your Action. This ensures that your Action has the secrets it needs to function correctly:

const tools = new Toolkit({
  secrets: ['SUPER_SECRET_KEY']
})

If any of the listed secrets are missing, the Action will fail and log a message.

token (optional)

You can pass a custom token used for authenticating with the GitHub API:

const tools = new Toolkit({
  token: '1234567890abcdefghi'
})

The github_token input or process.env.GITHUB_TOKEN will be used if no token was passed.

Toolkit.run

Run an asynchronous function that receives an instance of Toolkit as its argument. If the function throws an error (or returns a rejected promise), Toolkit.run will log the error and exit the action with a failure status code.

The toolkit instance can be configured by passing Toolkit options as the second argument to Toolkit.run.

Toolkit.run(async tools => {
  // Action code
}, { event: 'push' })

tools.github

Returns an Octokit SDK client authenticated for this repository. See https://octokit.github.io/rest.js for the API.

const newIssue = await tools.github.issues.create({
  ...tools.context.repo,
  title: 'New issue!',
  body: 'Hello Universe!'
})

You can also make GraphQL requests:

const result = await tools.github.graphql(query, variables)

See https://github.com/octokit/graphql.js for more details on how to leverage the GraphQL API.

Note: To make this function, you must pass a GitHub API token to your action. You can do this in the workflow - both of these are automatically used if they exist:

uses: your/action@v1
with:
  github_token: ${{ github.token }}
env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

tools.log

This library comes with a slightly-customized instance of Signale, a great logging utility. Check out their docs for the full list of methods. You can use those methods in your action:

tools.log('Welcome to this example!')
tools.log.info('Gonna try this...')
try {
  risky()
  tools.log.success('We did it!')
} catch (error) {
  tools.log.fatal(error)
}

In the GitHub Actions output, this is the result:

โ„น  info      Welcome to this example!
โ„น  info      Gonna try this...
โœ–  fatal     Error: Something bad happened!
    at Object.<anonymous> (/index.js:5:17)
    at Module._compile (internal/modules/cjs/loader.js:734:30)

tools.inputs

GitHub Actions workflows can define some "inputs" - options that can be passed to the action:

uses: JasonEtco/example-action@v1
with:
  foo: bar

You can access those using tools.inputs:

console.log(tools.inputs.foo) // -> 'bar'

Note! This is not a plain object, it's an instance of Proxy, so be aware that there may be some differences.


tools.outputs

GitHub Actions workflows can define some "outputs" - options that can be passed to the next actions. You can access those using tools.outputs:

tools.outputs.foo = 'bar'

Note! This is not a plain object, it's an instance of Proxy, so be aware that there may be some differences.


tools.command(command, (args, match) => Promise)

Respond to a slash-command posted in a GitHub issue, comment, pull request, pull request review or commit comment. Arguments to the slash command are parsed by minimist. You can use a slash command in a larger comment, but the command must be at the start of the line:

Hey, let's deploy this!
/deploy --app example --container node:alpine
tools.command('deploy', async (args: ParsedArgs, match: RegExpExecArray) => {
  console.log(args)
  // -> { app: 'example', container: 'node:alpine' }
})

The handler will run multiple times for each match:

/deploy 1
/deploy 2
/deploy 3
let i = 0
await tools.command('deploy', () => { i++ })
console.log(i)
// -> 3

tools.getPackageJSON()

Get the package.json file in the project root and returns it as an object.

const pkg = tools.getPackageJSON()

tools.readFile(path, [encoding = 'utf8'])

Get the contents of a file in the repository. Should be used with actions/checkout to clone the repository in the actions workflow.

const contents = await tools.readFile('example.md')

tools.exec

Run a CLI command in the workspace. This uses @actions/exec under the hood so check there for the full usage.

const result = await tools.exec('npm audit')

tools.token

The GitHub API token being used to authenticate requests.


tools.workspace

A path to a clone of the repository.


tools.exit

A collection of methods to end the action's process and tell GitHub what status to set (success, neutral or failure). Internally, these methods call process.exit with the appropriate exit code. You can pass an optional message to each one to be logged before exiting. This can be used like an early return:

if (someCheck) tools.exit.neutral('No _action_ necessary!')
if (anError) tools.exit.failure('We failed!')
tools.exit.success('We did it team!')

tools.context

tools.context.action

The name of the action

tools.context.actor

The actor that triggered the workflow (usually a user's login)

tools.context.event

The name of the event that triggered the workflow

tools.context.payload

A JSON object of the webhook payload object that triggered the workflow

tools.context.ref

The Git ref at which the action was triggered

tools.context.sha

The Git sha at which the action was triggered

tools.context.workflow

The name of the workflow that was triggered.

tools.context.issue

The owner, repo, and issue_number params for making API requests against an issue or pull request.

tools.context.pullRequest

The owner, repo, and pull_number params for making API requests against a pull request.

tools.context.repo

The owner and repo params for making API requests against a repository. This uses the GITHUB_REPOSITORY environment variable under the hood.

How to test your GitHub Actions

Similar to building CLIs, GitHub Actions usually works by running a file with node <file>; this means that writing a complete test suite can be tricky. Here's a pattern for writing tests using actions-toolkit, by mocking Toolkit.run:

index.js
const { Toolkit } = require('actions-toolkit')
Toolkit.run(async tools => {
  tools.log.success('Yay!')
})
index.test.js
const { Toolkit } = require('actions-toolkit')
describe('tests', () => {
  let action

  beforeAll(() => {
    // Mock `Toolkit.run` to redefine `action` when its called
    Toolkit.run = fn => { action = fn }
    // Require the index.js file, after we've mocked `Toolkit.run`
    require('./index.js')
  })

  it('logs successfully', async () => {
    // Create a fake instance of `Toolkit`
    const fakeTools = new Toolkit()
    // Mock the logger, or whatever else you need
    fakeTools.log.success = jest.fn()
    await action(fakeTools)
    expect(fakeTools.log.success).toHaveBeenCalled()
  })
})

You can then mock things by tweaking environment variables and redefining tools.context.payload. You can check out this repo's tests as an example.

Motivation

actions-toolkit is a wrapper around some fantastic open source libraries, and provides some helper methods for dealing with the GitHub Actions runtime. Actions all run in Docker containers, so this library aims to help you focus on your code and not the runtime. You can learn more about building Actions in Node.js to get started!

After building a GitHub Action in Node.js, it was clear to me that I was writing code that other actions will want to use. Reading files from the repository, making requests to the GitHub API, or running arbitrary executables on the project, etc.

So, I thought it'd be useful to build those out into a library to help you build actions in Node.js ๐ŸŽ‰

FAQ

Aren't these just wrappers around existing functions?

Yep! I just didn't want to rewrite them for my next Action, so here we are.

What's the difference between this and actions/toolkit?

This library was the inspiration for the official toolkit. Nowadays, it's an opinionated alternative. My goal for the library is to make building simple actions easy, while the official toolkit needs to support more complicated use-cases (like performance and scaling concerns).

More Repositories

1

todo

๐Ÿค–โœ… GitHub App that creates new issues from actionable comments in your code.
JavaScript
741
star
2

create-an-issue

A GitHub Action for creating a new issue from a template file.
TypeScript
268
star
3

rss-to-readme

๐Ÿ“ก๐Ÿ“ A GitHub Action that updates a section of a README from an RSS feed.
TypeScript
221
star
4

is-sponsor-label-action

๐Ÿ’–๐Ÿ”– A GitHub Action that labels issues/PRs if the author sponsors the owner of the repo
JavaScript
221
star
5

activity-box

โšก๏ธ๐Ÿ“Œ Update a pinned gist to contain the latest activity of a user
JavaScript
212
star
6

upload-to-release

A GitHub Action that uploads a file to a new release.
Shell
177
star
7

build-and-tag-action

๐Ÿ“ฆ๐Ÿ”– A GitHub Action for publishing JavaScript Actions
TypeScript
94
star
8

gist-box

๐Ÿ“Œ๐Ÿ“‹ A helper class for updating a single-file Gist
TypeScript
84
star
9

action-badges

๐Ÿ›กโšก๏ธ A README badge service for GitHub Actions
JavaScript
61
star
10

ci-reporter

๐Ÿšง๐Ÿ“ GitHub App to show CI failure logs in PR comments
JavaScript
48
star
11

flintcms

๐Ÿ”ฅ๐Ÿ’ฅ A Node.js CMS
JavaScript
45
star
12

readme-box

๐Ÿ“โš™๏ธ Lil' helper for replacing a section of the contents of a README.
TypeScript
31
star
13

npm-audit-fix-action

[WIP] GitHub Action that opens a pull request following an npm audit fix
JavaScript
29
star
14

jasonet.co

๐Ÿ“ My personal site and blog
Nunjucks
27
star
15

readme-guestbook

A little web app that transforms a README into a guestbook.
HTML
21
star
16

good-first-pin

๐Ÿค–๐Ÿ“Œ A GitHub App built with Probot that rotates pinned issues based on Good First Issue labels
TypeScript
16
star
17

octokit-create-new-file

Creates a new file on a new branch and opens a new pull request.
JavaScript
15
star
18

action-record

๐Ÿ“‘ An "ORM" for storing data to a GitHub repository using GitHub Actions
TypeScript
13
star
19

smee-action

๐Ÿ”ด๐Ÿ“œ Use smee.io to debug GitHub Action runs
JavaScript
13
star
20

JasonEtco

11
star
21

slash-assign-action

A GitHub Action that listens for a `/assign` "command" and assigns the commenter to the issue.
TypeScript
10
star
22

github-user-status

A CLI for setting your GitHub user status
TypeScript
9
star
23

progressvg

๐Ÿ’ฏ% Progress bar as a service
JavaScript
6
star
24

push-to-gh-pages

๐Ÿ“ฆ๐Ÿ’ป A GitHub Action that pushes a directory to the gh-pages branch
Shell
6
star
25

test-selector

๐ŸŽญ๐Ÿ‘ˆ Prompts the user to run specific test suites in a project.
JavaScript
6
star
26

validate-semver-release

๐Ÿ”–๐Ÿค” GitHub Action that validates GitHub Releases against semantic versioning
JavaScript
6
star
27

emojify-everything

๐Ÿ†๐Ÿ”ฅ๐Ÿ’ฏ There aren't enough emojis in your websites. This extension fixes that.
JavaScript
6
star
28

signoff-commit-action

โœ๏ธ Action that creates an empty commit with a list of commits to "sign off on"
6
star
29

craft-emailwhitelist

๐Ÿ”’โœ‰ A whitelist of emails for Craft
PHP
5
star
30

dotfiles

๐Ÿ’ป Public repo for my personal dotfiles.
Shell
3
star
31

actions-counter

JavaScript
3
star
32

flintcms-site

๐Ÿ“™ Landing page & Docs for FlintCMS
CSS
2
star
33

nunjucks-octicons-extension

A Nunjucks extension for using Octicons
JavaScript
2
star
34

jolt

CSS
2
star
35

text-to-emoji

JavaScript
2
star
36

streamydoo

Easy to use stream request handler for your browser
JavaScript
1
star
37

hover

Example of WebSockets using hover behaviors
JavaScript
1
star
38

find-code

๐Ÿ”๐Ÿ’ป Find code snippets in your project
JavaScript
1
star
39

business-card

JavaScript
1
star
40

notarikon4d

JavaScript
1
star
41

tote

[WIP] ๐Ÿ‘œ tote, a markdown note-taking PWA
JavaScript
1
star
42

khaliun-batmunkh

JavaScript
1
star
43

url-shortener

๐Ÿ”— URL Shortener, built on a ๐Ÿš†
JavaScript
1
star
44

grunt-jekyll-post

Prompts questions in command line, then creates a Jekyll post template with the answers.
JavaScript
1
star
45

talks

A repo to store my conference talk slide decks
1
star
46

nunjucks-pre-lexer

๐Ÿค“ A tool for identifying and fetching the data that a Nunjucks template expects
TypeScript
1
star
47

notarikon

Notarikon means deriving a word from the first letter of each word in a sentence (using an anagram)
JavaScript
1
star
48

smee-client-rb

[WIP]: A programmatic client for Smee, in Ruby.
Ruby
1
star
49

dinner

๐Ÿฆƒ Cyberspace Thanksgiving Dinner, with all the people you'd expect.
JavaScript
1
star
50

nunjucks-await-filter

Brings async/await functions to your Nunjucks templates.
JavaScript
1
star
51

server-smee-action

An Action for Servers with Smee
TypeScript
1
star
52

a-learning-lab-course-template

The template repository for the a-learning-lab-course course on Learning Lab.
1
star
53

ondesign-xyz

JavaScript
1
star
54

revolution

JavaScript
1
star
55

personal-site

๐ŸŒˆ๐Ÿ‘Œ๐Ÿ˜ My personal website and portfolio
JavaScript
1
star
56

discord-namer

๐ŸŽฎ Changes my Discord nickname when I'm @-mentioned, using a random emoji.
JavaScript
1
star
57

github-bulk-transfer

Simple CLI utility to trigger bulk transfers of github repos through a headless browser
JavaScript
1
star