Skip to content

GitHub Actions

Tips and Tricks

Run a GitHub Action workflow step if a file exists

Link

yaml
- name: Is file created?
  if: ${{ hashFiles('test.txt') != '' }}
  run: echo "File exists"

Continue on error

See documentation

yaml
# Linting is not working and immediately fails
- name: Lint code
  run: pnpm lint

- name: Format code
  if: always()
  run: pnpm format

- name: Build code
  if: always()
  run: pnpm build

Warning: Avoid using always for any task that could suffer from a critical failure, for example: getting sources, otherwise the workflow may hang until it times out. If you want to run a job or step regardless of its success or failure, use the recommended alternative:

yaml
if: ${{ !cancelled() }}

SSH Issues

When performing Git operations, you might encounter the following

sh
Error: authentication required # ![code error]

Or after installing the SSH key, you might encounter

sh
Could not open a connection to your authentication agent. # ![code error]

Possible solution

Manually set up SSH key in the Workflow

yaml
- name: Set up SSH key
  run: |
    mkdir -p ~/.ssh
    echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    ssh-keyscan github.com >> ~/.ssh/known_hosts

Output to stdout (standard output)

In CI/CD workflows like GitHub Actions, everything printed to stdout (standard output) by a script will be captured and assigned to variables if you're using command substitution (e.g., ENV_VARIABLE=$(...)). This means loggins statements like this (in JavaScript);

js
console.log('Task created with keys');

Will be capture by the GitHub Actions as an entire output.

Solution

  1. using console.error() instead of console.log() (stderr)
  2. Filter the output
sh

## Cheatsheet

```sh
# Using secrets in a file
# act.secrets should be written as a simple key/value as in env files e.g.
# GITHUB_TOKEN=your_token
act --secret-file ../location-of-secret-file/act.secrets

Composite Actions

Example from GitHub Docs
yaml
name: 'Hello World'
description: 'Greet someone'
inputs:
  who-to-greet: # id of input
    description: 'Who to greet'
    required: true
    default: 'World'
outputs:
  random-number:
    description: 'Random number'
    value: ${{ steps.random-number-generator.outputs.random-number }}
runs:
  using: 'composite'
  steps:
    - name: Set Greeting
      run: echo "Hello $INPUT_WHO_TO_GREET."
      shell: bash
      env:
        INPUT_WHO_TO_GREET: ${{ inputs.who-to-greet }}

    - name: Random Number Generator
      id: random-number-generator
      run: echo "random-number=$(echo $RANDOM)" >> $GITHUB_OUTPUT
      shell: bash

    - name: Set GitHub Path
      run: echo "$GITHUB_ACTION_PATH" >> $GITHUB_PATH
      shell: bash
      env:
        GITHUB_ACTION_PATH: ${{ github.action_path }}

    - name: Run goodbye.sh
      run: goodbye.sh
      shell: bash
Reuse workflow and steps

How to reuse workflows and steps in GitHub Actions (2024)

For larger units of work, a reusable workflow should be used. A composite action should be used for smaller units of work that may run on the same runner and share the same work area.

GitHub repo

Using secrets in a composite action

"Reusable workflows has secrets but actions are limited to inputs" - StackOverflow

yaml
# Use action inputs to pass secrets
name: 'test'

description: 'test'

inputs:
  token:
    description: 'A Github PAT'
    required: true

runs:
  using: 'composite'
  steps:
    - name: Create Branch
      run: echo "git branch test"
      env:
        GITHUB_TOKEN: ${{ inputs.token }}
      shell: bash

Resources

Web Performance

Lighthouse

Lighthouse with WPT Network Emulation Profiles, Github Action Edition

Uses Puppeteer to start up Chrome with network emulation settings defined by WebPageTest. Supports saving of artifacts to the Github Action run. Supports custom Lighthouse configuration via JavaScript file. Supports Lighthouse budget.json for failing PRs. Supports Lighthouse-based data model scores.js for failing PRs based on any audit score or category. Posts results of audit run as a comment on your PR.

Basic usage

yaml
name: Audit Web Performance
on: [pull_request]
jobs:
  perf:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Generate Lighthouse Report
        uses: justinribeiro/lighthouse-action@master
        with:
          secret: ${{ secrets.GITHUB_TOKEN }}
          url: https://${{ github.sha }}-dot-${{ secrets.GAE_PID }}.appspot.com
          wptConnectionSpeed: threegfast
      - name: Saving Lighthouse Audit Artifacts
        uses: actions/upload-artifact@master
        with:
          name: lighthouse-artifacts
          path: './results'

act - Running GitHub Actions locally

GitHub Repo

Run a specific workflow

sh
act -W '.github/workflows/checks.yml'

Using secrets

sh
# Directly in command
act -s MY_SECRET=somevalue

#  Using secrets in a file
act --secret-file my.secrets

GitHub Token

  1. Manually create a personal access token and pass it to act
sh
act -s GITHUB_TOKEN=[insert token or leave blank and omit equals for secure input]
  1. Using GitHub CLI directly
sh
act -s GITHUB_TOKEN="$(gh auth token)"

Pass Inputs to Workflow

sh
act --input NAME=somevalue

# Using a file (same format as a .env)
act --input-file my.input

Github as a database

GitHub repo example

You should not use Git as a database


Common issues

Node.js

npm not found in GitHub action

Issue

sh
err: zsh:11: command not found: npm

Solution

The problem is that NVM installs node.js to a user's local directory, and updates that user's .profile.

Stack Overflow

sh
n=$(which node);n=${n%/bin/node}; chmod -R 755 $n/bin/*; sudo cp -r $n/{bin,lib,share} /usr/local

pnpm command not found

GitHub pnpm issue