diff --git a/Taskfile.yml b/Taskfile.yml index 5c1bef4..c4a66ff 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -9,6 +9,15 @@ # task stats → notification counts by type / reason / org # task mark-repo-read → mark one repo's notifications as read (REPO=owner/repo) # +# ORG AUDIT & VISIBILITY +# task migration-status → release pipeline migration progress (FILTER= optional) +# task open-prs → all open PRs across the org (FILTER=, AUTHOR=, LABEL= optional) +# task ci-status → repos with failing CI on main (FILTER= optional) +# task label-sync → ensure required labels exist on all repos (DRY_RUN=true, FILTER= optional) +# task secrets-check → verify release pipeline secrets at org level +# task stale-repos → repos with no push in MONTHS=12 (FILTER= optional) +# task pending-releases → open release-please PRs waiting to be merged +# # WORKFLOW & RELEASE PIPELINE # task cancel-runs → cancel in-progress Actions runs (ORG=, REPO= optional) # task update-release-pipeline → full 9-step release pipeline migration (REPO=) @@ -69,41 +78,33 @@ tasks: set tmpfile (mktemp) gh api /notifications --paginate --jq '.[]' | jq -s '.' > $tmpfile - set total (jq 'length' < $tmpfile) + # Single jq pass: compute total, dismiss IDs, and preserve count together + set parsed (jq -c '{ + total: length, + dismiss_ids: [.[] | select( + ((.subject.title | ascii_downcase | test("failed|merged|closed")) or + (.reason == "state_change")) + and not (.repository.owner.login == "sous-chefs" and .subject.type == "Issue") + ) | .id], + preserve_count: ([.[] | select( + .repository.owner.login == "sous-chefs" and .subject.type == "Issue" + )] | length) + }' < $tmpfile) + rm $tmpfile + + set total (echo $parsed | jq '.total') + set dismiss_ids (echo $parsed | jq -r '.dismiss_ids[]') + set preserve_count (echo $parsed | jq '.preserve_count') + set dismiss_count (count $dismiss_ids) set_color '#88C0D0' echo " Found $total unread notification(s) total" set_color normal - # Build list of thread IDs to dismiss - set dismiss_ids (jq -r ' - [ - .[] | select( - ( - (.subject.title | ascii_downcase | test("failed|merged|closed")) or - (.reason == "state_change") - ) and not ( - .repository.owner.login == "sous-chefs" and .subject.type == "Issue" - ) - ) | .id - ] | .[] - ' < $tmpfile) - - set preserve_count (jq ' - [ - .[] | select( - .repository.owner.login == "sous-chefs" and .subject.type == "Issue" - ) - ] | length - ' < $tmpfile) - - set dismiss_count (count $dismiss_ids) - if test $dismiss_count -eq 0 set_color '#A3BE8C' echo " Nothing to dismiss — inbox is clean!" set_color normal - rm $tmpfile exit 0 end @@ -111,16 +112,17 @@ tasks: echo " Dismissing $dismiss_count notification(s)..." set_color normal + # Fire PATCH calls in batches of 10 concurrent requests set marked 0 for id in $dismiss_ids - gh api --method PATCH /notifications/threads/$id > /dev/null + gh api --method PATCH /notifications/threads/$id > /dev/null & set marked (math $marked + 1) - if test (math "$marked % 25") -eq 0 + if test (math "$marked % 10") -eq 0 + wait echo " ... $marked / $dismiss_count dismissed" end end - - rm $tmpfile + wait echo "" set_color '#A3BE8C' @@ -821,3 +823,690 @@ tasks: set_color normal bash "{{.ROOT_DIR}}/scripts/manage-webhooks.sh" disable end + + # =========================================================================== + # ORG AUDIT & VISIBILITY + # =========================================================================== + + # --------------------------------------------------------------------------- + # migration-status: Release pipeline migration progress across all repos. + # Checks for release-please-config.json via GitHub code search (fast, no + # local clones). Results may lag a few minutes after a recent push. + # Optional: FILTER= to narrow by repo name. + # --------------------------------------------------------------------------- + migration-status: + desc: "Show release pipeline migration progress across all {{.ORG}} repos. Optional: FILTER=" + silent: true + vars: + FILTER: '{{.FILTER | default ""}}' + cmds: + - | + #!/usr/bin/env fish + + set org "{{.ORG}}" + set filter "{{.FILTER}}" + + set_color '#88C0D0' + echo "" + echo " Release Pipeline Migration Status — $org" + echo " ══════════════════════════════════════════════════" + set_color normal + + set_color '#EBCB8B' + echo " Fetching repo list..." + set_color normal + + set all_repos (gh repo list $org --limit 1000 \ + --json name,isArchived \ + --jq '[.[] | select(.isArchived == false)] | .[].name' | sort) + + if test -n "$filter" + set all_repos (string match -a "*$filter*" $all_repos) + set_color '#EBCB8B' + echo " Filter: $filter" + set_color normal + end + + set total (count $all_repos) + + set_color '#EBCB8B' + echo " Searching for migrated repos via code search..." + set_color normal + + # Code search for repos containing release-please-config.json + # (rate: 10 req/min auth'd; 100 results/page; max 1000 total) + set migrated_search (gh api \ + "search/code?q=filename%3Arelease-please-config.json+org%3A$org&per_page=100" \ + --paginate \ + --jq '.items[].repository.name' 2>/dev/null | sort | uniq) + + set migrated_list + set not_migrated_list + + for repo in $all_repos + if contains $repo $migrated_search + set migrated_list $migrated_list $repo + else + set not_migrated_list $not_migrated_list $repo + end + end + + set migrated_count (count $migrated_list) + set not_count (count $not_migrated_list) + + set pct 0 + if test $total -gt 0 + set pct (math --scale=0 "floor($migrated_count * 100 / $total)") + end + + # Progress bar + set filled (math --scale=0 "floor($pct / 5)") + set empty (math "20 - $filled") + set bar (string repeat -n $filled "█")(string repeat -n $empty "░") + + echo "" + set_color '#A3BE8C' + echo " [$bar] $pct% — $migrated_count / $total repos migrated" + set_color normal + echo "" + + if test $not_count -gt 0 + set_color '#EBCB8B' + echo " Not yet migrated ($not_count):" + set_color normal + for repo in $not_migrated_list + set_color '#BF616A' + echo " ❌ $repo" + set_color normal + end + echo "" + set_color '#88C0D0' + echo " To migrate: task update-release-pipeline REPO=" + set_color normal + else + set_color '#A3BE8C' + echo " All repos have been migrated!" + set_color normal + end + + echo "" + + # --------------------------------------------------------------------------- + # open-prs: All open PRs across the org in one table. + # Uses gh search (fast). Age-coloured: green <7d, yellow 7-30d, red >30d. + # Optional: FILTER=, AUTHOR=, LABEL= + # --------------------------------------------------------------------------- + open-prs: + desc: "Show all open PRs in {{.ORG}}. Optional: FILTER=, AUTHOR=, LABEL=