# swb deploy

Upgrades an installed app to a version, the way the console's **Deploy
version…** action does.

## Synopsis

```
usage: swb deploy <app> <version> --env <env> [--json]
```

## Arguments and flags

| Argument or flag | Takes | Default |
|---|---|---|
| `<app>` | The app's **id** — the app whose install is upgraded. Required. | — |
| `<version>` | The **version** to deploy, as the build published it: `1.8.2`. Its release tag, `v1.8.2`, names the same version and is read as it. Otherwise taken as given; the control plane is what refuses a version with no build. Required. | — |
| `--env` | An environment's **name or id**; a name is matched first. Required. | — |
| `--json` | Nothing. Prints the deploy record as the API answered it instead of the one-line summary. | off |
| `--help`, `-h` | Prints the command's help and exits. | off |

## What it does

Finds the app's install in that environment and calls
`Mutation.upgradeInstall` with a fresh client token, so a repeated call is
one deploy rather than two. What it prints afterwards is the deploy the
control plane returned, never a prediction.

## What it prints

```
deploy dep-91c4 QUEUED: direct-install 1.8.1 -> 1.8.2 in prod
```

— the deploy's id and status, the app, the version the install was on
(`No version yet` where it runs none), the version asked for, and the
environment.

`--json` prints the deploy as the API answered it: `id`, `installId`,
`appId`, `environmentId`, `kind`, `version`, `channel`, `preview`, `trigger`,
`triggerDetail`, `requestedBy`, `requestedByName`, `status`, `githubCheckUrl`,
`startedAt`, `finishedAt` and `error`.

The command returns as soon as the deploy is started. Follow it with
[`swb deploys --env <env>`](/command-line/deploys).

An install held at a version takes no deploy this way, of that version or
any other: while the hold stands, the deploy the hold wrote is the one that
runs. Release the hold with [`swb release-hold`](/command-line/release-hold),
or hold the version you want with [`swb hold`](/command-line/hold).

## The operation and the permission

`Mutation.upgradeInstall`. The caller needs `swb.deploys.run` on the tenant.
`swb deploy` also reads `Query.me` once for the tenant, `Query.tenant` to
turn the `--env` name into an id, and `Query.installs` to find the app's
install in that environment.

## The same act in the console

An app's page → **Deploy version…**, which calls the same operation with the
same arguments.

## Refusals and exit status

Exit status is 0 once the deploy is started, and 1 on every refusal below. A
deploy that starts and later fails is a `FAILED` row, not an exit status.

| Refusal | When |
|---|---|
| `swb deploy takes <app> <version>` | An argument is missing. |
| `swb deploy needs --env <env>` | `--env` was not given. |
| `no environment named "<env>" in tenant <tenant> (have: dev, staging, prod)` | No environment of the tenant has that name or id. |
| `<app> is not installed in <env> (installed in: dev, staging)` | The app has no install in that environment. |
| `not signed in or token expired — run swb login` | There is no usable credential. |
| `Refused: <app> in <env> is held at <version> by <who> since <time>; …` | The install is held: the refusal names the held version, who held it and when. Nothing is written; release the hold or hold another version. |
| The API's own error text | The control plane refused the write — a caller without `swb.deploys.run`, or a version with no published build. |

## Example

```console
$ swb deploy direct-install 1.8.2 --env prod
deploy dep-91c4 QUEUED: direct-install 1.8.1 -> 1.8.2 in prod
```
