Skip to content

feat(cli): openship deployment bisect — binary-search deployment history for the first bad deploy #541

Description

@Rish-it

Problem

When a project breaks somewhere in its deployment history, there is no supported way to find which deployment introduced the regression.

openship deployment list shows the history and openship deployment rollback <id> reverts to a chosen deployment, but nothing narrows "one of these 40 deployments broke it" to a single culprit. In practice that means walking the history one deployment at a time — O(n) rollbacks, each one mutating the active deployment.

The data needed to do this properly is already stored: deployment.version is a monotonic per-project counter, deployment.createdAt orders the history, and deployment.url is the visitable address.

Proposal

Add openship deployment bisect — a binary search over deployment history.

openship deployment bisect [--project <id>] [--env <environment>]
                           [--limit <n>] [--good <id>] [--bad <id>]
  1. Fetch the project's deployments, keep only those that actually deployed something visitable, sort ascending by createdAt.
  2. Treat the oldest as known-good and the newest as known-bad, unless --good / --bad override.
  3. Present the midpoint deployment — id, version, branch, timestamp, URL — open its URL when one exists, and ask good / bad / skip / abort.
  4. Narrow the range until only the good/bad boundary pair remains.
  5. Report the first bad deployment and the last known-good one, then offer to roll back to the good one.

skip covers a candidate that cannot be judged (expired artifact, feature-flagged off). A skipped candidate is never labelled, so the final bracket can be wider than the minimal transition pair — the reported boundaries stay truthful: the lower bound is genuinely good, the upper bound genuinely bad.

Roughly log2(n) checks instead of n: 40 deployments becomes 6 questions.

Why this fits the existing codebase

Additive only — no new API route, no schema change, no new dependency:

  • Reads GET /api/deployments?projectId=&environment=&perPage=, the route deployment list already uses.
  • Writes POST /api/deployments/:id/rollback, the route deployment rollback already uses.
  • version, url, commitSha and createdAt are already on that list response — presentDeployments masks env only, it does not project columns away.
  • Reuses existing CLI conventions: the run() ApiError wrapper, the ok()/err()/info() output helpers, readProjectLink() for project scope, @clack/prompts for the prompt, and the open dependency already used by openship open.

Status filter: only ready and partial_failure represent a deployment that serves something. queued/building/deploying have not finished; failed/cancelled/rejected have nothing to visit. Related: #410ready is the correct string, and a filter on success matches zero rows.

Acceptance criteria

  • The search logic is separable from the I/O and unit-tested on its own: midpoint selection, the good/bad/skip transitions, and convergence — including that a skipped candidate still yields a correct bracket.
  • Refuses to run without a TTY and under --json, with a clear message.
  • Errors clearly when fewer than two testable deployments are in range, when --good/--bad name a deployment outside the fetched window, and when --good is not chronologically before --bad. The fewer-than-two case must not blame --good/--bad when neither was passed.
  • Aborting, via the menu or Ctrl-C, exits non-zero and issues no rollback.
  • Declining the final rollback offer issues no rollback.
  • The rollback goes through the existing endpoint, not a new one.

Scope

CLI only. A dashboard equivalent would be a separate issue; the command stands on its own for anyone already using deployment list and rollback.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions