-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Assign Copilot during gh issue create
#11279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- updated command documentation for new `--assignee @copilot` syntax - updated `gh issue create` logic with feature detection for actor availability - fixed bug where `--assignee` would not select default assignees due to login vs display name mismatch - updated survey prompt logic to avoid parsing prompt options in favor of correlating with assignee / actor source One thing that is not included in these changes is incorporating the GraphQL mutation to replace assignees with actors, which I will continue iterating on.
This commit refactors how `gh issue create` and `gh pr create` retrieve information needed to resolve metadata to be more in line with the approach used in `gh issue edit` and `gh pr edit`. Previously, both commands used `prshared.fillMetadata(...)` function to retrieve assignees, reviewers, labels, and teams outside of `api.RepoMetadata(..)`. Now, these commands will consistently use the same logic and data for resolving metadata.
This commit is primarily focused on fixing the existing `gh issue create` tests with the changes to the underlying queries retrieving the data for resolving metadata. Additionally, a new test case for `gh issue create --web --assignee @copilot` was added to mirror existing tests. While exercising this capability, I found out the web UI apparently wants `copilot` instead of the `copilot-swe-agent` login, so changes to address that were a part of this commit.
These are the minimum fixes necessary to repair `gh pr create` tests after refactoring the underlying metadata resolution logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR expands gh issue create to support assigning Copilot during issue creation through multiple methods - interactively, non-interactively with --assignee @copilot, and via web browser. The implementation includes refactoring metadata retrieval logic for both issues and pull requests to support bots and actors.
Key changes:
- Added Copilot assignee support to
gh issue createcommand - Refactored metadata retrieval to use
RepoMetadatainstead ofRepoResolveMetadataIDs - Enhanced
CopilotReplacerto handle web mode differently
Reviewed Changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/cmd/issue/create/create.go | Added Copilot assignee support and ActorAssignees feature detection |
| pkg/cmd/pr/shared/survey.go | Enhanced metadata survey to handle actors vs users for assignees |
| pkg/cmd/pr/shared/state.go | Added ActorAssignees boolean field to IssueMetadataState |
| pkg/cmd/pr/shared/params.go | Refactored metadata retrieval and enhanced CopilotReplacer with web mode |
| pkg/cmd/pr/shared/editable.go | Updated CopilotReplacer usage to specify non-web mode |
| pkg/cmd/pr/create/create_test.go | Updated tests to use new metadata retrieval approach |
| pkg/cmd/issue/create/create_test.go | Added Copilot assignee tests and updated existing tests |
| api/queries_repo.go | Removed deprecated RepoResolveMetadataIDs function |
| api/queries_repo_test.go | Removed tests for deprecated function |
| for _, i := range selected { | ||
| values.Assignees = append(values.Assignees, assignees[i]) | ||
| // Previously, this logic relied upon `assignees` being in `<login>` or `<login> (<name>)` form, | ||
| // however the inclusion of actors breaks this convention. | ||
| // Instead, we map the selected indexes to the source that populated `assignees` rather than | ||
| // relying on parsing the information out. | ||
| if state.ActorAssignees { | ||
| values.Assignees = append(values.Assignees, metadataResult.AssignableActors[i].Login()) | ||
| } else { | ||
| values.Assignees = append(values.Assignees, metadataResult.AssignableUsers[i].Login()) | ||
| } | ||
| } |
Copilot
AI
Jul 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The logic for mapping selected indexes to source data could be extracted into a helper function to improve readability and reduce the complexity of this conditional block.
pkg/cmd/pr/shared/params.go
Outdated
| // CopilotReplacer resolves usages of `@copilot` to Copilot's login. | ||
| type CopilotReplacer struct{} | ||
| type CopilotReplacer struct { | ||
| webMode bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: I was mulling over how this is called webMode which does a good job of indicating when you'd want to use this property, but less so in communicating what it does. It made me wonder if something like useDisplayName might be more descriptive of the behavior. That comes at a trade-off of not really communicating when you'd want to use that, but perhaps it could be supplemented by a code comment.
I'll leave it up to you to decide if you like that idea or not 🙂 Either way, feel free to just resolve this comment when you've read it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a very good point and I'm open to rename it. 🤔 Since Copilot's display name is Copilot (AI), would there be confusion or errors by using displayName language?
pkg/cmd/pr/shared/params.go
Outdated
| // When Copilot is used as an assignee in web mode, the login is not used. | ||
| if r.webMode { | ||
| return "copilot" | ||
| } | ||
| return handle | ||
| return api.CopilotActorLogin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: do you think there would be value in returning an exported constant like api.CopilotActorDisplayName?
I'm not convinced there's value in it, which is why this is a question and not a suggestion. My intuition is to desire consistency with the existing return value, but that's pretty much the only motivation behind me bringing this up 🤪
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm open to the idea. How would this work given it's display name is Copilot (AI) in the existing experience?
| var assignees []string | ||
| for _, u := range metadataResult.AssignableUsers { | ||
| assignees = append(assignees, u.DisplayName()) | ||
| var assigneesDefault []string | ||
| if state.ActorAssignees { | ||
| for _, u := range metadataResult.AssignableActors { | ||
| assignees = append(assignees, u.DisplayName()) | ||
|
|
||
| if slices.Contains(state.Assignees, u.Login()) { | ||
| assigneesDefault = append(assigneesDefault, u.DisplayName()) | ||
| } | ||
| } | ||
| } else { | ||
| for _, u := range metadataResult.AssignableUsers { | ||
| assignees = append(assignees, u.DisplayName()) | ||
|
|
||
| if slices.Contains(state.Assignees, u.Login()) { | ||
| assigneesDefault = append(assigneesDefault, u.DisplayName()) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: This feels like there is an opportunity to collapse these into a single loop since the logic in each loop is the same aside from the set we're iterating through. I'll checkout the code and try it out - if it's fruitful I'll post a suggestion.
| r.Register( | ||
| httpmock.GraphQL(`query RepositoryInfo\b`), | ||
| httpmock.StringResponse(` | ||
| { "data": { "repository": { | ||
| "id": "REPOID", | ||
| "hasIssuesEnabled": true | ||
| } } }`)) | ||
| { "data": { "repository": { | ||
| "id": "REPOID", | ||
| "hasIssuesEnabled": true | ||
| } } }`)) | ||
| r.Register( | ||
| httpmock.GraphQL(`mutation IssueCreate\b`), | ||
| httpmock.GraphQLMutation(` | ||
| { "data": { "createIssue": { "issue": { | ||
| "URL": "https://github.com/OWNER/REPO/issues/12" | ||
| } } } } | ||
| `, func(inputs map[string]interface{}) { | ||
| { "data": { "createIssue": { "issue": { | ||
| "URL": "https://github.com/OWNER/REPO/issues/12" | ||
| } } } } | ||
| `, func(inputs map[string]interface{}) { | ||
| assert.Equal(t, "title", inputs["title"]) | ||
| assert.Equal(t, "body", inputs["body"]) | ||
| })) | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: I have a hard time understanding test cases formatted this way, so I realigned the GraphQL JSON responses. I would like to clean up some of the other cases if others find it helpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always a fan of better indentation/readability over here 👍
Thanks to @BagToad, this commit refactors the argument to `NewCopilotReplacer(bool)` from being where this is used to what it effect is has. Because there is already precedence for display name being `<login> (<name>)`, I worried there would be confusion for `Copilot (AI)` being display name for assignees and reviewers but `Copilot` when going to GitHub.com UI. Instead, I renamed the argument based on whether the login is returned / replaced.
Based on PR feedback from @BagToad, this commit creates a new constant for the Copilot bot name, which is used in the assignee / reviewer selection as well as replacing `@copilot` when going to GitHub.com UI
In refactoring how this parameter works, I forgot to update the related tests to match.
BagToad
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 🚀
Manual tests also look good 👍
It's very cool you were able to swap to the shared api.RepoMetadata. I compared behaviors and I don't see anything jumping out as concerning byproducts of this change.
I responded to you in https://github.com/cli/cli/pull/11279/files#r2211313179 regarding whether to conditionalize the copilot replacer based on actor support, but I don't think a decision either way on that should block this.
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [cli/cli](https://github.com/cli/cli) | minor | `v2.74.2` -> `v2.76.1` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>cli/cli (cli/cli)</summary> ### [`v2.76.1`](https://github.com/cli/cli/releases/tag/v2.76.1): GitHub CLI 2.76.1 [Compare Source](cli/cli@v2.76.0...v2.76.1) #### `gh pr create` regression fix This release fixes a regression introduced in `v2.76.0` where organization teams were retrieved outside of intentional use cases. This caused problems for GitHub Enterprise Server users using the GitHub Actions automatic token that does not have access to organization teams. For more information, see cli/cli#11360 #### What's Changed ##### 🐛 Fixes - Fix: `gh pr create`, only fetch teams when reviewers contain a team by [@​BagToad](https://github.com/BagToad) in cli/cli#11361 ##### 📚 Docs & Chores - add tenancy aware for san matcher by [@​ejahnGithub](https://github.com/ejahnGithub) in cli/cli#11261 - Run Lint and Tests on `push` to `trunk` branch by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11325 - update ownership of pkg/cmd/release/shared/ by [@​ejahnGithub](https://github.com/ejahnGithub) in cli/cli#11326 - Automate spam issue detection by [@​babakks](https://github.com/babakks) in cli/cli#11316 - Improve `api` `--preview` docs by [@​jsoref](https://github.com/jsoref) in cli/cli#11274 - Incorporate govulncheck into workflows by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11332 - chore(deps): bump advanced-security/filter-sarif from 1.0.0 to 1.0.1 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11298 - chore(deps): bump github.com/sigstore/sigstore-go from 1.0.0 to 1.1.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11307 **Full Changelog**: cli/cli@v2.76.0...v2.76.1 ### [`v2.76.0`](https://github.com/cli/cli/releases/tag/v2.76.0): GitHub CLI 2.76.0 [Compare Source](cli/cli@v2.75.1...v2.76.0) ####Copilot Coding Agent Support GitHub Copilot Pro+ and Copilot Enterprise subscribers can now assign issues to GitHub Copilot during issue creation using: - Command-line flag: `gh issue create --assignee @​copilot` - Launching web browser: `gh issue create --assignee @​copilot --web` - Or interactively selecting `Copilot (AI)` as assignee in `gh issue create` metadata For more details, refer to [the full changelog post for Copilot coding agent](https://github.blog/changelog/2025-05-19-github-copilot-coding-agent-in-public-preview/). #### What's Changed ##### ✨ Features - Assign Copilot during `gh issue create` by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11279 - Display immutable field in `release view` command by [@​bdehamer](https://github.com/bdehamer) in cli/cli#11251 ##### 🐛 Fixes - FIX: Do not fetch logs for skipped jobs by [@​babakks](https://github.com/babakks) in cli/cli#11312 - Transform `extension` and `filename` qualifiers into `path` qualifier for web code search by [@​samcoe](https://github.com/samcoe) in cli/cli#11211 ##### 📚 Docs & Chores - FIX: Workflow does not contain permissions by [@​BagToad](https://github.com/BagToad) in cli/cli#11322 - Add automated feature request response workflow by [@​BagToad](https://github.com/BagToad) in cli/cli#11299 **Full Changelog**: cli/cli@v2.75.1...v2.76.0 ### [`v2.75.1`](https://github.com/cli/cli/releases/tag/v2.75.1): GitHub CLI 2.75.1 [Compare Source](cli/cli@v2.75.0...v2.75.1) #### What's Changed ##### 🐛 Fixes - Ensure hostnames are visible in CLI website by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11295 - Revert "Fix: `gh pr create` prioritize `--title` and `--body` over `--fill` when `--web` is present" by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11300 ##### 📚 Docs & Chores - Ensure go directive is always .0 version in bump by [@​williammartin](https://github.com/williammartin) in cli/cli#11259 - Minor (1-word) documentation typo in generated `~/.config/gh/config.yml` by [@​kurahaupo](https://github.com/kurahaupo) in cli/cli#11246 - Automate closing of stale issues by [@​babakks](https://github.com/babakks) in cli/cli#11268 - Filter the `third-party/` folder out of CodeQL results by [@​BagToad](https://github.com/BagToad) in cli/cli#11278 - Exclude `third-party` source from golangci-lint by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11293 #####
Dependencies - Bump Go to 1.24.5 by [@​github-actions](https://github.com/github-actions)\[bot] in cli/cli#11255 - chore(deps): bump github.com/sigstore/protobuf-specs from 0.4.3 to 0.5.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11263 - chore(deps): bump golang.org/x/term from 0.32.0 to 0.33.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11266 - chore(deps): bump golang.org/x/sync from 0.15.0 to 0.16.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11264 - chore(deps): bump golang.org/x/text from 0.26.0 to 0.27.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11265 - chore(deps): bump golang.org/x/crypto from 0.39.0 to 0.40.0 by [@​dependabot](https://github.com/dependabot)\[bot] in cli/cli#11275 #### New Contributors - [@​kurahaupo](https://github.com/kurahaupo) made their first contribution in cli/cli#11246 - [@​github-actions](https://github.com/github-actions)\[bot] made their first contribution in cli/cli#11255 **Full Changelog**: cli/cli@v2.75.0...v2.75.1 ### [`v2.75.0`](https://github.com/cli/cli/releases/tag/v2.75.0): GitHub CLI 2.75.0 [Compare Source](cli/cli@v2.74.2...v2.75.0) #### What's Changed ##### ✨ Features - init release verify subcommands by [@​ejahnGithub](https://github.com/ejahnGithub) in cli/cli#11018 - Embed Windows resources (VERSIONINFO) during build by [@​babakks](https://github.com/babakks) in cli/cli#11048 - Support `--no-repos-selected` on `gh secret set` by [@​williammartin](https://github.com/williammartin) in cli/cli#11217 ##### 🐛 Fixes - Fix: `gh pr create` prioritize `--title` and `--body` over `--fill` when `--web` is present by [@​dankrzeminski32](https://github.com/dankrzeminski32) in cli/cli#10547 - fix: get token for active user instead of blank if possible by [@​anuraaga](https://github.com/anuraaga) in cli/cli#11038 - Use Actions API to retrieve job run logs as a fallback mechanism by [@​babakks](https://github.com/babakks) in cli/cli#11172 - Fix query object state mutation during pagination by [@​babakks](https://github.com/babakks) in cli/cli#11244 - Handle `HTTP 404` when deleting remote branch in `pr merge` by [@​babakks](https://github.com/babakks) in cli/cli#11234 ##### 📚 Docs & Chores - chore: fix function name by [@​jinjingroad](https://github.com/jinjingroad) in cli/cli#11149 - chore: update Go version to 1.24 in devcontainer configuration and docs by [@​tMinamiii](https://github.com/tMinamiii) in cli/cli#11158 - Ensure lint workflow checks whether 3rd party license and code is up to date by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11047 - docs: install\_linux.md: add Solus linux install instructions by [@​chax](https://github.com/chax) in cli/cli#10823 - Fix missing newline in install\_linux.md by [@​BagToad](https://github.com/BagToad) in cli/cli#11160 - Ensure automation uses pinned go-licenses version by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11161 - Add `workflow_dispatch` support to MR Help Wanted check by [@​BagToad](https://github.com/BagToad) in cli/cli#11179 - Remove unused `GH_TOKEN` env variable from workflow by [@​BagToad](https://github.com/BagToad) in cli/cli#11190 - Add workflow to automate go version bumping by [@​williammartin](https://github.com/williammartin) in cli/cli#11189 - Fix inconsistent use of tabs and spaces by [@​Stefan-Heimersheim](https://github.com/Stefan-Heimersheim) in cli/cli#11194 - Decouple arg parsing from MR finder by [@​babakks](https://github.com/babakks) in cli/cli#11192 - docs: consistently use `apt` in installation instructions by [@​tklauser](https://github.com/tklauser) in cli/cli#11216 - Ensure bump go script has git user configured by [@​williammartin](https://github.com/williammartin) in cli/cli#11229 - Inject token into bump-go workflow by [@​williammartin](https://github.com/williammartin) in cli/cli#11233 - Reinstating Primer Style CLI content within `cli/cli` repository by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11060 - Add setup-go to bump-go workflow by [@​williammartin](https://github.com/williammartin) in cli/cli#11237 - Ensure GoReleaser does not break on Mac OS and Linux when skipping Windows `.rsyso` generation script by [@​andyfeller](https://github.com/andyfeller) in cli/cli#11257 #####
Dependencies - Bump all dependencies except dev-tunnels by [@​williammartin](https://github.com/williammartin) in cli/cli#11203 - Update microsoft dev-tunnels to v0.1.13 by [@​williammartin](https://github.com/williammartin) in cli/cli#11205 - Consume dependabot minor versions for go modules by [@​williammartin](https://github.com/williammartin) in cli/cli#11213 #### New Contributors - [@​jinjingroad](https://github.com/jinjingroad) made their first contribution in cli/cli#11149 - [@​tMinamiii](https://github.com/tMinamiii) made their first contribution in cli/cli#11158 - [@​chax](https://github.com/chax) made their first contribution in cli/cli#10823 - [@​dankrzeminski32](https://github.com/dankrzeminski32) made their first contribution in cli/cli#10547 - [@​anuraaga](https://github.com/anuraaga) made their first contribution in cli/cli#11038 - [@​Stefan-Heimersheim](https://github.com/Stefan-Heimersheim) made their first contribution in cli/cli#11194 **Full Changelog**: cli/cli@v2.74.2...v2.75.0 </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90Il19-->
This should be a workaround for cli/cli#11279
Fixes github/cli#920
This pull request expands
gh issue createto support assigning Copilot during issue creation in multiple ways:Add metadataexperiencegh issue create --assignee @copilotgh issue create --assignee @copilot --webUnderlying changes that affect how
gh pr createworks but not the user experiencegh issue createandgh pr createused a custom bit of logic for looking up information to resolve metadata:cli/api/queries_repo.go
Lines 1045 to 1142 in 6419157
This logic needed to change to support Copilot and other bots. Additionally, there was a concern about inconsistent approaches to retrieving this data and the affect it would have on the 2 commands.
As such, this pull request includes a minor refactor to retrieving data to resolve metadata without changing the
gh pr createexperience.Work remaining
gh issue createtests aroundassignableUserson GHES versussuggestedActorson GHECgh pr createtests around changes around resolving metadata