ci: gate pull requests on the end-to-end systemtest suite - #142
Open
Janne6565 wants to merge 3 commits into
Open
ci: gate pull requests on the end-to-end systemtest suite#142Janne6565 wants to merge 3 commits into
Janne6565 wants to merge 3 commits into
Conversation
The image copied only package.json and ran a bare `bun install`, so every build re-resolved caret ranges and two builds of the same commit could ship different dependency versions. lint/test/type-check already use --frozen-lockfile, so the image and the checks could disagree. That matters more now: the systemtest PR gate installs this image, and a non-reproducible image means an unchanged pull request can flip red overnight on a dependency it never touched. Also drops the /temp/prod install. Nothing consumed it — `builder` takes /temp/dev/node_modules and the release stage is nginx serving the static dist — so it was a full dependency install for an artifact that was never read. Co-Authored-By: Claude <noreply@anthropic.com>
Builds this PR's frontend image locally, installs a real Cosy from scratch with it, and runs the @core suite through the actual UI. Cosy's compose file sets no pull_policy, so a locally tagged image is used without any registry push — no packages: write, nothing left in ghcr, and fork PRs work. Also resolves and builds a matching cosy-backend branch when one exists, because Cosy features are routinely cross-cutting and a frontend PR tested against a released backend goes red for a reason its author cannot fix. The required check is `systemtest-gate`, not `systemtest`: a skipped job reports nothing and a required check that never reports blocks the PR forever. The gate job is green on success or an allowlisted skip, red otherwise. See docs/pr-gate.md in Magenta-Mause/Cosy-Systemtest. Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a required end-to-end PR gate for Cosy-Frontend by building the PR’s frontend Docker image, installing a full Cosy instance with it, and running the @core UI-driven systemtest suite from Magenta-Mause/Cosy-Systemtest. It also makes the frontend image build reproducible by ensuring the committed Bun lockfile is used during Docker builds.
Changes:
- Make Docker builds deterministic by copying
bun.lockand usingbun install --frozen-lockfile(and removing an unused production install stage). - Add a new
systemtestworkflow that builds frontend (and optionally matching backend) images locally, installs Cosy, runs@coresystemtests, and uploads reports. - Add a
systemtest-gatejob intended for branch rulesets so the required check still reports even when the main systemtest job is skipped.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
Dockerfile |
Ensures reproducible dependency resolution in image builds via committed bun.lock + --frozen-lockfile. |
.github/workflows/systemtest.yml |
Adds the PR-gating end-to-end systemtest workflow and the systemtest-gate reporting job. |
Suppressed comments (2)
.github/workflows/systemtest.yml:70
FULL_SUITEreads PR labels, but onworkflow_dispatchthere is nopull_requestpayload. Guard the expression so manual runs default to@corecleanly.
FULL_SUITE: ${{ contains(github.event.pull_request.labels.*.name, 'systemtest:full') }}
.github/workflows/systemtest.yml:280
systemtest-gateuses PR label context to decide whether a skipped run is allowlisted, butworkflow_dispatchruns have nopull_requestpayload. Guard on event type so manual runs don't fail expression evaluation.
SKIP_LABELLED: ${{ contains(github.event.pull_request.labels.*.name, 'systemtest-skip') }}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+42
to
+44
| permissions: | ||
| contents: read | ||
|
|
| # Generous: a cold backend image build (rust cdylib + maven) plus a full install | ||
| # and the @core suite. See the wall-clock table in docs/pr-gate.md. | ||
| timeout-minutes: 75 | ||
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'systemtest-skip') }} |
Adds the channel/report-published inputs and a push step so this gate's runs show up in the dashboard's PR section. continue-on-error: telemetry must never decide whether a pull request can merge — the verdict is the allowlist assertion above. Skips itself with one INFO line when OTEL_INGEST_USER / OTEL_INGEST_PASSWORD are absent, which is always the case on a fork PR and is the case in this repo until those secrets are added. Nothing breaks; the runs simply do not appear. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds this PR's frontend image, installs a real Cosy from scratch with it, and runs the
@coresystemtest suite through the actual UI.Depends on Magenta-Mause/Cosy-Systemtest#5, which adds the shared actions this workflow calls. Both branches are named
ci/systemtest-pr-gate, so this PR's own run resolves that branch and exercises the new code — see the job summary for what it picked.Rationale and design: docs/pr-gate.md.
How it works
The image is built locally and never pushed. Cosy's
docker-compose.ymlsets nopull_policyandinstall_cosy.shruns a plaindocker compose up -d, so compose's defaultmissingpolicy uses a locally tagged image without contacting any registry. Hence: nopackages: write, nothing left behind in ghcr, and fork PRs work (they get no secrets). The shared action asserts this rather than assuming it.It also resolves and builds a matching cosy-backend branch when one exists. Cosy features are routinely cross-cutting —
feat/custom-webhook-formatexists in both repos right now — so testing a frontend PR against a released backend goes red for a reason the author cannot fix.Dockerfile fix, and why it belongs here
28a2ce6makes the image build from the committed lockfile. It previously copied onlypackage.jsonand ran a barebun install, so every build re-resolved caret ranges and two builds of the same commit could ship different dependency versions — whilelint/test/type-checkalready used--frozen-lockfile.That is a prerequisite, not a drive-by: the gate installs this image, and a non-reproducible image means an unchanged PR can flip red overnight on a dependency it never touched. That is exactly the kind of flake that gets a required check switched off.
The same commit drops the
/temp/prodinstall. Nothing consumed it —buildertakes/temp/dev/node_modulesand the release stage is nginx serving the staticdist— so it was a full dependency install for an artifact never read.Note on selectors
docs/test-architecture.mdin the systemtest repo says page objects track the released frontend, notmain. The gate is the deliberate exception: a frontend PR installs an image built from that PR, so its page objects run against unreleased UI. That is the point — a selector break is caught here rather than at 02:30. When a change needs a newdata-testid, put the systemtest change on a matching branch and the gate will resolve and run them together.Scope and escape hatches
@core(6 spec files + the teardown assertion) by default; the full suite via thesystemtest:fulllabel.systemtest-skipskips the gate. A sibling can be pinned from the PR body withBackend-Ref:/Systemtest-Ref:— note that editing a PR body fires no workflow event, so push a commit after adding one.The required check will be
systemtest-gate, notsystemtest: a skipped job reports nothing, and a required check that never reports blocks a PR forever.🤖 Generated with Claude Code