Automate routine tasks with GitHub Actions

and
Read on Russian

You'll spend less time testing your application, building it, checking the quality of your code, and keeping your tasks up-to-date if you automate routine processes. GitHub Actions is a service that will allow you to describe scenarios of any complexity and conditions to run it.

The service is free for open source projects. For private projects, there are a limited number of free scripting minutes. You can find the prices and limits on the service page.

What are GitHub Actions

Actions are pre-defined sets of commands that tell you how to do something when a trigger is activated - a commit to a branch, a task created, a new release published, and so on. Scripts can also be run on a timed basis, as is done with the cron utility.

Actions can interact with the application code and change history, with the repository workspace (tasks, projects, documentation, releases), with third party services to deploy the application or send some kind of notification request. It's a powerful tool that will work alongside you on the project.

How to describe a script

The script files - workflow - are stored in the .github/workflow directory in your project repository. These are YAML format configuration files.

Each script has a name, execution conditions, and tasks. Each task describes a set of individual steps.

name: ... on: ... jobs: ...

Each task can have a name, an operating system indication, a dependency on other tasks and a list of steps.

Each step can be either a set of bash commands or a ready-made action.

For example, consider a script that builds the frontend for codex.so in production mode and adds the build to the pull-request.

# Script name name: Build frontend # Prerequisites for execution: any actions with the pool-request on: [pull_request] # Task list jobs: build: # Task name name: Build frontend # Run on a virtual machine with Ubuntu runs-on: ubuntu-latest # List of steps steps: # Use project code from a specific commit # By default, the branch whose changes caused the script to run is used - uses: actions/checkout@v2 # Configuring Node.js 15 to run on a virtual machine - name: Use Node.js 15 uses: actions/setup-node@v1 with: node-version: 15 # Installation of project node packages and frontend assembly # The described bash commands will be executed - name: Go to app dir, Install Node.js packages, Build static files run: cd www && yarn && yarn build # Trying to commit frontend build updates to a branch on behalf of the github-actions bot (specify its name and email with the ID of the official github bot) - uses: EndBug/add-and-commit@v7 with: author_name: github-actions author_email: 41898282+github-actions[bot]@users.noreply.github.com message: 'Build frontend'

Check the GitHub documentation on working with scripts to learn more about the features of workflow files.

There is no local testing of the correctness of the scripts.

Where to look for actions

Try searching the directories for the right action before you create and publish your own.

The GitHub Marketplace has a separate section dedicated to Actions. Some are created by well-known companies, but most are created and published by independent developers.

github.com

The unofficial Awesome Actions catalogue is also worth a look.

github.com

You can find a lot of interesting solutions and inspiration here - perhaps you have a similar task and never thought it could be automated as well.

How to write your own Action

Suppose you didn't find a ready-made solution for the step you need, and describing the whole set of commands in a bash script is inconvenient or impossible. In this case, you can use instructions from GitHub. The action code can be written in JavaScript, assembled as a ready-made Docker image with any content. Alternatively, the set of steps can be described in a file as a list of console commands

However, you have to remember that docker-based actions can only be run on a Linux virtual machine.

For a new action, you need to create a separate repository with descriptions, source code and builds.

As an example, let's parse codex-team/action-nodejs-package-info, an action that gets the application name and version information from the package.json file.

The settings are stored in the action.yml file at the root of the project.

# Meta-information about an action is used to form a card in the marketplace # Action name name: 'Get package info' # Description description: 'Action for getting information from package.json file' # Icon and its background colour branding: icon: 'box' color: 'red' # Parameters that can or should be transmitted to the input inputs: path: description: 'Path to package.json file' required: false default: ./ # Parameters that will be available as a result of the step outputs: name: description: 'Package name' version: description: 'Package version' npmjs-link: description: 'Link to npmjs.com package page' # Code launch conditions runs: # Description of the environment and its version using: 'node12' # Path to the assembled script main: 'dist/index.js'

Next, you will need to install a couple of prefered node-dependencies to make the code work:

Let's add a build script to build the index.js source code with all dependencies (e.g. @actions/core) into a single dist/index.js file.

{ "name": "action-nodejs-package-info", "scripts": { "build": "ncc build index.js --minify" }, "devDependencies": { "@actions/core": "^1.2.6", "@vercel/ncc": "^0.25.1" } }

And the source file itself with simple logic. Get the path to the package.json file, read it and export some parameters.

import fs from 'fs'; import { join } from 'path'; const core = require('@actions/core'); /** * Read package.json file * @param {string} path * @returns {object} */ const readPackageJson = function (path) { const packageJson = fs.readFileSync(join(path, 'package.json')).toString(); return JSON.parse(packageJson); }; try { /** * Path to directory with package.json file * @type {string} */ const path = core.getInput('path'); /** * Get data from package.json file * @type {object} */ const packageInfo = readPackageJson(path); core.setOutput("name", packageInfo.name); core.setOutput("version", packageInfo.version); core.setOutput("npmjs-link", `https://www.npmjs.com/package/${packageInfo.name}`); } catch (error) { core.setFailed(error.message); }

Core.getInput() retrieves the values of the imported variables and core.setOutput() exports the values back to the script. Details of the key methods for handling actions are available in the @actions/core package description. 

Also, don't forget to add a README.md file describing how the action works and all parameters. And before committing changes, run the yarn build command to update the build file or set up a script that will do this for you. 

In order to use your Action in scripts, you need to create a tagged version. To do this, go to the Releases section of the project repository and create a new release. On the same page, you will be prompted to publish the action to the marketplace, after which it will appear in the search.

Test the action by using it in some script. At the time of writing this is the only option to test if the code works correctly.

Useful Links

Official Actions documentation from GitHub

List of available icons and colours for action icons

Examples of self-made actions

codex-team/action-nodejs-package-info - information about node-package name and version

codex-team/action-check-domain - check for expiration date of domain registration and SSL validity

codex-team/action-codex-bot-notify to Telegram or Slack chat

Examples of scripts used in CodeX projects

Publishing a package to npm

Checking code style with a linter

Build frontend in pull-requests

Build and publish docker images

Build and publish an electron application

Bump package version