Skip to main content

Github Actions

MNE-CPP uses GitHub Actions for all continuous integration (CI) work. GitHub Actions operates on repository events — pushes, pull requests, releases, and timers — which trigger workflows defined as YAML files in .github/workflows/. Each workflow contains one or more jobs, and each job runs a series of steps on a fresh virtual machine (runner). You can read more about the terminology in the GitHub Actions documentation.

Workflow Overview​

MNE-CPP's CI is organized around the Main – Staging – Feature branch model. The following table summarizes every CI workflow:

Event typeWorkflow NameWorkflow ScriptEffect
Pull Requests → staging or mainPullRequestpull-request.ymlBuild and tests on all platforms (maximum Qt), plus minimum Qt on Linux (on all platforms for PRs into main), and the WebAssembly build. PR cannot be merged until all jobs pass.
Pushes to staging, nightlyStagingstaging.ymlOn push: tests with code coverage threshold/regression checks on all platforms with minimum and maximum Qt, quality and documentation gates, and the WebAssembly build. On pushes that touch the build or packaging, nightly and on manual dispatch: also dev release binaries and dev website + Doxygen deployment.
Pushes to mainMainmain.ymlBuilds, tests, stable website + Doxygen deployment.
Tag v* on mainMain (release jobs)main.ymlFull stable release: platform binaries (Linux, macOS, Windows), installers, WebAssembly, Codecov upload.
Pushes to the wasm branchWasmTestwasmtest.ymlCreates new versions of the WebAssembly capable MNE-CPP applications and makes them accessible via the repository's gh-pages branch.
Timer runs outCoveritycoverity.ymlTriggers every two days to run Coverity static code analysis tools.
Pushes to the generateqt branchBuildQtBinariesbuildqtbinaries.ymlTriggers builds of all needed Qt versions and makes them accessible as artifacts via the Github Actions interface.

Reusable Workflows​

Common build and test logic is extracted into reusable workflows to avoid duplication:

WorkflowScriptPurpose
Reusable Build_reusable-build.ymlCross-platform build parameterized by Qt version
Reusable Tests_reusable-tests.ymlTest execution with configurable code coverage (Codecov upload, threshold check, or plain)

These are called by the main pipeline workflows using workflow_call.

How the Pull Request Workflow Works​

When a contributor opens or updates a pull request targeting staging (or main), pull-request.yml runs:

  1. The static quality gates.
  2. Builds and tests with the maximum supported Qt version on Linux, macOS, and Windows, and with the minimum supported Qt version on Linux, via the reusable test workflow (without coverage uploads).
  3. Builds the documentation to verify it compiles without errors.
  4. Builds WebAssembly (without deploying it).

The PR cannot be merged until all matrix jobs pass. This ensures that every change is validated on Linux, macOS, and Windows before it reaches the staging branch.

How the Staging Workflow Works​

staging.yml is the active development pipeline. Every push to staging runs:

  • The static quality gates
  • Tests with code coverage on all platforms — enforcing a minimum threshold (50%) and detecting coverage regressions — plus tests against the minimum Qt version on all platforms
  • The documentation gate (API docs, screenshots, website build)
  • The WebAssembly build (the dev deployment waits for the release run)

GitHub-hosted runners are shared by every repository in the mne-tools organization, so the release part of the pipeline runs only where it can be affected: nightly when staging has changed since the last nightly, on manual dispatch (Actions → Staging → Run workflow), and after a push that changed the build or packaging since the last dev build (a CMakeLists.txt or cmake/ outside the tests, scripts/build/, scripts/ci/, scripts/deploy/, or the staging and release workflows). Such a push starts the release as a separate run, which later pushes do not cancel. Once every test configuration compiles (failing tests do not block it), it:

  • Creates or updates the dev_build pre-release on GitHub with the latest development binaries
  • Invokes the platform-specific release workflows (release-linux.yml, release-macos.yml, release-windows.yml, release-installer.yml) to produce development binaries tagged as dev_build
  • Deploys the dev version of the documentation website to /dev/ and Doxygen API docs to /dev/

A failing nightly opens a "Nightly staging build failed" issue, which closes automatically when a later nightly passes. CodeQL security analysis, on a full build, runs weekly, on main and on manual dispatch (codeql.yml).

How the Main / Release Workflow Works​

main.yml handles two scenarios:

Pushes to main (no tag)​

On every push to main, the workflow:

  • Builds with minimum and maximum Qt versions
  • Runs tests (with Codecov upload)
  • Deploys the stable website and Doxygen API documentation (preserving the dev subdirectory)

Tagged releases (v*)​

When a version tag is pushed (e.g., v2.0.0), the workflow additionally:

  • Creates a GitHub Release from the tag
  • Invokes platform-specific release workflows to build and upload binaries for Linux, macOS, and Windows
  • Builds and uploads platform installers (.run, .dmg, .exe)
  • Builds and deploys WebAssembly applications
  • Uploads the Doxygen .qch file as a release asset

Each platform job follows the same high-level pattern: install Qt, configure CMake, build, deploy (bundle Qt libraries), package into an archive, and upload to the GitHub release.

Workflow File Structure​

All workflow YAML files live in .github/workflows/ and follow a common structure:

name: WorkflowName

on:
push:
branches: [staging]
pull_request:
branches: [staging, main]

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-24.04, macos-26, windows-2025]
steps:
- uses: actions/checkout@v4
- name: Install Qt
# ...
- name: Configure
run: cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
- name: Build
run: cmake --build build --parallel
- name: Test
run: cd build && ctest --output-on-failure

Key elements include the trigger (on:), the matrix strategy for cross-platform builds, and the steps that install dependencies, compile, test, and optionally deploy.

Secrets and Environment Variables​

Some workflows require GitHub repository secrets (configured in Settings → Secrets and variables → Actions):

SecretUsed byPurpose
GITHUB_TOKENAll release workflowsAutomatically provided; used to upload release assets
GH_PATRelease workflowsPersonal access token for cross-repo operations (optional fallback)
GIT_CREDENTIALSWebsite + Doxygen deployAuthentication for pushing to gh-pages branches
CODECOV_TOKENMain workflowToken for uploading coverage to Codecov
COVERITY_TOKENcoverity.ymlAuthentication token for Coverity Scan

Adding or Modifying a Workflow​

To add a new workflow:

  1. Create a new .yml file in .github/workflows/.
  2. Define the trigger event (on:) — push, pull_request, schedule, or workflow_dispatch.
  3. Define one or more jobs with the appropriate runner (runs-on:) and steps.
  4. Test the workflow by pushing to a feature branch and opening a PR against staging.

To modify an existing workflow, edit the corresponding .yml file and push the change. If the modification affects the PR workflow, open a PR to see the results immediately.