diff --git a/docs/specs/2026-10-18-repoman-run-path-design.md b/docs/specs/2026-10-18-repoman-run-path-design.md index ae22150..3a6061d 100644 --- a/docs/specs/2026-10-18-repoman-run-path-design.md +++ b/docs/specs/2026-10-18-repoman-run-path-design.md @@ -461,10 +461,12 @@ leans on the capability gate). remove the hardcoded org/person defaults — `REPORT_TARGET_REPO` and `SOURCE_REPO` in `link-health-scanner.sh` / `automation-health-dashboard.sh`, the committer identity in `link-health-fixer.sh`, and the personal `REPORT_PY` - default in `weekly-report.sh` (already env-overridable). 4 behavioral - constants across 3 files. #116 carries the authoritative per-line locations; - distinct from #99 (that is config *plumbing*; this is embedded org/person - *defaults*). + **fallback** in `weekly-report.sh` (already env-overridable). As of #127 that + wrapper resolves `REPORT_PY` from a candidate list — the bundled plugin path + first, the personal `$HOME/workspaces/...` path only as a fallback — so #116's + remaining task here is dropping that fallback candidate, not the whole default. + #116 carries the authoritative per-line locations; distinct from #99 (that is + config *plumbing*; this is embedded org/person *defaults*). - **#99** — scanner/fixer/dashboard param-driven decoupling (v0.1.1). - **#82** — automation commit/sign-off identity (gates fixer orchestration). - **#76** — unify program registry. diff --git a/scripts/weekly-report.sh b/scripts/weekly-report.sh index f721303..3500ca0 100755 --- a/scripts/weekly-report.sh +++ b/scripts/weekly-report.sh @@ -52,7 +52,8 @@ OPTIONS: --help, -h Show this help ENVIRONMENT: - REPORT_PY Path to report.py (default: the deployed report generator) + REPORT_PY Path to report.py (default: first of the bundled generator + beside this skill, then the $HOME/workspaces deploy path) PREREQUISITES: python3, gh (authenticated). The repo list comes from the RepoMan enrolled set @@ -74,9 +75,22 @@ if [ -z "$repos" ]; then exit 1 fi -# Locate the generator. Default points at the deployed github-weekly-report skill -# (the upstream skill name in agent-skills); override with REPORT_PY in dev. -REPORT_PY="${REPORT_PY:-$HOME/workspaces/shared/skills/github-weekly-report/scripts/report.py}" +# Locate the generator. When REPORT_PY is unset, try candidates in order and use +# the first that exists, so both deployment layouts work with no per-host config: +# 1. bundled — the plugin layout, where github-weekly-report sits beside the +# repoman skill (the self-contained install; the primary target). +# 2. deployed — the OpenClaw host layout under $HOME/workspaces. Transitional: +# the personal-path default is tracked for removal in #116, and +# falls away entirely if OpenClaw deployment is retired. +# If neither exists, keep the bundled path so the error names the expected location. +if [ -z "${REPORT_PY:-}" ]; then + bundled="$SCRIPT_DIR/../../github-weekly-report/scripts/report.py" + deployed="${HOME:-}/workspaces/shared/skills/github-weekly-report/scripts/report.py" + for candidate in "$bundled" "$deployed"; do + if [ -f "$candidate" ]; then REPORT_PY="$candidate"; break; fi + done + REPORT_PY="${REPORT_PY:-$bundled}" +fi if [ ! -f "$REPORT_PY" ]; then echo "Error: report generator not found at: $REPORT_PY" >&2 echo "Set REPORT_PY to the path of report.py." >&2 diff --git a/tests/test-weekly-report.sh b/tests/test-weekly-report.sh index 453b097..334e97e 100755 --- a/tests/test-weekly-report.sh +++ b/tests/test-weekly-report.sh @@ -78,5 +78,59 @@ if REPOMAN_REPOS_FILE="$TEST_TMPDIR/empty.json" \ echo "FAIL wrapper should error on empty enrolled set"; fail=1 fi +# REPORT_PY default is resolved RELATIVE TO THE WRAPPER (the bundled generator +# at ../../github-weekly-report/scripts/report.py), not a host-specific +# $HOME/workspaces path (rossoctl/automation#126). With REPORT_PY unset and the +# bundled copy absent (automation has the wrapper but not report.py), the +# "not found" error must name the wrapper-relative path and must NOT name a +# $HOME/workspaces path. +# Assert the PROPERTY, not an exact recomputed path: with no bundled generator +# present (automation ships the wrapper, not report.py) and no $HOME/workspaces +# copy, the error names the bundled github-weekly-report generator and never a +# workspaces path. A property check (not an exact string) keeps this green across +# the candidate-list resolution order. +err=$(HOME="$TEST_TMPDIR/nohome" REPOMAN_REPOS_FILE="$TEST_TMPDIR/repos.json" \ + bash "$WRAPPER" --output "$TEST_TMPDIR/x.md" 2>&1 >/dev/null) || true +case "$err" in + *workspaces*) + echo "FAIL default error still names a \$HOME/workspaces path: [$err]"; fail=1 ;; + *github-weekly-report/scripts/report.py*) + : ;; # names the bundled generator — correct + *) + echo "FAIL default error does not name the bundled generator: [$err]"; fail=1 ;; +esac + +# Positive path (candidate 1, bundled — #127): a real bundle layout with the +# generator present and REPORT_PY unset must FIND it, run it, and emit the report +# — proving "succeeds on a clean plugin install", not just the error. +bundle="$TEST_TMPDIR/bundle" +mkdir -p "$bundle/skills/repoman/scripts" "$bundle/skills/github-weekly-report/scripts" +cp "$SCRIPT_DIR/../scripts/"*.sh "$bundle/skills/repoman/scripts/" +printf 'import sys\nprint("RAN", " ".join(sys.argv[1:]))\n' \ + > "$bundle/skills/github-weekly-report/scripts/report.py" +# Capture full output first, then take line 1 — piping the wrapper directly into +# `head` makes head close the pipe early, and under `set -o pipefail` the SIGPIPE +# surfaces as exit 141 even though the assertion is fine. +full=$(HOME="$TEST_TMPDIR/nohome" REPOMAN_REPOS_FILE="$TEST_TMPDIR/repos.json" \ + REPOMAN_SKILL_DIR="$TEST_TMPDIR/meta" \ + bash "$bundle/skills/repoman/scripts/weekly-report.sh" 2>/dev/null) +got=$(printf '%s\n' "$full" | head -n 1) +[ "$got" = "RAN --repos rossoctl/alpha alice/beta" ] \ + || { echo "FAIL bundled default not found/run (REPORT_PY unset): [$got]"; fail=1; } + +# Positive path (candidate 2, deployed fallback — #127): bundled copy ABSENT, +# the $HOME/workspaces copy present. Proves the OpenClaw layout still resolves +# with REPORT_PY unset, so dropping or reordering the fallback candidate fails here. +rm "$bundle/skills/github-weekly-report/scripts/report.py" +mkdir -p "$TEST_TMPDIR/home/workspaces/shared/skills/github-weekly-report/scripts" +printf 'import sys\nprint("RAN", " ".join(sys.argv[1:]))\n' \ + > "$TEST_TMPDIR/home/workspaces/shared/skills/github-weekly-report/scripts/report.py" +full=$(HOME="$TEST_TMPDIR/home" REPOMAN_REPOS_FILE="$TEST_TMPDIR/repos.json" \ + REPOMAN_SKILL_DIR="$TEST_TMPDIR/meta" \ + bash "$bundle/skills/repoman/scripts/weekly-report.sh" 2>/dev/null) || true +got=$(printf '%s\n' "$full" | head -n 1) +[ "$got" = "RAN --repos rossoctl/alpha alice/beta" ] \ + || { echo "FAIL deployed fallback not used (REPORT_PY unset): [$got]"; fail=1; } + if [ "$fail" -eq 0 ]; then echo "PASS test-weekly-report.sh"; fi exit "$fail"