Add GitHub UserList management tools - #3202
Open
ppoffice wants to merge 2 commits into
Open
Conversation
Add GraphQL-backed tools for listing, creating, updating, deleting, and managing repository membership in GitHub UserLists. Include bounded cursor pagination, private-membership scope checks, IFC labeling, unit coverage, tool snapshots, and generated documentation.
Exercise the complete UserList lifecycle against GitHub: create, rename, add a repository, verify membership, remove the repository, delete the list, and clean up the temporary repository.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Membership replacement can overwrite concurrent changes, and the E2E pagination and cleanup issues must be addressed.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds GitHub UserList management, including paginated reads, CRUD operations, and repository membership tools.
Changes:
- Adds seven UserList and membership tools.
- Adds OAuth scope handling and IFC labels.
- Adds documentation, snapshots, unit tests, and E2E coverage.
File summaries
| File | Description |
|---|---|
README.md |
Documents the new tools. |
pkg/scopes/scopes.go |
Supports the user OAuth scope. |
pkg/scopes/scopes_test.go |
Tests scope registration. |
pkg/ifc/ifc.go |
Adds UserList IFC labeling. |
pkg/ifc/ifc_test.go |
Tests UserList labeling. |
pkg/http/oauth/oauth_test.go |
Updates supported-scope expectations. |
pkg/github/user_lists.go |
Implements UserList GraphQL tools. |
pkg/github/user_lists_test.go |
Tests UserList behavior. |
pkg/github/tools.go |
Registers the new tools. |
pkg/github/tool_scopes.go |
Adds dynamic read-scope policy. |
pkg/github/tool_scopes_test.go |
Tests scope metadata. |
pkg/github/__toolsnaps__/update_user_list.snap |
Snapshots update schema. |
pkg/github/__toolsnaps__/remove_repository_from_list.snap |
Snapshots remove schema. |
pkg/github/__toolsnaps__/list_user_lists.snap |
Snapshots list schema. |
pkg/github/__toolsnaps__/list_user_list_items.snap |
Snapshots item-list schema. |
pkg/github/__toolsnaps__/delete_user_list.snap |
Snapshots delete schema. |
pkg/github/__toolsnaps__/create_user_list.snap |
Snapshots create schema. |
pkg/github/__toolsnaps__/add_repository_to_list.snap |
Snapshots add schema. |
e2e/e2e_test.go |
Adds UserList lifecycle E2E coverage. |
Review details
Suppressed comments (2)
pkg/github/user_lists_test.go:211
- The GraphQL schema makes
descriptionnullable, but this response uses an empty string, so the new tests never exercise the normalnullreturned for a list without a description. Usenullhere (or add an equivalent case) to verify that decoding a description-less list succeeds, as claimed in the PR coverage.
return http.StatusOK, `{"data":{"viewer":{"lists":{"nodes":[{"id":"list-2","name":"Second","description":"","isPrivate":true}],"pageInfo":{"hasNextPage":false,"hasPreviousPage":true,"startCursor":"second","endCursor":"second"},"totalCount":2}}}}`
pkg/github/user_lists_test.go:65
- The PR summary states that nullable descriptions are covered, but both list cases return non-null strings and the update cases never exercise an explicitly empty description. Add a GraphQL response with
"description": nullfor the read path and an update case withdescription: ""to verify both nullable decoding and clearing semantics.
map[string]any{
"id": githubv4.ID("list-1"),
"name": githubv4.String("My list"),
"description": githubv4.String("A list"),
"isPrivate": githubv4.Boolean(true),
- Files reviewed: 19/19 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+443
to
+446
| input := githubv4.UpdateUserListsForItemInput{ | ||
| ItemID: repoID, | ||
| ListIDs: result, | ||
| } |
Comment on lines
+2018
to
+2028
| currentListName := listName | ||
| t.Cleanup(func() { | ||
| t.Logf("Cleaning up list %q...", currentListName) | ||
| resp, err := mcpClient.CallTool(ctx, &mcp.CallToolParams{ | ||
| Name: "delete_user_list", | ||
| Arguments: map[string]any{"name": currentListName}, | ||
| }) | ||
| if err == nil && resp.IsError { | ||
| t.Logf("Cleanup: failed to delete list %q: %+v", currentListName, resp) | ||
| } | ||
| }) |
Comment on lines
+2105
to
+2108
| resp, err = mcpClient.CallTool(ctx, &mcp.CallToolParams{ | ||
| Name: "list_user_lists", | ||
| Arguments: map[string]any{"include_items": true}, | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds GitHub UserList support to the existing
stargazerstoolset. UserLists are the lists available at github.com/stars for organizing repositories independently of star state.Tools
list_user_lists: cursor-paginated list metadata with an optional bounded item preview.list_user_list_items: cursor-paginated repositories for one list.create_user_listupdate_user_listdelete_user_listadd_repository_to_listremove_repository_from_listDesign
updateUserListsForItemreplaces complete membership, so mutations first derive and preserve existing memberships, including memberships found beyond the first item page.userOAuth scope is supported but remains outside the default scope set.Changes
pkg/github/user_lists.go.Verification
go vet -tags e2e ./e2e/passes.TestUserListspasses against the live GitHub API in in-process e2e mode.