feat: interpolate variables at script-run time#20
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
${VAR}interpolation was resolved at script-generation time (against compose2pod's ownos.environ, added in #18). For the tool's real use case — generate a script now, run it later in CI where the secrets/tokens actually exist — that baked any variable unset at generation time to an empty string. This branch defers interpolation to script-run time: compose-derived values are emitted as double-quoted POSIX-shell fragments whose variable references stay live, so the generated script's own shell expands them against the environment present when it runs.Design and rationale:
planning/changes/2026-07-08.07-runtime-variable-interpolation.md.What changed
compose2pod/shell.py:to_shell()re-encodes a compose string into a shell fragment ($$→$, bare$VAR→${VAR-}so an unset var expands to empty and survivesset -eu, operator forms pass through, command substitution and literal specials escaped);variable_names()extracts referenced names.emitclassifies each token as literal (shlex.quote) or expandable (_Expand→to_shell).environment,image,command,volumes,tmpfs,env_file, and healthchecktestinterpolate at run time; tool/CLI values (--project-dir,--image, pod name,--command) stay literal.emit.referenced_variables, sourced from the same tokensto_shellrenders).compose2pod/interpolate.pyand its generation-timeinterpolateexport;to_shellreplaces it in the public API.architecture/supported-subset.mdandREADME.mdupdated.Consequences (deliberate)
${VAR}expands to empty at run time.${VAR:?msg}now fails the script at run time when unset/empty (POSIXshenforces it, aborting before podman runs) instead of failing generation.Testing
just test-cipasses at 100% line coverage (119 tests);just lint-ciclean.test_shell.pyexecutes emitted fragments under realsh -eucto prove runtime expansion, the${VAR:?}abort, and command-substitution inertness.🤖 Generated with Claude Code