Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Comments

Close side panel

Add --query flag to project item-list#12696

Merged
williammartin merged 12 commits intotrunkcli/cli:trunkfrom
wm-filter-assigneecli/cli:wm-filter-assigneeCopy head branch name to clipboard
Feb 18, 2026
Merged

Add --query flag to project item-list#12696
williammartin merged 12 commits intotrunkcli/cli:trunkfrom
wm-filter-assigneecli/cli:wm-filter-assigneeCopy head branch name to clipboard

Conversation

@williammartin
Copy link
Member

@williammartin williammartin commented Feb 16, 2026

Description

Fixes #12664

Acceptance Criteria

Given I am targeting github.com
When I run project item-list with the --query flag
Then the query is respected in the results

➜ ./bin/gh project item-list 9 --owner williammartin --format json --query "assignee:williammartin-cli-triaging"
{
  "items": [
    {
      "assignees": [
        "williammartin-cli-triaging"
      ],
      "content": {
        "body": "test",
        "number": 25,
        "repository": "williammartin-test-org/test-repo",
        "title": "test title",
        "type": "Issue",
        "url": "https://github.com/williammartin-test-org/test-repo/issues/25"
      },
      "id": "PVTI_lAHOABiW9s4A1ms7zgY4CN4",
      "repository": "https://github.com/williammartin-test-org/test-repo",
      "title": "test title"
    }
  ],
  "totalCount": 1
}

➜  ./bin/gh project item-list 9 --owner williammartin --format json --query "assignee:babakks"
{
  "items": [],
  "totalCount": 0
}

Given I am targeting a version of GHES that doesn't support the query flag
When I run project item-list with the --query flag
Then I receive an informative error

➜ ✗ GH_HOST=ghe.io ./bin/gh project item-list 9 --owner williammartin --format json --query "assignee:babakks"
the `--query` flag is not supported on this GitHub host; most likely you are targeting a version of GHES that does not yet have the query field available

Copilot AI review requested due to automatic review settings February 16, 2026 13:05
@williammartin williammartin requested a review from a team as a code owner February 16, 2026 13:05
Copy link
Contributor

Copilot AI left a 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 adds a --query flag to gh project item-list to allow server-side filtering of project items using the GitHub Projects filter syntax (e.g. assignee:..., -status:...), addressing issue #12664.

Changes:

  • Extend the project items GraphQL query plumbing to accept a query string and pass it to ProjectV2.items.
  • Add --query flag parsing + end-to-end command behavior (including output) tests.
  • Introduce feature detection for whether a host’s schema supports the ProjectV2.items(query:) argument (with mocks/tests).

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/cmd/project/shared/queries/queries.go Adds query arg support to ProjectItems GraphQL query and method signature.
pkg/cmd/project/shared/queries/queries_test.go Updates expected GraphQL variables and call signature for ProjectItems.
pkg/cmd/project/item-list/item_list.go Adds --query flag and gates it behind feature detection.
pkg/cmd/project/item-list/item_list_test.go Adds parsing + runtime tests for --query and unsupported-host behavior.
internal/featuredetection/feature_detection.go Adds ProjectFeatures() to detect ProjectV2.items(query:) support on enterprise hosts.
internal/featuredetection/feature_detection_test.go Adds tests validating ProjectFeatures() behavior across hosts/schema variants.
internal/featuredetection/detector_mock.go Updates detector mocks to implement the new interface method.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

pkg/cmd/project/shared/queries/queries.go Show resolved Hide resolved
pkg/cmd/project/item-list/item_list.go Outdated Show resolved Hide resolved
@williammartin williammartin marked this pull request as draft February 16, 2026 13:14
luisfagon76

This comment was marked as spam.

Copy link
Member

@babakks babakks left a comment

Choose a reason for hiding this comment

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

Didn't fully test it, but I'm concerned about the query: $queryItems arg add to the GraphQL tag on Project.Items field.

internal/featuredetection/feature_detection.go Outdated Show resolved Hide resolved
pkg/cmd/project/item-list/item_list.go Outdated Show resolved Hide resolved
if host == "" {
host = ghinstance.Default()
}
config.detector = fd.NewDetector(api.NewCachedHTTPClient(httpClient, time.Hour*24), host)
Copy link
Member

Choose a reason for hiding this comment

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

I think in other places we populate the detector in the runX func, ofc if it's nil.

pkg/cmd/project/shared/queries/queries.go Show resolved Hide resolved
@williammartin williammartin marked this pull request as ready for review February 18, 2026 11:32
williammartin and others added 5 commits February 18, 2026 13:06
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Member

@babakks babakks left a comment

Choose a reason for hiding this comment

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

The code seems okay, although it's getting more complicated.

However, I'm seeing something weird when I run gh project list (in comparison to latest gh):

Image

Seems like the changes have messed up with something.

internal/featuredetection/feature_detection.go Outdated Show resolved Hide resolved
Long: heredoc.Doc(`
List the items in a project.

If supported by the API host (github.com and GHES 3.20+), the --query option can
Copy link
Member

Choose a reason for hiding this comment

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

question: are we sure about GHES 3.20 support for this?

Copy link
Member Author

Choose a reason for hiding this comment

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

Well it's not in now in 3.19 and schema changes are always pulled in on release.

pkg/cmd/project/item-list/item_list.go Outdated Show resolved Hide resolved
pkg/cmd/project/item-list/item_list.go Outdated Show resolved Hide resolved
pkg/cmd/project/shared/queries/queries.go Outdated Show resolved Hide resolved
Comment on lines 150 to 608
@@ -147,6 +173,27 @@ type Project struct {
}
}

func newProjectFromWithoutItemQuery(source projectWithoutItemQuery) *Project {
project := &Project{
Number: source.Number,
URL: source.URL,
ShortDescription: source.ShortDescription,
Public: source.Public,
Closed: source.Closed,
Title: source.Title,
ID: source.ID,
Readme: source.Readme,
Fields: source.Fields,
}
project.Items.PageInfo = source.Items.PageInfo
project.Items.TotalCount = source.Items.TotalCount
project.Items.Nodes = source.Items.Nodes
project.Owner.TypeName = source.Owner.TypeName
project.Owner.User.Login = source.Owner.User.Login
project.Owner.Organization.Login = source.Owner.Organization.Login
return project
}

func (p Project) DetailedItems() map[string]interface{} {
return map[string]interface{}{
"items": serializeProjectWithItems(&p),
@@ -508,8 +555,10 @@ func (p ProjectItem) ExportData(_ []string) map[string]interface{} {
}

// ProjectItems returns the items of a project. If the OwnerType is VIEWER, no login is required.
// If limit is 0, the default limit is used.
func (c *Client) ProjectItems(o *Owner, number int32, limit int) (*Project, error) {
// If limit is 0, the default limit is used. The queryStr parameter is passed as a server-side
// filter to the items connection, using the same syntax as the GitHub Projects filter bar
// (e.g. "assignee:octocat", "status:done").
func (c *Client) ProjectItems(o *Owner, number int32, limit int, queryStr string) (*Project, error) {
project := &Project{}
if limit == 0 {
limit = LimitDefault
@@ -528,20 +577,35 @@ func (c *Client) ProjectItems(o *Owner, number int32, limit int) (*Project, erro
"afterFields": (*githubv4.String)(nil),
"number": githubv4.Int(number),
}
if queryStr != "" {
variables["queryItems"] = githubv4.String(queryStr)
}

var query pager[ProjectItem]
var queryName string
switch o.Type {
case UserOwner:
variables["login"] = githubv4.String(o.Login)
query = &userOwnerWithItems{} // must be a pointer to work with graphql queries
if queryStr == "" {
query = &userOwnerWithItemsNoQuery{} // must be a pointer to work with graphql queries
} else {
query = &userOwnerWithItems{} // must be a pointer to work with graphql queries
}
queryName = "UserProjectWithItems"
case OrgOwner:
variables["login"] = githubv4.String(o.Login)
query = &orgOwnerWithItems{} // must be a pointer to work with graphql queries
if queryStr == "" {
query = &orgOwnerWithItemsNoQuery{} // must be a pointer to work with graphql queries
} else {
query = &orgOwnerWithItems{} // must be a pointer to work with graphql queries
}
queryName = "OrgProjectWithItems"
case ViewerOwner:
query = &viewerOwnerWithItems{} // must be a pointer to work with graphql queries
if queryStr == "" {
query = &viewerOwnerWithItemsNoQuery{} // must be a pointer to work with graphql queries
} else {
query = &viewerOwnerWithItems{} // must be a pointer to work with graphql queries
}
Copy link
Member

Choose a reason for hiding this comment

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

These are getting out of our hands. We already have had 2-3 types per owner type, and we're now adding 3 more.

I'm not blocking this PR, but we should prioritise a follow up to simplify this approach. Perhaps we should fallback to plain text queries?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, the range is wrong. I meant the last switch statement.

williammartin and others added 7 commits February 18, 2026 14:45
Co-authored-by: Babak K. Shandiz <babakks@github.com>
Co-authored-by: Babak K. Shandiz <babakks@github.com>
Co-authored-by: Babak K. Shandiz <babakks@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@williammartin williammartin merged commit 8dcfd33 into trunk Feb 18, 2026
11 checks passed
@williammartin williammartin deleted the wm-filter-assignee branch February 18, 2026 15:34
return err
}
if !features.ProjectItemQuery {
return fmt.Errorf("the `--query` flag is not supported on this GitHub host; most likely you are targeting a version of GHES that does not yet have the query field available")
Copy link
Member

Choose a reason for hiding this comment

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

nit: this seems extra for an error message

Comment on lines +617 to +636
if queryStr == "" {
query = &userOwnerWithItemsNoQuery{} // must be a pointer to work with graphql queries
} else {
query = &userOwnerWithItems{} // must be a pointer to work with graphql queries
}
queryName = "UserProjectWithItems"
case OrgOwner:
variables["login"] = githubv4.String(o.Login)
query = &orgOwnerWithItems{} // must be a pointer to work with graphql queries
if queryStr == "" {
query = &orgOwnerWithItemsNoQuery{} // must be a pointer to work with graphql queries
} else {
query = &orgOwnerWithItems{} // must be a pointer to work with graphql queries
}
queryName = "OrgProjectWithItems"
case ViewerOwner:
query = &viewerOwnerWithItems{} // must be a pointer to work with graphql queries
if queryStr == "" {
query = &viewerOwnerWithItemsNoQuery{} // must be a pointer to work with graphql queries
} else {
query = &viewerOwnerWithItems{} // must be a pointer to work with graphql queries
}
Copy link
Member

Choose a reason for hiding this comment

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

nit: code comments here could probably be just one comment for all of them

williammartin added a commit that referenced this pull request Feb 18, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Babak K. Shandiz <babakks@github.com>
williammartin added a commit that referenced this pull request Feb 18, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Babak K. Shandiz <babakks@github.com>
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.

[FR] gh project item-list ; filter on assignee

4 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.