Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/_lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Python lint: run `make lint` (ruff via uv) over the sim/test harness. uv reads
# pyproject.toml + uv.lock to provision ruff; make stays the runner so the same
# `make lint` works locally. The Makefile's `include CONFIG` means every target
# needs a CONFIG, so stage it from CONFIG.example like the other jobs.
on:
workflow_call:

jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Install uv
uses: astral-sh/setup-uv@v7

- name: Create CONFIG
run: cp CONFIG.example CONFIG

- name: Lint Python harness
run: make lint
9 changes: 4 additions & 5 deletions .github/workflows/tests.yml → .github/workflows/_test.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
name: Tests CI

# Run the simulation-server regression tests (tests/Makefile) against a freshly
# built sim_server, inside the pandablocks-dev-container. make is the runner.
on:
push:
pull_request:
workflow_call:

jobs:
test:
Expand All @@ -14,7 +13,7 @@ jobs:

steps:
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v5
with:
path: PandABlocks-server

Expand Down
92 changes: 49 additions & 43 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,67 +1,73 @@
name: Docs CI
name: CI

# Build + verify the docs on every event, then publish on INTERNAL events. The
# build (the shared `docs.yml`) runs for PRs (including forks), pushes to main, and
# tags, and uploads each build's `docs` artifact. Publishing is nested here (the
# `publish` job -> the shared `publish.yml`) so its status is visible on the
# PR/commit, but ONLY for internal events on this repo: a fork PR's build runs with a
# read-only token and must never deploy.
# Single entry point for this repo's GitHub Actions CI. The code/test half is local
# reusable `_*.yml` workflows; the docs half consumes the shared version-switcher
# reusable workflows (DiamondLightSource/myst-version-switcher-plugin) pinned at a tag:
#
# Both halves are consumed from DiamondLightSource/myst-version-switcher-plugin at a
# pinned tag — this repo carries no docs-build/publish workflow of its own.
# publish.yml reconstructs the whole versioned site from durable sources (main's
# latest build persisted at _sources/main.zip, each release's docs.zip asset, every
# open PR's build artifact) and deploys it to Pages directly; there is no gh-pages
# branch.
# lint -> _lint.yml Python lint (ruff via uv; `make lint`)
# test -> _test.yml native sim_server build + regression tests
# docs -> docs.yml@<tag> versioned MyST docs build (build-command input)
# release -> release.yml@<tag> GitHub Release on a tag (attaches docs.zip)
# publish -> publish-dispatch.yml deploy the assembled docs site (the shim that
# pins publish.yml@<tag>; it branches internally)
#
# make is the runner throughout (test/docs); CI only orchestrates. CI is a native
# build only: the `test` job compiles sim_server (the one natively buildable target)
# and runs the regression tests. The cross-compiled server/driver and zpkg/boot
# packaging come from meta-panda, so nothing here needs PandABlocks-rootfs.
#
# Docs detail: the build (docs.yml) runs for every event including fork PRs and uploads
# each build's `docs` artifact, but NEVER publishes. Publishing is nested here (the
# `publish` job → publish-dispatch.yml shim → publish.yml) so its status shows on the
# PR/commit. ONE publish job covers every event in the canonical repo; publish.yml
# branches internally: deploy (internal PR / main push), tag re-dispatch (a same-SHA
# tag deploy is dropped by Pages unless dispatched), or fork-PR warn (forks build with
# a read-only token and never deploy). So there is no fork guard here.
on:
pull_request:
push:
branches: [main]
tags: ['*'] # '*' never matches '/'

jobs:
# --- Python -----------------------------------------------------------------
lint:
uses: ./.github/workflows/_lint.yml

# --- Native build + regression tests ---------------------------------------
test:
uses: ./.github/workflows/_test.yml

# --- Docs build (every event; never publishes) ------------------------------
docs:
uses: DiamondLightSource/myst-version-switcher-plugin/.github/workflows/docs.yml@v0.7.0
uses: DiamondLightSource/myst-version-switcher-plugin/.github/workflows/docs.yml@v0.18.0
with:
# `make docs` drives npx mystmd (pinned by MYSTMD_VERSION) and reads build
# settings from CONFIG, so create it first. eval runs the compound command.
# `make docs` reads build settings (incl. MYSTMD_VERSION) from CONFIG; docs.yml
# sets BASE_URL and packs/uploads the docs.zip artifact.
build-command: cp CONFIG.example CONFIG && make docs
# The fork-PR warning links here so a maintainer can publish a fork preview.
preview-workflow: preview-fork.yml

# Tag-only: attach this build's docs.zip (bare html/ root) to the GitHub Release
# so `assemble` can reconstruct that released version on future deploys.
docs-release:
needs: [docs]
# Tag-only: create the GitHub Release and attach this run's artifacts (the `docs`
# artifact = docs.zip) so `assemble` can reconstruct that released version later.
release:
needs: [lint, test, docs]
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
uses: DiamondLightSource/myst-version-switcher-plugin/.github/workflows/release.yml@v0.18.0
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
name: docs
- env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "${{ github.ref_name }}" docs.zip --clobber --repo "${{ github.repository }}"
contents: write # create the GitHub Release + attach assets

# Internal events only: an internal PR, or a push to main/tag, has a same-repo
# build we can trust + deploy. Fork PRs (head repo != this repo) are excluded —
# docs.yml's build job warns them instead. publish.yml defaults guard-default-branch
# to true, so every deploy asserts main is present and can never silently drop
# /main/ (main is self-durable via _sources/main.zip).
# One publish job for every event in the canonical repo — publish.yml (reached via
# the publish-dispatch.yml shim) owns the branching (deploy / tag re-dispatch /
# fork-PR warn), so there's no fork or ref guard here. `actions: write` lets the
# re-dispatch job re-fire the shim; `version-name` injects this run's build inline.
publish:
needs: [docs]
if: >-
github.repository == 'PandABlocks/PandABlocks-server' &&
( github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.full_name == github.repository )
uses: DiamondLightSource/myst-version-switcher-plugin/.github/workflows/publish.yml@v0.7.0
needs: [lint, test, docs]
if: github.repository == 'PandABlocks/PandABlocks-server'
uses: ./.github/workflows/publish-dispatch.yml
with:
version-name: ${{ needs.docs.outputs.version-name }}
permissions:
contents: read
actions: read
actions: write
pages: write
id-token: write
statuses: write
80 changes: 0 additions & 80 deletions .github/workflows/code.yml

This file was deleted.

31 changes: 0 additions & 31 deletions .github/workflows/preview-fork.yml

This file was deleted.

39 changes: 39 additions & 0 deletions .github/workflows/publish-dispatch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Publish (dispatch)

# Thin shim — the one dispatchable file in this repo. It forwards to the shared
# version-switcher engine (publish.yml), exposing it two ways:
# workflow_call — ci.yml's `publish` job, for every event (publish.yml branches
# into deploy / tag re-dispatch / fork warn).
# workflow_dispatch — the tag re-dispatch, the fork-PR preview (`pr`), and manual
# re-deploys.
# A reusable workflow can't be workflow_dispatch'd cross-repo, so this shim must live
# here; publish.yml's re-dispatch job re-fires it by name (`dispatch-workflow`). This
# is the single place this repo pins publish.yml@<tag>.
on:
workflow_call:
inputs:
version-name:
description: Version name of the in-run build to inject (passed by ci.yml's inline publish).
required: false
default: ""
type: string
workflow_dispatch:
inputs:
pr:
description: External fork PR number to approve (pins its head SHA) and preview. Leave empty to just re-deploy.
required: false
default: ""

jobs:
publish:
uses: DiamondLightSource/myst-version-switcher-plugin/.github/workflows/publish.yml@v0.18.0
with:
version-name: ${{ inputs.version-name }} # "" on dispatch → pure durable gather
pr: ${{ inputs.pr }} # set (dispatch only) → pin that fork head SHA
dispatch-workflow: publish-dispatch.yml # the file the tag re-dispatch re-fires
permissions:
contents: read
actions: write # publish.yml's re-dispatch job re-fires this shim via gh
pages: write
id-token: write
statuses: write
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@
tests/fpga_sequences
/venv

# uv-managed virtual environment + tool caches
/.venv
.ruff_cache/

# MyST build output
docs/_build/
4 changes: 2 additions & 2 deletions CONFIG.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Copy this file to a file named CONFIG and edit as appropriate.

# Note that this file is used as part of github Continuous Integration (see
# .github/workflows/{code,docs}.yml and so the entries in this file must refer
# to valid paths in the CI container.
# .github/workflows/ci.yml) and so the entries in this file must refer to valid
# paths in the CI container.


# Default build location. Default is to build in build subdirectory.
Expand Down
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ tests: sim_server
.PHONY: tests


# ------------------------------------------------------------------------------
# Python lint
#
# Lint the Python sim/test harness with ruff, run through uv (which provisions
# the dev environment from pyproject.toml + uv.lock). This is the only Python
# quality gate wired into CI; the tests above stay driven through `make tests`.

lint:
uv run ruff check python tests

.PHONY: lint


# ------------------------------------------------------------------------------

# This has global effect, and is mostly desirable behaviour.
Expand Down
3 changes: 1 addition & 2 deletions docs/myst.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ project:
title: PandABlocks-server
github: https://github.com/PandABlocks/PandABlocks-server
plugins:
- https://github.com/DiamondLightSource/myst-version-switcher-plugin/releases/download/v0.5.0/version-switcher.mjs
- https://github.com/DiamondLightSource/myst-version-switcher-plugin/releases/download/v0.18.0/version-switcher.mjs
# Cross-repository references (mystmd xref + Sphinx intersphinx).
# PROTOTYPE for upstreaming into the DLS python-copier-template (Stage A spec §6).
#
Expand Down Expand Up @@ -85,7 +85,6 @@ site:
# default flattened /commands.
folders: true
logo: images/PandA-logo-for-black-background.svg
logo_text: PandABlocks-server
# Pin the favicon to the bundled PandA logo so `myst build` never fetches the
# default favicon from mystmd.org (a flaky remote fetch that intermittently
# fails the build).
Expand Down
Loading