-
Notifications
You must be signed in to change notification settings - Fork 3
feat: Add weekly-report.sh scoped to core repos #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
rubambiza
merged 3 commits into
rossoctl:main
from
rubambiza:feat/weekly-report-wrapper
Aug 20, 2026
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # ============================================================================= | ||
| # Weekly Report (core-scoped) | ||
| # Resolves the org and the curated core-repo allowlist via the shared library, | ||
| # then invokes the Python report generator scoped to exactly those repos. | ||
| # | ||
| # Usage: | ||
| # bash weekly-report.sh --help | ||
| # bash weekly-report.sh --output /tmp/report.md --json-output /tmp/report-data.json | ||
| # bash weekly-report.sh --org rossoctl --since 2026-08-10 --until 2026-08-17 | ||
| # ============================================================================= | ||
|
|
||
| # --- Load shared library --- | ||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| # shellcheck disable=SC1091 | ||
| source "$SCRIPT_DIR/program-lib.sh" | ||
|
|
||
| # --- CLI args --- | ||
| SINCE="" | ||
| UNTIL="" | ||
| OUTPUT="" | ||
| JSON_OUTPUT="" | ||
| SHOW_HELP=false | ||
|
|
||
| while [[ $# -gt 0 ]]; do | ||
| case $1 in | ||
| --since) SINCE="$2"; shift 2 ;; | ||
| --until) UNTIL="$2"; shift 2 ;; | ||
| --output) OUTPUT="$2"; shift 2 ;; | ||
| --json-output) JSON_OUTPUT="$2"; shift 2 ;; | ||
| --profile) PROFILE_FLAG="$2"; shift 2 ;; | ||
| --org) ORG_FLAG="$2"; shift 2 ;; | ||
| --help|-h) SHOW_HELP=true; shift ;; | ||
| *) echo "Unknown option: $1" >&2; exit 1 ;; | ||
| esac | ||
| done | ||
|
|
||
| if [ "$SHOW_HELP" = true ]; then | ||
| cat << 'USAGE' | ||
| weekly-report -- Generate the weekly org report scoped to the core repos | ||
|
|
||
| USAGE: | ||
| weekly-report.sh [OPTIONS] | ||
|
|
||
| OPTIONS: | ||
| --since DATE Start of reporting window (YYYY-MM-DD; default: 7 days ago) | ||
| --until DATE End of reporting window (YYYY-MM-DD; default: today) | ||
| --output FILE Write the Markdown report to FILE (default: stdout) | ||
| --json-output FILE Write structured JSON for AI synthesis to FILE | ||
| --profile NAME Org profile to load (config/org.<name>.env; default org.env) | ||
| --org NAME GitHub org (default: from profile, config/org.env) | ||
| --help, -h Show this help | ||
|
|
||
| ENVIRONMENT: | ||
| REPORT_PY Path to report.py (default: the deployed report generator) | ||
|
|
||
| PREREQUISITES: | ||
| python3, gh (authenticated). The core-repo list comes from config/core-repos.txt | ||
| via the shared library (get_core_repos). | ||
| USAGE | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Resolve org identity (sets ORG, honoring --org/--profile/env/profile precedence). | ||
| load_org_profile | ||
|
|
||
| # The curated allowlist, owner-qualified (e.g. rossoctl/operator), one per line. | ||
| repos="$(get_core_repos)" | ||
| if [ -z "$repos" ]; then | ||
| echo "Error: get_core_repos returned no repos" >&2 | ||
| 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}" | ||
| 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 | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Build args. $repos is intentionally unquoted so each line becomes a separate | ||
| # --repos value; core repo names never contain whitespace. | ||
| # shellcheck disable=SC2086 | ||
| set -- --org "$ORG" --repos $repos | ||
| [ -n "$SINCE" ] && set -- "$@" --since "$SINCE" | ||
| [ -n "$UNTIL" ] && set -- "$@" --until "$UNTIL" | ||
| [ -n "$OUTPUT" ] && set -- "$@" --output "$OUTPUT" | ||
| [ -n "$JSON_OUTPUT" ] && set -- "$@" --json-output "$JSON_OUTPUT" | ||
|
|
||
| exec python3 "$REPORT_PY" "$@" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Verifies scripts/weekly-report.sh builds the generator invocation from the | ||
| # core-repo allowlist. Hermetic: a fixture allowlist via $CORE_REPOS_FILE and a | ||
| # stub report.py via $REPORT_PY, so no gh / network / real config is touched. | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| WRAPPER="$SCRIPT_DIR/../scripts/weekly-report.sh" | ||
|
|
||
| TEST_TMPDIR=$(mktemp -d) | ||
| trap 'rm -rf "$TEST_TMPDIR"' EXIT | ||
|
|
||
| fail=0 | ||
|
|
||
| # Fixture allowlist (bare names; owner is derived from ORG). | ||
| cat > "$TEST_TMPDIR/repos.txt" <<'EOF' | ||
| # comment | ||
| alpha | ||
| beta | ||
| EOF | ||
|
|
||
| # Stub generator: echo the args it was called with. | ||
| cat > "$TEST_TMPDIR/report.py" <<'PY' | ||
| import sys | ||
| print(" ".join(sys.argv[1:])) | ||
| PY | ||
|
|
||
| got=$(ORG=rossoctl \ | ||
| CORE_REPOS_FILE="$TEST_TMPDIR/repos.txt" \ | ||
| REPORT_PY="$TEST_TMPDIR/report.py" \ | ||
| bash "$WRAPPER" --output /tmp/ignored.md) | ||
| want="--org rossoctl --repos rossoctl/alpha rossoctl/beta --output /tmp/ignored.md" | ||
| [ "$got" = "$want" ] || { echo "FAIL wrapper args: got [$got] want [$want]"; fail=1; } | ||
|
|
||
| # --since / --until pass through. | ||
| got2=$(ORG=rossoctl \ | ||
| CORE_REPOS_FILE="$TEST_TMPDIR/repos.txt" \ | ||
| REPORT_PY="$TEST_TMPDIR/report.py" \ | ||
| bash "$WRAPPER" --since 2026-08-10 --until 2026-08-17) | ||
| want2="--org rossoctl --repos rossoctl/alpha rossoctl/beta --since 2026-08-10 --until 2026-08-17" | ||
| [ "$got2" = "$want2" ] || { echo "FAIL wrapper window args: got [$got2] want [$want2]"; fail=1; } | ||
|
|
||
| # Missing generator fails loud. | ||
| if ORG=rossoctl CORE_REPOS_FILE="$TEST_TMPDIR/repos.txt" \ | ||
| REPORT_PY="$TEST_TMPDIR/does-not-exist.py" \ | ||
| bash "$WRAPPER" >/dev/null 2>&1; then | ||
| echo "FAIL wrapper should error on missing REPORT_PY"; fail=1 | ||
| fi | ||
|
|
||
| if [ "$fail" -eq 0 ]; then echo "PASS test-weekly-report.sh"; fi | ||
| exit "$fail" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: all three invocations set
REPORT_PYexplicitly (here, line 39, and line 46), so the built-in default is never exercised — which is why the wrong path in the other comment ships with CI fully green.That is the correct call for the two happy-path assertions: they must be hermetic, and pointing at a real deployed generator would break that.
If you want a cheap regression guard for the default without giving up hermeticity, assert on its shape rather than its resolvability — e.g. run the wrapper with
REPORT_PYunset andHOMEpointed at a temp dir, then check that the error message names the expected skill directory:That pins the default against future renames while still touching no network and no real config. Entirely optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deferring this one to a follow-up. The shape-only guard is the right call, but the exact error-message shape depends on the finalized canonical path (which settles once agent-skills#32 lands and the host dir is renamed). Tracking it so it is not lost.