korg: add userinfo command for org and OWNERS lookup - #6398
palnabarun wants to merge 1 commit into
Conversation
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: palnabarun The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/assign @kubernetes/owners |
d785d6c to
427a4cc
Compare
Priyankasaggu11929
left a comment
There was a problem hiding this comment.
Thank you, @palnabarun!
left a few inline comments.
cblecker
left a comment
There was a problem hiding this comment.
Nice addition — this fills a genuine gap and the overall structure is solid. The errgroup concurrency pattern is correct, Hound failures degrade gracefully, and it's good to see tests land alongside the new code. A few things worth addressing before this merges, mostly around the JSON output dropping failed users and a double-print in main(). The go.mod changes are covered separately.
427a4cc to
573e357
Compare
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: palnabarun The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
573e357 to
b4e3c9e
Compare
|
@Priyankasaggu11929 @cblecker PTAL again. Thank you. 🙏🏽 |
c575655 to
65a1640
Compare
There was a problem hiding this comment.
The batch path is the most complex control flow here but only gets tested with single-user inputs. A mixed-batch test (e.g. ["alice", "ghost", "bob"] where ghost 404s) would exercise both branches of the JSON assembly loop in a single call and catch ordering / nil-dereference regressions.
There was a problem hiding this comment.
Text mode is the default output but has no test coverage -- all runUserinfo tests pass outputJSON=true. A TestRunUserinfoText that checks for the === username header, Company: line, Orgs: section, and tabwriter table would guard against formatting regressions in renderText.
There was a problem hiding this comment.
TestRunUserinfoText covers the happy path now. A few edge branches in text mode are still untested: the ERROR block (lines 433-435), the Company: **Not Found** fallback for empty company, and the (none) display for empty orgs. A mixed-batch text test (similar to TestRunUserinfoJSONMixedBatch but with outputJSON=false) would close the gap.
65a1640 to
65cbfc2
Compare
|
@cblecker addressed all four: nil-guard on the JSON error entry, tightened the "- " match to require an exact username (not just substring) after the dash, and added tests for the mixed-batch case and the default text-mode renderer. PTAL 🙏🏽 |
| return err | ||
| } | ||
|
|
||
| hc := &http.Client{Timeout: defaultHTTPTimeout} |
There was a problem hiding this comment.
The hc client is shared between newGitHubClient and searchOwnerFiles. The go-github library mutates the provided http.Client's Transport in-place to inject Authorization: Bearer <token> headers. After newGitHubClient(hc) returns, every subsequent hc.Do(req) — including hound requests to cs.k8s.io — sends the GitHub token.
Fix: use separate http.Client instances for GitHub API and hound requests.
| default: | ||
| info.OwnerFiles = make([]OwnerFile, 0, len(hits)) | ||
| for _, hit := range hits { | ||
| content, err := fetchOwnerFileContent(ctx, hit.Repo, hit.Path) |
There was a problem hiding this comment.
The fail-open behavior here (keep the hit + add a warning when verification fails) is a deliberate design choice, but no test exercises it. If someone refactored this to drop unverifiable hits, no test would break.
Consider adding a subtest where stubGHCLI returns an error for one of two hits, then assert both hits are preserved and a warning is emitted.
Adds `korg userinfo <user>...` to answer the recurring question this repo
exists for: which Kubernetes orgs is a user in, with what role, and where
do they appear in OWNERS files.
Sources:
- GitHub user API for company / profile
- config/<org>/org.yaml (Members / Admins) for k8s org membership
- cs.k8s.io (hound) for OWNERS / OWNERS_ALIASES references
Behavior:
- Honors GITHUB_TOKEN / GH_TOKEN to avoid the 60/hr unauth limit. GitHub
and hound use separate http.Client instances, so the token is never
sent to cs.k8s.io
- Per-request context with a 30s timeout; SIGINT cancels in flight
- Multi-user batches run concurrently (errgroup, bounded to 4) with
output preserved in input order
- One bad username does not kill the batch; per-user errors render in
both text and JSON output, and the process exits non-zero
- Hound failures degrade to a warning instead of dropping org info
- `--output json` for scripting
OWNERS matching:
- Anchors the hound query on "- <user>" and keeps a hit only when the
YAML list item equals the username exactly, so prose mentions,
commented-out entries and substring near-misses ("- alice-bot" for
"alice") are all dropped. Surrounding quotes and trailing inline
comments are stripped first, so `- "alice"` and "- alice # area expert"
still match
- Each surviving hit is confirmed against the file's real content via
`gh api` to exclude emeritus-only entries, toggled by --verify-owners.
A hit that cannot be fetched is kept with a warning rather than dropped
- Results render as an aligned REPO / PATH / URL table; the URL uses
/blob/HEAD/ so the link resolves to the default branch
Tests:
- Table-driven coverage of the OWNERS match filter (quoted values, inline
comments, commented-out entries, substring near-misses), emeritus
exclusion, and the fail-open path when a hit cannot be verified
- Batch coverage for both output modes: input ordering, mixed
success/failure runs, and the text renderer's company / orgs fallbacks
- Asserts hound requests carry no Authorization header while GitHub
requests stay authenticated
Dependencies:
- adds github.com/google/go-github/v88 for the user API
- promotes golang.org/x/sync from indirect v0.2.0 to direct v0.8.0 for
errgroup
- go directive 1.22.4 -> 1.25.0
Signed-off-by: Nabarun Pal <pal.nabarun95@gmail.com>
65cbfc2 to
8b238be
Compare
|
/test pull-org-verify-all |
| return nil, fmt.Errorf("unexpected gh invocation: %v", args) | ||
| }) | ||
|
|
||
| ghHits := 0 |
There was a problem hiding this comment.
nit: ghHits is incremented but never read or asserted on — it's dead code. Either remove it or add an assertion like if ghHits == 0 { t.Error("expected at least one GitHub API call") } to make the intent explicit.
Adds
korg userinfo <user>...to answer the recurring question this repoexists for: which Kubernetes orgs is a user in, with what role, and where
do they appear in OWNERS files.
Sources:
Behavior:
and hound use separate http.Client instances, so the token is never
sent to cs.k8s.io
output preserved in input order
both text and JSON output, and the process exits non-zero
--output jsonfor scriptingOWNERS matching:
YAML list item equals the username exactly, so prose mentions,
commented-out entries and substring near-misses ("- alice-bot" for
"alice") are all dropped. Surrounding quotes and trailing inline
comments are stripped first, so
- "alice"and "- alice # area expert"still match
gh apito exclude emeritus-only entries, toggled by --verify-owners.A hit that cannot be fetched is kept with a warning rather than dropped
/blob/HEAD/ so the link resolves to the default branch
Tests:
comments, commented-out entries, substring near-misses), emeritus
exclusion, and the fail-open path when a hit cannot be verified
success/failure runs, and the text renderer's company / orgs fallbacks
requests stay authenticated
Dependencies:
errgroup
(This PR has gotten assistance from AI tools)