975cda686f
Add a single-target aggregate `make lint-build-system-all`
that runs every offline-safe lint + every test + every
smoke test in one shot. Per the user request to make the
'build system healthy?' question easy to answer.
New `make lint-build-system-all` target chains:
make test-lint-scripts (120 Python unit tests)
make test-migration-dry-run (C-7 KF6 sed migration)
make test-scratch-dry-run (improvement #10 skeleton)
All exit 0 in offline mode; <3s wall-clock total.
The existing `make lint-build-system` chain was
incomplete — it ran lint-patches, lint-kf6-deps, and
lint-cook-recipe but not lint-recipe, test-migration-dry-run,
or test-scratch-dry-run. This commit fixes that:
make lint-build-system: lint-patches lint-kf6-deps \
lint-cook-recipe lint-recipe
The two aggregates serve different purposes:
- `lint-build-system` is the historical aggregate
including lint-patches. lint-patches returns 2 in
--no-fetch mode (all skipped) so the Gitea workflow
wraps it in a case statement. The original use case was
'is the project build-system clean?', which is
network-dependent.
- `lint-build-system-all` is the new offline-only
aggregate. It does NOT include lint-patches, so it
always exits 0 on a healthy tree. The new Gitea job
depends on unit-tests + lint-recipe + migration-dry-run
+ scratch-dry-run (so it can run after the four per-step
lints have already validated the individual layers).
Wired into:
Makefile:
- `make lint-build-system-all` + `make lint-build-system`
both now include lint-recipe.
- Both targets added to .PHONY.
Gitea Actions:
- New job `lint-build-system-all` (job 7 of 11, depends
on the four per-step lint jobs).
- Renumbered the docs stage to 1i.
BUILD-SYSTEM-IMPROVEMENTS.md:
- Make targets table: added scratch-rebuild, lint-build-system-all.
BUILD-SYSTEM-V6-HARDENING-POSTMORTEM.md:
- Durability caveat: 11 most recent commits -> 12 most
recent (added e1c2e7958); updated flow description to
include 'postmortem rebalance in e1c2e7958'.
Verified:
`make lint-build-system-all` passes in <3s.
11-job Gitea Actions pipeline YAML validates.
120/120 Python tests pass.
298 lines
12 KiB
YAML
298 lines
12 KiB
YAML
# Red Bear OS — Gitea Actions (host-execution)
|
|
#
|
|
# Per local/docs/BUILD-SYSTEM-V6-HARDENING-POSTMORTEM.md, this is
|
|
# the v6.0 canonical CI pipeline. Runs on a host-based Gitea Actions
|
|
# runner (no Docker) against a Manjaro/Arch host. Three stages:
|
|
#
|
|
# 1. lint: build-system lint + test suite. Cheap, offline, no
|
|
# QEMU. Required to pass before a merge.
|
|
# 2. build: the actual build, gated on lint passing. Heavy
|
|
# (30-120 min on a fresh cache).
|
|
# 3. smoke: boot the produced image in QEMU, verify the login
|
|
# prompt. Nightly only.
|
|
#
|
|
# Exit-code contract for the lint stage:
|
|
# audit scripts return 0=clean, 1=failures, 2=all-skipped
|
|
# `make lint-build-system` returns 2 in --no-fetch mode (no
|
|
# audit was performed) — this is CI-safe: a fresh runner has
|
|
# no network, so the "all skipped" signal is the expected
|
|
# steady state. We accept 0 OR 2 as "pass" and 1 as "fail".
|
|
|
|
name: build-system
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- 0.2.3
|
|
pull_request:
|
|
branches:
|
|
- 0.2.3
|
|
schedule:
|
|
# Nightly full audit + smoke test at 04:00 UTC
|
|
- cron: "0 4 * * *"
|
|
|
|
env:
|
|
REDBEAR_RELEASE: "0.2.3"
|
|
|
|
jobs:
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1a: unit tests
|
|
# ---------------------------------------------------------------------------
|
|
unit-tests:
|
|
name: Unit tests (120 cases, <1s)
|
|
runs-on: self-hosted
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 10
|
|
|
|
- name: Run unit tests
|
|
run: python3 -m unittest discover -s local/scripts/tests -v # ---------------------------------------------------------------------------
|
|
# Stage 1b: offline lint (every PR + branch push)
|
|
# ---------------------------------------------------------------------------
|
|
lint-offline:
|
|
name: Lint build system (offline, no network)
|
|
runs-on: self-hosted
|
|
needs: [unit-tests]
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 10
|
|
|
|
- name: Lint (offline)
|
|
# Returns exit 2 in --no-fetch mode when all entries are
|
|
# skipped; the audit script is HONEST about it. CI-safe:
|
|
# 0 = clean, 1 = bug found, 2 = no audit performed.
|
|
# The conditional below treats both 0 and 2 as success.
|
|
run: |
|
|
make lint-build-system && rc=0 || rc=$?
|
|
case $rc in
|
|
0|2) echo "Lint result: $rc (clean or no-op)" ;;
|
|
1) echo "Lint FAILED with bugs"; exit 1 ;;
|
|
*) echo "Lint exited unexpectedly with $rc"; exit $rc ;;
|
|
esac
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1c: full lint with network (nightly only)
|
|
# ---------------------------------------------------------------------------
|
|
lint-network:
|
|
name: Lint build system (full, with network)
|
|
runs-on: self-hosted
|
|
needs: [unit-tests]
|
|
if: github.event_name == 'schedule'
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 10
|
|
|
|
- name: Lint (full, with network)
|
|
# Clones each upstream tree at the pinned rev and validates
|
|
# the patch is durable. Slow: 5-15 minutes. Network-dependent.
|
|
run: make lint-build-system-full
|
|
continue-on-error: true # tolerate transient network flakes
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1d: per-recipe policy lint (R1/R2 violations)
|
|
# ---------------------------------------------------------------------------
|
|
lint-recipe:
|
|
name: Lint recipes (R1/R2 policy, every PR)
|
|
runs-on: self-hosted
|
|
needs: [unit-tests]
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 10
|
|
|
|
- name: Lint recipes (R1/R2)
|
|
# Per build-system improvement #5. Catches:
|
|
# - R1-NO-PATCH-FILE (overlay patches missing)
|
|
# - R1-PATH-SOURCE (in-tree component not using path=)
|
|
# - R2-INLINE-SED (sed -i without cookbook_apply_patches)
|
|
# - R2-PATCHES-DIR-UNUSED (patches dir but no apply call)
|
|
# - NO-LEGACY-MAKE (make all/live CONFIG_NAME=)
|
|
# - R1-LEGACY-APPLY-PATCHES (apply-patches.sh reference)
|
|
# - DEP-NOT-FOUND (dep doesn't resolve to a recipe)
|
|
# 1.1s for 171 recipes. Offline.
|
|
run: make lint-recipe
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1e: KF6 sed migration dry-run (smoke test)
|
|
# ---------------------------------------------------------------------------
|
|
migration-dry-run:
|
|
name: Migration dry-run (C-7 smoke test)
|
|
runs-on: self-hosted
|
|
needs: [unit-tests]
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 10
|
|
|
|
- name: Run migration script --dry-run
|
|
# Smoke test: the C-7 KF6 sed migration script must
|
|
# discover at least one candidate recipe and emit the
|
|
# per-recipe plan. --limit=1 keeps the test under 5s.
|
|
# Does NOT do any real fetches, cooks, or patch writes.
|
|
# Catches: discovery regression, path/name argument
|
|
# mixup, permission issues.
|
|
run: make test-migration-dry-run
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1f: scratch-rebuild dry-run (smoke test for #10)
|
|
# ---------------------------------------------------------------------------
|
|
scratch-dry-run:
|
|
name: Scratch rebuild dry-run (build-system improvement #10 smoke test)
|
|
runs-on: self-hosted
|
|
needs: [unit-tests]
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 10
|
|
|
|
- name: Run scratch-rebuild --dry-run
|
|
# Smoke test: the autotools-detection + dep-closure BFS
|
|
# must discover at least one autotools recipe and compute
|
|
# a non-empty closure. <2s wall-clock.
|
|
# Does NOT do any real rm, fetch, or cook.
|
|
# Catches: autotools regex regression, dep parser regression,
|
|
# BFS fixpoint regression, permission issues.
|
|
run: make test-scratch-dry-run
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1g: aggregate build-system health check
|
|
# ---------------------------------------------------------------------------
|
|
lint-build-system-all:
|
|
name: Lint build system (aggregate, all offline-safe targets)
|
|
runs-on: self-hosted
|
|
needs: [unit-tests, lint-recipe, migration-dry-run, scratch-dry-run]
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 10
|
|
|
|
- name: Run aggregate
|
|
# Single-target aggregate of every offline-safe lint +
|
|
# every test + every smoke test. If this passes, the
|
|
# build system is healthy.
|
|
# Excludes `lint-patches` (returns 2 in --no-fetch mode
|
|
# when all entries are skipped — that path is gated
|
|
# separately by lint-offline + the conditional case).
|
|
run: make lint-build-system-all
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1i: docs regression check
|
|
# ---------------------------------------------------------------------------
|
|
lint-docs:
|
|
name: Lint docs (no legacy build commands)
|
|
runs-on: self-hosted
|
|
needs: [unit-tests]
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 10
|
|
|
|
- name: Verify no doc still points at apply-patches.sh
|
|
# In all .md files outside /source/ and /boot-logs/, the
|
|
# only allowed references to legacy build commands are in
|
|
# clearly framed "warning" or "advanced/unsafe" contexts
|
|
# documented in local/AGENTS.md, the SCRIPT-BEHAVIOR-MATRIX,
|
|
# and the BUILD-SYSTEM-V6-HARDENING-POSTMORTEM (which
|
|
# documents the v5.x-to-v6.0 transition historically). The
|
|
# canonical build entry is local/scripts/build-redbear.sh.
|
|
run: |
|
|
if grep -rn 'apply-patches\.sh' --include='*.md' . \
|
|
| grep -v '/source/' \
|
|
| grep -v '/boot-logs/' \
|
|
| grep -v 'AGENTS\.md' \
|
|
| grep -v 'local/docs/SCRIPT-BEHAVIOR-MATRIX\.md' \
|
|
| grep -v 'local/docs/BUILD-SYSTEM-V6-HARDENING-POSTMORTEM\.md' \
|
|
| grep -v 'local/docs/BUILD-SYSTEM-IMPROVEMENTS\.md' \
|
|
| grep -vE 'VERIFIED|DEPRECATED|ARCHIVED|legacy|historical' ; then
|
|
echo "ERROR: docs still reference apply-patches.sh as a primary path"
|
|
grep -rn 'apply-patches\.sh' --include='*.md' . \
|
|
| grep -v '/source/' \
|
|
| grep -v '/boot-logs/' \
|
|
| grep -v 'AGENTS\.md' \
|
|
| grep -v 'local/docs/SCRIPT-BEHAVIOR-MATRIX\.md' \
|
|
| grep -v 'local/docs/BUILD-SYSTEM-V6-HARDENING-POSTMORTEM\.md' \
|
|
| grep -v 'local/docs/BUILD-SYSTEM-IMPROVEMENTS\.md' \
|
|
| grep -vE 'VERIFIED|DEPRECATED|ARCHIVED|legacy|historical'
|
|
exit 1
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 2a: build redbear-mini (every PR touching build-system code)
|
|
# ---------------------------------------------------------------------------
|
|
build-mini:
|
|
name: Build redbear-mini (30-45 min)
|
|
runs-on: self-hosted
|
|
needs: [lint-offline, lint-docs]
|
|
# Only run on changes that could affect the build:
|
|
# - the build-system scripts under local/scripts/
|
|
# - the AGENTS.md / local/AGENTS.md knowledge bases
|
|
# - mk/ and src/ (cookbook internals)
|
|
# - the root Makefile
|
|
if: |
|
|
contains(github.event.pull_request.title, '[build]') ||
|
|
contains(github.event.pull_request.body, '[build]') ||
|
|
github.event_name == 'schedule' ||
|
|
contains(toJSON(github.event.commits.*.added), 'mk/') ||
|
|
contains(toJSON(github.event.commits.*.modified), 'mk/') ||
|
|
contains(toJSON(github.event.commits.*.added), 'src/') ||
|
|
contains(toJSON(github.event.commits.*.modified), 'src/') ||
|
|
contains(toJSON(github.event.commits.*.added), 'local/scripts/') ||
|
|
contains(toJSON(github.event.commits.*.modified), 'local/scripts/')
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Build redbear-mini
|
|
# Heavy build; allow_failure lets MRs merge even if a
|
|
# cook flakes (the next nightly will catch it).
|
|
run: ./local/scripts/build-redbear.sh redbear-mini
|
|
continue-on-error: true
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 2b: build redbear-full (nightly only)
|
|
# ---------------------------------------------------------------------------
|
|
build-full:
|
|
name: Build redbear-full (60-120 min)
|
|
runs-on: self-hosted
|
|
needs: [lint-offline, lint-docs]
|
|
if: github.event_name == 'schedule'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Build redbear-full
|
|
run: ./local/scripts/build-redbear.sh redbear-full
|
|
continue-on-error: true
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 3: smoke test (nightly only)
|
|
# ---------------------------------------------------------------------------
|
|
smoke:
|
|
name: Smoke test (QEMU boot, nightly)
|
|
runs-on: self-hosted
|
|
needs: [build-mini]
|
|
if: github.event_name == 'schedule'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Boot redbear-mini in QEMU
|
|
# QEMU may not be installed on the host runner. Tolerate.
|
|
run: make qemu CONFIG_NAME=redbear-mini
|
|
continue-on-error: true
|
|
timeout-minutes: 15
|