ci: run checks, builds, releases and the website on CircleCI #417
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
beanstalk: approved @ 1697603
beanstalk: approved @ 2c5a62e
beanstalk: approved @ 4fd82b7
beanstalk: approved @ 64d6d09
beanstalk: approved @ 6f91fae
beanstalk: approved @ 70a78f9
beanstalk: approved @ 8015c9a
beanstalk: approved @ 8d361dc
beanstalk: approved @ 9d8356e
beanstalk: approved @ abf2227
beanstalk: approved @ d82f202
beanstalk: approved @ e5f1e40
beanstalk: approved @ ee8ab5f
ci: approved
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
4 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!417
Loading…
Reference in a new issue
No description provided.
Delete branch "drcrow/Longshot:ci/circleci"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type: ci · Risk: low · Tested on: Linux (devbox, Docker images of the CI jobs) · Needs: a live CircleCI run on main after merge
Why
Pull requests get only the title, description and third-party checks today. The game-free checks and the builders run by hand or at release, so a break is found after it merges. This moves CI and the release pipeline to CircleCI, which runs the checks and builders each pull request needs and nothing more. Until cutover, CircleCI's releases and website deploy are dry runs and Forgejo's workflows stay the live writers.
What changed
CircleCI runs the same checks and builders as the Forgejo workflows, chosen by what a PR changed, with one
ci/circleci: gatestatus to require; releases and the website deploy are dry runs until cutover.tests/run_all.pygains--list(the checks a run would start, running none),--junit FILE, and an opt-in--exact(names must match exactly; nothing matching fails closed) that CircleCI's test splitter uses.--shard,--write-timesand substring names are unchanged. Tests:tests/test_run_all_junit.py..circleci/config.ymlhas one small setup job per event (pull request, push to main,v*tag, schedule, manual API run). Each one looks at which areas changed (.circleci/mapping.conf: tests, gpu, linux, windows, website, third-party, docs) and continues with.circleci/shared.ymlplus that event's file in.circleci/events/. A docs-only PR runs lint, third-party andgate; agpu/change adds the Vulkan builds and SPIR-V fixtures.magicbeandev/ci, used by all three repos (source in MagicBeanDev/Orb). This repo keeps only its own jobs..circleci/test-suites.yml), split across 4 containers by timing, with JUnit results.release.ymldoes: the release jobs start only after every check and build passes, so a red main ships nothing.v*tags rerun the core checks, then release. Release jobs run main's copy ofscripts/release.py. Signing (release-sign, signing key only) and publishing (release-publish, Forgejo token only, one release at a time) are separate jobs. Until cutover, main, tags and the website refresh run as dry runs (throwaway key, nothing published or deployed), so Forgejo'srelease.ymlandwebsite.ymlstay the only writers; the cutover PR turns CircleCI live and removes them.docs/ci.mdlists each job and why)..circleci/forks.yml, started by a Forgejo webhook. A maintainer adds theci: approvedlabel (Forgejo only lets people with write access do that), and it runs that exact commit with no secrets, then postsci/circleci: gateon the PR. The label stays on, so new pushes keep running. After 14 quiet days it's removed.mise.tomlandmise.lock(pinned tools and thedeps,lint,test,ci:smoke,validatetasks), pre-commit hooks (commit-msg included) and a Chunk sidecar config.docs/ci.mdwith flow diagrams; CONTRIBUTING.md's CI lines and a section on the tools (mise, the CircleCI CLI and MCP servers, Chunk).mise run lintchecks what the branch changed, as CI does.Measurements
Verdict: no regression:
run_all.py --stricthas the same 4 failures on main and on this PR, one more check passes here, and the wall time is the same within noise.main:
9c9d69ed(2026-11-14)this PR: ci/circleci @ 02409403 (
tests/run_all.pyis the same in the head,b866a018)Hardware: devbox, x86_64 Linux, Docker; one Ubuntu 24.04 image with test-linux's packages (no game, no GPU)
Scene: none: CI only
Method:
run_all.py --strict, main and this PR interleaved (main, PR, main, PR), 2 runs each, the medianHow to reproduce: the same image and
python3 -I -B tests/run_all.py --stricton each checkout;mise run validatefor the CI config9c9d69edgaterun_all.py --strict(Linux, 24.04 image): passed / failed / skippedrun_all.py --strictwall timeRebased onto main
aa95d35fafter measuring: main has gained about 45 commits since (build, renderer, saves, release-script changes);tests/run_all.pystill only adds--list,--junitand--exacton top of main's (all checks listed and--shardunchanged), and the CircleCI jobs were re-synced with main's Forgejo workflows (the renderer build check with the committed play profile, #574; the Windows package's third-party objects, #629).Flags and settings
None. No game switch, menu row, ini key or build flag. CircleCI pipeline parameters (
release_dry_run,vulkan_dlss,full) are in docs/ci.md.Testing
Tested:
circleci config validateon every event's merged config withmagicbeandev/[email protected]; the orb's conftest policies (28 pass); one workflow per event with the tag null and empty;run_all.py --strictas measured above;tests/test_run_all_junit.py;mise run lint. The same orb and routing run live on the Site repo (PRs, main, fork PRs by label).Not tested: a live CircleCI run of this repo (it starts once this is on main), the Wine VM job, publishing (dry run until cutover), the website deploy.
Must be tested:
ci/circleci: gategreen on the commit (by hand: the pipeline and the commit's statuses).Risks
What could break: a wrong path rule could skip a job a change needed (main runs everything, so main catches it); a CircleCI job could fail where Forgejo passes.
Turning it off: revert this commit; the Forgejo workflows keep running until cutover.
Compatibility: Nothing changes for players: no game, builder or launcher code changes, and releases still come from Forgejo until cutover.
Issues
See #283
See #394
Checklist
Everyone
type(scope): description) of the status line's type.main.python -I -B tests/run_all.pypasses (any failure that also fails onmainis named).third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
tests/that reads changed source updated in this PR, not weakened.Looked over what runs when, at
6a8e3659. Read from the files; where I ran something it says so. Nothing here was seen in a live CircleCI run.Stops every run as written
1. The fork condition is always true, and it guards the checkout.
.circleci/shared.yml:80-105(get-source) and.circleci/events/fork.yml:4usegreater: [<< pipeline.parameters.fork_pr >>, 0].greateris not one of CircleCI's logic statements, and the compiler does not reject it: an unknown operator counts as true. I compiled a miniature ofget-sourcethrough CircleCI's config compiler: withfork_prat 0 the job gets the "Fork PR checkout" step and nocheckout; at 7 the same. Socircleci config validatepasses, and in every pull request, main and tag pipeline each job that usesget-source(lint, meta, the tests, the builders, the website jobs, the release builds) fetchespull/0/headand fails. Forms that compiled correctly: at step levelnot: {equal: [0, << pipeline.parameters.fork_pr >>]}; at workflow levelwhen: pipeline.parameters.fork_pr > 0(inside a step'scondition:that expression string also counted as true).2.
metacannot find the description template.shared.yml:380-384copies main's checker to/tmp/main-scripts/check_pr_description.pyand unpacks the template under/tmp/main-scripts/.forgejo/. The checker looks one folder above itself (scripts/check_pr_description.py:41), that is in/tmp/.forgejo/.3.
websitechecks a site it has not built.shared.yml:803-804runsnpm ciandnpm run check;website/scripts/check-site.tsstarts by readingdist. Forgejo'swebsite.ymlbuilds first.4. Lint installs from a lock file with no Linux Arm entries. The
smallexecutor isarm.medium.gen2, the install runs withMISE_LOCKED=1(shared.yml:255-261), andmise.locklistslinux-x64andmacos-arm64only. As I read mise's locked mode it refuses a platform the lock does not have; not run.5.
tests/run_all.pyloses--shard, which the Forgejo checks still pass. On this headpython -I -B tests/run_all.py --shard 1/2 --listends witherror: unrecognized arguments: --shard, and.forgejo/workflows/ci.yml:163runstests/run_all.py --strict --shard ...(so does the newscripts/ci/check.py:159-160). The Forgejo source checks would fail from the merge on, while they are meant to keep running alongside.Differs from the description
6. The nightly does not wait for the checks.
.circleci/events/main.ymlhas two workflows:ci(lines 3-43) andnightly-release(45-62). Signing requires the release builds and notes only, so a redcidoes not stop a signed nightly. Each workflow also has its owngate.7. Main does not run everything. In
ci,linux-appimage,windows-builder,windows-vulkanand the website jobs keep their path filters (main.yml:14-30);docs/ci.md:20says "All areas".8. Fork approval.
.circleci/approvers.txthas no login, sogatekeeper.py:220-224refuses every label. The gatekeeper also takes the label as a one-time approval that must come after the latest push and removes it (:225-242), where the team summary and the launcher and site descriptions say the label stays and new pushes keep running. And it reads the first 50 open pull requests only (:94); there are over 170 open.9.
full. The description lists afullparameter;.circleci/config.yml:6-27does not declare it andevents/manual.ymlhas no route for it.10. Paths. A
.circleci/change is "full" but the website jobs filter onwebsitealone (events/pr.yml:29-41). Forgejo'swebsite.ymlalso triggers ondocs/tested-configurations.mdanddocs/tested/**;mapping.conf:33haswebsite/only.mise.lock,ci/linux/and.forgejo/have no rule.Release chain
11. Main's
release.pyis run from.ci/main-release/(shared.yml:223-226), so its root is<checkout>/.ci(scripts/release.py:64). Loaded from there it finds 0 trusted keys and nocliff.toml; fromscripts/it finds 1 key and the file. Theverifyatshared.yml:1120then has no key to trust.12. A nightly's builder version is the word "nightly".
shared.yml:1028-1036turnsnightly-<n>-<hash>intoVERSION=nightlyfordotnet publish -p:Version. Forgejo'sbuild-windows.yml:103-104takes a numeric version or0.0.0.13. Dry-run signing.
shared.yml:1107-1108uses/tmp/dry-sign.pemas the key file, butkeygenmakes a folder of that name holdingrelease.pemandrelease.pub.pem(scripts/release.py:715-717), andverifygets no public key for it.14.
released-as ... || true(shared.yml:914) turns a failed check of an earlier release into "none found".15. The release Windows build restores a compiler cache.
release-windowsuses thellvm-mingwcommand, which restoresv1-llvm-mingw-*after the hash-checked install (shared.yml:196-207,:1017);docs/ci.md:21says release builds restore no caches.16. Two publishers.
.forgejo/workflows/release.ymlstill publishes on main and onv*tags. Which one is the only writer while both run?Smaller
shared.yml:878-886: the comment job, which holds the comment token, falls back to the pull request's copy of four helper scripts when main lacks them (it does today). Failing instead is safer..circleci/config.yml:79and:95-97putfork_sha, the branch and the tag into shell text; checkingfork_shaas 40 hex digits and passing the others through the environment avoids surprises.HEAD..HEAD(shared.yml:322-323).test-linux,arm.large.gen2); checks that skip off x86-64, such astests/test_fpx_sticky.py:189, then do not run anywhere. Intended?events/release.yml:release-versionandgatehave no tag filter while the jobs between them do. CircleCI's rule for tags asks for one on every job in the chain (https://circleci.com/docs/guides/orchestrate/workflows/#executing-workflows-for-a-git-tag).Checked and fine
The three examples hold: a docs change adds nothing to lint, meta and third-party;
gpu/adds the Linux checks, SPIR-V fixtures and Windows Vulkan build; the builder adds its CLI checks and the Windows builder. Withfork_prset, the checkout compares the fetched commit withfork_shabefore using it. Signing and publishing ask for separate contexts; the manual dry run has no publish job.run_all.py --liststill finds every existing check, and the new JUnit test passes.Questions
What turns Forgejo's events into the
pull_request,pushandapievents the setup expects, and what posts a failedci/circleci: gatewhen a required job fails and the gate job never starts? Which CircleCI settings limit the signing, bot and Cloudflare contexts to main and tags, given that a branch in this repository runs its own configuration?Thanks for this. It's the first ask in #394 (CI that gates merges), so I'm keen to see it land. mooki's review covers the config itself; these are the process points around the cutover. They apply to MagicBeanDev/LongshotLauncher#65 and MagicBeanDev/Site#10 too.
1. Make
ci/circleci: gatea required check on main as part of the cutover. Today main's protection requires no status checks in Longshot or LongshotLauncher, and Site's main isn't protected at all, so a red gate wouldn't stop a merge. Until the gate is required it's advice only. It's also what Forgejo's "merge when checks pass" needs if we use that in place of a merge bot: with no required check, it merges straight away.2. Get main green first. Once the gate is required and the nightly waits for it (mooki's point 6), a red main blocks every merge and every nightly.
test_pad_layout.py(failing since #137) needs fixing before the switch. After that, when main goes red, reverting the PR that broke it should be the first move, so nightlies don't stall.3. The fork label becomes a step before every merge. Most contributors work from forks. With the gate required, a fork PR can't merge until a maintainer adds
ci: approved, and in this PR the label is needed again after every push. Withapprovers.txtempty, that's one maintainer's waking hours again, so fork PRs would wait overnight for a label instead of a merge. Two asks before the cutover:approvers.txtspread across timezones.4. Where the release key lives. The signing key moves from a Forgejo secret to a CircleCI context. Keeping it to the sign job is good, but it does mean an outside service holds the key that signs every build the launcher installs. That may well be the right call; I'd just like the team to make it on purpose, and note it in RELEASING.md, rather than have it arrive with the CI move. This goes with mooki's question about how the contexts are kept to main and tags.
6a8e365958b866a018e3Thanks @mooki and @madebyjordan, both reviews were really useful. Since
6a8e3659the branch has been reworked: the shared setup, fork handling, signing and publishing moved into one orb (magicbeandev/ci), and the branch is rebuilt on current main. So some points are fixed by the rework and some by specific changes. Point by point:mooki
greater:is always true: confirmed withcircleci config process. The fork workflow now useswhen: pipeline.parameters.fork_pr > 0, which is dropped at 0 and kept at 7. The oldget-sourcestep condition is gone: fork checkout is a separate orb command, used only in the fork workflow.metatemplate path: gone. PR title and description checks stay on Forgejo, so CircleCI no longer runscheck_pr_description.py.websitechecks an unbuilt site: it now runsnpm run buildbeforenpm run check.linux-arm64entries.--shard: you were right, and it was worse than that: our change also made name selection exact-only, which brokerun_all.py ub_. Redone as purely additive.--shard,--write-timesand substring names are as on main; new are--list,--junit FILE, and an opt-in--exact(fail closed) that only CircleCI's splitter uses.tests/test_run_all_junit.pychecks that--shard 1/2and2/2cover every check exactly once.release-versionrequires lint, third-party, test-linux, builder-cli, spirv-fixtures and the builds, so a red main signs nothing. Av*tag reruns the core checks before it builds anything.force-fullnow.approvers.txtand the gatekeeper are gone. The label is the approval (Forgejo only lets people with write access add labels), it's sticky, so new pushes keep running, and it's removed after 14 quiet days. The new doorbell is webhook-driven, so there's no 50-PR scan.full: declared inconfig.ymland used by main, tags and API runs..circleci/is full and includes the website jobs. The website jobs also run fordocs/tested-configurations.mdanddocs/tested/**.mise.lockis full;.forgejo/is lint only.release.pyroot: main's copy now goes to.mb-main/release.pyin the checkout, so its root is the checkout: it finds the trusted key andcliff.toml. The orb's sign and publish jobs had the same bug and are fixed the same way.0.0.0, as inbuild-windows.yml.release-signuseskeygen'srelease.pemandrelease.pub.pemand verifies against the public key.released-as ... || true: removed.llvm-mingwtakes acacheparameter, and release builds passfalse.release.ymlandwebsite.ymlstay the only writers. The cutover PR turns CircleCI live and removes those workflows in the same commit.Smaller ones:
fork_sha, branch and tag in shell text: they go throughenvironment:now, and the orb's checkout refuses afork_shathat isn't 40 hex digits.HEAD..HEAD; it compares againstHEAD~1.test-linuxruns on x86 (large), sotest_fpx_stickyand the other x86-only checks still run.events/release.ymlhas one now, and so do the tag setup and noop jobs.Questions:
pushandpull_requestpipelines;apiis a manual run. Fork PRs come in through a second CircleCI project on this repo, started by a Forgejo webhook.gate: each job posts its ownci/circleci: <job>status, so the cause shows red on the commit;gatenever appears. Oncegateis required, that blocks the merge. I'd rather not givegatean API token on PR pipelines just to turn it red.release-signingispipeline.git.branch == "main" or pipeline.git.tag starts-with "v"and is limited to the Longshot and Launcher projects. Those values come from the event, not from the config, so a branch's own config can't change them.Jordan
v*tags, before "merge when checks pass" is turned on.test_pad_layout.pyneeds fixing before the gate is required, and reverting first when main goes red makes sense.The orb's source will be in MagicBeanDev/orb. The owner is creating it, and I'll link the first PR here as soon as it's up.
b866a018e328e4c0f709WIP: ci: run checks, builds, releases and the website on CircleCIto ci: run checks, builds, releases and the website on CircleCILooked over the rework at head
28e4c0f709ebf2d94b55690992b4489b5e460a16. It is the same six commits asb866a018rebased on main543846eb;git range-diffshows the patch did not change. I also read the orb at https://git.magicbean.dev/MagicBeanDev/Orb (tag v0.1.0,4a5209a32b9f651197340514dd336a87cf5ffc0e). It became readable ten minutes after the answer, so nothing waits for its source any more. Read from the files; where I ran something it says so. Nothing here was seen in a live CircleCI run.Settled at the new head
Points 1, 2, 3, 5, 7, 10, 11, 12, 14, 15, the five smaller points and Jordan's 3 hold.
circleci config process, orb packed in) the fork workflow is dropped atfork_pr0, kept at 7, and a PR'slintstarts withcheckout.# Fork PR pipeline (fork_pr / fork_sha from mb/fork-doorbell). Docs: docs/ci.md.workflows:fork-pr:when: pipeline.parameters.fork_pr > 0--shard 1/2plus2/2give all 556 checks,ub_still picks its 5.def test_shards_cover_every_check_once(self):_, everything = listed()_, first = listed("--shard", "1/2")_, second = listed("--shard", "2/2")self.assertEqual(sorted(first + second), sorted(everything))self.assertEqual(len(set(first + second)), len(everything))release.pyloaded from.mb-main/finds the trusted key andcliff.toml; the orb's dry-run signing, run on stand-in files, signs and verifies with the public key.keydir=$(mktemp -d)trap 'rm -rf "$keydir"' EXITif [ "${DRY_RUN:-false}" = true ]; thenpython3 -I "$rel" keygen "$keydir"else[ -n "${RELEASE_SIGNING_KEY:-}" ] || { echo "no RELEASE_SIGNING_KEY (release-signing context)" >&2; exit 1; }umask 077printf '%s\n' "$RELEASE_SIGNING_KEY" > "$keydir/release.pem"fipython3 -I "$rel" sign "$files/SHA256SUMS" --key "$keydir/release.pem" --out "$files/SHA256SUMS.sig"if [ "${DRY_RUN:-false}" = true ]; thenpython3 -I "$rel" verify "$files/SHA256SUMS" --sig "$files/SHA256SUMS.sig" --pub "$keydir/release.pub.pem" --files "$files"elsepython3 -I "$rel" verify "$files/SHA256SUMS" --files "$files"fi#!/usr/bin/env bash# Stale sweep, for open fork PRs carrying the approval label. Fails closed: if the timeline or the# statuses cannot be read, the PR is skipped and nothing is changed.# 1. A gate status that is still `pending` after 6 h becomes `error`.# 2. If the newest of (last pull_push, last label add; the PR creation when neither exists) is older# than DAYS days, remove the label and comment once.# shellcheck disable=SC2016 # jq programs use $vars on purposeset -euo pipefail: "${REPO:?}" "${FORGEJO_URL:?}" "${FORGEJO_TOKEN:?}"LABEL="${LABEL:-ci: approved}"DAYS="${DAYS:-14}"# shellcheck disable=SC1090,SC1091 # forgejo-lib.sh is written to /tmp by the job first. "${FORGEJO_LIB:-/tmp/forgejo-lib.sh}"now=$(date +%s)cutoff=$((now - DAYS * 86400))msg="Approval expired after $DAYS days without new commits. A maintainer can re-add \`$LABEL\` to resume CI."ev() { jq -r "$@" | newest; }pulls=$(list "pulls?state=open") || { echo "cannot list PRs; nothing changed"; exit 0; }printf '%s' "$pulls" | jq -c --arg l "$LABEL" '.[] | select(.head.repo.id != null and .head.repo.id != .base.repo.idand ([.labels[].name] | index($l) != null))| {n: .number, sha: .head.sha, created: .created_at, lid: (.labels[] | select(.name == $l) | .id)}' |while read -r pr; don=$(printf '%s' "$pr" | jq -r .n); sha=$(printf '%s' "$pr" | jq -r .sha)if ! statuses=$(list "statuses/$sha?") || ! timeline=$(list "issues/$n/timeline?"); thenecho "PR $n: cannot read statuses or timeline, skipped"; continuefistuck=$(printf '%s' "$statuses" | jq -r '[.[] | select(.context == "ci/circleci: gate")] | sort_by(.created_at)| last // empty | select(.state == "pending") | .created_at')if [ -n "$stuck" ] && [ "$(date -d "$stuck" +%s)" -lt $((now - 21600)) ]; thenapi -X POST -d "$(jq -nc '{context: "ci/circleci: gate", state: "error", description: "CI run did not finish; re-add ci: approved"}')" \"$FORGEJO_URL/api/v1/repos/$REPO/statuses/$sha" > /dev/nullecho "PR $n: stuck pending gate set to error"fiat=$(printf '%s' "$timeline" | ev --arg l "$LABEL" '.[] | select(.type == "pull_push" or (.type == "label" and .body == "1" and .label.name == $l)) | .created_at')if [ "$at" -eq 0 ]; then at=$(date -d "$(printf '%s' "$pr" | jq -r .created)" +%s); fiif [ "$at" -lt "$cutoff" ]; thenapi -X DELETE "$FORGEJO_URL/api/v1/repos/$REPO/issues/$n/labels/$(printf '%s' "$pr" | jq -r .lid)" > /dev/nullapi -X POST -d "$(jq -nc --arg b "$msg" '{body: $b}')" "$FORGEJO_URL/api/v1/repos/$REPO/issues/$n/comments" > /dev/nullecho "PR $n: approval expired, label removed"elseecho "PR $n: fresh, kept"fidoneOnly partly there
mise.lockhas linux-arm64 for six tools, not python ([[tools.python]]version = "3.12.15"backend = "core:python"specifiers = ["3.12.15"][tools.python."platforms.linux-x64"]checksum = "sha256:6d7521138fd33afddc1ccd08abb007d9a2829e38117c2576f9efdc0ec73ce772"url = "https://github.com/astral-sh/python-build-standalone/releases/download/20261021/cpython-3.12.15+20261021-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"provenance = "github-attestations"[tools.python."platforms.macos-arm64"]checksum = "sha256:7b8d00b751db21cea87dc551a8f8165147c5fbc5251d5537d7e5497dde00a219"url = "https://github.com/astral-sh/python-build-standalone/releases/download/20261021/cpython-3.12.15+20261021-aarch64-apple-darwin-install_only_stripped.tar.gz"provenance = "github-attestations"MISE_LOCKED(echo "export PATH=\"$bin:\$HOME/.local/share/mise/shims:\$PATH\"" >> "${BASH_ENV:-/dev/null}"export PATH="$bin:$HOME/.local/share/mise/shims:$PATH"mise trust -qy "${MISE_DIR:-.}"mise installfullis declared, but an API run with onlyfull: truegoes tosetup-noop-apiand does nothing (setup-noop-api:when:and:- equal: [api, << pipeline.event.name >>]- equal: [false, << pipeline.parameters.release_dry_run >>]- equal: [false, << pipeline.parameters.vulkan_dlss >>]jobs:- setup-noop:name: setup-noop-apiNew problems from the rework
setup-mainandsetup-manualpassnightly: false({"nightly":false,"release_dry_run":true,"website_refresh":false,release-versiononly makes a nightly tag when it is true (elif [ "<< pipeline.parameters.nightly >>" = true ]; thenhead=$(git rev-parse origin/main)if [ "$head" != "$ref" ]; thenecho "main moved on: skip nightly for $ref"tag=""elselast=$(git tag -l 'nightly-*' --sort=-version:refname | head -1)if [ -n "$last" ] && git diff --quiet "${last}^{commit}" HEAD -- . ':(exclude)docs/**' ':(exclude)*.md'; thenecho "no shipped changes since $last"tag=""elsetag=$(python3 -I "$MAIN_RELEASE_PY" nightly-name)fififirelease.envisTAG=. Every release job halts, no nightly ships after the cutover, and the dry run tests nothing.release-stagefails on every tag run. It runscp -a tools.lock files/in a job with no checkout, and no job savestools.lock(release-stage:executor: smallsteps:- attach_workspace:at: .- run:name: Collect release artifacts into files/command: |set -euo pipefail. release.envif [ -z "${TAG:-}" ]; thencircleci-agent step haltfirm -rf filesmkdir -p filesshopt -s nullglobfor f in build-linux/Longshot-"$TAG"-x86_64.AppImage build-linux/*.AppImage; doif [ -f "$f" ]; thencp -a "$f" "files/Longshot-${TAG}-x86_64.AppImage"breakfidonefor f in dist/LongshotBuilder-"$TAG"-windows-x64.zip dist/*.zip; doif [ -f "$f" ]; thencp -a "$f" "files/LongshotBuilder-${TAG}-windows-x64.zip"breakfidonecp -a tools.lock files/ls -la files/- persist_to_workspace:root: .paths:- filescp: cannot stat 'tools.lock', exit 1, after two 90-minute builds.test-linux,fork-test-linuxandspirv-fixturescannot set up. They run on a bareubuntu:24.04(ubuntu2404-large:docker:- image: ubuntu:24.04@sha256:2198e4c65076e9cb0b3d695219df667c0e3b0072da64ca3c2648aca17dcecaf5resource_class: largeubuntu2404:docker:- image: ubuntu:24.04@sha256:2198e4c65076e9cb0b3d695219df667c0e3b0072da64ca3c2648aca17dcecaf5resource_class: mediumtest-deps-linuxrunsgitfirst (throughfetch_commit.sh), then pip and curl, but only installs g++, clang, spirv-tools, ccache and libdav1d (test-deps-linux:steps:- run:name: Pinned SPIR-V and Vulkan headers (.forgejo/workflows/ci.yml)command: |set -euo pipefailscripts/fetch_commit.sh https://github.com/KhronosGroup/SPIRV-Headers \04f10f650d514df88b76d25e83db360142c7b174 _deps/spirv-headersscripts/fetch_commit.sh https://github.com/KhronosGroup/Vulkan-Headers \74d8a6cb930c68ef617b202c3ff3c59d919e086b _deps/vulkan-headers- run:name: Compilers and SPIR-V validator (Forgejo ci.yml)command: |set -euo pipefailexport DEBIAN_FRONTEND=noninteractiveapt-get update -qqapt-get install -y --no-install-recommends g++ clang spirv-tools ccache libdav1d-dev- run:name: Python packages for the tests (Forgejo ci.yml)command: |set -euo pipefailpython3 -m pip install --disable-pip-version-check --break-system-packages --no-deps \zstandard==0.25.0 pillow==13.0.0 numpy==2.5.4- run:name: Pinned glslang 16.6.0 (x86_64 release tarball)command: |set -euo pipefailtool_dir="$HOME/glslang-16.6.0"mkdir -p "$tool_dir"curl -fL --retry 3 -o "$tool_dir/glslang.tar.gz" \https://github.com/KhronosGroup/glslang/releases/download/16.6.0/glslang-16.6.0-linux-x86_64-release.tar.gzecho '2c34071f56ecf39d16233294d3739cf43f981fd39080f2fd9dccb782101191ce '"$tool_dir/glslang.tar.gz" | sha256sum -c --stricttar -xzf "$tool_dir/glslang.tar.gz" -C "$tool_dir""$tool_dir/bin/glslangValidator" --version | head -1- run:name: Compiler cache and test environmentcommand: |set -euo pipefailmkdir -p "$HOME/ccache" "$HOME/ccache-bin"for c in cc c++ gcc g++ clang clang++; do ln -sf "$(command -v ccache)" "$HOME/ccache-bin/$c"; done{echo "export LONGSHOT_SPIRV_HEADERS=$PWD/_deps/spirv-headers/include"echo "export LONGSHOT_VULKAN_HEADERS=$PWD/_deps/vulkan-headers/include"echo "export PATH=\"$HOME/glslang-16.6.0/bin:$HOME/ccache-bin:\$PATH\""echo 'export CCACHE_DIR=$HOME/ccache CCACHE_MAXSIZE=400M'} >> "$BASH_ENV"if ! command -v circleci >/dev/null; thenif [ -n "${CIRCLECI:-}" ] && [ "${CIRCLECI_LOCAL_HARNESS:-}" != "1" ]; thenecho "circleci CLI should be injected by the CircleCI agent in docker jobs"exit 1spirv-fixturesinstalls git but no ca-certificates before it fetches from github.com; that part is my inference.get-source(job_uses_get_source(job) if {some s in job.stepss == "get-source"}job_uses_get_source(job) if {some s in top_level_step_names(job)s == "get-source"}job_uses_get_source(job) if {some s in nested_step_names(job)s == "get-source"}mb/get-source. conftest on the real merged configs passes 32 tests, and still passes withrelease-signingorcloudflare-prodattached tolintortest-linux. The PR body says the policies keep secrets off any job that runs PR code.mb/gatehas noname:(- mb/gate:ci/circleci: <job_name>(https://circleci.com/docs/guides/integration/status-updates/). That givesci/circleci: mb/gate, not theci/circleci: gatethat the docs, the orb and the fork reports use. The Forgejo integration is not documented, so this needs one live run.release_dry_runandvulkan_dlssare declared in both the setup and the continued config and passed back in ({"full":true,"nightly":false,"release_dry_run":<< pipeline.parameters.release_dry_run >>,"website_refresh":false,"vulkan_dlss":<< pipeline.parameters.vulkan_dlss >>,"fork_pr":0,"fork_sha":""}Still open from the first review and not in the answer:
release-linuxinstalls g++-12 only (apt-get update -qq && apt-get install -y --no-install-recommends git python3 curl ca-certificates xz-utils zstd \build-essential g++-12 clang cmake ninja-build pkg-config); the fresh release zip and AppImage get none of the Wine, PE or player-build checks; tags and nightlies share one serial group, so CircleCI skips the older pipeline's publish (
serial-group: << pipeline.project.slug >>/release); preview links ignore page depth; website deploy has no check.
Waiting for settings, the registry or the cutover
What turns Forgejo events into pipelines (CircleCI's docs list no Forgejo), the status names, the context restrictions, the schedules, and whether the registry's version 0.1.0 of
magicbeandev/ciis the tagged source. CircleCI says restricting contexts for custom webhook triggers is not supported (https://circleci.com/docs/guides/security/contexts/), and the expression quoted forrelease-signinglacks thenot job.ssh.enabledandnot (pipeline.config_source starts-with "api")parts of CircleCI's own example. The required gate, protection of Site's main and thev*tags,RELEASING.mdon the signing key andtest_pad_layout.pyare promises; none is in the diff.Questions
forgejo-commentcontext defineFORGEJO_TOKEN? The orb's preview comment needs that name (: "${REPO:?}" "${FORGEJO_URL:?}" "${FORGEJO_TOKEN:?}"FORGEJO_COMMENT_TOKEN.forgejo-botrestricted in the forks project, given the custom webhook limit above?d17e28aadcdbf8719733Removed the devcontainer here too, as you asked on Site#10 (mise is the dev setup). Config, policies and lint still pass.
1df6fa7b136314fa5c47@ -0,0 +6,4 @@- third-party- test-linux:requires: [lint]- builder-cli:I think we can remove this as now both Windows and Linux builders are CLI-only?
Thanks @mooki and @HumanBean. All addressed, now at
4a9707a1, rebased on main, one commit per point:setup-mainpassesnightly: true(stillrelease_dry_run: trueuntil cutover), so the nightly chain gets its tag (efbd8e12).tools.lockinrelease-stage:release-versionnow persists it (cabf41e7).fetch_commit.shintest-deps-linuxandspirv-fixtures(43cf9afb).gate, so the status isci/circleci: gate(332e3f5a). The PR gate doesn't wait for the preview comment (dbe52d0f).release_dry_run/vulkan_dlsstwice (eec860b2). An API run withfullgoes to a newsetup-api-fullroute, the main chain as a dry run, instead of a no-op (02d7fa5f).windows-builderonly needslint(d57c1563).get-source: right again. The orb's policy didn't seemb/get-sourcecalled as a map step, so its "no secrets next to PR code" rule was checking nothing. Fixed inmagicbeandev/[email protected], which this branch now uses. It then caughtwebsite-deploy(cloudflare-prod) using the fork-aware checkout; it's a plaincheckoutnow, since it only ever runs on main (0b4c583d).Also from Site's first live runs on CircleCI:
pipeline.git.tagis null, not "", on Forgejo;Not changed: the MISE_LOCKED and g++-12 notes are left as documentation. The RELEASING.md key note lands with the cutover PR.
4a9707a1c0d7dbeb729a