Skip to main content

Readable, per-host summaries of ansible-playbook --check --diff runs, with explicit flagging of tasks that cannot be previewed.

Project description

playcheck

CI PyPI Python ansible-core License: MIT

Readable previews for ansible-playbook --check --diff.

Ansible's check mode tells you what a playbook would change — but the raw output is an unstructured scroll, and tasks that can't be simulated (shell, command, raw, …) are silently skipped with the same skipping: line as an ordinary conditional skip. People read "no diff shown" as "no change", and that's false.

playcheck runs the check for you and reformats the result so it's readable in ten seconds:

  • Per-host groupingweb-01: 4 changes · 2 not previewable
  • Colored add/remove diffs instead of raw unified-diff walls
  • Explicit flagging of every task that could not be previewed, including tasks with check_mode: false that executed for real during the check
  • Top-line summary — hosts affected, tasks that would change, tasks that could not be simulated
$ playcheck run site.yml -i inventory.ini

web-01  4 changes · 2 not previewable
  ~ Write nginx config (copy)
      +server {
      +  listen 80;
      +}
  ! Restart nginx (shell)  NOT PREVIEWED — Command would have run if not in check mode
  ~ Write API token (copy)  [diff censored (no_log)]

SUMMARY
  hosts: 2 of 2 would change
  tasks: 5 would change (2 with hidden diffs)
  ⚠ 3 tasks were NOT simulated (module does not support check mode) — the real run may change more than shown.

Install

pipx install playcheck   # or: pip install playcheck

Requires Python ≥ 3.9 and an existing ansible-playbook on PATH (ansible-core ≥ 2.9). No other dependencies.

Usage

playcheck run <playbook> -i <inventory> [-l LIMIT] [-t TAGS] [--no-color] [--quiet]

Anything after -- is passed to ansible-playbook unchanged:

playcheck run site.yml -i prod.ini -- -e env=prod --vault-password-file .vault

playcheck adds --check --diff itself — it never applies changes. The exit code mirrors ansible-playbook's (0 on success even when changes are pending; non-zero on task failures or unreachable hosts).

For CI gating there are two opt-in exit codes, checked in this order after a clean ansible run:

flag exit code meaning
--fail-on-changes 3 at least one task would change something
--fail-on-unpreviewable 4 at least one task could not be simulated

--format markdown emits a GitHub-flavored report (collapsible per-host sections, fenced diffs) suitable for PR comments and $GITHUB_STEP_SUMMARY.

GitHub Action

Post the preview as a PR comment, terraform plan-style. The comment is updated in place on subsequent pushes instead of spamming the thread:

on: pull_request

jobs:
  preview:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: Cjayy77/Playcheck@v0
        with:
          playbook: site.yml
          inventory: inventory/prod.ini
          ansible-core-version: "2.17"   # optional
          extra-args: "-l web -e env=prod"

How it works

playcheck doesn't scrape ansible's human-readable output (which is ambiguous — an unsupported-check-mode skip and a when:-conditional skip print identically). Instead it ships a tiny stdout callback plugin and invokes ansible-playbook with ANSIBLE_STDOUT_CALLBACK=playcheck_jsonl, receiving one structured JSON event per task result, including diffs, skip reasons, and check-mode metadata.

Safety notes:

  • no_log results are censored by Ansible before they reach any callback; playcheck never sees the secret.
  • diff: false tasks arrive with an empty diff; playcheck marks them [diff hidden by task setting] rather than pretending nothing changed.
  • Any skip that can't be positively attributed to a when: condition is flagged as not previewed. Over-flagging is a feature: silently missing an unsimulated task is the exact failure this tool exists to prevent.

Status

Alpha. CLI formatter and GitHub Action work; GitLab CI wrapper is planned.

Verified against ansible-core 2.15, 2.17, 2.19, and 2.21 with real --check --diff runs — the test suite replays against fresh captures from each version (scripts/version_matrix.sh, also run in CI), not hand-written fixtures. Classification never depends on exact skip-message text: any skip that can't be positively attributed to a when: conditional is flagged, which is what catches raw (skipped with no message at all) and whatever future ansible versions do differently.

Development

pip install -e . pytest
pytest

# regenerate fixtures from a real run (Linux/WSL, needs ansible-core):
ANSIBLE_STDOUT_CALLBACK=playcheck_jsonl \
ANSIBLE_CALLBACK_PLUGINS=src/playcheck/_ansible/callback_plugins \
ansible-playbook testdata/site.yml -i testdata/inventory.ini --check --diff \
  > tests/fixtures/jsonl_output.jsonl

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

playcheck-0.1.0.tar.gz (19.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

playcheck-0.1.0-py3-none-any.whl (17.9 kB view details)

Uploaded Python 3

File details

Details for the file playcheck-0.1.0.tar.gz.

File metadata

  • Download URL: playcheck-0.1.0.tar.gz
  • Upload date:
  • Size: 19.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for playcheck-0.1.0.tar.gz
Algorithm Hash digest
SHA256 87a4c3303ec52d64831bc253b2abcc7a1f38d01ccf41883c03391d60042e6852
MD5 5ab7d77a4996875de1b854a60ed8f3e3
BLAKE2b-256 056977da6c35a68be3e43697b154f5cb1843ad5a158b684ca3f8e28b600eb4e0

See more details on using hashes here.

Provenance

The following attestation bundles were made for playcheck-0.1.0.tar.gz:

Publisher: release.yml on Cjayy77/Playcheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file playcheck-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: playcheck-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for playcheck-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b54abcb5eccd5df2acd80e1b8c1ad55557994e2a9bcfb41c87daac2a066d71f2
MD5 d5361a1d70893e53b5d9c12e4c5e4e4a
BLAKE2b-256 5826862e33b48983c4ac3e560f5d3684e792d944b513beb1106a9889a216c6a2

See more details on using hashes here.

Provenance

The following attestation bundles were made for playcheck-0.1.0-py3-none-any.whl:

Publisher: release.yml on Cjayy77/Playcheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page