Skip to content

fix: issue #358 (automated) - #359

Open
imagile-bot[bot] wants to merge 1 commit into
mainfrom
claude/issue-358-20260821-2115
Open

fix: issue #358 (automated)#359
imagile-bot[bot] wants to merge 1 commit into
mainfrom
claude/issue-358-20260821-2115

Conversation

@imagile-bot

@imagile-bot imagile-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Closes #358

…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

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

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, pr-status, draft lifecycle, labels, reviewers, assignees). GraphQL/REST separation is clean, test coverage is thorough, and the two-call node_id resolution pattern is the right pragmatic approach.

Requested Changes — 1 blocking issue:

--method casing inconsistency (commands.ts:215, commands.ts:247)
enable-auto-merge and enqueue-pr use UPPERCASE choices (MERGE, SQUASH, REBASE) while merge-pr uses lowercase (merge, squash, rebase). Copying a method value between commands gives an invalid-option error. Fix: accept lowercase on the CLI and call .toUpperCase() before the GraphQL variable.

Suggestions / Nits:

  • pr-status checks aggregation gap (client.ts:598-605): skipped/cancelled/neutral conclusions count in total but not in passed + failed + pending. Add an other bucket or fold them into passed.
  • Inline import() in type positions (client.ts:667, client.ts:685): GitHubLabel and GitHubUser should be added to the top-of-file import block rather than using inline import().
  • Misleading parameter type name (client.ts:695): removeReviewers accepts AddReviewersOpts — rename to ReviewersOpts or a neutral alias.

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']))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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: squash

gets 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:

Suggested change
.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,

Fix this →

Comment on lines +598 to +605
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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 other field (or skipped) to the output, or
  • Counting skipped/neutral as passed (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[] }> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix this →

);
}

async removeReviewers(opts: AddReviewersOpts): Promise<void> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-status checks aggregation: skipped/cancelled/neutral conclusions go into total but not into passed + failed + pending. Worth an other field or treating them as non-blocking passes (see inline comment on client.ts:598-605).
  • addLabels and addReviewers use inline import() in return type positions for GitHubLabel/GitHubUser — both are already exported from types/github.ts and should just be added to the top-of-file import block (client.ts:667).
  • removeReviewers parameter type is named AddReviewersOpts (client.ts:695) — worth renaming to a neutral ReviewersOpts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GitHub PR automerge and high-value gh parity commands

0 participants