Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09b7c369c5 | ||
|
|
ce633b4d50 | ||
|
|
cb9a0d1642 | ||
|
|
781a1fddc5 | ||
|
|
420507da77 | ||
|
|
bdf9f68175 | ||
|
|
d339e8fd21 |
+28
-6
@@ -2,16 +2,38 @@
|
|||||||
# node:24-alpine + python3/make/g++/postgresql-client + pnpm + a warm pnpm
|
# node:24-alpine + python3/make/g++/postgresql-client + pnpm + a warm pnpm
|
||||||
# store. The install step resolves from the baked store (--prefer-offline)
|
# store. The install step resolves from the baked store (--prefer-offline)
|
||||||
# instead of paying a ~731s cold fetch + native compile every run.
|
# instead of paying a ~731s cold fetch + native compile every run.
|
||||||
|
#
|
||||||
|
# PINNED to an immutable lock-tag (#1328, brain D27): ci-image.yml pushes
|
||||||
|
# lock-<sha256(pnpm-lock.yaml)[:12]> atomically with :latest, so the two are
|
||||||
|
# byte-identical at push time. A mutable :latest resolves per-pod at pull time
|
||||||
|
# on the k8s backend, which made CI verdicts non-reproducible (same tree, same
|
||||||
|
# config, different images across runs; see #1324 comment 23382/23386). The pin
|
||||||
|
# changes ONLY through reviewed commits; a wrong tag fails loudly at image pull.
|
||||||
|
#
|
||||||
|
# Bump procedure: when a recipe change (pnpm-lock.yaml / Dockerfile.ci) lands on
|
||||||
|
# main, ci-image.yml pushes lock-<new>; a follow-up PR updates this anchor.
|
||||||
|
# Until then pipelines keep the old pin: reproducible, with the documented
|
||||||
|
# network-fallback lag (frozen-lockfile resolves missing packages from network).
|
||||||
|
# Known limitation: lock- addresses the lockfile only, so a Dockerfile-only
|
||||||
|
# change re-pushes the same tag with new content (#1328 follow-up: recipe-hash).
|
||||||
variables:
|
variables:
|
||||||
- &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:latest'
|
- &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:lock-9cb7ffcd8828'
|
||||||
- &enable_pnpm 'corepack enable'
|
- &enable_pnpm 'corepack enable'
|
||||||
|
|
||||||
when:
|
when:
|
||||||
# PR + manual CI run on any branch — the pull_request pipeline is the merge gate.
|
# PR + manual CI run on any branch: the pull_request pipeline is the merge
|
||||||
# push CI is restricted to protected branches (main) so a feature-branch push no
|
# gate (next is protected and the default branch since 2026-08-19).
|
||||||
# longer fires a redundant SECOND pipeline alongside its PR pipeline. This ~halves
|
# Push CI runs on main only. next deliberately runs NO push ci: post-merge
|
||||||
# CI load on the storage-constrained runner with zero loss of gating (branch
|
# verification on next is carried by publish.yml's `verify` step
|
||||||
# protection requires no push/ci status context; main still gets full push CI).
|
# (pnpm verify:release), which mirrors this pipeline's complete mandatory
|
||||||
|
# set step-for-step, enforced by scripts/verify-release.test.mjs. PR CI
|
||||||
|
# tests the PR HEAD tree (refs/pull/N/head, measured 2026-08-19), not a
|
||||||
|
# merge ref, so if next advances before a merge the landed tree differs
|
||||||
|
# from the tested one; publish verify re-runs the full set on the landed
|
||||||
|
# tree (PGlite path). Measured 2026-08-19: the 21 most recent push events
|
||||||
|
# on next each ran exactly one pipeline (publish), zero ci.
|
||||||
|
# Keeping push ci off next also avoids a redundant second full-suite run
|
||||||
|
# per merge on the storage-constrained runner.
|
||||||
- event: [pull_request, manual]
|
- event: [pull_request, manual]
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
|
|||||||
@@ -18,7 +18,12 @@
|
|||||||
variables:
|
variables:
|
||||||
# Pre-baked CI base (see .woodpecker/ci-image.yml): node:24-alpine +
|
# Pre-baked CI base (see .woodpecker/ci-image.yml): node:24-alpine +
|
||||||
# toolchain + warm pnpm store. Kills the second cold install publish pays.
|
# toolchain + warm pnpm store. Kills the second cold install publish pays.
|
||||||
- &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:latest'
|
# PINNED to the immutable lock-tag, not :latest (#1328, brain D27): a mutable
|
||||||
|
# tag resolves per-pod at pull time on the k8s backend and made CI verdicts
|
||||||
|
# non-reproducible (#1324). Byte-identical to :latest at pin time (pushed
|
||||||
|
# atomically by the same kaniko run, main 712c770, 2026-07-26). Bump only via
|
||||||
|
# reviewed PR, per the procedure in .woodpecker/ci.yml's header comment.
|
||||||
|
- &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:lock-9cb7ffcd8828'
|
||||||
- &enable_pnpm 'corepack enable'
|
- &enable_pnpm 'corepack enable'
|
||||||
# Heavy kaniko image builds (~25 min) — gate them so a merge that only touches
|
# Heavy kaniko image builds (~25 min) — gate them so a merge that only touches
|
||||||
# the npm-only CLI (@mosaicstack/mosaic) or docs does NOT rebuild the platform
|
# the npm-only CLI (@mosaicstack/mosaic) or docs does NOT rebuild the platform
|
||||||
|
|||||||
@@ -11,13 +11,8 @@ Git operations via Mosaic wrapper scripts. Platform-aware (Gitea or GitHub).
|
|||||||
|
|
||||||
Scripts auto-detect platform from git remote. Run from inside the repo directory.
|
Scripts auto-detect platform from git remote. Run from inside the repo directory.
|
||||||
|
|
||||||
For force-merge (branch protection bypass):
|
Credentials come from the framework credentials loader (never from a shared env
|
||||||
|
file):
|
||||||
```bash
|
|
||||||
GITEA_TOKEN=$(cat ~/.config/mosaic/credentials/gitea.env | grep TOKEN | cut -d= -f2)
|
|
||||||
```
|
|
||||||
|
|
||||||
Or use the credentials loader:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
source ~/.config/mosaic/tools/_lib/credentials.sh
|
source ~/.config/mosaic/tools/_lib/credentials.sh
|
||||||
@@ -86,14 +81,10 @@ cd ~/src/<repo>
|
|||||||
~/.config/mosaic/tools/git/pr-merge.sh -n <pr#> -d
|
~/.config/mosaic/tools/git/pr-merge.sh -n <pr#> -d
|
||||||
```
|
```
|
||||||
|
|
||||||
**Force-merge bypassing branch protection:**
|
Branch protection is a gate, not an obstacle: if it blocks a merge, fix the cause —
|
||||||
|
a failing check, a moved head, or a missing review. Never bypass it with a raw
|
||||||
```bash
|
API call, a shared credential, or `force_merge`. Exceptional cases go to the
|
||||||
GITEA_TOKEN=$(cat ~/.config/mosaic/credentials/gitea.env | grep TOKEN | cut -d= -f2)
|
operator or the coordinating seat, still merged through the wrapper.
|
||||||
curl -X POST "https://git.mosaicstack.dev/api/v1/repos/<org>/<repo>/pulls/<PR>/merge" \
|
|
||||||
-H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \
|
|
||||||
-d '{"Do":"squash","force_merge":true}'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@@ -85,10 +85,6 @@ function Get-QueueState {
|
|||||||
$state = "$($Payload.state)".ToLowerInvariant()
|
$state = "$($Payload.state)".ToLowerInvariant()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($pending -contains $state) { return "pending" }
|
|
||||||
if ($failure -contains $state) { return "terminal-failure" }
|
|
||||||
if ($success -contains $state) { return "terminal-success" }
|
|
||||||
|
|
||||||
$values = @()
|
$values = @()
|
||||||
$statuses = @()
|
$statuses = @()
|
||||||
if ($null -ne $Payload.statuses) { $statuses = @($Payload.statuses) }
|
if ($null -ne $Payload.statuses) { $statuses = @($Payload.statuses) }
|
||||||
@@ -101,7 +97,15 @@ function Get-QueueState {
|
|||||||
if (-not [string]::IsNullOrEmpty($v)) { $values += $v }
|
if (-not [string]::IsNullOrEmpty($v)) { $values += $v }
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($values.Count -eq 0 -and [string]::IsNullOrEmpty($state)) { return "no-status" }
|
# Zero contexts is classified FIRST: Gitea reports a synthetic aggregate
|
||||||
|
# state of "pending" alongside statuses:null / total_count:0 (a commit
|
||||||
|
# with no CI at all), and honoring that aggregate would poll to the
|
||||||
|
# timeout. With zero contexts there is nothing to wait on.
|
||||||
|
if ($values.Count -eq 0) { return "no-status" }
|
||||||
|
|
||||||
|
if ($pending -contains $state) { return "pending" }
|
||||||
|
if ($failure -contains $state) { return "terminal-failure" }
|
||||||
|
if ($success -contains $state) { return "terminal-success" }
|
||||||
if (($values | Where-Object { $pending -contains $_ }).Count -gt 0) { return "pending" }
|
if (($values | Where-Object { $pending -contains $_ }).Count -gt 0) { return "pending" }
|
||||||
if (($values | Where-Object { $failure -contains $_ }).Count -gt 0) { return "terminal-failure" }
|
if (($values | Where-Object { $failure -contains $_ }).Count -gt 0) { return "terminal-failure" }
|
||||||
if ($values.Count -gt 0 -and ($values | Where-Object { -not ($success -contains $_) }).Count -eq 0) { return "terminal-success" }
|
if ($values.Count -gt 0 -and ($values | Where-Object { -not ($success -contains $_) }).Count -eq 0) { return "terminal-success" }
|
||||||
|
|||||||
@@ -52,7 +52,11 @@ except Exception:
|
|||||||
print("malformed")
|
print("malformed")
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
# Gitea returns "statuses": null (not []) for a commit with zero status
|
||||||
|
# contexts -- e.g. any repo with no CI configured. Treat null as empty.
|
||||||
raw_statuses = payload.get("statuses", [])
|
raw_statuses = payload.get("statuses", [])
|
||||||
|
if raw_statuses is None:
|
||||||
|
raw_statuses = []
|
||||||
raw_state = payload.get("state", "")
|
raw_state = payload.get("state", "")
|
||||||
if not isinstance(raw_statuses, list) or not isinstance(raw_state, str):
|
if not isinstance(raw_statuses, list) or not isinstance(raw_state, str):
|
||||||
print("malformed")
|
print("malformed")
|
||||||
@@ -75,14 +79,18 @@ for item in statuses:
|
|||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
values.append(raw_value.lower())
|
values.append(raw_value.lower())
|
||||||
|
|
||||||
if any(value in pending_values for value in values) or state in pending_values:
|
# Zero contexts is classified FIRST: Gitea reports a synthetic aggregate
|
||||||
|
# state of "pending" alongside total_count:0, and an aggregate with no
|
||||||
|
# contexts behind it must not read as an in-flight pipeline (it would poll
|
||||||
|
# to the timeout). With zero contexts there is nothing to wait on.
|
||||||
|
if not values:
|
||||||
|
print("no-status")
|
||||||
|
elif any(value in pending_values for value in values) or state in pending_values:
|
||||||
print("pending")
|
print("pending")
|
||||||
elif any(value in failure_values for value in values) or state in failure_values:
|
elif any(value in failure_values for value in values) or state in failure_values:
|
||||||
print("terminal-failure")
|
print("terminal-failure")
|
||||||
elif values and all(value in success_values for value in values) and state in {"", "success"}:
|
elif all(value in success_values for value in values) and state in {"", "success"}:
|
||||||
print("terminal-success")
|
print("terminal-success")
|
||||||
elif not values:
|
|
||||||
print("no-status")
|
|
||||||
else:
|
else:
|
||||||
print("unknown")
|
print("unknown")
|
||||||
'
|
'
|
||||||
@@ -467,6 +475,11 @@ while true; do
|
|||||||
echo "Error: ASSERTED_NOT_READY state=no-status; --require-status was set for ${BRANCH}." >&2
|
echo "Error: ASSERTED_NOT_READY state=no-status; --require-status was set for ${BRANCH}." >&2
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
|
# A head with zero status contexts has no CI queue to wait on.
|
||||||
|
# For push, that is queue-clear (a repo with no CI must remain
|
||||||
|
# pushable) -- mirroring record_cannot_assert's dispositions
|
||||||
|
# (push=degraded-pass, merge=hold). Merge stays fail-closed:
|
||||||
|
# no-status there may just mean CI has not reported yet.
|
||||||
if [[ "$PURPOSE" == "push" ]]; then
|
if [[ "$PURPOSE" == "push" ]]; then
|
||||||
echo "[ci-queue-wait] queue-clear state=no-status purpose=push branch=${BRANCH}; no queued or running CI."
|
echo "[ci-queue-wait] queue-clear state=no-status purpose=push branch=${BRANCH}; no queued or running CI."
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Regression harness for ci-queue-wait.sh's zero-status-context handling.
|
||||||
|
#
|
||||||
|
# Gitea's combined-status endpoint returns, for a commit with NO status
|
||||||
|
# contexts (e.g. a repo with no CI configured at all):
|
||||||
|
# {"state":"pending","sha":"...","total_count":0,"statuses":null,...}
|
||||||
|
# -- statuses is JSON null (not []), and state is a synthetic "pending"
|
||||||
|
# even though nothing is running. Captured live from a Gitea 1.22 host,
|
||||||
|
# 2026-08-09, on a Gitea-hosted repo with no pipeline configured.
|
||||||
|
#
|
||||||
|
# Before the fix, `payload.get("statuses", [])` received null, failed the
|
||||||
|
# isinstance(list) check, and the guard reported ASSERTED_NOT_READY
|
||||||
|
# state=malformed (exit 3) -- blocking every push to a CI-less repo. Had
|
||||||
|
# null been tolerated, the synthetic aggregate "pending" would instead
|
||||||
|
# have polled to the timeout (exit 124). The fix must:
|
||||||
|
# 1. treat statuses:null as an empty list, and
|
||||||
|
# 2. classify zero status VALUES as "no-status" regardless of the
|
||||||
|
# synthetic aggregate state, and
|
||||||
|
# 3. treat no-status for --purpose push (without --require-status) as
|
||||||
|
# queue-clear (exit 0) -- a repo with no CI has no queue to wait on;
|
||||||
|
# this mirrors record_cannot_assert's disposition table
|
||||||
|
# (push=degraded-pass, merge=hold).
|
||||||
|
#
|
||||||
|
# Covers:
|
||||||
|
# (a) statuses:null + synthetic state:pending, purpose=push
|
||||||
|
# -> exit 0, queue-clear/no-status message (THE live fault).
|
||||||
|
# (b) same payload, purpose=merge -> still fail-closed (exit 3).
|
||||||
|
# (c) same payload, push + --require-status -> still fail-closed (exit 3).
|
||||||
|
# (d) statuses:[] + state:"" -> same as (a) (exit 0).
|
||||||
|
# (e) a real pending context -> still polls (times out, 124),
|
||||||
|
# proving the relaxation didn't swallow genuine pending states.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/ci-queue-wait-no-status}"
|
||||||
|
REPO_DIR="$WORK_DIR/repo"
|
||||||
|
STUB_DIR="$WORK_DIR/stubs"
|
||||||
|
|
||||||
|
rm -rf "$WORK_DIR"
|
||||||
|
mkdir -p "$REPO_DIR" "$STUB_DIR"
|
||||||
|
|
||||||
|
git -C "$REPO_DIR" init -q
|
||||||
|
git -C "$REPO_DIR" remote add origin https://git.example.test/acme/widgets.git
|
||||||
|
|
||||||
|
# Minimal curl stub (same conventions as test-ci-queue-wait-branch-absent.sh):
|
||||||
|
# branch lookup answers 200 with a fixed SHA; the status endpoint's payload
|
||||||
|
# is selected by MOSAIC_STUB_STATUS_MODE.
|
||||||
|
cat > "$STUB_DIR/curl" <<'SH'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
has_w=0
|
||||||
|
url=""
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
-w) has_w=1 ;;
|
||||||
|
http://*|https://*) url="$arg" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
case "$url" in
|
||||||
|
*/branches/*)
|
||||||
|
body='{"commit":{"id":"deadbeefcafef00d0123456789abcdef01234567"}}'
|
||||||
|
if [[ "$has_w" == 1 ]]; then
|
||||||
|
printf '%s\n200' "$body"
|
||||||
|
else
|
||||||
|
printf '%s' "$body"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*/status)
|
||||||
|
mode="${MOSAIC_STUB_STATUS_MODE:?MOSAIC_STUB_STATUS_MODE not set}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "curl stub: unrecognized URL: $url" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$mode" in
|
||||||
|
# Verbatim shape of the live Gitea response (repository object elided).
|
||||||
|
gitea-null-statuses)
|
||||||
|
body='{"state":"pending","sha":"deadbeefcafef00d0123456789abcdef01234567","total_count":0,"statuses":null,"url":"","commit_url":""}'
|
||||||
|
;;
|
||||||
|
empty-statuses)
|
||||||
|
body='{"state":"","statuses":[]}'
|
||||||
|
;;
|
||||||
|
real-pending)
|
||||||
|
body='{"state":"pending","statuses":[{"context":"ci/woodpecker","status":"running","target_url":""}]}'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "curl stub: unknown mode=$mode" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
printf '%s' "$body"
|
||||||
|
SH
|
||||||
|
chmod +x "$STUB_DIR/curl"
|
||||||
|
|
||||||
|
run_ci_queue_wait() {
|
||||||
|
(
|
||||||
|
cd "$REPO_DIR"
|
||||||
|
export PATH="$STUB_DIR:$PATH"
|
||||||
|
export MOSAIC_CREDENTIALS_FILE="$WORK_DIR/no-credentials.json"
|
||||||
|
export MOSAIC_CI_QUEUE_AUDIT_LOG="$WORK_DIR/audit.jsonl"
|
||||||
|
export GITEA_TOKEN="stub-token"
|
||||||
|
export GITEA_URL="https://git.example.test"
|
||||||
|
"$SCRIPT_DIR/ci-queue-wait.sh" -B main -t 3 -i 1 "$@"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fail=0
|
||||||
|
|
||||||
|
# (a) THE live fault: statuses:null + synthetic pending, purpose=push -> exit 0.
|
||||||
|
set +e
|
||||||
|
out_a=$(MOSAIC_STUB_STATUS_MODE=gitea-null-statuses run_ci_queue_wait --purpose push 2>&1)
|
||||||
|
status_a=$?
|
||||||
|
set -e
|
||||||
|
if [[ "$status_a" -ne 0 ]]; then
|
||||||
|
echo "FAIL(a): expected exit 0 for null-statuses/no-CI repo on push, got $status_a" >&2
|
||||||
|
echo "$out_a" >&2
|
||||||
|
fail=1
|
||||||
|
elif [[ "$out_a" == *"malformed"* ]]; then
|
||||||
|
echo "FAIL(a): null statuses must not be classified as malformed" >&2
|
||||||
|
echo "$out_a" >&2
|
||||||
|
fail=1
|
||||||
|
elif [[ "$out_a" != *"no-status"* ]]; then
|
||||||
|
echo "FAIL(a): expected a no-status/queue-clear message, got:" >&2
|
||||||
|
echo "$out_a" >&2
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# (b) Same payload, purpose=merge -> hold, fail-closed exit 3.
|
||||||
|
set +e
|
||||||
|
out_b=$(MOSAIC_STUB_STATUS_MODE=gitea-null-statuses run_ci_queue_wait --purpose merge 2>&1)
|
||||||
|
status_b=$?
|
||||||
|
set -e
|
||||||
|
if [[ "$status_b" -ne 3 ]]; then
|
||||||
|
echo "FAIL(b): expected exit 3 for no-status on merge, got $status_b" >&2
|
||||||
|
echo "$out_b" >&2
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# (c) Same payload, push + --require-status -> strictness opt-in still fails.
|
||||||
|
set +e
|
||||||
|
out_c=$(MOSAIC_STUB_STATUS_MODE=gitea-null-statuses run_ci_queue_wait --purpose push --require-status 2>&1)
|
||||||
|
status_c=$?
|
||||||
|
set -e
|
||||||
|
if [[ "$status_c" -ne 3 ]]; then
|
||||||
|
echo "FAIL(c): expected exit 3 for --require-status with no contexts, got $status_c" >&2
|
||||||
|
echo "$out_c" >&2
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# (d) statuses:[] + state:"" (the shape the code always tolerated) -> exit 0 on push.
|
||||||
|
set +e
|
||||||
|
out_d=$(MOSAIC_STUB_STATUS_MODE=empty-statuses run_ci_queue_wait --purpose push 2>&1)
|
||||||
|
status_d=$?
|
||||||
|
set -e
|
||||||
|
if [[ "$status_d" -ne 0 ]]; then
|
||||||
|
echo "FAIL(d): expected exit 0 for empty-statuses on push, got $status_d" >&2
|
||||||
|
echo "$out_d" >&2
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# (e) A REAL pending context must still block: polls to timeout, exit 124.
|
||||||
|
set +e
|
||||||
|
out_e=$(MOSAIC_STUB_STATUS_MODE=real-pending run_ci_queue_wait --purpose push 2>&1)
|
||||||
|
status_e=$?
|
||||||
|
set -e
|
||||||
|
if [[ "$status_e" -ne 124 ]]; then
|
||||||
|
echo "FAIL(e): expected exit 124 (timeout) for a genuinely pending context, got $status_e" >&2
|
||||||
|
echo "$out_e" >&2
|
||||||
|
fail=1
|
||||||
|
elif [[ "$out_e" != *"ci/woodpecker=running"* ]]; then
|
||||||
|
echo "FAIL(e): expected the pending context to be reported, got:" >&2
|
||||||
|
echo "$out_e" >&2
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$fail" -eq 0 ]]; then
|
||||||
|
echo "ci-queue-wait no-status regression passed (5/5 cases)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit "$fail"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
|
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
|
||||||
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/promotion_binding_unittest.py && python3 src/lease-broker/promotion_trigger_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/receipt_observer_client_unittest.py && python3 src/lease-broker/invariant_r_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-ci-queue-wait-tristate.sh && bash framework/tools/git/test-ci-queue-wait-github-checks.sh && bash framework/tools/git/test-pr-merge-queue-branch.sh && bash framework/tools/git/test-pr-merge-head-pin.sh && bash framework/tools/git/test-pr-merge-message-field.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/_scripts/test-mosaic-init-rce.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh && bash framework/tools/glpi/test-list-http-status.sh && bash framework/tools/orchestrator/test-board-roll.sh && bash framework/tools/woodpecker/test-ci-wait-exit-matrix.sh && bash framework/tools/_scripts/test-fleet-transport-check.sh && bash framework/tools/_scripts/test-brain-home-check.sh"
|
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/promotion_binding_unittest.py && python3 src/lease-broker/promotion_trigger_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/receipt_observer_client_unittest.py && python3 src/lease-broker/invariant_r_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-no-status.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-ci-queue-wait-tristate.sh && bash framework/tools/git/test-ci-queue-wait-github-checks.sh && bash framework/tools/git/test-pr-merge-queue-branch.sh && bash framework/tools/git/test-pr-merge-head-pin.sh && bash framework/tools/git/test-pr-merge-message-field.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/_scripts/test-mosaic-init-rce.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh && bash framework/tools/glpi/test-list-http-status.sh && bash framework/tools/orchestrator/test-board-roll.sh && bash framework/tools/woodpecker/test-ci-wait-exit-matrix.sh && bash framework/tools/_scripts/test-fleet-transport-check.sh && bash framework/tools/_scripts/test-brain-home-check.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mosaicstack/brain": "workspace:*",
|
"@mosaicstack/brain": "workspace:*",
|
||||||
|
|||||||
Reference in New Issue
Block a user