#!/usr/bin/env bash # Run every check this repo has. CI and pre-commit call the same script. # Usage: scripts/check.sh [--changed] set -euo pipefail shopt -s nullglob cd "$(dirname "${BASH_SOURCE[0]}")/.." changed=0 for arg in "$@"; do case "$arg" in --changed) changed=1 ;; *) echo "unknown argument: $arg" >&2 echo "usage: scripts/check.sh [--changed]" >&2 exit 2 ;; esac done # Ansible and uv want writable caches. Keep them in the checkout so the script # works when $HOME is read-only, which is the case in the agent sandbox. export ANSIBLE_CONFIG="${ANSIBLE_CONFIG:-$PWD/ansible.cfg}" export ANSIBLE_HOME="${ANSIBLE_HOME:-$PWD/.ansible/home}" export ANSIBLE_LOCAL_TEMP="${ANSIBLE_LOCAL_TEMP:-$PWD/.ansible/tmp}" export ANSIBLE_GALAXY_CACHE_DIR="${ANSIBLE_GALAXY_CACHE_DIR:-$PWD/.ansible/galaxy_cache}" export UV_CACHE_DIR="${UV_CACHE_DIR:-$PWD/.ansible/uv-cache}" export UV_TOOL_DIR="${UV_TOOL_DIR:-$PWD/.ansible/uv-tools}" export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$PWD/.scratch/cache}" export PIP_CACHE_DIR="${PIP_CACHE_DIR:-$PWD/.scratch/cache/pip}" mkdir -p "$ANSIBLE_LOCAL_TEMP" "$UV_CACHE_DIR" "$UV_TOOL_DIR" \ "$ANSIBLE_GALAXY_CACHE_DIR" "$ANSIBLE_HOME" "$XDG_CACHE_HOME" "$PIP_CACHE_DIR" if [ -f requirements.yml ]; then echo "== ansible-galaxy collection install ==" ansible-galaxy collection install -r requirements.yml fi run() { local tool="$1" shift if command -v "$tool" >/dev/null 2>&1; then "$tool" "$@" else uvx "$tool" "$@" fi } # YAML files that differ from HEAD, including new files that are not staged yet. yaml_files=() if [ "$changed" = 1 ]; then while IFS= read -r file; do [ -n "$file" ] && yaml_files+=("$file") done < <( git diff --name-only --diff-filter=ACMR HEAD -- '*.yml' '*.yaml' git ls-files --others --exclude-standard -- '*.yml' '*.yaml' ) fi # ansible-lint only understands Ansible files, so keep the changed files that # live under a service with a playbook. ansible_files=() if [ "$changed" = 1 ]; then for file in "${yaml_files[@]}"; do service="${file%%/*}" if [ -f "$service/playbook.yml" ]; then ansible_files+=("$file") fi done fi if [ "$changed" = 1 ] && [ "${#yaml_files[@]}" -eq 0 ]; then echo "== changed mode: no YAML files changed ==" else echo "== yamllint ==" if [ "$changed" = 1 ]; then run yamllint "${yaml_files[@]}" else run yamllint . fi echo "== ansible-lint ==" if [ "$changed" = 1 ] && [ "${#ansible_files[@]}" -eq 0 ]; then echo "no changed Ansible files" elif [ "$changed" = 1 ]; then run ansible-lint "${ansible_files[@]}" else run ansible-lint fi fi echo "== layout ==" layout_ok=1 for playbook in */playbook.yml; do service="${playbook%/playbook.yml}" if [ ! -s "$service/readme.md" ]; then echo "missing or empty $service/readme.md" >&2 layout_ok=0 fi done for entrypoint in */roles/*/tasks/main.yml */roles/*/handlers/main.yml; do echo "role entrypoint must use .yaml: $entrypoint" >&2 layout_ok=0 done if [ "$layout_ok" -ne 1 ]; then exit 1 fi echo "== gitleaks ==" ./scripts/check-secrets.sh echo "== ansible-playbook --syntax-check ==" playbooks=() if [ "$changed" = 1 ]; then for file in "${yaml_files[@]}"; do service="${file%%/*}" if [ -f "$service/playbook.yml" ]; then playbooks+=("$service/playbook.yml") fi done if [ "${#playbooks[@]}" -gt 0 ]; then mapfile -t playbooks < <(printf '%s\n' "${playbooks[@]}" | sort -u) fi else playbooks=(*/playbook.yml) fi if [ "${#playbooks[@]}" -eq 0 ]; then echo "no playbooks to check" else for playbook in "${playbooks[@]}"; do echo "-- $playbook" ansible-playbook --syntax-check "$playbook" done fi