.PHONY: all setup setup-ci setup-quality setup-molecule setup-release install-devx install update lint ansible-lint makefile-lint lint-all test test-unit pytest-cov molecule molecule-all test-all clean workflow-lint workflow-dryrun workflow-check install-tools PYTHON := python3 VENV := .venv BIN := $(VENV)/bin CHECKMAKE := $(shell command -v checkmake 2>/dev/null || echo $(HOME)/go/bin/checkmake) all: setup # Pinned devx version — update this when upgrading devx. # All workflow files (.gitea/workflows/*.yml) must be updated to match. DEVX_VERSION := v0.12.0 install-devx: $(VENV)/bin/activate @# REPO_TOKEN may come from .env (local) or environment (CI secrets) @if [ -z "$$REPO_TOKEN" ]; then . ./.env 2>/dev/null; fi; \ if [ -z "$$REPO_TOKEN" ]; then echo "REPO_TOKEN not set (check .env or environment)"; exit 1; fi; \ $(BIN)/pip install "devx==$(shell echo $(DEVX_VERSION) | sed 's/^v//')" \ --extra-index-url "https://emil:$$REPO_TOKEN@git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple/" # Full setup for local development (all deps, tools, collections, hooks) # install-devx must run before install-tools (which uses devx modules) setup: $(VENV)/bin/activate .env activate-scripts install-devx checkmake install-tools @export PATH="$(HOME)/.local/bin:$$PATH"; \ $(BIN)/python -m devx.tools.setup --bin "$(BIN)" # Lean setup for CI jobs that need pytest + lint tools + runtime deps # (detect-changes, discover-runners, pr-review, sync-wiki, badges) # badges job runs generate_badges.py which needs ruff, pyright, bandit setup-ci: $(VENV)/bin/activate .env install-devx @$(BIN)/python -m devx.tools.setup --bin "$(BIN)" --extras "ci,lint" --no-ansible-collections --no-pre-commit --no-tea-login # Setup for the quality job (lint + test deps, actionlint tool) # install-devx must run before install-tools (which uses devx modules) setup-quality: $(VENV)/bin/activate .env install-devx install-tools @export PATH="$(HOME)/.local/bin:$$PATH"; \ $(BIN)/python -m devx.tools.setup --bin "$(BIN)" --extras "ci,lint" --no-ansible-collections --no-pre-commit --no-tea-login # Full setup for molecule testing (needs ansible, molecule, collections) setup-molecule: $(VENV)/bin/activate .env install-devx install-tools @export PATH="$(HOME)/.local/bin:$$PATH"; \ $(BIN)/python -m devx.tools.setup --bin "$(BIN)" --extras "ci,molecule" --no-pre-commit --no-tea-login # Setup for release jobs (needs git-cliff, tea, and lint tools for release.py) setup-release: $(VENV)/bin/activate .env install-devx @$(BIN)/python -m devx.tools.install_tools --tool git-cliff --tool tea @export PATH="$(HOME)/.local/bin:$$PATH"; \ $(BIN)/python -m devx.tools.setup --bin "$(BIN)" --extras "ci,lint" --no-ansible-collections --no-pre-commit .env: @if [ ! -f .env ]; then \ cp .env.example .env; \ echo "Created .env from .env.example — please edit it with your credentials."; \ fi $(VENV)/bin/activate: @python3 -c "import sys; v=sys.version_info; assert v >= (3, 12), f'Python 3.12+ required, found {v.major}.{v.minor}'; print(f'Python {v.major}.{v.minor}.{v.micro} OK')" $(PYTHON) -m venv $(VENV) $(BIN)/pip install --upgrade pip setuptools wheel activate-scripts: $(VENV)/bin/activate @test -f activate.sh || (echo '#!/usr/bin/env bash' > activate.sh && echo 'source "$$(cd "$$(dirname "$${BASH_SOURCE[0]}")" && pwd)/.venv/bin/activate"' >> activate.sh && chmod +x activate.sh) @test -f activate.fish || (echo '#!/usr/bin/env fish' > activate.fish && echo 'set -l script_dir (dirname (status --current-filename))' >> activate.fish && echo 'source "$$script_dir/.venv/bin/activate.fish"' >> activate.fish && chmod +x activate.fish) @test -f activate.zsh || (echo '#!/usr/bin/env zsh' > activate.zsh && echo '0="$${ZERO:-$${0:#$$ZSH_ARGZERO}}"' >> activate.zsh && echo '0="$${$${(M)0:#/*}:-$$PWD/$$0}"' >> activate.zsh && echo 'source "$${0:A:h}/.venv/bin/activate"' >> activate.zsh && chmod +x activate.zsh) install-hooks: @cp hooks/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit @cp hooks/pre-push .git/hooks/pre-push && chmod +x .git/hooks/pre-push @echo "Git hooks installed." checkmake: install-devx @$(BIN)/python -m devx.tools.install_checkmake install-tools: install-devx @$(BIN)/python -m devx.tools.install_tools install: @if [ -z "$(HOST)" ]; then echo "HOST is required. Example: make install HOST=192.168.1.10"; exit 1; fi $(BIN)/grm install $(HOST) $(if $(USER),--user $(USER),) $(if $(KEY),--key $(KEY),) $(if $(NAME),--name $(NAME),) $(if $(TOKEN),--token $(TOKEN),) $(if $(ASK_BECOME_PASS),--ask-become-pass,) update: @if [ -z "$(HOST)" ]; then echo "HOST is required. Example: make update HOST=192.168.1.10"; exit 1; fi $(BIN)/grm update $(HOST) $(if $(USER),--user $(USER),) $(if $(KEY),--key $(KEY),) $(if $(VERSION),--version $(VERSION),) $(if $(ASK_BECOME_PASS),--ask-become-pass,) start: @if [ -z "$(HOST)" ]; then echo "HOST is required. Example: make start HOST=192.168.1.10"; exit 1; fi $(BIN)/grm start $(NAME) $(if $(HOST),--host $(HOST),) $(if $(USER),--user $(USER),) $(if $(ASK_BECOME_PASS),--ask-become-pass,) stop: @if [ -z "$(HOST)" ]; then echo "HOST is required. Example: make stop HOST=192.168.1.10"; exit 1; fi $(BIN)/grm stop $(NAME) $(if $(HOST),--host $(HOST),) $(if $(USER),--user $(USER),) $(if $(ASK_BECOME_PASS),--ask-become-pass,) enable: @if [ -z "$(HOST)" ]; then echo "HOST is required. Example: make enable HOST=192.168.1.10"; exit 1; fi $(BIN)/grm enable $(NAME) $(if $(HOST),--host $(HOST),) $(if $(USER),--user $(USER),) $(if $(ASK_BECOME_PASS),--ask-become-pass,) disable: @if [ -z "$(HOST)" ]; then echo "HOST is required. Example: make disable HOST=192.168.1.10"; exit 1; fi $(BIN)/grm disable $(NAME) $(if $(HOST),--host $(HOST),) $(if $(USER),--user $(USER),) $(if $(TOKEN),--token $(TOKEN),) $(if $(ASK_BECOME_PASS),--ask-become-pass,) status: @if [ -z "$(HOST)" ]; then echo "HOST is required. Example: make status HOST=192.168.1.10"; exit 1; fi $(BIN)/grm status $(NAME) $(if $(HOST),--host $(HOST),) $(if $(USER),--user $(USER),) $(if $(ASK_BECOME_PASS),--ask-become-pass,) remove: @if [ -z "$(HOST)" ]; then echo "HOST is required. Example: make remove HOST=192.168.1.10"; exit 1; fi $(BIN)/grm remove $(NAME) $(if $(HOST),--host $(HOST),) $(if $(USER),--user $(USER),) $(if $(TOKEN),--token $(TOKEN),) $(if $(ASK_BECOME_PASS),--ask-become-pass,) lint-ruff: $(BIN)/ruff check src/ tests/ lint-format: $(BIN)/ruff format --check src/ tests/ typecheck: $(BIN)/pyright lint: lint-ruff lint-format typecheck lint-bandit lint-bandit: $(BIN)/bandit -r src/ lint-deps: @echo "Checking dependencies for known vulnerabilities..." @.venv/bin/python -m ensurepip 2>/dev/null || true @PIPAPI_PYTHON_LOCATION=$$(pwd)/.venv/bin/python \ .venv/bin/pip-audit --desc --skip-editable 2>&1 || true ansible-lint: PATH="$(PWD)/$(BIN):$$PATH" $(BIN)/ansible-lint ansible/ makefile-lint: @if command -v $(CHECKMAKE) >/dev/null 2>&1 || [ -x "$(CHECKMAKE)" ]; then \ $(CHECKMAKE) Makefile; \ else \ echo "checkmake not found, skipping Makefile lint"; \ fi lint-all: lint ansible-lint makefile-lint workflow-lint workflow-lint: @command -v actionlint >/dev/null 2>&1 || { \ echo "actionlint not found. Install: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)"; \ exit 1; \ } actionlint -config-file .gitea/actionlint.yaml .gitea/workflows/*.yml workflow-dryrun: @command -v act_runner >/dev/null 2>&1 || { echo "act_runner not found. Install: https://gitea.com/gitea/act_runner/releases"; exit 1; } @echo "Dry-running all workflows (no Docker containers started)..." act_runner exec --dryrun -W .gitea/workflows/ 2>&1 | grep -E 'DRYRUN|ERROR|FAIL|Job' workflow-check: workflow-lint workflow-dryrun @echo "Workflow checks passed (static lint + dry-run)." test-unit: $(BIN)/pytest tests/unit/ -v --no-cov test-integration: $(BIN)/pytest tests/integration/ -v --no-cov pytest-cov: $(BIN)/pytest tests/ -v --cov=src/gitea_runner_manager --cov-report=term-missing --cov-fail-under=100 MOLECULE := $(realpath $(BIN))/molecule MOLECULE_BASE := cd $(CURDIR)/ansible/roles/gitea-runner && ANSIBLE_ALLOW_BROKEN_CONDITIONALS=true ANSIBLE_INJECT_INVOCATION=1 $(MOLECULE) # Quick local test: Ubuntu 22.04 only, all scenarios molecule: @set -e; for s in default multi-instance lifecycle template-content deregister update; do if [ "$$s" = "default" ]; then $(MOLECULE_BASE) test; else $(MOLECULE_BASE) test -s $$s; fi; done # All scenarios on all supported platforms (sequential; use CI matrix for parallel execution) molecule-all: @$(BIN)/python -m devx.molecule.molecule_all --bin "$(BIN)" test: test-all test-all: pytest-cov molecule clean: find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true find . -type f -name "*.pyc" -delete 2>/dev/null || true rm -rf .coverage htmlcov/ .molecule/