fix: issue #358 (automated) - #359
Conversation
…mmands P0 — auto-merge: - `github enable-auto-merge --number <n> [--method MERGE|SQUASH|REBASE] [--match-head-commit <sha>]` Uses the `enablePullRequestAutoMerge` GraphQL mutation. Never falls back to immediate merge when auto-merge is requested. - `github disable-auto-merge --number <n>` — `disablePullRequestAutoMerge` mutation. - `github enqueue-pr --number <n> [--method] [--match-head-commit <sha>]` Enqueues via `addPullRequestToMergeQueue` when the repo uses a merge queue. - `merge-pr` description now clarifies it is an immediate merge only. - `--match-head-commit` maps to GraphQL `expectedHeadOid`, preventing race conditions when another commit is pushed before the mutation fires. P1 — parity: - `github pr-status --number <n>` — GraphQL aggregation of review decision, mergeable state, draft flag, auto-merge request, and all check statuses (total/passed/failed/pending) in a single JSON object. - `github convert-to-draft --number <n>` — `convertPullRequestToDraft` mutation. - `github ready-for-review --number <n>` — `markPullRequestReadyForReview` mutation. - `github reopen-pr --number <n>` — PATCH with `state: open`. - `github add-labels / remove-label` — REST label management. - `github add-reviewers / remove-reviewers` — reviewer request management, supports both user logins and team slugs. - `github add-assignees / remove-assignees` — assignee management. Implementation notes: - All new mutations look up the PR's GraphQL `node_id` via a REST GET before firing, using the existing `node_id` field now declared on `GitHubPR`. - URL-encodes label names via the `new URL()` constructor (not `encodeURIComponent`, which would double-encode when passed through buildUrl). - 22 new unit tests covering all new methods. Closes #358 Co-authored-by: Sunny Kolattukudy <kolatts@users.noreply.github.com>
|
Claude finished @imagile-bot[bot]'s task in 4m 13s —— View job PR Review Complete
Overall: Well-structured addition of 12 new GitHub commands (auto-merge, merge queue, Requested Changes — 1 blocking issue:
Suggestions / Nits:
|
| gh.command('enable-auto-merge') | ||
| .description('Enable auto-merge on a pull request (merges automatically when all requirements are met)') | ||
| .requiredOption('--number <n>', 'Pull request number') | ||
| .addOption(new Option('--method <method>', 'Merge method').choices(['MERGE', 'SQUASH', 'REBASE'])) |
There was a problem hiding this comment.
Blocking — --method casing inconsistency
enable-auto-merge and enqueue-pr require UPPERCASE choices (MERGE, SQUASH, REBASE) while merge-pr uses lowercase (merge, squash, rebase). A user who runs:
pncli github merge-pr --method squash # ✓ works
pncli github enable-auto-merge --method squash # ✗ Invalid option: squashgets a confusing mismatch. The casing difference is justified internally (REST vs GraphQL enum), but the CLI contract should be uniform. Accept lowercase in both commands and uppercase-convert before passing to the GraphQL variable — or at minimum document the difference in --help.
Suggested fix for enable-auto-merge and enqueue-pr:
| .addOption(new Option('--method <method>', 'Merge method').choices(['MERGE', 'SQUASH', 'REBASE'])) | |
| .addOption(new Option('--method <method>', 'Merge method').choices(['merge', 'squash', 'rebase'])) |
Then in the action body:
mergeMethod: opts.method?.toUpperCase() as 'MERGE' | 'SQUASH' | 'REBASE' | undefined,| const passed = details.filter(d => d.conclusion === 'success' || d.status === 'success').length; | ||
| const failed = details.filter(d => | ||
| d.conclusion === 'failure' || d.conclusion === 'timed_out' || | ||
| d.conclusion === 'action_required' || d.status === 'failure' || d.status === 'error' | ||
| ).length; | ||
| const pending = details.filter(d => | ||
| d.status === 'queued' || d.status === 'in_progress' || d.status === 'pending' | ||
| ).length; |
There was a problem hiding this comment.
Suggestion — checks aggregation has an uncovered bucket
skipped, cancelled, and neutral CheckRun conclusions don't match any of the three filters, so they count in total but not in passed + failed + pending. On repos that use required status skipping (e.g. path-based skip conditions), consumers will see total: 5, passed: 2, failed: 0, pending: 1 and need to infer the remaining 2.
Consider either:
- Adding an
otherfield (orskipped) to the output, or - Counting
skipped/neutralaspassed(GitHub itself treats them as non-blocking)
At minimum, a comment here noting the gap would help future maintainers.
|
|
||
| // ── Labels ───────────────────────────────────────────────────────── | ||
|
|
||
| async addLabels(owner: string, repo: string, issueNumber: number, labels: string[]): Promise<{ labels: import('../../types/github.js').GitHubLabel[] }> { |
There was a problem hiding this comment.
Nit — inline import() in return type annotation
GitHubLabel and GitHubUser are already exported from ../../types/github.ts — add them to the existing import type { … } block at the top of the file rather than using inline dynamic imports in the signature. The inline form is valid TypeScript but unusual and harder to scan.
| ); | ||
| } | ||
|
|
||
| async removeReviewers(opts: AddReviewersOpts): Promise<void> { |
There was a problem hiding this comment.
Nit — misleading parameter type name
removeReviewers accepts AddReviewersOpts but the operation is a removal. The struct is identical so reusing is fine, but either rename it to ReviewersOpts / RequestedReviewersOpts, or add a type alias type RemoveReviewersOpts = AddReviewersOpts; so call sites and future readers aren't confused.
There was a problem hiding this comment.
Request Changes — one blocking UX issue
This is a solid addition: 12 new commands (auto-merge, merge queue, pr-status, draft lifecycle, labels, reviewers, assignees), clean GraphQL/REST separation, good test coverage, and the two-call pattern for node_id resolution is the right pragmatic choice. The pr-status aggregation is a useful one-stop query for agents.
Blocking
The --method flag on enable-auto-merge and enqueue-pr uses UPPERCASE choices (MERGE, SQUASH, REBASE) while merge-pr uses lowercase (merge, squash, rebase). This is a UX inconsistency — a user who copies a method value between commands gets an invalid-option error. The fix is to accept lowercase on the CLI and call .toUpperCase() before passing to the GraphQL variable (see inline comment on commands.ts:215).
Suggestions / Nits
pr-statuschecks aggregation:skipped/cancelled/neutralconclusions go intototalbut not intopassed + failed + pending. Worth anotherfield or treating them as non-blocking passes (see inline comment on client.ts:598-605).addLabelsandaddReviewersuse inlineimport()in return type positions forGitHubLabel/GitHubUser— both are already exported fromtypes/github.tsand should just be added to the top-of-file import block (client.ts:667).removeReviewersparameter type is namedAddReviewersOpts(client.ts:695) — worth renaming to a neutralReviewersOpts.
Closes #358