#!/bin/bash # Runs a role's Molecule scenario locally. # # Called through `just molecule [role] [args...]`. With no role, lists the roles # that have a scenario. # # The same scenarios run in CI (.github/workflows/molecule.yml), but running one # here is the faster loop while writing or fixing a role: CI only tells you after # a push, and only about the roles that push touched. # # Deliberately NOT wired into prek. A run takes minutes, pulls container images # and needs a working Docker - which is fine when you ask for it, and not fine on # every commit. # # Usage: # just molecule # list roles that have a scenario # just molecule matrix-alertmanager-receiver # just molecule matrix-alertmanager-receiver converge # any molecule subcommand # # Environment: # MOLECULE_DISTRO base image to test on (default: ubuntu2604) set -euo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" roles_dir="${repo_dir}/roles/custom" venv_dir="${repo_dir}/var/molecule-venv" list_roles() { find "${roles_dir}" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' \ | while read -r candidate; do if [ -f "${roles_dir}/${candidate}/molecule/default/molecule.yml" ]; then echo "${candidate}" fi done \ | sort } role="${1:-}" if [ -z "${role}" ]; then echo "Roles with a Molecule scenario:" found="$(list_roles)" if [ -z "${found}" ]; then echo " (none yet)" else printf ' %s\n' ${found} fi echo echo "Run one with: just molecule " exit 0 fi shift || true if [ ! -f "${roles_dir}/${role}/molecule/default/molecule.yml" ]; then echo "No Molecule scenario at roles/custom/${role}/molecule/default" >&2 echo >&2 echo "Roles that have one:" >&2 list_roles | sed 's/^/ /' >&2 exit 1 fi # The virtualenv lives under var/, which is gitignored, and is shared by every # role - the dependencies are the same for all of them. if [ ! -x "${venv_dir}/bin/molecule" ]; then echo "Creating the Molecule virtualenv in ${venv_dir/#$HOME/\~} ..." python3 -m venv "${venv_dir}" "${venv_dir}/bin/pip" install --quiet --upgrade pip "${venv_dir}/bin/pip" install --quiet -r "${repo_dir}/molecule-shared/requirements.txt" fi # Galaxy content is installed with `force: true` on every run, so two scenarios # running at once will re-extract collections and roles into the same directory # and pull them out from under each other mid-play. It shows up as a collection # that was working moments earlier going missing: # # the connection plugin 'community.docker.docker' was not found # # ANSIBLE_HOME relocates both `collections/` and `roles/`, so one variable is # enough to give each role its own. The scenarios' ANSIBLE_ROLES_PATH follows it. # # Unset in CI, where it falls back to ~/.ansible - each role runs in its own job # there, so there is nothing to collide with and nothing to gain from isolation. export ANSIBLE_HOME="${ANSIBLE_HOME:-${repo_dir}/var/molecule-ansible-home/${role}}" export MOLECULE_DISTRO="${MOLECULE_DISTRO:-ubuntu2604}" export PY_COLORS="${PY_COLORS:-1}" export ANSIBLE_FORCE_COLOR="${ANSIBLE_FORCE_COLOR:-1}" echo "Running Molecule for ${role} on ${MOLECULE_DISTRO} ..." cd "${roles_dir}/${role}" if [ $# -eq 0 ]; then exec "${venv_dir}/bin/molecule" test --scenario-name default fi exec "${venv_dir}/bin/molecule" "$@" --scenario-name default