Github Actions

Get status of private action with bash

Before running this command, you will need to create a Personal Access Token and set the env var PAT to its value.

curl -u "$(git config user.name):${PAT}" \
  -s "https://api.github.com/repos/username/somerepo/actions/workflows/someaction.yml/runs" | \
  jq -r '.workflow_runs[0].status'time

Resource: https://stackoverflow.com/questions/65953108/how-can-i-get-the-passing-failing-status-of-a-github-action-workflow

Get latest commit hash with github actions

# Set it:
- name: Add SHORT_SHA env property with commit short sha
  run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV

# Use it:
- name: My step
  run: myscript ${SHORT_SHA}

Resource: https://stackoverflow.com/questions/59810838/how-to-get-the-short-sha-for-the-github-workflow

Test github actions locally

If you need to specifically test macOS functionality:

act -P macos-latest=-self-hosted

Debug github actions

This will allow you to manually trigger a debug run:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # Enable tmate debugging of manually-triggered workflows if the input option was provided
      - name: Setup tmate session
        uses: mxschmitt/action-tmate@v3
        # Only allow access using your registered public keys
        # in github
        with:
          limit-access-to-actor: true
        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}

Debug only if the previous step failed

name: CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup tmate session
        if: ${{ failure() }}
        # Only allow access using your registered public keys
        # in github
        with:
          limit-access-to-actor: true
        uses: mxschmitt/action-tmate@v3

Resources:

Delete old workflow runs

The following action can be used to delete all of the old github action workflow runs in your project:

---
name: Delete old workflow runs
on:
  workflow_dispatch:
  pull_request:
    branches: ["main"]

jobs:
  del_runs:
    runs-on: ubuntu-latest
    permissions:
      actions: write
    steps:
      - name: Delete workflow runs
        uses: Mattraks/delete-workflow-runs@v2
        with:
          token: ${{ github.token }}
          repository: ${{ github.repository }}
          retain_days: 30
          keep_minimum_runs: 6

This particular example will remove runs older than 30 days and will only keep the last 6 runs.

Resource: https://github.com/marketplace/actions/delete-workflow-runs

Test action locally

act -W ./.github/workflows/youraction.yaml

Composite action

This allows you to turn a workflow into an ingestible action. Example repo: https://github.com/fbsamples/caldera-security-tests

Resources:

Close stale issues

name: "Close stale issues"
on:
  schedule:
    - cron: "0 0 * * *"
jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@v3.0.14
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          stale-issue-message: "This issue has been marked as stale because it has been open for 90 days with no activity. This thread will be automatically closed in 30 days if no further activity occurs."
          exempt-issue-labels: "keep open,v4.x,in progress"
          days-before-stale: 90
          days-before-close: 30
          operations-per-run: 100

Resources: https://github.com/helm/helm/blob/main/.github/workflows/stale-issue-bot.yaml


Azure Pipelines

This is a great alternative to Travis CI or Circle CI. I was using it quite a bit for a number of projects before switching over to github actions.

Test a github project without committing

If you want to debug a pipeline without committing code to your github repo, you can do the following:

  1. Login to Azure Devops
  2. Click + New project
  3. Give the project a name, specify Private for the Visibility, and click Create

Once the project has been created, you’ll need to import the repo code:

  1. Click on Repos in the left-hand menu
  2. Click Import
  3. Specify the URL for your project and click Import

You should now be able to modify the azure-pipelines.yml file local to the project you’ve created. However, you will need to set up the Pipeline in order to start seeing test results:

  1. Click Pipelines in the left-hand menu
  2. Click Create Pipeline
  3. Select Azure Repos Git
  4. Click the Project you created previously
  5. Modify the yaml if you’d like, otherwise click Run

Delete a Project

  1. Login to Azure Devops
  2. Click on the Project you want to delete
  3. Click the gear icon in the bottom left-hand menu
  4. Click Delete
  5. Type in the name of the project and click Delete

Create a trigger that runs a specific pipeline

This can be used to have a pipeline for a specific area of your project. The idea is you have multiple pipelines to test certain things, so that you don’t end up with a massive monolith:

trigger:
  branches:
    include:
      - master
  paths:
    include:
      - path/to/specific/area/of/project/*
      - Tests/project*
      - azure-pipelines-project.yml

Specify Behavior for Pull Requests

This will dictate what to do whenever you do a pull request. In this case it will run a pipeline to test a specific area of a project:

pr:
  branches:
    include:
      - master
  paths:
    include:
      - path/to/specific/area/of/project/*
      - Tests/project*
      - azure-pipelines-project.yml

Run Pipeline on a schedule

schedules:
  - cron: "0 0 * * 0"
    displayName: Weekly midnight (UTC) build
    branches:
      include:
        - master
    always: true

Pre-commit

Create custom hook

  1. Create directory to store them in the root of your repo:

    mkdir .hooks
    
  2. Create a bash script with your logic in .hooks. For example: go-no-replacement.sh:

    #!/bin/bash
    
    REPO=$(cat .git/config | grep url | awk -F 'https://' '{print $2}' \
        | rev | cut -c5- | rev)
    
    if grep "replace ${REPO}" $@ 2>&1 >/dev/null ; then
        echo "ERROR: Don't commit a replacement in go.mod!"
        exit 1
    fi
    
  3. Call it in your .pre-commit-config.yaml:

    - repo: local
      hooks:
        - id: go-no-replacement
          name: Avoid committing a go module replacement
          entry: .hooks/go-no-replacement.sh
          language: script
          files: go.mod
    

Resources:

Check write access to repo with PAT

This is expected to fail since GITHUB_TOKEN has read only access:

- name: Check write access to repo
  run: |
    token_login=$(curl -H "Authorization: Bearer ${token}" https://api.github.com/user | jq -r '.login')
    echo token login is ${token_login}
    echo $(curl  -H "Authorization: Bearer ${token}" https://api.github.com/repos/${repo}/collaborators/${token_login}/permission) > result
    cat result | jq  '.permission == "admin" // .permission == "write"' > /dev/null || ( echo "Token does not have write access to ${repo}" >> ${GITHUB_STEP_SUMMARY}; exit 1)
    curl -sS -f -I -H "Authorization: Bearer ${token}" https://api.github.com | \
      grep 'x-oauth-scopes:' | grep 'repo' > /dev/null && exit 0 || echo "Token does not have repo scope on ${repo}" >> ${GITHUB_STEP_SUMMARY}    
  env:
    repo: ${{ github.repository }}
    token: ${{ secrets.GITHUB_TOKEN }}

Resource: https://github.com/peter-evans/create-pull-request/issues/1300

Test github action locally

This particular example will run the molecule job associated with the workflow at .github/workflows/molecule.yaml. We also specify --container-architecture if we are running on an ARM-based system.

act -j molecule -W .github/workflows/molecule.yaml --container-architecture linux/amd64