1 of 28

2 of 28

Automate Maintainer Tasks with GitHub Actions

Severin Neumann (OpenTelemetry)

3 of 28

Being a maintainer is fun …

“Maintenance involves functional checks, servicing, repairing, or replacing necessary devices, equipment, machinery, building infrastructure, and supporting utilities"

​

Wikipedia: Maintenance

​

4 of 28

… until you do the same thing

Image by Jackie (CC BY 2.0)

… and again,

and again,

and again

​

​

and again

and again

and again

and again

and

again

​

​

​

and

again…

again …

5 of 28

Image by xkcd.com (CC BY-NC 2.5)

We all know the answer:

Automation!

6 of 28

Automation Without Hurting Yourself

1.

Reuse what is out there

2.

script first, workflow later

3.

Learn the basics

(and then use a LLM…)

4.

Common Pitfalls

x

too much

7 of 28

Reuse what is out there

Before you write any automation on your own, make sure you use what others have created before you:

​

8 of 28

CODEOWNERS

The easiest way to get PRs assigned to the right person or team*:

​

  1. Add a .github/CODEOWNERS file to your repository
  2. Add entries for files and owners:

​

​

​

​

​

  • Require that pull requests have to be approved by code owners

​

​

​

* Limitation: Groups and users need write permissions on the repo!

* @your-project/project-owners

**/docs @your-project/project-docs-owners

*.cpp @username

9 of 28

Dependabot

Another automation you can enable without writing any scripts or workflows!

​

  1. In your repository’s “Code security” settings you can enable Dependabot
  2. Add a “.github/dependabot.yml” file to your repository for detailed configuration

version: 2

updates:

- package-ecosystem: github-actions

directory: /

schedule:

interval: weekly

10 of 28

GitHub’s GitHub Actions

Common actions to add to your repo:

​

  • Labeler: Automatically label new pull requests
  • Stale: Warns/closes issues/PRs without activity
  • Add-to-Project: add issue/PRs to a GitHub project

name: 'Label PR'

on:

pull_request_target:

types: [opened,reopened]

​

jobs:

labeler:

name: 'Add component labels'

permissions: [...]

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: actions/labeler@v5

with:

configuration-path: '.github/component-label-map.yml'

11 of 28

Docker’s GitHub Actions

All you need to build containers!

​

  • Login
  • Setup (qemu, buildx)
  • Metadata
  • Build and Push

steps:

- name: Docker meta

uses: docker/metadata-action@<hash>

tags: “type=semver,pattern={{ version }}”

- name: Log into GitHub Container Registry

uses: docker/login-action@<hash>

with:

registry: ghcr.io

- name: Set up QEMU

uses: docker/setup-qemu-action@<...>

- name: Set up Docker Buildx

uses: docker/setup-buildx-action@<...>

- name: Build and push images

uses: docker/build-push-action@<...>

with: …

12 of 28

OpenSSF Scorecard’s GitHub Actions

Checks for issues with software security for each commit! Easy setup:

​

github.com/org/repo/actions/new?category=security&query=scorecard

​

After running the workflow go to

​

securityscorecards.dev/viewer/?uri=github.com%2Forg%2Frepo

13 of 28

OpenSSF Scorecard’s GitHub Actions

14 of 28

… and more

GitHub has a marketplace for Actions (and Apps), so always check if there is something reusable.

​

But as with any other dependency, pay attention:

​

(March, 2024) Multiple tags in this action are compromised

​

  • Verify your actions
  • Pin to commit SHA + Dependabot/Renovate
  • Limit permissions & token usage
  • …

15 of 28

script first, workflow later

Image by chriscom (CC BY-SA 2.0)

16 of 28

script first, workflow later

If there is no “ready to use” workflow by a third party, go half the way from manual to semi-automatic:

​

  1. Create a script for the task and store it in your repo
  2. When needed, run the script manually
  3. Test it for a few runs, make sure it works well
  4. Add the GitHub workflow

17 of 28

Learn the basics

If you have a script that you want to run based on a trigger wrapping it into a GitHub action is (relatively) easy

name: Run my script

​

# what triggers the workflow?

on:

# the following allows you to manually trigger the workflow

workflow_dispatch:

schedule:

# hourly at minute 10

- cron: 10 * * * *

​

# a list of (parallel) jobs that this workflow will execute

jobs:

my-script:

name: run-my-script

# the name of the runner used, “ubuntu-*” is a good starting point

runs-on: ubuntu-24.04

# The sequential steps the script will take

steps:

# Checkout the repo

- uses: actions/checkout@<hash> # v4.2.x

# Run the script

- run: ./scripts/my-script.sh

18 of 28

… and then use an LLM

Writing and testing GitHub actions can be painful, but gladly most LLMs do a decent job in creating you something you can start from, e.g.

“I need a github action that writes a thank you note below a merged PR and shares a link to a survey with the contributor. Make sure that you follow security best practices for github actions, and the the gh tool is used where applicable”

name: Thank Contributor

​

on:

pull_request_target:

types:

- closed

​

permissions:

pull-requests: write # Required to comment on PRs

contents: read # Minimal required permission

​

jobs:

thank_contributor:

if: github.event.pull_request.merged == true

runs-on: ubuntu-latest

steps:

- name: Comment on PR

env:

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

SURVEY_URL: "https://example.com/contributor-survey"

run: |

gh pr comment ${{ github.event.pull_request.number }} \

--body "🎉 Thank you for your contribution! We appreciate your effort. 🙌

We'd love to hear your feedback—please take a moment to fill out our survey: [$SURVEY_URL]($SURVEY_URL)"

19 of 28

common pitfalls

20 of 28

common pitfalls

21 of 28

common pitfalls

Things that can go wrong:

​

  1. your script runs on your local machine but not on the GH runner
  2. permission and token issues
  3. …

22 of 28

Runs locally but not on the GH runner

Common problems:

​

  • Software versions and variants
  • Path is not resolved correctly
  • Environment variables are not resolved as expected

How to fix them:

​

  • Review and compare local and runner’s versions/variants, e.g. ubuntu-24.04
  • On MacOS: “date”, “sed” and others are not GNU!
  • Try out nektos/act

23 of 28

Runs locally but not on the GH runner

24 of 28

Runs locally but not on the GH runner

25 of 28

Permission & token issues

This type of issue is the hardest to solve, because often it can

not be reproduced

  • locally
  • and in your fork!

​

What you can do:

  • read the docs
  • set your permissions for GITHUB_TOKEN
  • make sure you use the right type of token

26 of 28

Set your permissions for GITHUB_TOKEN

name: Thank Contributor

​

on:

pull_request_target:

types:

- closed

​

permissions:

issues: read

​

jobs:

thank_contributor:

permissions:

contents: write

pull-requests: write

You can set global permissions, and local permissions per job.

27 of 28

Token Types for actions

  • Use GITHUB_TOKEN whenever possible for internal operations—it’s secure and short-lived
  • Cross-repo actions or bot-actions require a personal access token (PAT)
  • Trigger a workflow from a workflow run does not work with GITHUB_TOKEN, use a PAT
  • Use actions/create-github-app-token for creating a GitHub App installation access token (e.g. bots)

28 of 28

Thank you