# `Forecastle.Deployment`
[🔗](https://github.com/ausimian/forecastle/blob/1.0.0/lib/forecastle/deployment.ex#L1)

Controls a release during an upgrade test.

A deployment can use an existing release tree through `new/3`, or copy a
`rel:`, `tar:` or `ref:` baseline into an isolated destination through
`deploy!/3`. Copying protects the baseline cache from runtime changes.

The module starts and stops the stock Mix launcher, invokes `bin/castle`, runs
RPC expressions, and supervises one-stage emulator restarts. Tests define
their own success criteria; see `Forecastle.UpgradeCase` for an example.

Commands unset inherited emulator flags and release-launcher defaults before
applying the environment supplied by the caller. This keeps the deployment
independent of the shell or CI process running the test.

# `env`

```elixir
@type env() :: [{binary(), binary() | nil}]
```

Command environment in `System.cmd/3` form. A `nil` value unsets the variable.

# `t`

```elixir
@type t() :: %Forecastle.Deployment{
  boot_timeout: pos_integer(),
  cd: Path.t(),
  env: env(),
  name: binary(),
  root: Path.t()
}
```

A release tree: its root, release name, command working directory, command
environment and boot timeout in milliseconds.

# `await_boot!`

```elixir
@spec await_boot!(t(), env()) :: :ok
```

Waits until the release accepts an RPC call.

The deployment's `:boot_timeout` is a total budget. Pass the same environment
used to start a release with a custom node name or cookie.

# `await_exit!`

```elixir
@spec await_exit!(binary(), pos_integer()) :: :ok
```

Waits for an operating-system process to exit.

Raises an ExUnit failure when the process remains after the timeout.

# `castle`

```elixir
@spec castle(t(), [binary()], env()) :: {binary(), non_neg_integer()}
```

Runs `bin/castle`, returning `{output, status}`.

# `castle!`

```elixir
@spec castle!(t(), [binary()], env()) :: binary()
```

Runs `bin/castle`, raising on a non-zero exit.

# `deploy!`

```elixir
@spec deploy!(binary(), Path.t(), keyword()) :: t()
```

Resolves a baseline and copies its release into an isolated destination.

Accepts `rel:`, `tar:` and `ref:` specs. The function validates the source and
destination before emptying `into`, and refuses overlapping paths or a release
already running there. Options are the same as `new/3`.

# `install_supervised`

```elixir
@spec install_supervised(t(), binary(), env()) :: {binary(), non_neg_integer()}
```

Installs a restart-based transition while acting as the external supervisor.

Runs `bin/castle install`, waits for the old process to exit, starts the release
again, and returns `{output, status}` after Castle confirms the target. Use
`castle/3` for hot installs, which do not exit their process.

# `install_supervised!`

```elixir
@spec install_supervised!(t(), binary(), env()) :: binary()
```

Runs `install_supervised/3` and raises on a non-zero exit.

# `launcher`

```elixir
@spec launcher(t(), [binary()], env()) :: {binary(), non_neg_integer()}
```

Runs the stock Mix launcher, returning `{output, status}`.

# `launcher!`

```elixir
@spec launcher!(t(), [binary()], env()) :: binary()
```

Runs the stock Mix launcher, raising on a non-zero exit.

# `new`

```elixir
@spec new(Path.t(), binary(), keyword()) :: t()
```

Describes an existing release tree.

`root` contains `bin`, `lib` and `releases`; `name` selects `bin/<name>`.
Options are `:cd`, `:env`, and `:boot_timeout`, which defaults to 20 seconds.

# `os_pid`

```elixir
@spec os_pid(t(), env()) :: binary()
```

Returns the operating-system pid reported by the running release.

The RPC is bounded and the final output line must contain only the pid.

# `rpc!`

```elixir
@spec rpc!(t(), binary(), env()) :: binary()
```

Evaluates an expression in the running release.

# `scrubbed_env`

```elixir
@spec scrubbed_env(env()) :: env()
```

Returns the environment used for deployment commands.

It unsets inherited emulator flags and Mix launcher defaults, then applies the
caller's entries.

# `stage!`

```elixir
@spec stage!(t(), Path.t()) :: Path.t()
```

Copies a release tarball into the deployment's `releases` directory.

Returns the copied path.

# `start!`

```elixir
@spec start!(t(), env()) :: binary()
```

Starts the release as a daemon and waits for it to accept RPC calls.

Returns combined launcher output. The launcher and boot waits are bounded. A
timeout fails the test but may leave the operating-system process running, so
callers must still register `stop/2` with `on_exit/1`.

# `stop`

```elixir
@spec stop(t(), env()) :: {binary(), non_neg_integer()} | :timeout
```

Stops the release, returning `{output, status}`.

A stopped or unreachable release is tolerated for teardown. Returns `:timeout`
when the stop RPC does not answer within the probe deadline.

# `version`

```elixir
@spec version(t()) :: binary()
```

Returns the deployed release version from `releases/start_erl.data`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
