feat(controls): add 'kosli update control' command#988
Merged
Conversation
Adds the missing "update" of CRUD for controls, wrapping the released
PUT /api/v2/controls/{org}/{identifier} endpoint (body ControlPutInput).
- --name/-n, --description/-d, and repeatable --link (name=url)
- only flags the user set are sent, so omitted fields are left untouched
(matches the server's model_fields_set merge); --link replaces all links
- RequireAtLeastOneOfFlags gives an actionable error when no updatable
flag is provided; not-found and validation errors surface verbatim
- beta-gated (betaCLIAnnotation), consistent with the other control commands
Closes #6096
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Claude finished @pbeckham's task in 1m 56s —— View job PR Review —
|
| Check | Result |
|---|---|
go build ./... |
✅ clean |
go vet ./cmd/kosli/ |
✅ clean |
go mod tidy + git diff go.mod go.sum |
✅ no changes |
What's done well
- Merge semantics are correct. Building the payload as
map[string]interface{}and gating each key oncmd.Flags().Changed(...)(updateControl.go:78-87) is exactly right for the server'smodel_fields_setmerge — omitted flags leave fields untouched, and--linkreplaces the whole links map as documented. - The prior review comment is addressed. The dry-run test at
updateControl_test.go:59-66now pins the core behaviour — a name-only update must serialize to exactly{"name": ...}with no straydescription/links. This guards the regression that plain success-message assertions would miss. 👍 - Consistent with the codebase — beta annotation,
RequireGlobalFlagsinPreRunE,addDryRunFlag, untyped payload (likeupdate service-account, so no OpenAPI drift-test entry needed), and good long-desc/example help text. - Good test coverage — arg validation, no-flags client-side error, single/multi-field success, not-found error, and the dry-run payload assertion.
Minor observations (non-blocking, no action required)
- No way to clear all links.
StringToStringVarcan't represent "set links to empty", so a user can replace links but not remove them entirely via this command. Fine if the API/product doesn't need it; worth a mention only if clearing is a real use case. urlshadows thenet/urlimport (updateControl.go:70) — harmless and consistent withcreateControl.go, so no change warranted.
Nice work — this is ready to merge as far as I can see.
Adds a dry-run case pinning the command's core behaviour: a name-only
update must send exactly {"name": ...} in the PUT body, with no stray
empty description or links. Guards the model_fields_set merge against
regressions the success-message assertions couldn't catch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
Author
|
Thanks for the thorough review. Triage of the remaining (non-blocking) points — all skipped, with reasoning:
|
jumboduck
approved these changes
Jul 2, 2026
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.
What
Adds
kosli update control CONTROL-IDENTIFIER— the missing update of CRUD for controls, wrapping the releasedPUT /api/v2/controls/{org}/{identifier}endpoint (bodyControlPutInput). Follows on from the controls CLI in #986.Flags:
--name/-n--description/-d--link(repeatable,name=url)How it matches the API semantics
ControlPutInputhas all-optional fields and the server merges based onmodel_fields_set— only keys present in the JSON body are touched. So:map[string]interface{}and a key is added only when the user set that flag (cmd.Flags().Changed(...)). Omitted flags leave that field unchanged;--linkreplaces the whole links map, matching the server.RequireAtLeastOneOfFlagsgives a clear client-side error before hitting the API.get/archive control.betaCLIAnnotation), consistent with the other control commands.update service-account), so the OpenAPI contract drift test needs no new entry.Testing
make test_integration_single TARGET=TestUpdateControlCommandTestSuite— green. Cases: arg validation, no-flags error, name/description/links/multi-field success, not-found error.make lint— 0 issues;make vet— clean.kosli update control --helprenders the beta notice and flags correctly.Closes kosli-dev/server#6096
🤖 Generated with Claude Code