[CLI-22] Add op version list --project command - #21
Conversation
https://community.openproject.org/wp/cli-22 The `--version`/`--not-version` work-package filters accept version IDs, but there was no way to discover them. This commit adds a command to list versions of a project for this purpose. Actually it adds the command back: the absence of version listing was a regression from commit 17de261, which originally resolved `--version` by name and printed the available-versions list as a fallback; that lookup path (and its only caller) was dropped in bbef582 when the filter switched to raw IDs.
|
@cbliard I'd personally find this more useful if we could sort the items (locally?) before displaying. |
There was a problem hiding this comment.
Looks good overall. Just a few issues:
Naming the subcommand
Many popular CLIs support a version subcommand and flag, e.g. GitHub'S CLI which supports gh version and gh --version. On the other hand, op version and op --version do different things. Are we ok with the (conceptual) collision here?
Noun first has made this more confusing IMO.
The --version flag also collides/means different things: op --version vs work-package list --project DREAM --version 2323.
I don't really have a better suggestion. Renaming the noun to something else (e.g. project-versions or releases would probably be even more confusing/problematic for users already familiar with OpenProject. Just wanted to highlight this!
Documentation
CLAUDE.md hasn't been updated to mention the subcommand.
Other issues
Claude found two additional issues with existing code, that may now become apparent:
- Nil pointer panic::
dtos/version.go:33directly dereferencesdto.Embedded.Elementswithout a priorif dto.Embedded == nil guard(unlikedtos/budget.go:21). - Silent pagination truncation:
components/resources/projects/versions.go:12passesnilinstead ofrequests.NewPaginatedQuery(-1, nil)for the query, leaving it at default page limits.
| } | ||
| } | ||
|
|
||
| func TestListVersionsPrintsAvailableVersions(t *testing.T) { |
There was a problem hiding this comment.
Although an unlikely scenario in real-world usage (at least aT OP), We're missing a test for an empty version collection. This contrasts with cmd/workpackage/search.go:51 which explicitly prints No work package found for search input.
| expected := fmt.Sprintf("%s %s\n", printer.Red(" #2"), printer.Cyan("13.0")) | ||
| expected += fmt.Sprintf("%s %s\n", printer.Red(" #4"), printer.Cyan("13.1")) | ||
| expected += fmt.Sprintf("%s %s\n", printer.Red("#43"), printer.Cyan("45.5")) |
There was a problem hiding this comment.
We're only testing TextRenderer. Shouldn't we exercise JsonRenderer as well?
|
|
||
| func listVersions(_ *cobra.Command, _ []string) error { | ||
| if err := projects.ValidateIdentifier(listProjectId); err != nil { | ||
| printer.ErrorText(err.Error()) |
There was a problem hiding this comment.
Shouldn't we contextualise the error message? (as cmd/budget/list.go:25 does)
| printer.ErrorText(err.Error()) | |
| printer.ErrorText(fmt.Sprintf("--project: %s", err.Error())) |
| "github.com/opf/openproject-cli/cmd/status" | ||
| "github.com/opf/openproject-cli/cmd/timeentry" | ||
| "github.com/opf/openproject-cli/cmd/user" | ||
| "github.com/opf/openproject-cli/cmd/version" |
There was a problem hiding this comment.
Import shadowing (claude finding): cmd/root.go:143's func Execute(version *configuration.Version) parameter strictly shadows the newly added github.com/opf/openproject-cli/cmd/version import.
There was a problem hiding this comment.
Pull request overview
Adds a new op version list --project <project> command to list a project’s versions (IDs) so users can discover values for work-package --version / --not-version filters. The change fits into the CLI’s existing noun/verb command structure and extends the printer renderer abstraction to support both text and JSON output for version listings.
Changes:
- Introduces
op version list --projectcommand (wired intocmd/root.go) that fetches and prints available project versions. - Refactors
printer.Versionsto dispatch through theRendererinterface, adding text + JSON renderer implementations. - Updates CLI documentation to point users to the new command when using version filters.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| components/printer/versions.go | Routes version printing through activeRenderer instead of inline formatting. |
| components/printer/versions_test.go | Updates expected output to match renderer-driven text formatting. |
| components/printer/text_renderer.go | Adds text rendering implementation for version lists (aligned IDs). |
| components/printer/renderer.go | Extends Renderer interface with Versions. |
| components/printer/json_renderer.go | Adds JSON rendering for version lists. |
| cmd/version/version.go | Adds version noun root command and registers list subcommand + --project flag. |
| cmd/version/list.go | Implements version listing logic (validate project id/identifier, fetch versions, print). |
| cmd/version/list_test.go | Adds command-level tests for invalid project and successful listing. |
| cmd/root.go | Registers the new version command with the root CLI. |
| .claude/op.md | Documents new op version list --project usage and references it from work-package filter docs. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { | ||
| response.Header().Set("Content-Type", "application/json") | ||
| _, _ = response.Write([]byte(`{ |
There was a problem hiding this comment.
Not sure about this finding.
| import ( | ||
| "errors" | ||
| "net/http" | ||
| "net/http/httptest" | ||
| "net/url" | ||
| "strings" | ||
| "testing" | ||
|
|
||
| openerrors "github.com/opf/openproject-cli/components/errors" | ||
| "github.com/opf/openproject-cli/components/printer" | ||
| "github.com/opf/openproject-cli/components/requests" | ||
| ) |
| testingPrinter := &printer.TestingPrinter{} | ||
| printer.Init(testingPrinter) | ||
| listProjectId = "example" | ||
| t.Cleanup(func() { listProjectId = "" }) | ||
|
|
||
| if err := listVersions(nil, nil); err != nil { | ||
| t.Fatalf("listVersions error = %v, want nil", err) | ||
| } | ||
|
|
||
| if !strings.Contains(testingPrinter.Result, "v17") || !strings.Contains(testingPrinter.Result, "v42") { | ||
| t.Errorf("expected output to contain versions 'v17' and 'v42', got: %q", testingPrinter.Result) | ||
| } | ||
| } |
Ticket
https://community.openproject.org/wp/cli-22
What are you trying to accomplish?
The
--version/--not-versionwork-package filters accept version IDs, but there was no way to discover them. This commit adds a command to list versions of a project for this purpose.Screenshots
What approach did you choose and why?
Actually it adds the command back: the absence of version listing was a regression from commit 17de261, which originally resolved
--versionby name and printed the available-versions list as a fallback; that lookup path (and its only caller) was dropped in bbef582 when the filter switched to raw IDs.So it rewires the dead code back, and use the printer
Rendererinterface to have both text and json output available.Merge checklist