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
60 changes: 0 additions & 60 deletions .github/actions/macos-setup/action.yml

This file was deleted.

10 changes: 5 additions & 5 deletions .github/buildomat/jobs/helios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
#: from_output = "/work/cores-illumos.tar.zst"
#
# The whole suite on illumos, acceptance included, capturing the
# illumos fixture set. The set is published for the macOS job that
# reads it (`macos` in .github/workflows/ci.yml), which fetches it by
# illumos fixture set. The set is published for the linux job that
# reads it (`linux` in .github/workflows/ci.yml), which fetches it by
# commit once this job's check run has passed.
#
# The default target size: the job is done minutes before that macOS
# check finishes building, so a larger machine only reserves more.
# The default target size. The linux job waits for this one once its
# own captures are done; a larger machine would shorten that wait.
#
# Buildomat publishes the first file it is given for a commit and
# refuses every later one, even from a rerun, so the archive is built
Expand Down Expand Up @@ -109,7 +109,7 @@ ls -l /work/cores-illumos.tar.zst
# Buildomat does not upload an output over its per-file cap (1 GiB by
# default), and the publish naming it then publishes nothing, silently.
# A red check here says so, where a missing file would only time out
# the macOS check waiting for it.
# the linux check waiting for it.
max=$((1024 * 1024 * 1024))
size=$(wc -c </work/cores-illumos.tar.zst)
if (( size > max )); then
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/wait-helios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# The job is not an Actions job, so nothing here can `needs:` it: this
# polls its check run instead, for as long as buildomat takes to queue
# and run it, up to a ceiling that only a hang should reach. A failed
# helios job fails this at once, naming it, so a red macOS check says
# helios job fails this at once, naming it, so a red linux check says
# which side broke. A queue that is merely slow delays the check
# without failing it.
#
Expand Down
59 changes: 0 additions & 59 deletions .github/scripts/wait-linux.sh

This file was deleted.

152 changes: 48 additions & 104 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,22 @@
#
# The merge gate. Every Linux and illumos run builds the fixture
# programs, cores them, and checks the cores against the committed
# goldens; macOS cannot core an ELF process, so it reads the cores
# those runs took, through the same production readers, against the
# same goldens. Four checks:
# goldens. The linux job also reads the illumos set, through the same
# production readers, against the same goldens: a core read away from
# the system that took it, as one is whenever an illumos core is
# copied to a laptop. Three checks:
#
# lint rustfmt over both manifests, clippy
# linux the whole suite in the pinned image (.github/image/),
# capturing the linux and linux-floor sets
# capturing the linux and linux-floor sets and reading the
# illumos set beside them
# helios the whole suite on illumos, capturing the illumos set
# (buildomat: .github/buildomat/jobs/helios.sh)
# macos the whole suite over the cores both of them took, built
# once while they run
#
# The jobs that read cores test a pull request's head commit, not the
# merge commit Actions checks out by default: buildomat builds the head
# and publishes the illumos cores under it, and one macOS build reads
# every set, each of which must have been captured from the tree it
# runs in.
# The linux job tests a pull request's head commit, not the merge
# commit Actions checks out by default: buildomat builds the head and
# publishes the illumos cores under it, and a set is read only by the
# tree it was captured from.
#
# The version matrix is not among them: it is dispatched by hand
# (matrix.yml).
Expand All @@ -30,8 +29,9 @@
# test binary, and a runner has disk for little else.
#
# A golden read from cores is blessed only by the host that captures
# its set; a diff only macOS shows is a reader bug, and one a host
# and this workflow disagree on is a canonicalization gap.
# its set; a diff only the linux job's read of the illumos set shows
# is a reader bug, and one a host and this workflow disagree on is a
# canonicalization gap.

name: ci

Expand Down Expand Up @@ -60,8 +60,7 @@ env:
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}

jobs:
# Its own job, so a lint failure neither stops the suite from running
# nor leaves the macOS check without cores to read.
# Its own job, so a lint failure does not stop the suite from running.
lint:
name: lint
runs-on: ubuntu-26.04
Expand All @@ -88,7 +87,14 @@ jobs:
linux:
name: linux
runs-on: ubuntu-26.04
timeout-minutes: 120
# The wait for helios below lasts as long as buildomat does.
timeout-minutes: 180
permissions:
contents: read
packages: read
checks: read
env:
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v7
with:
Expand Down Expand Up @@ -118,19 +124,39 @@ jobs:
- name: Fixtures
run: .github/scripts/in-image.sh target/ci/examples/build_fixtures

# The illumos set, unpacked beside this job's own: a capturing
# system reads every set it finds there (testkit::cores::sets).
# Waited for only now, so that buildomat's run overlaps this
# job's build and captures. A helios job that delivers nothing
# leaves this job's own sets read, and fails it by name after.
- id: helios
name: Wait for helios
continue-on-error: true
run: .github/scripts/wait-helios.sh "$HEAD_SHA" "$HANSEI_CORES"

# Again, now that it is there: the illumos set's bundles.
- name: Fixtures (illumos)
if: steps.helios.outcome == 'success'
run: .github/scripts/in-image.sh target/ci/examples/build_fixtures

- name: Test
run: .github/scripts/in-image.sh cargo nextest run --workspace --locked --no-fail-fast --profile ci --cargo-profile ci

- name: Illumos set read?
if: ${{ !cancelled() && steps.helios.outcome == 'failure' }}
run: |
echo "::error::helios delivered no cores, so the illumos set went unread; see its check"
exit 1

- name: Disk
if: always()
run: df -h / "${{ steps.image.outputs.scratch }}"

# Whatever was captured, pass or fail: the macOS job reads it
# (.github/scripts/wait-linux.sh), and a failure here is
# root-caused from it. A Linux core is
# mostly holes, which --sparse keeps out of the archive and the
# reader's disk alike. The dot-named bookkeeping is this host's
# own.
# Whatever was captured, pass or fail: a failure here is
# root-caused from it, and a Mac reads it with `gh run download`.
# A Linux core is mostly holes, which --sparse keeps out of the
# archive and the reader's disk alike. The dot-named bookkeeping
# is this host's own.
- id: cores
name: Archive cores
if: always()
Expand All @@ -155,85 +181,3 @@ jobs:
path: ${{ runner.temp }}/cores-linux.tar.zst
compression-level: 0
retention-days: ${{ github.event_name == 'pull_request' && 7 || 30 }}

# One build reads every set: it compiles while the linux job and
# buildomat's helios job take their cores, waits for both, and runs
# the suite once over whatever they delivered. A side that delivered
# nothing leaves the others read, and fails the job by name after.
macos:
name: macos
runs-on: macos-26
# The waits below last as long as the linux job and buildomat do.
timeout-minutes: 180
permissions:
contents: read
actions: read
checks: read
env:
DEVELOPER_DIR: /Applications/Xcode_26.5.app/Contents/Developer
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ env.HEAD_SHA }}

- uses: ./.github/actions/macos-setup
with:
save: "true"

- name: Fixture toolchain
run: .github/scripts/fixture-toolchain.sh

# Before any cores arrive: the Mach-O fixture builds and the
# bundles extracted from them.
- name: Build
run: |
cargo nextest run --workspace --locked --no-run --cargo-profile ci
target/ci/examples/build_fixtures

- id: linux
name: Wait for linux
continue-on-error: true
run: .github/scripts/wait-linux.sh "$RUNNER_TEMP/cores"

- id: helios
name: Wait for helios
continue-on-error: true
run: .github/scripts/wait-helios.sh "$HEAD_SHA" "$RUNNER_TEMP/cores"

- name: Sets
env:
LINUX: ${{ steps.linux.outcome }}
HELIOS: ${{ steps.helios.outcome }}
run: |
sets=()
[ "$LINUX" = success ] && sets+=(linux linux-floor)
[ "$HELIOS" = success ] && sets+=(illumos)
if [ ${#sets[@]} -eq 0 ]; then
echo "::error::neither the linux job nor helios delivered cores; see their logs"
exit 1
fi
{
echo "HANSEI_CORES=$RUNNER_TEMP/cores"
echo "HANSEI_SETS=$(IFS=,; echo "${sets[*]}")"
} >>"$GITHUB_ENV"

# Again, now that there are cores: each set's bundles.
- name: Fixtures
run: target/ci/examples/build_fixtures

- name: Test
run: cargo nextest run --workspace --locked --no-fail-fast --profile ci --cargo-profile ci

- name: Every set read?
if: ${{ !cancelled() }}
env:
LINUX: ${{ steps.linux.outcome }}
HELIOS: ${{ steps.helios.outcome }}
run: |
missing=0
[ "$LINUX" = success ] \
|| { echo "::error::the linux job delivered no cores, so its sets went unread; see its log"; missing=1; }
[ "$HELIOS" = success ] \
|| { echo "::error::helios delivered no cores, so the illumos set went unread; see its check"; missing=1; }
exit "$missing"
7 changes: 5 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ Green means green on **all three platforms**: macOS, illumos and Linux.
Each has caught a failure the other two could not, so a suite run on one
proves little about the others. Detection is covered portably by the golden
tests below; a real cored target on an illumos or Linux host is where the
render side and the acceptance suite are exercised.
render side and the acceptance suite are exercised. CI runs on Linux and
illumos only, so macOS is green only when someone has run it there.

**A flaky test is a bug with a cause, and the cause must be identified
every time one occurs.** Re-running a failed test and moving on because
Expand Down Expand Up @@ -292,7 +293,9 @@ check:
reader, canonicalized and masked so two captures print the same.
- Linux and illumos take their own sets every run (`linux` and
`linux-floor`; `illumos`) into `HANSEI_CORES` (default
`test-programs/fixtures/cores`). macOS takes none and reads copies:
`test-programs/fixtures/cores`), and read any other set already
there: CI's linux job reads the illumos set that way, a core read
away from the system that took it. macOS takes none and reads copies:
`check-all.sh`'s local leg copies the hosts', and
`gh run download <run>` fetches CI's. A set whose cores are missing
fails every test reading it, with one message saying how to get them.
Expand Down
4 changes: 2 additions & 2 deletions hansei-runtime/src/testkit/cores.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ pub const CAPTURED: &[&str] = if cfg!(target_os = "linux") {

/// Names the sets a run reads, comma-separated, in place of the ones
/// [`sets`] would choose. For a run that holds only some sets' cores on
/// purpose: CI's macOS job names the sets whose cores arrived, so a
/// capturing system that delivered none leaves the others read.
/// purpose: a Mac that has copied one host's sets and not the other's
/// names those it has, and reads them without failing on the rest.
pub const SETS: &str = "HANSEI_SETS";

/// The sets a run reads cores of: those [`SETS`] names, if it names
Expand Down