Skip to content

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

Merged
williammartin merged 12 commits intotrunkfrom
wm-filter-assignee
Feb 18, 2026
Merged

Add --query flag to project item-list#12696
williammartin merged 12 commits intotrunkfrom
wm-filter-assignee

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

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.

@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.

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.

@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.

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.

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>
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Feb 25, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [cli/cli](https://github.com/cli/cli) | minor | `v2.86.0` → `v2.87.3` |

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.87.3`](https://github.com/cli/cli/releases/tag/v2.87.3): GitHub CLI 2.87.3

[Compare Source](cli/cli@v2.87.2...v2.87.3)

#### What's Changed

- Fix project mutation query variable usage by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;12757](cli/cli#12757)

**Full Changelog**: <cli/cli@v2.87.2...v2.87.3>

### [`v2.87.2`](https://github.com/cli/cli/releases/tag/v2.87.2): GitHub CLI 2.87.2

[Compare Source](cli/cli@v2.87.1...v2.87.2)

#### ℹ️ Note

This release was cut primarily to resolve a publishing issue. We recommend reviewing [the v2.87.1 release notes](https://github.com/cli/cli/releases/tag/v2.87.1) for the complete set of latest features and fixes.

#### What's Changed

- chore(deps): bump golang.org/x/crypto from 0.47.0 to 0.48.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12659](cli/cli#12659)

**Full Changelog**: <cli/cli@v2.87.1...v2.87.2>

### [`v2.87.1`](https://github.com/cli/cli/releases/tag/v2.87.1): GitHub CLI 2.87.1

[Compare Source](cli/cli@v2.87.0...v2.87.1)

#### ⚠️ Incomplete Release

The v2.87.1 release experienced a failure in our workflow and is not fully published to the designated package managers/repositories. This is resolved in [v2.87.2](https://github.com/cli/cli/releases/tag/v2.87.2), so we recommend using that release instead.

#### What's Changed

- Remove license bundling debris by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;12716](cli/cli#12716)
- fix(agent-task/capi): use a fixed CAPI API version by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;12731](cli/cli#12731)

**Full Changelog**: <cli/cli@v2.87.0...v2.87.1>

### [`v2.87.0`](https://github.com/cli/cli/releases/tag/v2.87.0): GitHub CLI 2.87.0

[Compare Source](cli/cli@v2.86.0...v2.87.0)

#### `gh workflow run` immediately returns workflow run URL

One of our most requested features - with the latest changes in GitHub API, `gh workflow run` will immediately print the created workflow run URL.

#### Improved `gh auth login` experience in VM/WSL environments

We have observed rare cases of time drift between the wall and monotonic clocks, mostly in WSL or VM environments, causing failures during polling for the OAuth token. This new release implements measures to account for such situations.

If you continue to experience `gh auth login` issues in WSL, please comment in [#&#8203;9370](cli/cli#9370)

#### :copilot: Request Copilot Code Review from `gh` + performance improvements

`gh pr edit` now supports [Copilot Code Review](https://docs.github.com/en/copilot/using-github-copilot/code-review/using-copilot-code-review) as a reviewer. You can request a review from Copilot using the `--add-reviewer @&#8203;copilot` flag or interactively by selecting reviewers in the prompts.

This release also introduces a new search experience for selecting reviewers and assignees in `gh pr edit`. Instead of loading all collaborators and teams upfront, results are now fetched based on inputs to a new search option. Initial options are suggestions based on those involved with the pull request already.

```
? Reviewers  [Use arrows to move, space to select, <right> to all, <left> to none, type to filter]
  [ ]  Search (7472 more)
  [x]  BagToad (Kynan Ware)
> [x]  Copilot (AI)
```

This experience will follow in `gh pr create` and `gh issue` for assignees in a later release.

#### What's Changed

##### ✨ Features

- Bundle licenses at release time by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;12625](cli/cli#12625)
- Add `--query` flag to `project item-list` by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;12696](cli/cli#12696)
- feat(workflow run): retrieve workflow dispatch run details by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;12695](cli/cli#12695)
- Pin REST API version to 2022-11-28 by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;12680](cli/cli#12680)
- Respect `--exit-status` with `--log` and `--log-failed` in `run view` by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;12679](cli/cli#12679)
- Fork with default branch only during pr create by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;12673](cli/cli#12673)
- `gh pr edit`: Add support for Copilot as reviewer with search capability, performance and accessibility improvements by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12567](cli/cli#12567)
- `gh pr edit`: new interactive prompt for assignee selection, performance and accessibility improvements by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12526](cli/cli#12526)

##### 📚 Docs & Chores

- Clean up project item-list query addition changes by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;12714](cli/cli#12714)
- `gh release upload`: Clarify `--clobber` flag deletes assets before re-uploading by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12711](cli/cli#12711)
- Add usage examples to `gh gist edit` command by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12710](cli/cli#12710)
- Remove feedback issue template by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12708](cli/cli#12708)
- Migrate issue triage workflows to shared workflows by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12677](cli/cli#12677)
- Migrate MR triage workflows to shared workflows by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12707](cli/cli#12707)
- Add missing TODO comments for featuredetection if-statements by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12701](cli/cli#12701)
- Add manual dispatch to bump-go workflow by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12631](cli/cli#12631)
- typo: dont to don't by [@&#8203;cuiweixie](https://github.com/cuiweixie) in [#&#8203;12554](cli/cli#12554)
- Fix fmt.Errorf format argument in ParseFullReference by [@&#8203;mikelolasagasti](https://github.com/mikelolasagasti) in [#&#8203;12516](cli/cli#12516)
- Lint source.md by [@&#8203;Sethispr](https://github.com/Sethispr) in [#&#8203;12521](cli/cli#12521)

##### :dependabot: Dependencies

- chore(deps): bump golang.org/x/text from 0.32.0 to 0.33.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12468](cli/cli#12468)
- chore(deps): bump golang.org/x/term from 0.38.0 to 0.39.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12616](cli/cli#12616)
- Bump go to 1.25.7 by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12630](cli/cli#12630)
- chore(deps): bump golang.org/x/crypto from 0.46.0 to 0.47.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12629](cli/cli#12629)
- chore: bump `cli/oauth` to `v1.2.2` by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;12573](cli/cli#12573)
- update Go to 1.25.6 by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;12580](cli/cli#12580)
- chore(deps): bump actions/attest-build-provenance from 3.1.0 to 3.2.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12558](cli/cli#12558)
- chore(deps): bump github.com/sigstore/rekor from 1.4.3 to 1.5.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12524](cli/cli#12524)
- chore(deps): bump github.com/theupdateframework/go-tuf/v2 from 2.3.1 to 2.4.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12555](cli/cli#12555)
- chore(deps): bump github.com/gdamore/tcell/v2 from 2.13.4 to 2.13.7 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12469](cli/cli#12469)
- chore(deps): bump github.com/sigstore/sigstore from 1.10.0 to 1.10.4 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12525](cli/cli#12525)
- chore(deps): bump github.com/theupdateframework/go-tuf/v2 from 2.3.0 to 2.3.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12515](cli/cli#12515)
- chore(deps): bump actions/download-artifact from 6 to 7 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12314](cli/cli#12314)
- chore(deps): bump actions/upload-artifact from 5 to 6 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12315](cli/cli#12315)
- chore(deps): bump goreleaser/goreleaser-action from 6.0.0 to 6.4.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;12354](cli/cli#12354)

#### New Contributors

- [@&#8203;Sethispr](https://github.com/Sethispr) made their first contribution in [#&#8203;12521](cli/cli#12521)
- [@&#8203;cuiweixie](https://github.com/cuiweixie) made their first contribution in [#&#8203;12554](cli/cli#12554)

**Full Changelog**: <cli/cli@v2.86.0...v2.87.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:eyJjcmVhdGVkSW5WZXIiOiI0My4yNC4yIiwidXBkYXRlZEluVmVyIjoiNDMuMzEuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
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

5 participants