Prepearing for GitHub certification - Build continuous integration (CI) workflows by using GitHub Actions
Table of Contents
- Prepearing for GitHub certification - Build continuous integration (CI) workflows by using GitHub Actions
How do I use GitHub Actions to create workflows for CI?
Create a workflow from a template
- Create your workflow
- Use templates or build it yourself
- Sample of Node.js template workflow:
{% highlight yml %} name: Node.js CI
on: push: branches: [ master ] pull_request: branches: [ master ]
jobs: build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test {% endhighlight %}
Action Logs for the build
- Workflow run produces a log that includes the details of what happened and any errors or test failures.
Customize workflow templates
- Might want to target a different version of eg. Node and different operating systems
- Separate build and test steps into different jobs
strategy:
matrix:
os: [ubuntu-lastest, windows-2016]
node-version: [8.x, 10.x]- Sample of build matrix
- enables testing across multiple OS and language versions
- will produce 4 builds for each OS paired with each version of Node
- Good practice to move tests to separate job
- This sample job tests against multiple targets
{% highlight yml %} test: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-lastest, windows-2016] node-version: [8.x, 10.x] steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }}
-
name: npm install, and test run: | npm install npm test env: CI: true {% endhighlight %}
- Separating build and test will help easier to understand the workflow log
What are artifacts?
- Artifact - produced by a workflow that is not a log entry
- For example, the Node.js build will produce a Docker container that can be deployed
- The artifact can be uploaded to storage using the action actions/upload-artifact
- The artifact can be downloaded from storage using the action actions/download-artifact
- Storing an artifact helps to preserve it between jobs
Artifact storage
- Artifacts are stored in storage space on GitHub
- It’s free for public repositories
- Limited storage for private repositories
- Artifact is stored for 90 days
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: npm install and build webpack
run: |
npm install
npm run build
- uses: actions/upload-artifact@master
with:
name: webpack artifacts
path: public/- Notice the
path:attribute in theactions/upload-artifact@masteraction- This is the path to store the artifact
- Everything is uploaded to directory public/ or you can upload a single file public/mytext.txt
- To download the artifact
- Build mas have completed successfully
- Artifact is uploaded
test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/download-artifact@master
with:
name: webpack artifacts
path: public- Read more about Persisting workflow data using artifacts
Automate reviews in GitHub using workflows
- Possible to run a workflow after a reviewer has approved the pull request
- trigger needed:
pull-request-review - Optional is to add a label to a pull request
- needs pullreminders/label-when-approved-action action
{% highlight yml %} steps: - name: Label when approved uses: pullreminders/label-when-approved-action@master env: APPROVALS: “1” GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ADD_LABEL: “approved” {% endhighlight %}
- Note the block
env:- This sets the environment variables for the action
- Eg. can set number of approvers needed
- the
GITHUB_TOKENvariable is needed because action must make changes to your repository
Customize your workflow with environment variables and artifact data
- Use default environment variables
- Use custom environment variables
- Use custom scripts
- Cache dependencies
- Pass artifacts data between jobs
Default environment variables and contexts
- There are default environment variables to use
- Only within a runner that is executing a job
- Are case-sensitive
- Reference to configuration values for the system and the current user
- Recommended to use reference to filesystem rather than using hard-coded file paths
- Specify
$followed by the environment variable’s name
jobs:
prod-check:
steps:
- run: echo "Deploying to production server on branch $GITHUB_REF"- Also can use defined variables as contexts
- Context variables can be used at any point within the workflow
- Eg. enable to run an
ifstatement to evaluate an expression before the runner is executed
name: CI
on: push
jobs:
prod-check:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to production server on branch $GITHUB_REF"- This example is using
github.ref - Note: the default environment variables are all uppercase where context variables are all lowercase
Custom environment variables
- Can create custom variable
- Need to define it in the workflow file using the
envcontext- if you want to use it inside a runner
name: CI
on: push
jobs:
prod-check:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: echo "Nice work, $First_Name. Deploying to production server on branch $GITHUB_REF"
env:
First_Name: MonaScripts in your workflow
- Can use the
runkeyword to run actions or scripts.
jobs:
example-job:
steps:
- run: npm install -g bats- Can also run a script as an action
- Store script in your repository
.github/scriptsdirectory
jobs:
example-job:
steps:
- name: Run build script
run: ./.github/scripts/build.sh
shell: bashCache dependencies with the cache action
- The need to reuse the same outputs or download dependencies from one run to another
- Can make the workflow run faster and more efficient
- To cache use GitHub’s
cacheaction- This retrieves a cache identified by a unique key that you provided
| Parameter | Description | Required |
|---|---|---|
| Key | Refers to the key identifier created when saving and searching for a cache. | yes |
| Path | Refers to the file path on the runner to cache or search. | yes |
| Restore-keys | consists of alternative existing keys to caches if the desired cache key is not found. | no |
{% highlight yml %} steps:
-
uses: actions/checkout@v2
-
name: Cache NPM dependencies uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-npm-cache-${{ hashFiles(‘**/package-lock.json’) }} restore-keys: | ${{ runner.os }}-npm-cache- {% endhighlight %}
- Above sample sets the
pathto~/.npmand thekeyincludes the runner’s OS and the SHA-256 hash of thepackage-lock.jsonfile - Prefixing the key with ID is useful when using
restore-keysfallback and have multiple caches
Pass artifact data between jobs
- Possible to pass data between jobs within the same workflow
- Use
upload-artifactanddownload-artifactactions - Jobs that are depended on a previous jobs artifact must wait for the dependent job to complete successfully
name: Share data between jobs
on: push
jobs:
job_1:
name: Upload File
runs-on: ubuntu-latest
steps:
- run: echo "Hello World" > file.txt
- uses: actions/upload-artifact@v2
with:
name: file
path: file.txt
job_2:
name: Download File
runs-on: ubuntu-latest
needs: job_1
steps:
- uses: actions/download-artifact@v2
with:
name: file
- run: cat file.txtEnable step debug logging in a workflow
- Can enable additional debug logging for two options
- run
- steps
- Enabling this is done by setting some repository secrets that require
adminaccess to the repository totrue. - Two options
- To enable runner diagnostic logging, set the
ACTIONS_RUNNER_DEBUGsecret in the repository that contains the workflow totrue. - To enable step diagnostic logging, set the
ACTIONS_STEP_DEBUGsecret in the repository that contains the workflow totrue.
- To enable runner diagnostic logging, set the
Access the workflow logs from the REST API
- For public repository keep in mind that anyone with read access to the repository can use this endpoint
- If the repository is private you must use an access token with the
reposcope.
GET /repos/{owner}/{repo}/actions/runs/{run_id}/logs