From 80263000051c57d1e2875bab9e4f771c24854880 Mon Sep 17 00:00:00 2001 From: he Date: Fri, 14 Aug 2026 17:19:28 -0400 Subject: [PATCH] chore(ci): report gate result as ci-ok/ci-fail tags + scripts/ci-status.sh --- .gitea/workflows/lint.yml | 18 +++++++++++ AGENT_TODO.md | 1 + DOC/DEV.md | 7 +++++ scripts/ci-status.sh | 65 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100755 scripts/ci-status.sh diff --git a/.gitea/workflows/lint.yml b/.gitea/workflows/lint.yml index ef233ee..b2fed42 100644 --- a/.gitea/workflows/lint.yml +++ b/.gitea/workflows/lint.yml @@ -2,6 +2,7 @@ name: gates on: push: + branches: [main] pull_request: jobs: @@ -10,9 +11,26 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run the repo gates (gen drift, check, lint) + id: gates run: | set -e make gen git diff --exit-code make check make lint + - name: Report gate result as a git tag (ci-ok/ / ci-fail/) + if: always() && github.event_name == 'push' + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + if [ "${{ steps.gates.conclusion }}" = "success" ]; then + tag="ci-ok/$GITHUB_SHA" + else + tag="ci-fail/$GITHUB_SHA" + fi + if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then + echo "tag already present: $tag" + else + git tag "$tag" "$GITHUB_SHA" + git push "http://oauth2:${GITEA_TOKEN}@gitea.skink-platy.ts.net:3000/admin/Linux_post_install.git" "refs/tags/$tag" + fi diff --git a/AGENT_TODO.md b/AGENT_TODO.md index fe8a883..e7a84eb 100644 --- a/AGENT_TODO.md +++ b/AGENT_TODO.md @@ -122,3 +122,4 @@ summary (newest last). - **2026-08-14** — Gitea Actions gate added: `.gitea/workflows/lint.yml` runs `make gen` + `git diff --exit-code` (gen-drift) + `make check` + `make lint` on every push/PR. Verified locally the exact four steps pass (gen idempotent, check OK, lint 0 FAIL / 0 WARN). "no CI" lines updated in AGENTS.md (Quick facts → CI bullet, notes a registered act_runner is required) and DEV.md (stub harnesses note: CI runs static gates only, not behaviour suites). Gitea 1.26.4 confirmed reachable; runner registration completed the same day (see the entry above). - **2026-08-14** — Convention-drift maintenance fix session (completed the audit backlog `MAINTENANCE.md`, M-001..M-023, all VERIFIED; gate `scripts/lint-conventions.sh` + `make lint` now 0 FAIL / 0 WARN; `make gen && make check` green). P0 bugs: M-002/003/004 added `docker-compose docker-vbox network-hotspot` to `INTERACTIVE_CMDS` (stdin/log-pipe prompt swallow); M-005 `install.sh --steps` now expands documented `N-M` ranges via `normalize_steps_spec()` (dry-run verified); M-006 feature-vs-docs decision: `--send`/`--markdown` **not restored** (health is a console-only reporter by design since fe7708f; scheduler `NOTIFY=always` covers delivery) — 5 docs corrected instead; M-007 `lib/notify.sh:57` fallback routed to stderr (stdout-leak on standalone source). P1: M-008..M-014 deps guards moved **before** `-h|--help` in docker-health/docker-ps (converted to `command -v X || err`), network-scan, share-usb-server, media-mp3/mp4 (guards before help with a `--dry-run` pre-scan preserving the documented no-deps preview); system-health documented as the sanctioned graceful-degradation no-guard pattern in DEV.md — lint refined accordingly (`first_guard_line` only matches real guards; `first_line` skips comments; precision fixes, not weakenings); M-015 system-firewall gained `usage()`+`-h|--help` (root-gated first; verified via sudo); M-016 `ffmpeg` added to preinstall PACKAGES. P2: M-017/M-018 autostart + usb-automount gained the feature-template preamble (flags.sh load, usage); M-019 `chmod +x apps/media/scrcpy.sh`; M-020 `SCALE_DIR`/`CONFIG_ENV` `:-` seams in pos-docker-compose (verified via overrides; follow-on fix: `DIM` color var missing from common.sh crashed `pos docker compose config` — added it); M-021 `CONFIG_DIR` centralized as the canonical XDG-aware seam in common.sh, per-file duplicates dropped (standalone-sourced notify.sh/config-ui.sh/matrix+telegram tools keep an identical guarded copy — "no shared lib? inline fallbacks"); M-022 `plugin_*` prefix collision resolved by renaming the internal registry helpers to `ent_plugin_*` (the documented plugin-authoring API `plugin_have`/`plugin_require`/`plugin_load_config`/`plugin_http_json` kept for user plugins); M-023 six tools (pos-config, pos-tree, pos-entertainment-{config,enable,disable,status}) now filename-referenced in DOC/POS.md. Hand-maintained AGENT_Context line-count rows bumped (install.sh 223→248, preinstall 75→76, common.sh 144→151, notify.sh 76→87 stale-corrected, autostart 14→50, usb-automount 134→138); `make lint` target wired in the Makefile. `MAINTENANCE.md` kept as the working record (uncommitted by design). - **2026-08-14** — `pos system backup` optional encryption (`--no-encrypt` flag + `BACKUP_ENCRYPT=0` env, flag-or-env — user chose "Flag + env only"): plain path keeps a verified `.tar.gz` with no password prompt (headless/cron safe); encrypt path unchanged (prompt → gpg AES-256 → decrypt-verify; the gpg dep-guard moved into the encrypt branch so plain backups no longer require `gnupg`). Arg parsing rewritten as a loop over `"$@"` so `pos system backup --no-encrypt` works with the flag after the folder; usage() documents all three forms + the plain artifact name; `# POS_FLAGS: --service --no-encrypt`; `config/system.env` template gains `#BACKUP_ENCRYPT=0`; POS.md row + howto/system.md section updated. Verified: stub suite +2 cases (T18 flag / T19 env: plain .tar.gz artifact, gpg never called via `$GPG_CALLED`, USB copy + sha256 of the plain archive, notify wording) — 65/65 green; `bash -n`, `make gen && make check`, `make lint` 0 FAIL / 0 WARN. +- **2026-08-14** — CI green-check via plain git (no SSH to the runner, no API tokens — user chose "CI tags + git ls-remote" + "scripts/ci-status.sh helper"): `.gitea/workflows/lint.yml` scoped to `on: push: branches: [main]` (tag pushes no longer re-trigger it) and the gate step now reports its own outcome as a lightweight tag — `ci-ok/$GITHUB_SHA` on success / `ci-fail/$GITHUB_SHA` on failure, pushed over HTTP with the jobs automatic `GITEA_TOKEN` to `http://oauth2:${GITEA_TOKEN}@gitea.skink-platy.ts.net:3000/admin/Linux_post_install.git` (runner container already host-maps that hostname to 100.111.241.54); `steps.gates.conclusion` decides ok/fail, `if: always()` (guarded to `push` events) covers failed gate runs, and an existing-tag guard makes re-runs idempotent. New executable `scripts/ci-status.sh [--wait] []` reads the tags via `git ls-remote` (origin, `CI_STATUS_REMOTE` override): GREEN (0) / RED (1) / PENDING (2); `--wait` polls every 10s up to 10 min. DEV.md §CI gains a "Checking green without SSH" bullet. Verified: `bash -n`, yaml-parse OK, `make gen && make check`, `make lint` 0 FAIL / 0 WARN; first live-tag verification pending the push (fallback if Gitea clamps token-push: PAT as workflow secret). diff --git a/DOC/DEV.md b/DOC/DEV.md index 61b3449..14b7444 100644 --- a/DOC/DEV.md +++ b/DOC/DEV.md @@ -394,6 +394,13 @@ Actions. like `pos-config` start with `|`, which collated after letters under that locale, reordering the generated tables). `scripts/gen-docs.sh` sets `export LC_ALL=C`; keep that in mind for any new generator. +- **Checking green without SSH** — the workflow reports its own outcome as a + lightweight git tag: `ci-ok/` on success, `ci-fail/` on failure + (pushed with the job's automatic `GITEA_TOKEN`; the workflow only triggers on + `push` to `main`, so tag pushes don't re-trigger it). Check from the dev box + with plain git — `scripts/ci-status.sh [--wait] []` (reads the tags via + `git ls-remote`, exit 0/1/2 = green/red/pending). No SSH to the runner, no API + tokens. - **Limits** — CI proves the *static* gates only; it never runs behaviour suites (stub harnesses stay throwaway in `/tmp`). diff --git a/scripts/ci-status.sh b/scripts/ci-status.sh new file mode 100755 index 0000000..f04a52e --- /dev/null +++ b/scripts/ci-status.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# Report whether the `gates` workflow has finished for a commit, using only +# git against the remote (no SSH to the runner box, no API tokens). +# +# `.gitea/workflows/lint.yml` pushes a lightweight tag `ci-ok/` when the +# gates pass and `ci-fail/` when they fail. This script reads those tags +# with `git ls-remote`. +# +# Usage: +# scripts/ci-status.sh [] # one-shot check (default: current HEAD) +# scripts/ci-status.sh --wait [] # poll until done (max 10 min) +# +# Exit codes: 0 = green, 1 = red, 2 = still running / not reported. +set -euo pipefail + +REMOTE="${CI_STATUS_REMOTE:-origin}" +INTERVAL=10 +TIMEOUT=600 + +sha="${1:-}" +if [ "$sha" = "--wait" ]; then + wait=1 + sha="${2:-}" +fi +[ -n "$sha" ] || sha="$(git rev-parse HEAD)" + +check() { + local ok="" fail="" + ok="$(git ls-remote "$REMOTE" "refs/tags/ci-ok/$sha" | awk '{print $1}')" + fail="$(git ls-remote "$REMOTE" "refs/tags/ci-fail/$sha" | awk '{print $1}')" + if [ -n "$ok" ]; then + echo "GREEN — gates passed for $sha ($ok)" + return 0 + fi + if [ -n "$fail" ]; then + echo "RED — gates failed for $sha ($fail)" + return 1 + fi + echo "PENDING — no gate result yet for $sha" + return 2 +} + +if [ "${wait:-0}" -ne 1 ]; then + if check; then + exit 0 + else + rc=$? + exit "$rc" + fi +fi + +deadline=$((SECONDS + TIMEOUT)) +while :; do + out="$(check 2>&1)" && { echo "$out"; exit 0; } + rc=$? + if [ "$rc" -eq 1 ]; then + echo "$out" + exit 1 + fi + if (( SECONDS >= deadline )); then + echo "TIMEOUT after ${TIMEOUT}s — no gate result for $sha" + exit 2 + fi + sleep "$INTERVAL" +done