gates: catalog_gates --fast + pre-push hook
--fast selects only gates that touch no network and no container runtime: gate 1 (check-image-pins) runs, image-resolvable and volume-persistence do NOT. Default behaviour with no flag is unchanged. The skip is ANNOUNCED with the reason and with what still owes a periodic run — a silently narrowed run reads as 'covered everything' when it did not. Why the runtime gates are never in a hook: a push that pulls images and starts containers gets bypassed within a week, and the bypass becomes the habit. They stay deliberate periodic runs at the start of a catalog campaign, before a publish train, and when a template's volumes: block or image tag changes — on a scratch host, never a customer box. .githooks/pre-push runs catalog_gates.py --fast and refuses the push. Per-clone and --no-verify-able, both stated in the hook itself. test_catalog_gates.py pins --fast's CONTENT, not just its exit code: the runtime gates must not run, the skip must be announced, and the no-flag path must still select all three. Red-proofed: an inert run_gate turns it red.
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
python3 scripts/catalog_gates.py # every AVAILABLE app, all three gates
|
||||
python3 scripts/catalog_gates.py papra wishlist # only these app dirs (the normal case)
|
||||
python3 scripts/catalog_gates.py --all # include hidden/abandoned apps too
|
||||
python3 scripts/catalog_gates.py --fast # gate 1 only — no network, no containers;
|
||||
# this is what .githooks/pre-push runs
|
||||
|
||||
Gates, in order (all must pass; **non-zero exit on any failure**):
|
||||
|
||||
@@ -49,11 +51,18 @@ import sys
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
SCRIPTS = os.path.join(ROOT, "scripts")
|
||||
|
||||
# (label, filename, accepts_app_scope)
|
||||
# (label, filename, accepts_app_scope, fast)
|
||||
#
|
||||
# `fast` = touches NO network and NO container runtime, so it is safe to run on every push.
|
||||
# image-resolvable talks to registries and volume-persistence deploys containers for minutes per
|
||||
# app — neither belongs in a hook. A push that pulls images and starts containers gets bypassed
|
||||
# within a week, and the bypass becomes the habit; both stay deliberate periodic runs (start of a
|
||||
# catalog campaign, before a publish train that vouches the catalog, whenever a template's
|
||||
# volumes: block or image tag changes) — on a scratch host, never a customer box.
|
||||
GATES = [
|
||||
("image-pins", "check-image-pins.py", False),
|
||||
("image-resolvable", "check-image-resolvable.py", True),
|
||||
("volume-persistence", "check-volume-persistence.py", True),
|
||||
("image-pins", "check-image-pins.py", False, True),
|
||||
("image-resolvable", "check-image-resolvable.py", True, False),
|
||||
("volume-persistence", "check-volume-persistence.py", True, False),
|
||||
]
|
||||
|
||||
VERDICT = {0: "OK", 1: "FAILED", 2: "INCONCLUSIVE"}
|
||||
@@ -74,19 +83,30 @@ def run_gate(label, script, args):
|
||||
|
||||
def main(argv):
|
||||
include_hidden = "--all" in argv
|
||||
fast = "--fast" in argv
|
||||
apps = [a for a in argv if not a.startswith("-")]
|
||||
unknown = [a for a in argv if a.startswith("-") and a != "--all"]
|
||||
unknown = [a for a in argv if a.startswith("-") and a not in ("--all", "--fast")]
|
||||
if unknown:
|
||||
print("unknown option(s): %s" % " ".join(unknown))
|
||||
print(__doc__.strip().splitlines()[0])
|
||||
return 2
|
||||
|
||||
scope_note = ("apps: " + ", ".join(apps)) if apps else (
|
||||
"static gate only" if fast else
|
||||
"ALL apps (runtime gate deploys every template — scratch host only)")
|
||||
print("catalog_gates — %s%s" % (scope_note, " [--all: incl. hidden/abandoned]" if include_hidden else ""))
|
||||
print("catalog_gates — %s%s%s" % (scope_note, " [--fast]" if fast else "",
|
||||
" [--all: incl. hidden/abandoned]" if include_hidden else ""))
|
||||
|
||||
selected = [g for g in GATES if g[3] or not fast]
|
||||
skipped = [g[0] for g in GATES if not (g[3] or not fast)]
|
||||
if skipped:
|
||||
print(" --fast SKIPPED: %s — they need network and a container runtime and take minutes\n"
|
||||
" per app, so they are NEVER in a hook. They remain deliberate periodic runs: start\n"
|
||||
" of a catalog campaign, before a publish train, or when a template's volumes:/image\n"
|
||||
" changes. Run them with no --fast, on a scratch host." % ", ".join(skipped))
|
||||
|
||||
results = []
|
||||
for label, script, scoped in GATES:
|
||||
for label, script, scoped, _f in selected:
|
||||
args = []
|
||||
if include_hidden:
|
||||
args.append("--all")
|
||||
|
||||
Reference in New Issue
Block a user