From a3525a2c5ae063fb47d2768ee80562088065ef57 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Thu, 9 Jul 2026 08:05:34 +0300 Subject: [PATCH] docs: add 0.1.8 release notes --- planning/releases/0.1.8.md | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 planning/releases/0.1.8.md diff --git a/planning/releases/0.1.8.md b/planning/releases/0.1.8.md new file mode 100644 index 0000000..9327767 --- /dev/null +++ b/planning/releases/0.1.8.md @@ -0,0 +1,68 @@ +# compose2pod 0.1.8 — interpolation moves to run time + +This release reverses 0.1.7: Compose `${VAR}` interpolation now happens when +the *generated script* runs, not when compose2pod generates it. compose2pod +emits a script that runs later — typically in CI, where the real secrets and +config live — so resolving against compose2pod's own environment at generation +time baked any variable that was unset then to an empty string. References are +now emitted as live POSIX-shell fragments that the runtime shell expands. + +## Change + +- **`${VAR}` is interpolated at script-run time, not generation time.** + `to_shell()` (new `compose2pod/shell.py`) re-encodes every compose-derived + value (`environment`, `image`, `command`, `volumes`, `tmpfs`, `env_file`, + healthcheck `test`) into a double-quoted shell fragment whose variable + references stay live, so the generated script's own shell resolves them + against its runtime environment. All the 0.1.7 forms still work — `$VAR`, + `${VAR}`, `${VAR:-default}`, `${VAR-default}`, `${VAR:?msg}`, `${VAR?msg}`, + `${VAR:+alt}`, `${VAR+alt}`, `$$` — mapping onto identical POSIX `sh` + parameter expansion. A bare `$VAR`/`${VAR}` is emitted as `${VAR-}` so an + unset variable expands to empty under the script's `set -eu` instead of + aborting; `${VAR:?msg}` now fails the script at run time (not at generation). + Command substitution and other shell metacharacters in literal text are + escaped, so nothing but a variable reference is ever live. The CLI prints one + informational note listing the variables the script references at run time. + +## Fix + +- **`environment` null value is host passthrough.** A null mapping value + (`KEY:`) now emits a bare `-e KEY` — passing `KEY` through from the host, + identical to the list form `- KEY` — instead of the literal `-e KEY=None`. +- **Malformed braced references are rejected.** A braced reference whose text + after the name is not a valid operator (e.g. `${FOO!bar}`) now raises a clear + `UnsupportedComposeError` instead of silently dropping the trailing text. + +## Packaging + +- Public API: the generation-time `interpolate` function is **removed**; + `to_shell` is exported in its place. `to_shell(value)` returns a + runtime-expandable shell fragment, not a resolved value. + +## Why + +The 0.1.7 model resolved `${VAR}` against `os.environ` at generation time. For +compose2pod's actual use — generate a script now, run it later in CI — that was +the wrong moment: the variables are supposed to be unset at generation and set +at run time, so 0.1.7 baked them to empty and emitted a spurious "variable not +set" warning. Deferring to the runtime shell resolves them where they exist. + +## Downstream + +- **Compose files:** set `${VAR}` values in the *runtime* environment of the + generated script (e.g. your CI job), not in the environment that runs + compose2pod. An unset bare `${VAR}` now expands to empty at run time; write + `${VAR:?message}` where you want a missing variable to fail the run. +- **API consumers:** `compose2pod.interpolate` is gone. Use + `compose2pod.to_shell(value)`, which emits a runtime-expandable shell fragment + rather than resolving the value in-process. + +## Internals + +- `architecture/supported-subset.md` rewritten to describe run-time expansion, + the `${VAR-}`/`$$`/`${VAR:?}` semantics, `env_file` interpolation, the + reference note, null-value passthrough, and malformed-reference rejection. +- 123 tests at 100% line coverage (enforced); `ruff select=ALL`, `ty`, and + `eof-fixer` clean. `test_shell.py` executes emitted fragments under real + `sh -euc` to prove run-time expansion, the `${VAR:?}` abort, and + command-substitution inertness.