GitHub Actions workshop
This hands-on workshop provides a introduction to building pipeline workflows using GitHub Actions and creating your first GitHub Action using JavaScript, TypeScript or Docker.
Welcome
Welcome all to the full-day workshop on GitHub Actions and Packages
Agenda
- Introduction to GitHub Actions.
- Create a workflow with build, test, publish and deploy steps.
- Create a workflow that is triggered when an issue is opened.
- Create a JavaScript action using the tutorial.
- Create your own action using either JavaScript, TypeScript or Docker.
- Q&A
Prerequisites
- A verified GitHub account.
- We use a public repository under your personal account to run workflows.
- We use Zeit for deployments.
:warning: Make sure to configure two-factor-authentication for your GitHub account.
At the end of each labs you will find links to relevant resources.
Tip: follow the if applied, this commit will <your subject line here>
best practice for every commit message so you know what is being tested by the build run. For example:
Add build and test workflow
Resources
- Core concepts for GitHub Actions
- Automating your workflow with GitHub Actions
- Event Types & Payloads
- About pull requests
Lab 1: Create repository from template
Create a new repository from octocat-zen:
- Visit https://github.com/octodemo/octocat-zen.
- Click
Use this template
. - Create a public repository under your personal account.
- Provide a repository name, for example
<your handle>-octocat-zen
. - Click
Create repository from template
. - If you want to use your favorite editor, you can clone the repository to your local machine.
- In
package.json
update thename
from@octocat/octocat-zen
to the right owner and repository name and also update therepository url
and commit the change. - In
.npmrc
update the scope ands commit the change.
Resources
Lab 2: Add starter workflow
Let’s get started with GitHub Actions:
- Click the
Actions
tab. - Under Build and test your JavaScript repository select
Node.js
. - Click
Setup this workflow
. - Under
Start commit
selectCreate a new branch
. - Add a branch name, for example
add-nodejs
and clickPropose new file
. - Provide a pull request title and description and click
Create pull request
. - GitHub will start the build, go to the
Checks
tab to follow the build process. - Merge the pull request and delete the feature branch.
Note: GitHub Actions are free for public repositories and on a free plan you get 2000 build minutes.
Bonus: make a change in a new pull request that breaks the build.
For example you could add an array test in test.js
:
var assert = require('assert');
[...]
describe('Array', function () {
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
// replace 4 with value that is present in the array
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
Resources
Lab 3: Add a linter step
In this lab we remove the matrix build and add a linter step:
- Go to
.github/workflows/nodejs.yml
and click on edit. - Remove the following lines:
strategy:
matrix:
node-version: [8.x, 10.x, 12.x]
- Replace
$
with12.x
- Add a new step:
- name: Run linter
run: |
npm install eslint --save-dev
./node_modules/.bin/eslint --no-eslintrc .
- Commit the changes to a new branch like
add-linter
and open a pull request. - Visit the checks tab to follow the workflow run.
Note On GitHub Marketplace you can also find various actions for ESLint and other code quality tools.
Resources
Lab 4: Define a job level environment variable
You can use environment variables at the step and job level:
- Add the following lines under the job
build
:
env:
NODE_VERSION: 12.x
- Change all occurrences of
12.x
to$
. - Commit the change to the
add-linter
branch. - Check the build run.
- Merge the pull request and delete the branch.
Resources
Lab 5: Dump contexts
In this lab we add another workflow to take a look at the workflow context. We will also look at a few functions:
- In
.github/workflows/
create a new file, for example:dump-context.yml
- Add the following content:
name: Dump contexts
on: push
jobs:
echo:
runs-on: ubuntu-16.04
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: $
run: echo "$GITHUB_CONTEXT"
- name: Dump job context
env:
JOB_CONTEXT: $
run: echo "$JOB_CONTEXT"
- name: Dump steps context
env:
STEPS_CONTEXT: $
run: echo "$STEPS_CONTEXT"
- name: Dump runner context
env:
RUNNER_CONTEXT: $
run: echo "$RUNNER_CONTEXT"
- Commit the changes to a new branch like
dump-context
and open a pull request. - Visit the
Checks
tab to follow the workflow run. - Add a step that outputs the following variables from the GitHub context:
github.event_name
github.ref
- For example:
- name: Dump variables
env:
EVENT_NAME: $
REF: $
run: echo "Event name $EVENT_NAME and ref $REF"
- The
toSJON()
is an example of a built-in function. - Add the following function to the last
Dump variables
step:
format('Hello {0} {1} {2} {3}', 'Hubot', 'the', 'friendly', 'robot')
- For example:
- name: Outputs
env:
EVENT_NAME: ${{ github.event_name }}
REF: ${{ github.ref }}
ROBOT: ${{ format('Hello {0} {1} {2} {3}', 'Hubot', 'the', 'friendly', 'robot') }}
run: |
echo "Event name $EVENT_NAME and ref $REF"
echo "$ROBOT"
You can process the variables like any other environment variable, for example to replace Hubot
with Probot
:
echo "${ROBOT/Hubot/Probot}"
- Feel free to try a couple of other functions.
- Merge the pull request and delete the feature branch.
Resources
Lab 6: Add a comment to the pull request
Let’s add a comment to thank the developer for opening the pull request. We will use an if
statement to check if the pull request is opened
as we only want to add the comment once.
You can add if
statements both on the step
and job
level. You can also use or
operators (||
):
if: github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'reopened')
And and
operators (&&
):
if: github.event_name == 'pull_request' && github.event.action == 'closed'
And combine operators with functions:
if: github.event.action == 'opened' && ( startsWith(github.event.issue.title, 'demo') )
- Go to
.github/workflows/nodejs.yml
and click on edit. - Add the following step after the
checkout
step, we will useactions/github
to add the comment to the pull request:
- name: Add comment
if: github.event_name == 'pull_request' && (github.event.action == 'opened')
uses: actions/github@v1.0.0
env:
GITHUB_TOKEN: $
with:
args: comment "Thank you for opening this pull request :tada::sparkles:"
- Commit the changes to a new branch like
add-comment
and open a pull request. - Visit the checks tab to follow the workflow run.
- Merge the pull request and delete the feature branch.
Resources
Lab 7: Add caching for node_modules
Actions allow you to cache dependencies and build outputs in GitHub Actions:
- Go to
.github/workflows/nodejs.yml
and click on edit. - Add the following step after the checkout step:
- uses: actions/cache@v1
with:
path: ~/.npm
key: $-node-$
restore-keys: |
$-node-
- Commit the changes to a new branch like
add-caching
and open a pull request. - Visit the checks tab to follow the workflow run.
- Make another code change to verify if the cache gets restored, for example add a step name:
- name: Cache dependencies
- Merge the pull request and delete the feature branch.
You can also upload and download build artifacts, for example if you want to use build artifacts across different jobs in a workflow:
- name: Upload report
uses: actions/upload-artifact@master
with:
name: coverage
path: $/coverage
Resources
Lab 8: Deploy to Zeit
It is time to deploy our code. For this workshop we use Zeit as deployment target:
- Visit https://zeit.co/ and create an account using GitHub OAuth or email.
- Go to Settings, then Tokens and generate a token.
- Copy the token.
- Go to the GitHub repository and visit
Settings
,Secrets
and add a secret for the token with keyZEIT_TOKEN
. - Go to
.github/workflows/nodejs.yml
and click on edit. - Add the following step to the workflow:
- name: Deploy to Zeit
uses: amondnet/now-deployment@v1
with:
github-token: $
zeit-token: $
- Commit the changes to a new branch like
add-deployment
and open a pull request. - Visit the
Checks
tab to follow the workflow run. - If the run is successful you should see the deployment url created by Zeit.
- Visit the url to check our deployment.
- Navigate to the project in Zeit to view the deployment details.
Bonus: Update the workflow to only run when the branch is master
or update to run the deployment step only when the branch is master
. After this task, remove any branch filters and commit.
- Do not merge the pull request yet.
Resources
Lab 9: Add the deployment to the pull request
With the Deployment API you can report a deployment status in the pull request:
- Change the workflow event from
push
topull_request
. - Add the following step before the Zeit deployment step:
- uses: octokit/request-action@v1.x
id : create_deployment
with:
route: POST /repos/:owner/:repo/deployments
ref: $
required_contexts: "[]"
environment: "review"
env:
GITHUB_TOKEN: $
- We need to capture the deployment
id
from the response. We can use a tool likejq
to do that in a script, but we can also use the following action:
- uses: gr2m/get-json-paths-action@v1.x
id: parse_deployment
with:
json: $
id: "id"
- To update the deployment statuses, add the following steps after the Zeit deployment step:
- uses: octokit/request-action@v1.x
with:
route: POST /repos/:owner/:repo/deployments/:deployment_id/statuses
deployment_id: $
environment: "review"
state: "success"
target_url: $
env:
GITHUB_TOKEN: $
- uses: octokit/request-action@v1.x
if: failure()
with:
route: POST /repos/:owner/:repo/deployments/:deployment_id/statuses
deployment_id: $
environment: "review"
state: "failure"
env:
GITHUB_TOKEN: $
- Verify the build run.
- Merge the pull request and delete the feature branch.
Resources
Lab 10: Publish mpn package
In this lab we will publish our project as npm package to GitHub Package Registry.
- Check
package.json
to make sure thename
is set to the right owner and repository name. - Add the following job to the workflow:
Note: make sure to add your handle to the scope.
publish-gpr:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12.x
registry-url: https://npm.pkg.github.com/
scope: '@<your handle>'
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: $
- Now we might just want to run this when we push to
master
, so create a separate workflow that will deploy on a push tomaster
.
Resources
Lab 11: Add a badge
Let’s add a badge to the README
:
- Go to the
README
, select the pull request branch and open the file in the edit mode. - Add the following line under the title:

- Commit the change to the pull request branch.
- Visit the
README
in the pull request branch after the build completes. - Optionally make another change that will break the build and verify again.
- Merge the pull request and delete the feature branch.
Resources
Lab 12: Publish Docker container
GitHub Package Registry can also be used to publish Docker images.
Create a new job publish-docker
that builds and tags the image and then publishes the tagged image to GitHub Package Registry:
Note: make sure to update the tag names to reflect your handle and repository name.
publish-docker:
needs: [build]
runs-on: [ubuntu-latest]
steps:
- uses: actions/checkout@master
- run: |
docker build -t docker.pkg.github.com/<your handle/octocat-zen/octocat-zen:$ .
docker login docker.pkg.github.com -u <your handle> -p $GITHUB_TOKEN
docker push docker.pkg.github.com/<your handle>/octocat-zen/octocat-zen:$
env:
GITHUB_TOKEN: $
Resources
Lab 13: Create release
For a JavaSCript project you can use semantic-release
to automatically create releases. This is a bit harder to test as it will closely examine your commits to judge if it justifies a release.
on:
push:
branches:
- master
- next
name: Release
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@v1
with:
node-version: "12.x"
- run: npx semantic-release -r git@github.com:<your handle>/octocat-zen.git
env:
GITHUB_TOKEN: $
NPM_TOKEN: $
- You can also create releases using the Releases API or the create-release action, but this requires you to add the versioning and changelog manually.
Resources
Lab 14: Use the issue event
In the following example we will use the issue event to add a comment to an issue when it is created. We use actions/github
to comment on the issue when it is opened.
- Create a new workflow file in
.github/workflows
for example calledzen-comment.yml
:
name: GitHub Zen
on:
issues:
types: [opened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- id: zen
run: echo ::set-output name=quote::$(curl https://api.github.com/zen)
- name: GitHub Zen comment
uses: actions/github@v1.0.0
env:
GITHUB_TOKEN: $
with:
args: comment ">$ :heart::octocat:"
- You can also use
actions/github
to assign a user to an issue or apply a label. See entrypoint.js for examples. - As an alternative you can also use
request-action
:
- name: GitHub zen comment
uses: octokit/request-action@v1.x
with:
route: POST /repos/:owner/:repo/issues/:issue_number/comments
issue_number: $
body: '">$ :heart::octocat:"'
env:
GITHUB_TOKEN: $
- And there is another way of doing this using github-script. This action is under development.
Resources
- GitHub Action for GitHub
- octokit/request-action
- github-script
- cURL
- Issues
- IssuesEvent
- Outputs
- Mastering Markdown
Lab 15: Creating a JavaScript action
Follow the tutorial Creating a JavaScript action to create your first JavaScript action.
You can also use Docker to create actions.
Resources
- Building actions
- Development tools for GitHub Actions
- Publishing actions in GitHub Marketplace
- zeit/ncc
- GitHub Actions
- Working with GitHub Actions
Lab 16: Create your own action
- Create small teams of two to three people.
- Start with brainstorming to come up with a great idea for a GitHub Action that can help you to improve your workflow. Remember that you can use any event on GitHub.
- Build and test your action.
- Add documentation in the README.
- Provide a sample workflow.
- Prepare to present your action to the workshop audience.
If you want to interact with GitHub you can install and import the @actions/github
library and create a client
:
import * as core from '@actions/core';
import * as github from '@actions/github';
import * as yaml from 'js-yaml';
async function run() {
try {
const ref = core.getInput('ref', { required: true });
const task = core.getInput('task');
const autoMerge: boolean = yaml.load(core.getInput('auto_merge'));
const client = new github.GitHub(token);
core.debug('Returning the ref value');
core.setOutput('ref', ref)
} catch (error) {
core.setFailed(error.message);
}
}
Scheduled events and dispatcher event
Scheduled events
GitHub Actions also supports scheduled events. See actions/stale for an example.
Dispatch event
You can use the GitHub API to trigger a webhook event called repository_dispatch
when you want to trigger a workflow for activity that happens outside of GitHub.
Resources
Appendix 1: the complete nodejs.yml
workflow
The following workflow is an example of the completed nodejs.yml
workflow:
Note: if you want to use this workflow please updated the owner value to match your handle and make sure you use your repository path and name.
name: Node CI
on: [pull_request]
jobs:
build:
env:
NODE_VERSION: 12.x
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Add comment
if: github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'reopened')
uses: actions/github@v1.0.0
env:
GITHUB_TOKEN: $
with:
args: comment "Thank you for opening this pull request :tada::sparkles:"
- name: Cache dependencies
uses: actions/cache@v1
with:
path: ~/.npm
key: $-node-$
restore-keys: |
$-node-
- name: Use Node.js $
uses: actions/setup-node@v1
with:
node-version: $
- name: npm install, build, and test
run: |
npm ci
npm run build --if-present
npm test
env:
CI: true
- name: Run linter
run: |
npm install eslint --save-dev
./node_modules/.bin/eslint --no-eslintrc .
- uses: octokit/request-action@v1.x
id: create_deployment
with:
route: POST /repos/:owner/:repo/deployments
ref: $
required_contexts: "[]"
environment: "review"
env:
GITHUB_TOKEN: $
- uses: gr2m/get-json-paths-action@v1.x
id: parse_deployment
with:
json: $
id: "id"
- name: Deploy to Zeit
uses: amondnet/now-deployment@v1
id: zeit_deployment
with:
github-token: $
zeit-token: $
- uses: octokit/request-action@v1.x
with:
route: POST /repos/:owner/:repo/deployments/:deployment_id/statuses
deployment_id: $
environment: "review"
state: "success"
target_url: $
env:
GITHUB_TOKEN: $
- uses: octokit/request-action@v1.x
if: failure()
with:
route: POST /repos/:owner/:repo/deployments/:deployment_id/statuses
deployment_id: $
environment: "review"
state: "failure"
env:
GITHUB_TOKEN: $
publish-gpr:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12.x
registry-url: https://npm.pkg.github.com/
scope: '@<your handle>s'
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: $
publish-docker:
needs: [build]
runs-on: [ubuntu-latest]
steps:
- uses: actions/checkout@master
- run: |
docker build -t docker.pkg.github.com/<yourhandle>/octocat-zen/octocat-zen:$ .
docker login docker.pkg.github.com -u <your handle> -p $GITHUB_TOKEN
docker push docker.pkg.github.com/<your handle>/octocat-zen/octocat-zen:$
env:
GITHUB_TOKEN: $
Appendix 2: Popular actions
The number of community GitHub Actions is fast growing. Here are some actions for commonly used tools and services: