Skip to content

feat: add a group filter to project list - #689

Open
NickJosevski wants to merge 5 commits into
mainfrom
nj/project-list-group-filter
Open

feat: add a group filter to project list#689
NickJosevski wants to merge 5 commits into
mainfrom
nj/project-list-group-filter

Conversation

@NickJosevski

@NickJosevski NickJosevski commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Adds an optional group filter to octopus project list:

octopus project list --group 'Default Project Group'
octopus project ls -g ProjectGroups-1

Why

There was no way to narrow project list to a single project group. The nearest thing was project-group view, which shows group metadata with the projects nested inside it — fine for a look, awkward when the projects are what you actually want.

This is the alternative shape proposed on #388, which added a project-group projects list command instead. Putting the filter on project list is more discoverable (people looking for projects reach for project list), matches the -g/--group flag project create and project clone already use, and avoids a three-level project-group projects list whose middle noun would exist to hold a single verb. Credit for spotting the gap goes to @nate-christensen.

Behaviour

  • No flag: unchanged — Projects.GetAll(), same output and columns as before.
  • With a group: resolved by name or ID, then listed from that group's own Projects link, which the server pages for us rather than us fetching every project and discarding most of them. (The projects collection has no projectGroupId filter, so this is the available route either way.)
  • Unknown group: cannot find a project group with name or ID of 'X', matching the wording in the delete commands, rather than the SDK's bare cannot find the item. Other lookup errors pass through untouched.

The selection logic sits in a small getProjects function taking callbacks, so it is unit-testable without a factory mock — five tests cover no-filter, filter, unknown group, nil group and unrelated-error paths.

Verification

Build, vet, gofmt and tests clean. Against a local instance: created a throwaway group and project, confirmed the filter discriminates by both name and ID (16 projects total, 1 in the temp group, 15 in the default), then removed them. Also diffed the raw field sets returned by /projects and /projectgroups/X/projects — identical, ProjectTags included, so the TAGS column behaves the same on either path.

Decision

Resolved: we're going with this shape. #388 proposed the same capability as a
project-group projects list command; it has been closed in favour of this PR, with
thanks to @nate-christensen for spotting the gap. The reasoning, plus two flag
registration bugs from that branch worth knowing about regardless, is written up in
#388 (comment).

Out of draft and ready for review.

🤖 Generated with Claude Code

`octopus project list` had no way to narrow to a single project group, so
finding the projects in a group meant either `project-group view`, whose
output is group metadata with the projects nested inside it, or filtering
the full list client side.

Add an optional `-g/--group` filter taking a group name or ID, matching the
flag `project create` and `project clone` already use. With no flag the
command behaves exactly as before. When a group is given the projects come
from that group's own Projects link, which the server pages for us, rather
than fetching every project in the space and discarding most of them.

An unknown group reports `cannot find a project group with name or ID of
'X'`, the wording the delete commands use, rather than the SDK's bare
"cannot find the item". Other lookup errors pass through untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread pkg/cmd/project/list/list.go
Comment thread pkg/cmd/project/list/list_test.go
NickJosevski and others added 4 commits August 31, 2026 12:02
getProjectGroup is client.ProjectGroups.GetByIDOrName, which never
returns (nil, nil) - a miss comes back as services.ErrItemNotFound from
GetByName. Fold the unreachable nil branch into the not-found branch so
the message is written once while staying defensive.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The unit tests exercise getProjects directly but nothing drove the cobra
wiring. Add a MockHttpServer/rootCmd.ExecuteC() suite in the same shape
as pkg/cmd/package/list, covering the unfiltered path, --group by ID,
the -g shorthand with a group name in json (ID lookup misses, partial
name lookup resolves), and the unknown-group error.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
35a5361 applied the review suggestion a second time, but that suggestion's
diff context came from 4e955bb - before 74ad1b4 had already collapsed the
duplicated not-found message. Re-applying the stale suggestion against the
collapsed code matched the wrong line range and swallowed

	if group == "" {
		return getAllProjects()
	}

leaving a bare `if group == ""` header wrapped around the group resolution
path and no closing brace on the function. The package stopped compiling
(`list.go:124:1: syntax error: unexpected EOF, expected }`), which took the
whole test suite added in e25bfdf down with it. Had it compiled, an
unfiltered `project list` would have called getProjectGroup("") instead of
getAllProjects(), breaking the no-flag path the feature promises to leave
untouched.

Revert to the e25bfdf text, which already carries the suggestion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@NickJosevski
NickJosevski marked this pull request as ready for review September 4, 2026 04:08
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.

1 participant