Use login-based assignee mutation on github.com#13009
Conversation
When ActorAssignees is true (github.com), pass assignee logins directly to the ReplaceActorsForAssignable mutation instead of resolving logins to node IDs. This eliminates the need to bulk fetch all assignable users/actors and fixes a bug where providing assignees via CLI flag and then interactively adding metadata would fail with 'not found' because the cached MetadataResult had no assignee data. Changes: - Set state.ActorAssignees = true in pr create (was missing) - AddMetadataToIssueParams: pass assigneeLogins when ActorAssignees is true, skip fetch and ID resolution entirely - CreatePullRequest/IssueCreate: call ReplaceActorsForAssignableByLogin after creation to assign via logins - Consolidate replaceActorsForAssignable mutation into api/ package (ReplaceActorsForAssignableByLogin + ReplaceActorsForAssignableByID) - Remove duplicate replaceActorAssigneesForEditable from editable_http.go - Add TODO replaceActorsByLoginCleanup markers on edit paths Fixes #13000 Co-authored-by: Copilot <[email protected]>
…flag flows When ActorAssignees is true (github.com), the --add-assignee and --remove-assignee flag flows now pass logins directly to ReplaceActorsForAssignableByLogin instead of bulk fetching all assignable actors and resolving logins to node IDs. Changes: - New AssigneeLogins() method on Editable that computes the final login set (defaults + add - remove) without ID resolution - UpdateIssue: call AssigneeLogins + ByLogin when ActorAssignees is true - EditableOptionsFetch: skip assignee bulk fetch for flag flows on github.com (only fetch on GHES where ID resolution is needed) Co-authored-by: Copilot <[email protected]>
The assigneeSearchFunc previously accumulated actors into editable.Metadata.AssignableActors so that MembersToIDs could later resolve logins to node IDs. Now that the edit flow uses AssigneeLogins + ReplaceActorsForAssignableByLogin on github.com, this accumulation is no longer needed. Co-authored-by: Copilot <[email protected]>
Add AssigneeSearchFunc to gh issue edit interactive flow, matching the pattern already used in gh pr edit. This eliminates the bulk RepositoryAssignableActors fetch for interactive assignee selection, using dynamic SuggestedAssignableActors search instead. Also clean up pr edit assigneeSearchFunc signature to remove the unused editable parameter (no longer needed after removing the actor accumulation hack). Co-authored-by: Copilot <[email protected]>
- Fix tests: assert logins (not display names) in actorLogins - Remove dead ReplaceActorsForAssignableByID (no callers) - Extract shared AssigneeSearchFunc to pkg/cmd/pr/shared/editable.go - Remove duplicate assigneeSearchFunc from pr/edit and issue/edit Co-authored-by: Copilot <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR fixes gh pr create -a @me failing when interactive metadata is added during PR creation by switching github.com assignee handling to a login-based mutation path (skipping node ID resolution and bulk assignable-actor fetches), while keeping GHES on the legacy ID-based flow.
Changes:
- Enable actor-based assignee handling in
pr create(state.ActorAssignees = true) and pass assignee logins through to mutations on github.com. - Add a shared
ReplaceActorsForAssignableByLoginhelper and use it for PR/issue creation and edit flows on github.com. - Rework edit flows to avoid bulk assignee metadata fetches on github.com and share an assignee search function; fix
Editable.Clone()to preserve search funcs.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/cmd/pr/shared/params.go | Avoid assignee ID resolution on github.com; pass assigneeLogins instead. |
| pkg/cmd/pr/shared/editable_http.go | Use the shared login-based replace-actors mutation for actor assignees; remove local mutation helper. |
| pkg/cmd/pr/shared/editable.go | Add AssigneeLogins(), preserve search funcs in Clone(), reduce assignee metadata fetching, and extract shared AssigneeSearchFunc. |
| pkg/cmd/pr/edit/edit.go | Switch to the shared assignee search function. |
| pkg/cmd/pr/edit/edit_test.go | Update expectations to assert actorLogins usage and no assignee metadata prefetch. |
| pkg/cmd/pr/create/create.go | Ensure actor assignees are enabled when ActorIsAssignable is available. |
| pkg/cmd/pr/create/create_test.go | Expect assignee assignment via ReplaceActorsForAssignable with actorLogins. |
| pkg/cmd/issue/edit/edit.go | Wire the shared assignee search function for interactive actor-assignee selection. |
| pkg/cmd/issue/edit/edit_test.go | Remove bulk assignable-actors fetch stubs; assert actorLogins usage. |
| pkg/cmd/issue/create/create_test.go | Expect post-create actor assignment via ReplaceActorsForAssignable with actorLogins (and include created issue id). |
| api/queries_pr.go | Assign assignees post-create via login-based replace-actors mutation; add ReplaceActorsForAssignableByLogin. |
| api/queries_issue.go | Allow assigneeLogins param and perform post-create login-based assignment. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…adataSurvey Wire up MultiSelectWithSearch for assignees in MetadataSurvey, replacing the static MultiSelect that required bulk fetching all assignable actors. This applies to both gh pr create and gh issue create interactive flows when selecting assignees via the 'Add metadata' prompt. Changes: - Add assigneeSearchFunc parameter to MetadataSurvey - Skip assignee bulk fetch when search func is available - New SearchRepoAssignableActors API function for repo-level search (create flows have no issue/PR node ID yet) - New RepoAssigneeSearchFunc in shared editable.go - Refactor actorsToSearchResult helper shared by both search functions Co-authored-by: Copilot <[email protected]>
f11b008 to
11f177a
Compare
| useReviewerSearch := state.ActorReviewers && reviewerSearchFunc != nil | ||
| useAssigneeSearch := state.ActorAssignees && assigneeSearchFunc != nil | ||
| metadataInput := api.RepoMetadataInput{ | ||
| Reviewers: isChosen("Reviewers") && !useReviewerSearch, | ||
| TeamReviewers: isChosen("Reviewers") && !useReviewerSearch, | ||
| Assignees: isChosen("Assignees"), | ||
| ActorAssignees: isChosen("Assignees") && state.ActorAssignees, | ||
| Assignees: isChosen("Assignees") && !useAssigneeSearch, | ||
| ActorAssignees: isChosen("Assignees") && !useAssigneeSearch && state.ActorAssignees, | ||
| Labels: isChosen("Labels"), | ||
| ProjectsV1: isChosen("Projects") && projectsV1Support == gh.ProjectsV1Supported, | ||
| ProjectsV2: isChosen("Projects"), | ||
| Milestones: isChosen("Milestone"), |
There was a problem hiding this comment.
Why is there no ReviewerActors check? ActorReviewers?
…lot expansion The inline replaceSpecialAssigneeNames closures in AssigneeIds and AssigneeLogins were duplicated. Extract them into an exported SpecialAssigneeReplacer type that consolidates MeReplacer and CopilotReplacer into a single ReplaceSlice call, parameterised by actorAssignees and copilotUseLogin. Adopt the new type in the issue create flow as well, replacing the manual MeReplacer + conditional CopilotReplacer sequence. Co-authored-by: Copilot <[email protected]>
|
Reviewer/assignee actor-mode asymmetry Leaving a note here for future context since this came up during review. When GitHub.com introduced actor-based APIs (the ability to assign Copilot, bots, etc.), we needed to change how the CLI fetches, displays, and mutates assignees and reviewers. The old GHES path resolves everything through node IDs: you fetch all assignable users, present them, and send IDs to the mutation. The new actor path works with logins directly and supports search-based selection. I wired up the assignee side of this pretty thoroughly, but the reviewer side ended up taking a different shape, and honestly I'm frustrated with the asymmetry. Here's what I mean: How assignees work: There are two flows, create (
Each layer has an explicit flag that says "we're in actor mode." The flag flows top-to-bottom through both create and edit. How reviewers work: ✅ = the same as assignees, ❌ = different
So the mutation layer and the top-level state are fine, but the middle of the stack (the editable struct, the metadata fetch, and the survey option building) all have the assignee actor path but not the reviewer equivalent. Reviewers work today because search-func-presence happens to be a reliable proxy for "are we in actor mode," but it's a different pattern than what assignees use. What should we do about it? I'm not sure the right fix is just adding Not addressing in this PR since the scope is assignee metadata for create/edit flows. The reviewer paths work correctly. I'll open a follow-up PR to tackle this frustrating asymmetry. |
Two bugs introduced in #13009 found during acceptance testing: 1. `pr create --assignee @copilot` sent the literal `@copilot` to the API because NewIssueState only ran MeReplacer on assignees, not CopilotReplacer. Fixed by switching to SpecialAssigneeReplacer (which handles both @me and @copilot) like issue create already does. 2. The replaceActorsForAssignable mutation requires the [bot] suffix on bot actor logins (e.g. `copilot-swe-agent[bot]`), unlike requestReviewsByLogin which has a separate botLogins field. Added the suffix in ReplaceActorsForAssignableByLogin for CopilotAssigneeLogin. Co-authored-by: Copilot <[email protected]>
Fixes #13000
Description
gh pr create -a @mefails withcould not assign user: 'xx' not foundwhen the user interactively adds metadata (reviewers, labels, etc.) during the PR creation flow, because the assignee login cannot be resolved to a node ID from the cached metadata that only contains the interactively selected fields. This has been broken since the actor assignee work shipped a few weeks ago.While investigating, we found that all assignee flows on github.com were still going through an unnecessary bulk fetch and ID resolution step, even though the API already supports assigning by login directly. This PR fixes the original bug and migrates all assignee paths to use the login-based approach.
To Fix
This PR migrates all github.com assignee flows to pass logins directly to the mutation, and wires up the multi-select with search UX. This experience avoids bulk fetching of IDs. GHES retains the legacy ID-based path unchanged.
Before
gh pr create -agh pr create -a+ interactive metadatagh pr createinteractive assigneesgh issue create -agh issue createinteractive assigneesgh pr editinteractivegh pr edit --add-assigneegh issue editinteractivegh issue edit --add-assigneeAfter
gh pr create -agh pr create -a+ interactive metadatagh pr createinteractive assigneesgh issue create -agh issue createinteractive assigneesgh pr editinteractivegh pr edit --add-assigneegh issue editinteractivegh issue edit --add-assigneeKey Changes
state.ActorAssignees = trueinpr createthat caused the original bugreplaceActorsForAssignablemutation via itsactorLoginsfield. No more fetching all assignable actors just to resolve a login to a node ID--add-assigneeand--remove-assigneeflag paths for bothpr editandissue editskip the bulk fetch entirely on github.com. A newAssigneeLogins()method computes the final set from logins directlyMultiSelectWithSearchon github.com:pr createandissue createviaMetadataSurvey(newassigneeSearchFuncparameter, backed by newSearchRepoAssignableActorsrepo-level API)issue editwired up withAssigneeSearchFunc(previously missing, was using static list)pr editalready had search, now simplified (actor accumulation hack removed)AssigneeSearchFuncextracted to shared location,actorsToSearchResulthelper shared by both repo-level and node-level search functionsEditable.Clone()was silently droppingAssigneeSearchFuncandReviewerSearchFuncReviewer Notes
replaceActorsForAssignablemutation has always acceptedactorLoginsalongsideactorIdson github.com. We just never used it until nowAssigneeIds()onEditableis now only called on GHES. On github.com,AssigneeLogins()is used insteadMetadataSurveynow accepts anassigneeSearchFuncparameter alongside the existingreviewerSearchFuncSearchRepoAssignableActors(repo-level, no issue/PR ID needed), edit flows useSuggestedAssignableActors(node-level)RepositoryAssignableUsers+assigneeIdsAcceptance & Regression Testing
16 scenarios tested across github.com and GHES (3.20), all passing: Acceptance test results
Covers
pr create,issue create,pr edit(flags + interactive),issue edit(flags + interactive), multi-issue edit, remove-all-assignees, and zero-bulk-fetch verification on both hosts.The full automated acceptance test suite (
go test -tags=acceptance ./acceptance) was also run locally against github.com with all relevant tests passing.