-
-
Notifications
You must be signed in to change notification settings - Fork 146
Description
Describe the Feature
Add a configuration option — at either the global atmos.yaml level or per-component source: block — that instructs Atmos to always re-pull from the remote source when a JIT-vendored component is used, rather than reusing an existing .workdir directory.
Expected Behavior
When the option is enabled, every atmos terraform $command would fetch the latest content from the configured source.uri + source.version, even if a .workdir for that component already exists on disk. The stale .workdir would be replaced rather than reused.
When the option is disabled (current default), behavior is unchanged — existing .workdir contents are reused as a cache.
Use Case
During active development of a JIT-vendored Terraform module, the inner loop looks like:
- Make a change to the upstream module and push it to the remote.
- Run
atmos terraform plan <component> -s <stack>locally to validate.
With the current behavior, Atmos detects that a .workdir already exists and skips the pull entirely. The developer is silently running against stale code. The only workarounds today are:
- Manually delete
.workdirbefore every plan (rm -rf .workdir/terraform/<component>). - Run
atmos terraform source pull --forceas a separate step before every plan. - Remember to do this — which they won't, and which breaks CI parity.
This is especially painful when:
- The
source.versionis a branch or floating ref (e.g.,main,develop) rather than a pinned tag, where "latest" genuinely changes. - Multiple engineers are iterating on the same upstream module and expect their colleagues' pushes to be picked up automatically.
- CI pipelines run in ephemeral environments where
.workdirdoesn't persist, but local developer environments do — creating a behavioral gap.
Describe Ideal Solution
components:
terraform:
source:
force_pull: true # re-pull on every command invocation; default: falseOption 2 — Per-component source: block override
components:
terraform:
my-module-iac:
source:
uri: "git::https://github.com/org/repo.git"
version: "main"
force_pull: true # overrides global default for this component only
provision:
workdir:
enabled: true
metadata:
component: "my-module"Both options should be composable: a global force_pull: false with a per-component force_pull: true lets teams pin stable components while keeping actively-developed ones fresh.
A CLI flag override would also be welcome for one-off use without changing config:
atmos terraform plan my-module-iac -s demo-dev --jit-pull-strategy=alwaysAlternatives Considered
1. Always run atmos terraform source pull --force manually before plan
Problem: Requires discipline and adds a manual step. Breaks when forgotten. Not enforceable in a shared workflow. Also currently affected by the workdir path mismatch bug (see related issue).
2. Delete .workdir before running
Problem: Blunt instrument — nukes all cached components, not just the one being developed. Slow in monorepos with many JIT components. Error-prone.
3. Use a pinned version/tag instead of a branch ref
Problem: Doesn't apply during the development cycle itself, where by definition the "version" is work-in-progress and not yet tagged. Forces an artificial tagging overhead for every iteration.
4. Content-hash or git-sha staleness check
A more sophisticated alternative to a hard force_pull would be a staleness check: compare the commit SHA of the remote ref against what was last pulled, and only re-pull on mismatch. This would be ideal for floating refs like branch names and avoids unnecessary network traffic for pinned tags. This could be a separate, complementary option:
source:
uri: "git::https://github.com/org/repo.git"
version: "main"
pull_strategy: "if-changed" # options: "cached" (default) | "always" | "if-changed"Additional Context
- Bug: JIT
source pullwrites to a different workdir thaninit/planwhenmetadata.componentdiffers from instance name (see companion issue) JIT vendoring (source pull) writes to a different workdir thanterraform plan/initwhenmetadata.componentdiffers from the component instance name #2134
Demo
The following script shows what the proposed behavior would look like with force_pull: true enabled. It uses a local git repo as the upstream source so no credentials or network access are required.
Note (macOS):
/tmpand/varare symlinks to/private/tmpand/private/var. The script usespwd -Pto resolve the real path so thatfile://URIs are absolute and go-getter can clone them correctly.
#!/usr/bin/env bash
# ============================================================
# ATMOS FEATURE DEMO: force_pull — always re-pull JIT source
# ============================================================
set -euo pipefail
WORKDIR="$(mktemp -d -t atmos-repro-XXXXXX)"
# Resolve macOS symlinks (/var -> /private/var) so file:// URIs are absolute
WORKDIR="$(cd "${WORKDIR}" && pwd -P)"
echo "Working in: ${WORKDIR}"
cd "${WORKDIR}"
# --- 1) Create a local git repo to act as the upstream module ---
UPSTREAM="${WORKDIR}/upstream"
mkdir -p "${UPSTREAM}"
cd "${UPSTREAM}"
git init -b main
git config user.email "demo@example.com"
git config user.name "Demo"
cat <<'TFEOF' > main.tf
# version: 1
output "version" { value = "v1" }
TFEOF
git add .
git commit -m "v1"
cd "${WORKDIR}"
# --- 2) atmos.yaml with proposed force_pull setting ---
cat <<EOF > atmos.yaml
base_path: "."
components:
terraform:
base_path: "components/terraform"
command: "tofu"
deploy_run_init: true
auto_generate_backend_file: true
source:
force_pull: true # <-- proposed global setting: always re-pull on invocation
stacks:
name_template: "{{ .vars.name }}"
base_path: "stacks"
included_paths:
- "**/*"
EOF
# --- 3) Stack with a JIT-sourced component on a floating branch ref ---
mkdir -p stacks
cat <<EOF > stacks/demo.yaml
vars:
name: demo
terraform:
backend_type: local
components:
terraform:
my-module:
source:
uri: "git::file://${UPSTREAM}"
version: "main"
provision:
workdir:
enabled: true
EOF
# --- 4) First init — pulls v1 from upstream ---
echo
echo "=== init (v1 in upstream) ==="
atmos terraform init my-module -s demo
echo "--- .workdir contents ---"
grep -r 'value' .workdir/ --include="*.tf" || true
# --- 5) Commit v2 to upstream (simulates a teammate pushing a change) ---
echo
echo "=== committing v2 to upstream ==="
cd "${UPSTREAM}"
cat <<'TFEOF' > main.tf
# version: 2
output "version" { value = "v2" }
TFEOF
git add .
git commit -m "v2"
cd "${WORKDIR}"
# --- 6) Second init — with force_pull: true, should detect and pull v2 ---
echo
echo "=== init (v2 pushed upstream, force_pull: true should re-pull) ==="
atmos terraform init my-module -s demo
echo "--- .workdir contents ---"
grep -r 'value' .workdir/ --include="*.tf" || true
echo
echo "Done. Workspace preserved at: ${WORKDIR}"Expected output with force_pull: true: the second init block shows v2, confirming the upstream change was picked up without manual intervention.