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
105 changes: 105 additions & 0 deletions .github/workflows/testbox.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# A Blacksmith testbox: a warm Linux x64 runner that runs builds and tests against the local tree
# (scripts/goport/testbox.sh). `blacksmith testbox warmup` dispatches this workflow, `testbox run` syncs
# the working tree to it and runs one command. The setup matches the Linux test job of ci.yml, with
# zbook's toolchains. Sticky disks keep target/ and the cargo registry warm between testboxes.
# A pull request that changes this file runs it in validation mode (no testbox_id).
name: Blacksmith Testbox

on:
workflow_dispatch:
inputs:
testbox_id:
type: string
description: "Testbox session ID"
required: true
pull_request:
paths:
- ".github/workflows/testbox.yml"

permissions:
contents: read

concurrency:
group: testbox-${{ inputs.testbox_id || github.ref }}
cancel-in-progress: false

env:
CARGO_TERM_COLOR: always
# The toolchain of shipped bins and --profile goport. Edit-loop builds use the nightly of
# scripts/run-cargo-capped.sh.
RUSTUP_TOOLCHAIN: 1.93.0
NIGHTLY_TOOLCHAIN: nightly-2026-06-17

jobs:
testbox:
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 360
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@v2
with:
testbox_id: ${{ inputs.testbox_id }}
- uses: actions/checkout@v5
with:
persist-credentials: false
# After checkout: its clean step would empty a disk mounted in the workspace.
- uses: useblacksmith/stickydisk@v1
with:
key: ts-rust-testbox-target
path: ${{ github.workspace }}/target
- uses: useblacksmith/stickydisk@v1
with:
key: ts-rust-testbox-cargo
path: ~/.cargo/registry
# main's Go pin is the saved state's batch.upstreamPin.to (AGENTS.md, "Pin"). The Go checkout sits
# outside the workspace, so a sync of the local tree does not touch it.
- name: Resolve the Go pin
id: pin
run: |
key=$(jq -r '.batch.upstreamPin.to // empty' docs/typechecker-state/current.json)
python3 scripts/upstream/pin.py show ${key:+"$key"} > "$RUNNER_TEMP/pin.json"
jq -r '"repo=\(.repo)", "commit=\(.commit)", "subdir=\(.subdir // "")", "go=\(.oracle.go | ltrimstr("go"))"' "$RUNNER_TEMP/pin.json" >> "$GITHUB_OUTPUT"
- name: Check out the pinned Go source
uses: actions/checkout@v5
with:
repository: ${{ steps.pin.outputs.repo }}
ref: ${{ steps.pin.outputs.commit }}
path: go-pin
sparse-checkout: ${{ steps.pin.outputs.subdir }}
persist-credentials: false
- name: Install the Go repo's typescript package
run: |
url=$(jq -r '.packages["node_modules/typescript"].resolved' go-pin/package-lock.json)
mkdir -p go-pin/node_modules/typescript
curl -sSfL "$url" | tar xz -C go-pin/node_modules/typescript --strip-components=1
mv go-pin "$HOME/go-pin"
- uses: actions/setup-go@v6
with:
go-version: ${{ steps.pin.outputs.go }}
cache: false
- run: |
rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal -c rustfmt,clippy
rustup toolchain install "$NIGHTLY_TOOLCHAIN" --profile minimal
# Remote commands run without this job's RUSTUP_TOOLCHAIN. 1.93.0 is the default, as on zbook;
# run-cargo-capped.sh picks the nightly for edit-loop builds.
rustup default "$RUSTUP_TOOLCHAIN"
# testbox.sh sources this file before each command: commands run over SSH, without this job's env.
# TS_CARGO_CGROUP_ACTIVE=1 skips the systemd user scope of run-cargo-capped.sh (no user session here).
- name: Write the testbox env
env:
SUBDIR: ${{ steps.pin.outputs.subdir }}
run: |
cat > "$HOME/testbox.env" <<EOF
export PATH="$(dirname "$(command -v go)"):$HOME/.cargo/bin:\$PATH"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
export CARGO_TERM_COLOR=always
export TS_GO_REPO="$HOME/go-pin${SUBDIR:+/$SUBDIR}"
export TSCTEST_TMP="$RUNNER_TEMP/tsctest"
export COMPILER_RUNNER_TMP="$RUNNER_TEMP/compiler-runner"
export TS_CARGO_CGROUP_ACTIVE=1
export TS_CARGO_JOBS=32
export TS_CARGO_SLOTS=1
EOF
cat "$HOME/testbox.env"
- name: Run Testbox
uses: useblacksmith/run-testbox@v2
if: always()
Comment thread
t3dotgg marked this conversation as resolved.
Comment thread
t3dotgg marked this conversation as resolved.
57 changes: 57 additions & 0 deletions scripts/goport/testbox.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Blacksmith testboxes: a warm 32 vCPU Linux x64 runner (.github/workflows/testbox.yml) that runs a command
# against this worktree's files. `run` syncs this worktree to the testbox (the CLI's rsync) and runs the
# command in the synced repo root. target/ and the cargo registry sit on sticky disks.
# usage: testbox.sh help this text
# testbox.sh warmup start a testbox; saves its ID to target/testbox-id
# testbox.sh run <command...> sync this worktree, then run the command with the testbox env
# (e.g. run scripts/run-cargo-capped.sh build --release -p ts_goport --bins).
# Arguments keep their boundaries; use run bash -c '...' for pipes and &&
# testbox.sh get <remote> [local] copy a file or dir back (remote path relative to the repo root)
# testbox.sh status | stop | list the saved testbox's status, stop it, list active testboxes
# TESTBOX_ID overrides the saved ID. TESTBOX_IDLE: idle minutes before the testbox stops (default 15).
# TESTBOX_REF: the ref the workflow runs from (default main: the workflow must be on the default branch).
# Auth: `blacksmith auth login` once per host (`blacksmith auth status` shows it).
set -euo pipefail
case "${1:-help}" in help | -h | --help) sed -n '2,/^set -euo/p' "$0" | sed '$d'; exit 0 ;; esac

repo_root="$(git -C "$(dirname -- "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
id_file="$repo_root/target/testbox-id"
cd "$repo_root"

saved_id() {
local id="${TESTBOX_ID:-$(cat "$id_file" 2>/dev/null || true)}"
[[ -n "$id" ]] || { echo "no testbox: run 'testbox.sh warmup' or set TESTBOX_ID" >&2; exit 2; }
echo "$id"
}

cmd="$1"
shift
case "$cmd" in
warmup)
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
rc=0
out="$(blacksmith testbox warmup testbox.yml --ref "${TESTBOX_REF:-main}" --idle-timeout "${TESTBOX_IDLE:-15}" 2>&1)" || rc=$?
Comment thread
coderabbitai[bot] marked this conversation as resolved.
echo "$out"
((rc == 0)) || exit "$rc"
id="$(grep -oE 'tbx_[A-Za-z0-9_-]+' <<<"$out" | head -1)"
[[ -n "$id" ]] || { echo "warmup printed no testbox ID" >&2; exit 1; }
mkdir -p "$(dirname "$id_file")"
echo "$id" >"$id_file"
echo "testbox $id (saved to target/testbox-id)"
;;
run)
(($#)) || { echo "usage: testbox.sh run <command...>" >&2; exit 2; }
printf -v remote_cmd '%q ' "$@"
blacksmith testbox run --id "$(saved_id)" ". ~/testbox.env && $remote_cmd"
;;
get) blacksmith testbox download --id "$(saved_id)" "$@" ;;
status) blacksmith testbox status --id "$(saved_id)" "$@" ;;
stop)
id="$(saved_id)"
blacksmith testbox stop --id "$id"
# Keep the saved ID when TESTBOX_ID stopped another testbox.
[[ "$(cat "$id_file" 2>/dev/null || true)" != "$id" ]] || rm -f "$id_file"
;;
list) blacksmith testbox list "$@" ;;
*) echo "unknown command: $cmd (testbox.sh help)" >&2; exit 2 ;;
esac
Loading