Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ For how Deployah compares to DevSpace, Werf, Score, Epinio, and Kubero, see
workers)
- **Metrics** - ServiceMonitor / PodMonitor when Prometheus Operator is present
- **Extras** - custom manifests and CRDs under `.deployah/`
- **Plan before apply** - `deployah plan` / `deployah deploy` with validation
and deploy guards
- **Plan, then deploy** - `deployah plan` inspects changes and is read-only;
`deployah deploy` validates, runs guards, and runs Helm

## Current limitations

Expand Down Expand Up @@ -422,8 +422,8 @@ These work with every command:
| `deployah validate <environment>` | Also load the platform file and check the resolved configuration for that environment. |
| `deployah resolve <environment>` | Preview the fully resolved hostname, TLS mode, context, and runtime environment, offline. Prints FileValues and ExplicitValues; do not treat the output as secret-safe CI output. Use `--output json` for machine-readable output. |
| `deployah resolve --environments` | List every environment from both files: where it is registered, its context (or the kubeconfig fallback), domains, and overrides. |
| `deployah plan <environment>` | Preview what a deploy would change, without applying anything. Extra manifests from `.deployah/manifests/` appear in the diff; CRD files from `.deployah/crds/` are listed with Helm's install-only lifecycle, not applied. Use `--offline` to render with no cluster access, `--raw` for raw Kubernetes field paths instead of the compact Deployah vocabulary, `--yaml` to show changed fields as YAML blocks, `--drift` to also compare against live cluster state, `--detailed-exitcode` to exit 2 when changes are pending, or `--output json` for CI. |
| `deployah deploy <environment>` | Deploy your project. Shows the plan and asks for confirmation before applying; use `-y`/`--yes` to skip the prompt, `--reapply` to upgrade even with no changes, `--skip-crds` to skip installing [chart CRDs](docs/custom-manifests-and-crds.md#helm-crd-lifecycle) on a fresh Helm install (a CRD added after that first install is not installed by a later deploy), `--explain` to print the resolution report first, `--force-hostname-change` to bypass the hostname guard, or `--resize-volumes` to grow [persistence](docs/workloads.md#growing-volumes) sizes. |
| `deployah plan <environment>` | Inspect changes for an environment, without applying anything. Extra manifests from `.deployah/manifests/` appear in the diff; CRD files from `.deployah/crds/` are listed with Helm's install-only lifecycle, not applied. Use `--offline` to render with no cluster access, `--raw` for raw Kubernetes field paths instead of the compact Deployah vocabulary, `--yaml` to show changed fields as YAML blocks, `--drift` to also compare against live cluster state, `--detailed-exitcode` to exit 2 when changes are pending, or `--output json` for CI. |
| `deployah deploy <environment>` | Deploy your project. Deployah validates the spec, runs deploy guards, then always runs a Helm install for a new release or a Helm upgrade for an existing one. Use `--skip-crds` to skip installing [chart CRDs](docs/custom-manifests-and-crds.md#helm-crd-lifecycle) on a fresh Helm install (a CRD added after that first install is not installed by a later deploy), `--explain` to print the resolution report first, `--force-hostname-change` to bypass the hostname guard, or `--resize-volumes` to grow [persistence](docs/workloads.md#growing-volumes) sizes. |
| `deployah run <task> <environment>` | Run a spec task as a one-off Job. Wait is the default; `--detach` returns after create. `--count` / `--parallelism` override fanout for that run. |
| `deployah status <project>` | Show the status of a deployed project. Use `--detailed` for pod details, `-e` for an environment. |
| `deployah logs <project>` | Stream logs. Filter with `--component`, `-e`, `--container`, `--since`, `--tail`. Use `--no-follow` for a one-off read. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ Those states answer different questions and are independent:

- Previous -> Desired: declarative / release intent change
- Previous -> Live: drift
- Live -> Desired: visible resource consequence when this invocation
actually performs the relevant write (ADR-0011)
- Live -> Desired: visible resource consequence when the semantic
plan includes the corresponding write (ADR-0011)

Do not infer a deployment operation merely by comparing Live and
Desired. Ordinary modified drift alone does not run Helm (ADR-0006).
Do not infer a release change merely by comparing Live and Desired.
Ordinary drift alone is not a release change (ADR-0006). Whether a
requested deployment runs is ADR-0016.

Drift is intrinsic. If Previous and Live are available, Previous ->
Live is always evaluated. There is no opt-in drift mode. When there
Expand Down
34 changes: 14 additions & 20 deletions docs/adr/0006-semantic-plan-follows-helm-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,17 @@ install.
## Decision

Deployah follows the lifecycle Helm actually performs. The semantic
plan describes the operations Deployah's real Helm execution path
would attempt.

Helm runs when this invocation is a Helm install, when Helm-managed
release intent changed (Previous vs Desired, including hook
definitions), or when the operator supplies explicit Helm re-execution
intent. Ordinary Live drift, including a missing Live object, does not
by itself cause Helm to run.

Explicit re-execution exists because Deployah may otherwise skip Helm
when release intent is unchanged. It is not a new HelmAction:
HelmAction remains Install, Upgrade, or None. On an existing release
it is an ordinary Upgrade; with no release it remains Install, with no
second upgrade after that install. Helm running does not fabricate
resource consequences (ADR-0011). Drift stays independent (ADR-0005).
Unchanged preDeploy and postDeploy hooks still run on that upgrade
(ADR-0014).
plan uses Helm lifecycle semantics to describe release changes and
their resource and task consequences. The plan does not decide
whether a requested deployment runs (ADR-0016).

The plan reports a release change when the desired release differs
from the release Helm last recorded, including hook definitions.
Ordinary live drift, including a missing live object, is not by
itself a release change. A plan with no release change does not
invent resource consequences (ADR-0011). Drift stays independent
(ADR-0005). When Helm upgrades, unchanged preDeploy and postDeploy
hooks still run (ADR-0014).

CRD lifecycle is ADR-0008.

Expand Down Expand Up @@ -66,9 +60,9 @@ unknown final name does not make the semantic plan partial.

### Positive

- Plan operations match the Helm install, upgrade, and uninstall path
Deployah actually runs, including server-side apply on install
Create.
- Planned release changes and their consequences follow Helm's
install, upgrade, and uninstall lifecycle, including server-side
apply on an install Create.

### Negative

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,25 @@ Accepted

## Context

Release change, Drift, and the writes Helm will perform can disagree.
Collapsing them into one action invents Updates because Helm runs, or
Deletes of objects that no longer exist.
Release change, Drift, and planned write consequences can disagree.
Collapsing them into one action invents Updates because a planned
Helm lifecycle transition exists, or Deletes of objects that no
longer exist.

The three states are defined in ADR-0005. This ADR owns the visible
resource consequence when this invocation actually performs the
relevant write.
resource consequence when the semantic plan includes the
corresponding write.

## Decision

Visible resource consequences use this vocabulary:

- Create: the relevant object does not exist Live and this invocation
will create it.
- Create: the relevant object does not exist Live, and the planned
Helm lifecycle transition includes that create.
- Update: the relevant Live object exists, differs from Desired, and
this invocation will write Desired.
the planned Helm lifecycle transition includes that write.
- Delete: the object exists Live, leaves Desired/release state, and
Helm will delete it.
the planned Helm lifecycle transition includes that delete.
- Retain: the object leaves Desired/release state, but Helm lifecycle
policy intentionally leaves it Live.

Expand All @@ -32,7 +33,7 @@ required output row. Do not add Replace. Immutable-field rejection and
replacement feasibility are outside semantic planning (ADR-0004).

Human-readable Create output shows the complete intended manifest. An
Update starts from Live when this invocation will write.
Update starts from Live when the semantic plan includes that write.

Retain's primary case is Live `helm.sh/resource-policy: keep`. When
that policy suppresses deletion, report Retain, not Delete. If
Expand All @@ -45,15 +46,17 @@ Representative combinations:

1. Previous differs from Desired, Live already equals Desired: release
change exists, Drift may exist, no resource consequence. Do not
invent an Update merely because Helm runs.
invent an Update merely because the plan includes a Helm lifecycle
transition.
2. Previous present, Desired absent, Live absent: release change and
missing-resource drift, no Delete.
3. Previous present, Live absent, Desired unchanged: missing-resource
drift only. Missing Live state alone does not trigger Helm
(ADR-0006).
4. If Helm is already running for another release-intent change and a
Desired resource that existed in Previous is missing Live, show
Create plus missing-resource drift.
drift only. Missing Live state alone is not a release change
(ADR-0006). It does not decide whether a requested deployment
runs (ADR-0016).
4. When the planned Helm lifecycle transition includes a write for a
release change, and a Desired resource that existed in Previous is
missing Live, show Create plus missing-resource drift.

Adoption is ADR-0012.

Expand All @@ -67,5 +70,6 @@ Adoption is ADR-0012.

### Negative

- A missing Live object is not recreated until Helm runs for a
declared release-intent reason.
- The plan does not show a recreate for a missing Live object
unless there is a release change. A requested deploy of an
existing release still follows Helm upgrade (ADR-0016).
28 changes: 15 additions & 13 deletions docs/adr/0014-task-planning-follows-the-helm-managed-footprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,32 @@ Accepted
Deployah tasks map onto Helm hooks, ordinary Helm resources, or a
one-time operation outside the release. Treating leftover hook Jobs as
declarative Drift, or listing a current manual task as a deploy
resource, invents a lifecycle Helm does not run. When Helm runs is
ADR-0006. Resource consequences are ADR-0011.
resource, invents a lifecycle Helm does not run. The lifecycle the
plan describes is ADR-0006. Whether a requested deployment runs is
ADR-0016. Resource consequences are ADR-0011.

## Decision

`preDeploy` and `postDeploy` definitions are Helm hooks. A change to
those definitions is release intent change. If Helm upgrades for
another reason, unchanged hook tasks still run because Helm executes
them as part of the upgrade.
those definitions is a release change. On a Helm upgrade, unchanged
hook tasks still run, because Helm executes them as part of the
upgrade.

Scheduled tasks are ordinary Helm-managed resources, for example
CronJobs. A schedule task does not independently decide whether Helm
runs.
CronJobs. A schedule task is a release change only when that
resource changes. The task type does not by itself make one.

A current manual task is outside the deploy semantic plan. It is not
shown as a deploy Task by itself, has no release Resource entry merely
because it exists in the spec, and does not trigger Helm.
shown as a deploy Task by itself, and has no release Resource entry
merely because it exists in the spec.

Jobs or other objects created by executing `preDeploy` and
`postDeploy` hooks are execution artifacts. Their existence, success,
failure, or leftover presence is not declarative Drift. They do not
independently trigger Helm. Semantic planning models the hook
definition, the task-level action, and whether that hook will run in
this invocation.
failure, or leftover presence is not declarative Drift. They are not
a release change. Semantic planning models the hook definition, the
task-level action, and whether that hook is part of the planned
release change. A requested deploy follows Helm's hook rules for the
install or upgrade it runs (ADR-0016).

Changing phase between Helm-managed phases is a Task Update.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# ADR-0016: Separate semantic planning from deployment execution

## Status

Accepted

## Context

Deployah both inspects a deployment and carries one out. Inspection
describes release changes and their consequences. Execution carries
out a deployment the operator asked for. Those are different jobs.
Inspection must not decide whether that deployment runs.

## Decision

Planning and inspection are read-only. They describe release changes
and the resource and task consequences of those changes. Cluster
state informs drift and those consequences. It is not itself a
release change.

A requested deployment runs after validation and guards succeed,
including any volume preparation that must happen before Helm. It
then runs Helm. Planning results do not determine whether that
deployment is executed.

Helm chooses install or upgrade from whether the release already
exists. A release that does not exist yet is an install. An existing
release follows Helm's normal upgrade path.

An unchanged desired deployment may produce no planned release
change, while explicitly running deploy still executes that upgrade
path. Hooks follow the same path. The upgrade can record a new
revision even when the plan shows no release change.

## Consequences

### Positive

- Inspection can show no release change without blocking a later
deploy.
- Existing releases follow Helm's upgrade path, including hooks and
a new revision.

### Negative

- Deploy can record a new Helm revision when the plan showed no
release change.
- Hook tasks can run on that upgrade even when their definitions
did not change.
2 changes: 1 addition & 1 deletion docs/cli/deployah.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ deployah [flags]
* [deployah init](deployah_init.md) - Creates deployah.yaml and a platform file so you can deploy.
* [deployah list](deployah_list.md) - List deployed projects
* [deployah logs](deployah_logs.md) - View logs for a deployed project
* [deployah plan](deployah_plan.md) - Preview the changes a deploy would make
* [deployah plan](deployah_plan.md) - Inspect changes for an environment
* [deployah resolve](deployah_resolve.md) - Show the fully resolved configuration for an environment
* [deployah run](deployah_run.md) - Run a spec task as a one-off Job
* [deployah shell](deployah_shell.md) - Connect to a shell in a container
Expand Down
4 changes: 1 addition & 3 deletions docs/cli/deployah_deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Deploy a project to a Kubernetes cluster on a given environment

### Synopsis

Deploy a project to a Kubernetes cluster on a given environment. Shows what would change and asks for confirmation before applying, unless --yes is set.
Deploy a project to a Kubernetes cluster for an environment. Deployah validates the spec and runs its deploy guards, then runs Helm: an install for a new release, an upgrade for an existing one. An existing release is always upgraded, even when nothing changed, so Helm creates a new revision and runs upgrade hooks. To inspect changes first, run `deployah plan <environment>`.

```text
deployah deploy <environment> [flags]
Expand All @@ -15,10 +15,8 @@ deployah deploy <environment> [flags]
```text
--explain Print the resolution report before cluster checks (visible even when cluster is unreachable)
--force-hostname-change Allow changing the resolved hostname even though it may break existing traffic (skips the hostname guard)
--reapply Upgrade the release even when the plan shows no changes
--resize-volumes Allow persistence.size increases by expanding PVCs; StatefulSet controllers are orphan-deleted when needed so volumeClaimTemplates can be rewritten
--skip-crds Skip installing CustomResourceDefinitions from the chart on a fresh Helm install
-y, --yes Apply without an interactive confirmation prompt
```

### Options inherited from parent commands
Expand Down
4 changes: 2 additions & 2 deletions docs/cli/deployah_plan.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
## deployah plan

Preview the changes a deploy would make
Inspect changes for an environment

### Synopsis

Render the chart for an environment and show what would change compared to the last successful release, without applying anything.
Render the chart for an environment and compare it with the last successful Helm release. With --drift, also compare the rendered manifests with live cluster state. Plan is read-only and never applies anything.

```text
deployah plan <environment> [flags]
Expand Down
2 changes: 1 addition & 1 deletion docs/workloads.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ place (no orphan-delete).
1. Deploy with the flag:

```sh
deployah deploy <environment> --resize-volumes --yes
deployah deploy <environment> --resize-volumes
```

1. Deployah then:
Expand Down
2 changes: 1 addition & 1 deletion examples/nginx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You need Docker or Podman. From the repo root:
```sh
cd examples/nginx
deployah cluster up
deployah deploy local --yes
deployah deploy local
deployah cluster status
```

Expand Down
Loading
Loading