How to run workshops in GitHub Actions

The launch-workshop action installs Workshop on a GitHub-hosted runner and launches an ephemeral workshop for the duration of a job. Use it to run your project’s tests, builds, or other tasks inside the same workshop you use locally, without standing up a self-hosted runner.

If you’d rather run jobs on your own hardware, use a workshop as a self-hosted runner instead; see How to run GitHub Actions locally.

Prerequisites

Before getting started, ensure you have:

  • A GitHub repository with Actions enabled

  • A workshop definition committed to the repository, at workshop.yaml or .workshop/<NAME>.yaml

Add the action to a workflow

The smallest useful workflow checks out the repository, launches the default workshop, and runs a command inside it:

.github/workflows/test.yaml
on:
  pull_request:
  push:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: canonical/launch-workshop@v1

      - run: workshop exec -- pytest

If the repository contains a single workshop.yaml at the project root, the action launches it automatically. For repositories with several workshops under .workshop/, set the workshop input to the one you need.

For production use, pin the action to a specific commit SHA. The @v1 shorthand shown above tracks the latest v1.* release and can be moved between versions; @main is even less stable.

Test across multiple workshops

To test a project against several workshops in parallel, parameterize the workshop input with a matrix:

.github/workflows/matrix.yaml
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        workshop: [dev-jammy, dev-noble]
    steps:
      - uses: actions/checkout@v6

      - uses: canonical/launch-workshop@v1
        with:
          workshop: ${{ matrix.workshop }}

      - run: workshop run "$WS" unit-tests
        env:
          WS: ${{ matrix.workshop }}

This pattern fits well for testing the same project against different Ubuntu releases, different SDK channels, or any other axis you encode in the workshop name.

Cache SDK data across runs

Some SDKs expose mount plugs that can be persisted between workflow runs, such as a package cache or a build cache. List the available plugs in your local workshop with workshop connections:

$ workshop connections --all

  INTERFACE  PLUG      SLOT          NOTES
  mount      uv:cache  system:mount  -

Pass the matching <SDK>:<PLUG> lines to the cache input, one per line:

.github/workflows/test.yaml
steps:
  - uses: canonical/launch-workshop@v1
    with:
      cache: |
        go:mod-cache
        rust:cargo-registry
        uv:cache

Each listed plug is mounted from a GitHub-managed cache, keyed by the SDK and plug name. Not every SDK defines cacheable plugs; check the SDK’s documentation when in doubt.

Inputs

The action exposes the following inputs:

Input

Description

channel

Channel used to install the Workshop snap. Optional; defaults to latest/stable.

revision

Specific revision of the Workshop snap to install. Optional.

project

Directory containing a workshop to launch. Defaults to the repository root.

workshop

Name of the workshop to launch. Required if the project defines several workshops.

cache

Mount plugs to cache across runs, one <SDK>:<PLUG> entry per line.

Security considerations

When integrating the action into your workflows:

  • Pin the action to a commit SHA so a compromised tag cannot push unreviewed code into your workflows.

See also

How-to guides: