Skip to content

Commit 47b67d5

Browse files
rdimitrovclaude
andauthored
Per-user reviewer attempts + @-mention fallback + widen toolhive docs paths (#776)
* @-mention non-collaborator release contributors; widen toolhive docs paths Two independent but related improvements to the upstream-release-docs pipeline: 1. Reviewer routing: @-mention contributors we can't auto-assign The existing reviewer-extract step batched all non-bot release commit authors and filtered to docs-website collaborators. On PR #759 that filter silently dropped four of five candidates (`reyortiz3`, `ChrisJBurns`, `jhroz`, `tgrunnag` are all upstream toolhive contributors but not collaborators on docs-website). The filter is mandatory because `gh pr edit --add-reviewer` returns 422 for any non-collaborator in the list, dropping the valid reviewers alongside the invalid ones. Now split the candidates: - ASSIGN_LIST (collaborators): batch-assigned as reviewers via `--add-reviewer`. Unchanged behavior. - MENTION_LIST (everyone else): @-mentioned in a new "Release contributors" section of the PR body so they see the PR documenting their work even though we can't request their review via the API. Detecting Stacklok employees directly (e.g. via the `stackers` team) requires a PAT with read:org scope -- `GITHUB_TOKEN` doesn't have it, and public-org-membership checks only see members with public membership. Deferred; noted in a comment. 2. Expand toolhive docs_paths hints The `toolhive` upstream is a monorepo shipping the CLI, the Kubernetes operator, and the vMCP gateway, plus cross-cutting features that land in concepts/, integrations/, tutorials/, and hand-written reference pages. The previous hints listed only the three guides-* folders. In practice the skill's Phase 3 impact map expanded beyond the hints (PR #759 touched concepts/, integrations/, tutorials/), so this is a focus improvement rather than a bug fix -- more accurate hints let Phase 2's source reading home in on the right areas without re-scanning unrelated docs. Other projects' hints are already accurate for their scope. toolhive-cloud-ui intentionally keeps docs_paths: [] -- no associated docs in this repo yet. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Assign reviewers per-user instead of pre-filtering by collaborator API Replaces the upfront `gh api repos/X/collaborators/Y` filter with per-user `gh pr edit --add-reviewer` attempts. Routes GitHub's own rejection (422) into the mention list instead of relying on our filter to pre-compute the split. Why: on PR #759 the collaborator check returned 404 for Stacklok employees who ARE collaborators via the `stackers` team (push permission on docs-website) -- `ChrisJBurns`, `jhrozek`, `reyortiz3`, `tgrunnagle`. Only `rdimitrov` passed, so four reviewers silently vanished. A local check with a PAT that has read:org confirms all five are collaborators; the discrepancy appears to be GITHUB_TOKEN treating team-based access differently at the collaborator endpoint, though we haven't pinned the exact rule. The authoritative answer is "will GitHub accept this person as a reviewer right now" -- asking that question directly (via the add-reviewer API) avoids the filter being wrong. Each attempt is independent, so one rejection doesn't kill the batch. The separate "Add reviewers" step is now redundant -- assignments happen inline during candidate iteration. Dropped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a661dc0 commit 47b67d5

2 files changed

Lines changed: 80 additions & 24 deletions

File tree

.github/upstream-projects.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,21 @@ projects:
3636
- id: toolhive
3737
repo: stacklok/toolhive
3838
version: v0.23.1
39+
# toolhive is a monorepo covering the CLI, the Kubernetes
40+
# operator, and the vMCP gateway. It also introduces cross-
41+
# cutting features that land in concepts/, integrations/,
42+
# tutorials/, and hand-written reference pages. These entries
43+
# are hints, not constraints -- the skill's Phase 3 impact map
44+
# decides what actually changes. Hints focus Phase 2's source
45+
# reading so the skill doesn't re-scan unrelated areas.
3946
docs_paths:
4047
- docs/toolhive/guides-cli
4148
- docs/toolhive/guides-k8s
4249
- docs/toolhive/guides-vmcp
50+
- docs/toolhive/concepts
51+
- docs/toolhive/integrations
52+
- docs/toolhive/tutorials
53+
- docs/toolhive/reference/authz-policy-reference.mdx
4354
assets:
4455
- release_asset: swagger.yaml
4556
destination: static/api-specs/toolhive-api.yaml

.github/workflows/upstream-release-docs.yml

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,14 @@ jobs:
391391
id: pre_skill
392392
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
393393

394-
- name: Extract reviewers from release compare
394+
- name: Assign reviewers and prepare contributor mentions
395395
id: reviewers
396396
env:
397397
REPO: ${{ steps.detect.outputs.repo }}
398398
PREV: ${{ steps.detect.outputs.prev_tag }}
399399
NEW: ${{ steps.detect.outputs.new_tag }}
400400
REVIEW_REPO: ${{ github.repository }}
401+
PR_NUMBER: ${{ steps.eff.outputs.number }}
401402
run: |
402403
# Get non-bot commit authors in the release range.
403404
if COMPARE=$(gh api "repos/$REPO/compare/$PREV...$NEW" \
@@ -408,29 +409,64 @@ jobs:
408409
echo "compare_ok=false" >> "$GITHUB_OUTPUT"
409410
fi
410411
411-
# Filter out bot accounts, then further filter to only this
412-
# repo's collaborators. GitHub rejects reviewer requests for
413-
# non-collaborators with 422, which would fail the whole
414-
# `gh pr edit --add-reviewer` call and drop the valid
415-
# reviewers along with the invalid ones. Community
416-
# contributors from the upstream repo often aren't
417-
# collaborators here; silently skip them.
412+
# Filter out bot accounts.
418413
CANDIDATES=$(echo "$COMPARE" |
419414
grep -Ev '(\[bot\]$|^github-actions|^stacklokbot$|^dependabot|^renovate|^copilot)' || true)
420415
421-
REVIEWERS=""
416+
# Attempt to assign each candidate as a reviewer individually,
417+
# rather than filtering upfront and batching. Rationale:
418+
# - `gh pr edit --add-reviewer "a,b,c"` is atomic. A single
419+
# 422 on any name aborts the whole call, dropping valid
420+
# names alongside invalid ones.
421+
# - `gh api repos/X/collaborators/Y` as a pre-filter is
422+
# unreliable from a GITHUB_TOKEN in Actions: on PR #759
423+
# the check returned 404 for Stacklok employees who ARE
424+
# collaborators via the `stackers` team (push perm on
425+
# this repo), and only `rdimitrov` slipped through. We
426+
# suspect the collaborator endpoint treats team-based
427+
# access differently for GITHUB_TOKEN vs PATs with
428+
# read:org, but haven't nailed down the exact rule.
429+
# Per-user attempts sidestep both issues: the authoritative
430+
# answer is "does GitHub accept this as a reviewer right now"
431+
# and we ask the API that question directly.
432+
#
433+
# Cap attempts at 5 to avoid review fatigue on big releases.
434+
TRIED=0
435+
ASSIGN_LIST=""
436+
MENTION_LIST=""
422437
while IFS= read -r login; do
423438
[ -z "$login" ] && continue
424-
if gh api "repos/$REVIEW_REPO/collaborators/$login" --silent 2>/dev/null; then
425-
REVIEWERS="${REVIEWERS:+$REVIEWERS,}$login"
439+
if [ "$TRIED" -ge 5 ]; then
440+
# Over the review-fatigue cap -- mention any additional
441+
# contributors instead of trying to assign them.
442+
MENTION_LIST="${MENTION_LIST:+$MENTION_LIST }@$login"
443+
continue
444+
fi
445+
TRIED=$((TRIED + 1))
446+
if gh pr edit "$PR_NUMBER" --add-reviewer "$login" 2>/dev/null; then
447+
ASSIGN_LIST="${ASSIGN_LIST:+$ASSIGN_LIST,}$login"
448+
echo "Assigned: $login"
449+
else
450+
MENTION_LIST="${MENTION_LIST:+$MENTION_LIST }@$login"
451+
echo "Mention (assignment rejected by GitHub): $login"
426452
fi
427453
done <<< "$CANDIDATES"
428454
429-
# Cap at 5 to avoid review fatigue.
430-
REVIEWERS=$(echo "$REVIEWERS" | tr ',' '\n' | head -5 | paste -sd, -)
431-
432-
echo "list=$REVIEWERS" >> "$GITHUB_OUTPUT"
433-
echo "Reviewers: ${REVIEWERS:-<none>}"
455+
# Exposed for diagnostic visibility in the PR body (e.g.,
456+
# "Auto-assigned: @alice @bob") and for the next workflow_
457+
# dispatch retry to know what was attempted.
458+
echo "list=$ASSIGN_LIST" >> "$GITHUB_OUTPUT"
459+
{
460+
echo "mention_block<<MENTION_EOF"
461+
if [ -n "$MENTION_LIST" ]; then
462+
echo "Release contributors we couldn't auto-assign as reviewers (review fatigue cap or GitHub rejected the assignment). Mentioning them so they see the PR documenting their work:"
463+
echo ""
464+
echo "$MENTION_LIST"
465+
fi
466+
echo "MENTION_EOF"
467+
} >> "$GITHUB_OUTPUT"
468+
echo "Auto-assigned: ${ASSIGN_LIST:-<none>}"
469+
echo "Mentioned: ${MENTION_LIST:-<none>}"
434470
435471
- name: Read docs_paths hint
436472
id: hints
@@ -797,6 +833,8 @@ jobs:
797833
GAPS_BLOCK: ${{ steps.signals.outputs.gaps_block }}
798834
AUTOGEN_NOTE: ${{ steps.autogen.outputs.note }}
799835
COMPARE_OK: ${{ steps.reviewers.outputs.compare_ok }}
836+
MENTION_BLOCK: ${{ steps.reviewers.outputs.mention_block }}
837+
ASSIGN_LIST: ${{ steps.reviewers.outputs.list }}
800838
run: |
801839
START='<!-- upstream-release-docs:start -->'
802840
END='<!-- upstream-release-docs:end -->'
@@ -830,8 +868,22 @@ jobs:
830868
echo "$GAPS_BLOCK"
831869
echo ""
832870
fi
833-
echo "Reviewers below are non-bot commit authors in the release range who are also collaborators on this repo."
871+
echo "### Release contributors"
834872
echo ""
873+
if [ -n "$ASSIGN_LIST" ]; then
874+
# Comma list -> @-mention list for rendering.
875+
ASSIGNED_MENTIONS=$(echo "$ASSIGN_LIST" | tr ',' '\n' | sed 's/^/@/' | paste -sd' ' -)
876+
echo "Auto-assigned as reviewers (collaborators on this repo): $ASSIGNED_MENTIONS"
877+
echo ""
878+
fi
879+
if [ -n "$MENTION_BLOCK" ]; then
880+
echo "$MENTION_BLOCK"
881+
echo ""
882+
fi
883+
if [ -z "$ASSIGN_LIST" ] && [ -z "$MENTION_BLOCK" ]; then
884+
echo "No non-bot contributors were found in the release range."
885+
echo ""
886+
fi
835887
echo "$END"
836888
} > /tmp/section.md
837889
@@ -855,13 +907,6 @@ jobs:
855907
856908
gh pr edit "$PR_NUMBER" --body-file /tmp/pr-body.md
857909
858-
- name: Add reviewers
859-
if: always() && steps.reviewers.outputs.list != ''
860-
env:
861-
PR_NUMBER: ${{ steps.eff.outputs.number }}
862-
REVIEWERS: ${{ steps.reviewers.outputs.list }}
863-
run: gh pr edit "$PR_NUMBER" --add-reviewer "$REVIEWERS"
864-
865910
- name: Comment on augmentation failure
866911
# Runs only when a preceding step failed. Comments a retry
867912
# pointer on the PR so a human can see the run URL.

0 commit comments

Comments
 (0)