Skip to content

Implement deploy rollback - #1744

Draft
gcirclest wants to merge 1 commit into
mainfrom
rollback-comm
Draft

Implement deploy rollback#1744
gcirclest wants to merge 1 commit into
mainfrom
rollback-comm

Conversation

@gcirclest

Copy link
Copy Markdown
Contributor

Adds circleci deploy rollback <target-version> over the V3 project rollback endpoint that landed in release-tracker#2219, POST /api/v3/projects/{id}/rollback. Every field of the request body is covered: namespace, reason, parameters, checkout_ref and config_ref alongside the four required ones.

$ circleci deploy rollback 1.2.0 --component web-frontend --environment production
Roll back web-frontend in production from 1.3.0 to 1.2.0? [y/N] y
✓ Rolling back web-frontend in production from 1.3.0 to 1.2.0
Pipeline run 8f0b… — follow it with: circleci run get 8f0b…

Design decisions worth a reviewer's attention:

  • Names, not just ids. --component and --environment take a name or a UUID. The endpoint addresses both by id, so a name is resolved through the same component and environment list endpoints the read commands use. An ambiguous component name reports the candidate ids rather than picking one, since the wrong pick would roll back the wrong thing.
  • --from is optional. Omitted, current_version is read from the component's versions filtered by the environment, which the API returns most recently deployed first. This does not weaken the endpoint's stale-state guard: the API re-checks the version, so a wrong inference fails the rollback rather than moving something unintended, and a 400 is reported as "rollback rejected" pointing at deploy version list.
  • --force and a prompt. A rollback changes what is deployed, so it goes through cmdutil.ConfirmOrForce like run cancel, with the resolved component, environment and both versions in the prompt. Non-interactive without --force exits 6 and never sends the request.
  • The output points at the work, not the request. data.id is either the triggered pipeline run or the queued release-agent command; rollback_type distinguishes them, and the two are followed in different places, so the human output names which one it is and gives the run get command for the pipeline case.
  • No --dry-run. The --help page lands at exactly the 40-line budget TestHelp enforces, and the overBudget allow-list is already at its 25-entry cap, so a further flag row would have meant raising maxOverBudget. The confirmation prompt already previews the resolved component, environment and both versions. For the same reason the target version is the positional argument rather than a --to flag paired with --from.

Errors are mapped for each failure the endpoint documents: 409 → rollback already in progress (exit 4), 400 → rollback rejected with the server's detail (exit 2), 404 → not found with a --namespace hint (exit 5).

Testing

  • 12 acceptance tests in acceptance/deploy_rollback_test.go: name resolution with an inferred --from, every optional field with the request body asserted through the recorder (including --param bool/int coercion), both rollback types, --json, missing flag and missing argument, unknown component and unknown environment, no recorded version, malformed --param, 400, 409, and no token. The --force-refused case also asserts the POST never left the CLI.
  • fakes.CircleCI grows the route plus SetRollback, with Status/Title/Detail for the error paths.
  • task test passes (2090 tests). task check fails on main in my environment too — golangci-lint/staticcheck cannot resolve honnef.co/go/tools/go/ir from tools/go.mod — so it is unrelated to this branch; gofmt, go vet and task license are clean and no dependencies were added.

Add `circleci deploy rollback <target-version>` over the V3 project rollback
endpoint, POST /api/v3/projects/{id}/rollback.

--component and --environment accept a name or a UUID. The endpoint addresses
both by id, so a name is resolved through the component and environment list
endpoints first; an ambiguous component name reports the candidate ids rather
than picking one.

--from (current_version) is optional. Omitted, it is read from the component's
versions filtered by the environment, which the API returns most recently
deployed first. The API re-checks it, so a stale inference fails the rollback
instead of moving the wrong version.

The response's id is the pipeline run or the release-agent command carrying the
rollback out, and rollback_type says which, so the output points at the right
place to follow it.
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