Files
Rust-Link/.gitea/workflows/pr-checks.yml
wtclaude b3b66b1cc2
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 3m53s
feat(sidecar): a Windows service, the egg and its launcher, and the first release workflow (phase 18)
Module-rust phase 18, step 4 of docs/modules/rust/PLAN.md §34.2.7.

The Windows service (D149, §34.2.5): src/windows.rs, ported from link's fix
for error 1053. The same exe tries the SCM handshake and falls through to a
console run on 1063; it reports Running only once the listener and store are
up, and logs to a daily file beside its config. One binary serves every
RunicGatewayRust-<id> instance, because the SCM ignores the dispatcher's name
for an own-process service.

An empty environment variable now counts as unset. A Pterodactyl egg exports
every variable it declares, so a blank RUSTLINK_WEB_TOKEN arrived as "" and
overrode the saved token, and a new one was generated and persisted on every
boot. That breaks D152, which this change makes true.

The egg (R20, R22, D151, D152, §34.2.6), in egg/:
- install.sh is egg 18's script with two changes. A wipe guard moves
  rust-link/ to /tmp around `rm -rf ${REMOVE_FILES}`. The bridge block then
  fetches a schema-2 Rust bundle (pinnable by RUNICGATEWAY_BUNDLE), checks
  every asset's sha256 and the plugin's protocol before placing anything, and
  places the plugin by FRAMEWORK. Vanilla installs nothing and does not fail.
- with-sidecar.sh is the launcher. It unsets blank variables, builds the web
  bind from RUSTLINK_WEB_PORT, and runs --print-config so that a newly
  generated token is printed once. It prints the URL and server id for the
  admin page, then execs the game. It no longer uses `set -e`: nothing the
  bridge gets wrong may keep the game from booting.
- The startup's launcher prefix is conditional, so a server with no bridge
  boots exactly as egg 18 does.
- build.sh assembles egg-rust-runicgateway.json. PR Checks runs it.

The release (D145, §34.2.1) reuses servuo-plugins' engine. It publishes the
static musl Linux binary, the Windows exe, the launcher, the egg and
SHA256SUMS, and dispatches the installer's bundle.yml. PR Checks gains a
clippy run for the Windows target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-09-25 23:14:57 -05:00

118 lines
5.1 KiB
YAML

# Gate every pull request into `main` on the checks this repository already had
# and nobody ran automatically.
#
# Phases 1 and 3 both wrote `cargo fmt`, `cargo clippy -D warnings` and a test
# suite, and both ran them BY HAND from a workstation. That is the whole gap
# this file closes: a guard nothing invokes is a guard whose state nobody knows,
# and the repository that gets released had nothing gating it at all.
#
# Adapted from RunicGateway/installer's pr-checks.yml, which is the other Rust
# crate in this project and already solved the toolchain-on-a-shared-runner
# problem. Two differences, both because of where the crate sits:
#
# • The crate is in `sidecar/`, not at the repo root, so every cargo step runs
# with that working directory and the cache key reads that lockfile.
# • There is no "does a crate exist yet" detection. The installer needed it
# because its CI landed before its code; here the code came first.
#
# Enforcement (one-time, in the Gitea UI):
# Repository Settings → Branches → Branch Protection (rule for `main`)
# • Enable Status Check
# • Status check patterns: PR Checks / *
# Gitea only lists a context in its dropdown after it has reported once, so let
# this run on one PR first; the glob matches without the dropdown and keeps
# matching as jobs are added.
#
# Scope note: `edge` is gated as well as `main` though this repo has no `edge`
# branch. Multi-phase work lands there first everywhere else in this project, and
# gating only the `main` hop would run these checks for the first time at the
# cutover — the one moment a red build is most expensive to find.
name: PR Checks
on:
pull_request:
branches: [main, edge]
concurrency:
group: pr-checks-${{ github.ref }}
cancel-in-progress: true
jobs:
rust-gates:
runs-on: ubuntu-latest
timeout-minutes: 30
defaults:
run:
working-directory: sidecar
steps:
- uses: actions/checkout@v4
# One job runs all three gates on purpose: installing the toolchain costs
# far more than the checks do, so splitting fmt/clippy/test into parallel
# jobs would pay that cost three times for no wall-clock win.
- name: Install Rust toolchain (rustfmt + clippy)
run: |
set -euo pipefail
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
$SUDO apt-get update
$SUDO apt-get install -y --no-install-recommends \
build-essential curl ca-certificates git jq gcc-mingw-w64-x86-64
if ! command -v cargo >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal --default-toolchain stable
fi
echo "${HOME}/.cargo/bin" >> "$GITHUB_PATH"
export PATH="${HOME}/.cargo/bin:${PATH}"
rustup component add rustfmt clippy
rustup target add x86_64-pc-windows-gnu
cargo --version && cargo fmt --version && cargo clippy --version
# Keyed on Cargo.lock: dependency builds are reused until a dep actually
# changes. A cache miss only makes the run slower, never wrong.
- name: Cache cargo registry and build dir
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
sidecar/target
key: ${{ runner.os }}-cargo-${{ hashFiles('sidecar/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
# Cheapest gate first — parses only, no compile, so a formatting slip fails
# in seconds instead of after a full build.
- name: cargo fmt --check
run: cargo fmt --check
# --all-targets covers the tests too, which is where most of this crate's
# interesting code is. -D warnings makes a lint a failure, so the crate
# starts clean at this bar and anything new is a regression from the PR.
- name: cargo clippy
run: cargo clippy --locked --all-targets -- -D warnings
# --locked also proves Cargo.lock is in sync with Cargo.toml rather than
# letting the build silently update it.
- name: cargo test
run: cargo test --locked
# The Windows service entry point (src/windows.rs) compiles only for
# Windows, so the Linux clippy above never sees it. Linted against the
# release's own target here, so a service-only fault fails a PR instead
# of waiting for a release to show up (docs/modules/rust/PLAN.md §34.2.5).
# MinGW is the C compiler for the bundled SQLite, as in release.yml.
- name: cargo clippy (Windows target)
env:
CC_x86_64_pc_windows_gnu: x86_64-w64-mingw32-gcc
AR_x86_64_pc_windows_gnu: x86_64-w64-mingw32-ar
run: cargo clippy --locked --target x86_64-pc-windows-gnu --all-targets -- -D warnings
# The egg the release publishes, assembled exactly as release.yml does:
# the install script and the launcher parse, and the egg carries the
# shape the panel's importer needs and every variable it exists to add.
- name: Build the egg
working-directory: .
run: bash egg/build.sh /tmp/egg-rust-runicgateway.json