nigig-org/.forgejo/workflows/repo-hygiene.yml
Arena Agent a0dbd192c1
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
ci: add an unfiltered repo-hygiene workflow
Every workflow in .forgejo/workflows is scoped with `paths:`. That is
right for build and test jobs -- no reason to compile the CAD module
because a payment file moved -- but it leaves a structural hole: a commit
touching only unfiltered paths runs no checks at all.

Commit 8c9ccb9 fell straight through it, pushing 30 unresolved
conflict-marker lines across five files. The worst of them was
.forgejo/workflows/nigig-build.yml itself: with markers in it the file is
not valid YAML, so all seven CAD gates silently stopped running. A
workflow that does not parse does not fail -- it does not run, which is
strictly worse than a red build because nothing announces it.

`git diff --check` would have caught this and was already a step. It was
in the file the same commit broke, and only ran for that workflow's
filtered paths.

So this workflow has no path filter, no toolchain dependency and no
network dependency -- it cannot be knocked out by an unrelated build
break -- and it validates the CI configuration itself:

1. No conflict markers anywhere in the tree.
2. Every workflow file parses as YAML and has a top-level `jobs:`.
3. Whitespace errors.

Verified against the real failure, not a synthetic one: checked out
8c9ccb9 and confirmed check 1 reports all 30 marker lines and check 2
names both unparseable workflows. Also probed for false positives --
`>>`/`<<` shift operators, `// =======` comments and a "=======" string
literal do not trip it, because the patterns are anchored to column 0 and
the closing marker requires the trailing space git writes.

Also fixes the fifth file from that commit, which I missed while
repairing the others because I only grepped .rs and .yml: ARCHITECTURE.md
still had two live conflicts on main. Both were stale-vs-current
versions of my own lines; kept the current text. While there, refreshed
every LOC figure in the file table from the actual files -- 14 of them
were stale, workspace.rs by 64 lines.
2026-07-31 19:41:10 +00:00

90 lines
3.6 KiB
YAML

name: repo hygiene
# The one workflow with NO path filter.
#
# Every other workflow in this directory gates a specific crate and is
# scoped with `paths:`. That is correct for build and test jobs -- there
# is no reason to compile the CAD module because a payment file moved.
# But it leaves a structural hole: a commit that touches only unfiltered
# paths runs no checks whatsoever.
#
# That hole is not hypothetical. Commit 8c9ccb9 pushed 30 unresolved
# conflict-marker lines across five files:
#
# .forgejo/workflows/nigig-build.yml <- invalid YAML: the CAD gates
# could not even be parsed,
# so they silently stopped running
# .forgejo/workflows/pdf.yml
# crates/apps/.../cad/workspace.rs <- ~3,000 lines also lost
# crates/apps/.../spreadsheet-engine/src/formula2.rs
# crates/apps/.../cad/ARCHITECTURE.md
#
# `git diff --check` already existed as a step inside nigig-build.yml and
# would have caught this -- but it was in the file the same commit broke,
# and it only ran for paths under that workflow's filter.
#
# So the checks here must satisfy three properties:
# 1. no path filter,
# 2. no dependency on the Rust toolchain or the network, so they cannot
# be knocked out by an unrelated build break, and
# 3. they must validate the CI configuration itself.
on:
push:
pull_request:
jobs:
hygiene:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
# An unresolved merge is the highest-severity thing that can reach
# main: the file does not parse, and if it is a workflow the checks
# that would have caught it stop running.
- name: No conflict markers anywhere in the tree
run: |
set -euo pipefail
# Anchored to line start, and the closing marker requires the
# trailing space git writes, so ordinary text (a Markdown rule,
# a Rust shift operator) does not trip it.
if git grep -nE '^(<{7} |={7}$|>{7} )' -- \
':(exclude).forgejo/workflows/repo-hygiene.yml'; then
echo
echo "ERROR: unresolved conflict markers are committed above."
echo "Resolve the merge before pushing; these files do not parse."
exit 1
fi
echo "OK"
# A workflow that is not valid YAML does not fail -- it does not run.
# That is strictly worse than a red build, because it is invisible.
- name: Every workflow file must be valid YAML
run: |
set -euo pipefail
python3 - <<'PY'
import sys, pathlib, yaml
bad = []
for f in sorted(pathlib.Path('.forgejo/workflows').glob('*.yml')):
try:
doc = yaml.safe_load(f.read_text())
except Exception as exc:
bad.append((f, exc))
continue
if not isinstance(doc, dict) or 'jobs' not in doc:
bad.append((f, 'no top-level `jobs:` mapping'))
for f, why in bad:
print(f"{f}: {why}")
if bad:
print()
print("ERROR: the workflow file(s) above do not parse, so their")
print("checks are silently not running.")
sys.exit(1)
print("OK")
PY
# Whitespace errors: trailing space, spaces-before-tab, and the
# marker-adjacent damage a bad merge leaves behind.
- name: Reject whitespace errors
run: git diff --check "$(git rev-list --max-parents=0 HEAD | tail -1)"..HEAD || git diff --check