Skip to content

make the local venv match CI - #24

Merged
vpzed-dev-lux merged 2 commits into
mainfrom
venv-matches-ci
Aug 28, 2026
Merged

make the local venv match CI#24
vpzed-dev-lux merged 2 commits into
mainfrom
venv-matches-ci

Conversation

@vpzed-dev-lux

Copy link
Copy Markdown
Collaborator

Why

CI and a workstation ran different software, and the difference decided lint results:

local (before) CI (before)
ansible ansible==14.3.1, 244 MB of collections in site-packages pipx install ansible-core, unpinned
ansible-lint same venv, ==26.8.0 pipx install ansible-lint, unpinned, with its own second ansible-core
collections whatever ansible 14.3.1 shipped (45 namespaces) exactly ansible/requirements.yml, in $RUNNER_TEMP
Python 3.14.7, uv-managed the runner's

So ansible/requirements.yml was authoritative in CI and decorative locally: a task using an unlisted community.* module passed on a workstation and failed in CI — which is how PR #22 went red.

Both sides now build the same environment from the same two files: requirements.txt for Python, ansible/requirements.yml for collections.

Not done, deliberately: giving CI the full ansible package. That would hand both sides collections nobody pinned and make ansible/requirements.yml inert — the guarantee worth having is that a missing pin fails everywhere.

What changed

  • requirements.txtansible out, ansible-core stays; regenerated with uv pip freeze the way the file was originally made. Only other movement is platformdirs 4.11.4 → 4.11.5 from the fresh resolve. black and yamllint are ansible-lint dependencies, so they survive.
  • scripts/install-collections.sh (new) — the one way collections get installed, run by both environments. Installs into the ANSIBLE_COLLECTIONS_PATH its caller names, --force so a copy elsewhere in galaxy's search path cannot turn it back into a "Nothing to do" no-op.
  • tofu.env — exports ANSIBLE_COLLECTIONS_PATH=$PWD/.venv/share/ansible/collections. Under .venv/ so recreating the venv takes the collections with it; setting it also replaces ansible's defaults, which is the point.
  • .github/workflows/validate.yaml — drops pipx for uv venv --python 3.14 --managed-python + uv pip install -r requirements.txt (the README's own commands), .venv/bin onto $GITHUB_PATH, and the same script. The path is a job-level env: entry built from github.workspace; runner is unavailable in that block, which is what produced the invalid-workflow run on golden image cutover #22.
  • scripts/check-ansible.sh — new first check: every pin in ansible/requirements.yml installed at exactly the pinned version, naming install-collections.sh when not. Without it a stale collection shows up only as an opaque ansible-lint failure three checks later.
  • DocsREADME.md (setup steps, tree, the "Collections are pinned" bullet), CLAUDE.md (what tofu.env exports, the venv/collections relationship), and the header of ansible/requirements.yml, which previously described this change as the fix to make.

Verification

ok    collections (2 pinned)
ok    inventory (1 host(s))
ok    site.yaml syntax
ok    ansible-lint
  • tofu validate and tofu fmt -check -recursive pass; tofu plan reports No changes — no VM is touched by this.
  • ansible-doc community.general.timezone resolves out of .venv/share/ansible/collections, so the module is found at execution time, not just by lint.
  • Negative test: temporarily pointing a base task at community.docker.docker_host_info now fails locally with syntax-check[unknown-module], which is the whole claim — before this, it would have linted clean here and failed in CI. Reverted.

CI and a workstation ran different software, and the difference decided lint
results: requirements.txt pinned the batteries-included `ansible` package, so
locally every collection in it resolved and ansible/requirements.yml was
decorative, while CI installed only the two pins into a pipx-based
environment. A task using an unlisted community.* module passed here and
failed there - which is exactly how PR #22 went red.

Both sides now build the same environment from the same two files:

- requirements.txt pins ansible-core instead of ansible (regenerated with
  uv pip freeze; platformdirs moved 4.11.4 -> 4.11.5 in the fresh resolve).
- CI drops pipx for `uv venv --python 3.14 --managed-python` plus
  `uv pip install -r requirements.txt`, the same commands README.md gives an
  operator, and puts .venv/bin on $GITHUB_PATH.
- scripts/install-collections.sh is the one way collections are installed,
  used by both, into the ANSIBLE_COLLECTIONS_PATH its caller names: tofu.env
  sets .venv/share/ansible/collections locally, the workflow's job env: block
  the same path under the workspace. Recreating the venv now takes the
  collections with it.
- check-ansible.sh verifies the installed collections against the pins before
  anything else, so a missing one says so instead of surfacing as an opaque
  ansible-lint "couldn't resolve module/action".

Verified: check-ansible.sh reports ok on all four checks, tofu validate and
fmt -check pass, tofu plan is unchanged, and pointing a task at an unpinned
collection now fails ansible-lint locally the way it always did in CI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzjHsAQ3HkQjLdgv5PVi55
@vpzed-dev-lux
vpzed-dev-lux requested a review from vpzed as a code owner August 28, 2026 22:32
@vpzed-dev-lux
vpzed-dev-lux requested a review from vpzed August 28, 2026 22:32
astral-sh/setup-uv publishes no moving major alias past v8: v9 and v10 exist
only as full version tags, so @v10 failed the run at "Prepare all required
actions" before any step ran. Pinning the exact version is what the rest of
this repo does anyway.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzjHsAQ3HkQjLdgv5PVi55
@vpzed-dev-lux
vpzed-dev-lux merged commit 0e80ad3 into main Aug 28, 2026
1 check passed
@vpzed-dev-lux
vpzed-dev-lux deleted the venv-matches-ci branch August 28, 2026 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants