# CLI Commands devx provides a CLI with three command groups: `ci`, `tools`, and `molecule`. Each subcommand delegates to the corresponding Python module via `python -m devx.*`, so `devx ci release` is equivalent to `python -m devx.ci.release`. ```bash devx --help # show all command groups devx --version # show package version devx ci --help # show CI commands devx tools --help # show tools commands devx molecule --help # show molecule commands ``` ## CI Commands ### `devx ci auto-merge` Auto-merge a PR when all CI checks pass. Reads the task ID from the branch name, validates the PR title format against the Vikunja task title, extracts the conventional commit message from PR commits, and squash-merges with `{PREFIX}-N ` title. If the head branch is behind master (HTTP 405), automatically pulls master, rebases, force-pushes, and retries the merge. ```bash devx ci auto-merge # Example: devx ci auto-merge DEVX-12-add-feature "DEVX-12: Add feature" oblachno-oss/devx 42 ``` ### `devx ci check-translations` Check translation files for gaps, dead keys, and missing languages. Validates translation files against the Python source code that uses them. By default, checks `src/devx/translations.json` against `src/devx/**/*.py`. Checks performed: - **Missing keys** — a `_()` call in code has no entry in the translations file - **Dead keys** — a key in the translations file is not used in any code - **Missing languages** — a key exists but is missing one of the six supported languages (en, bg, de, ru, zh, pl) ```bash devx ci check-translations devx ci check-translations --translations path/to/translations.json ``` ### `devx ci classify-changes` Classify git changes as user-facing or workflow-only. Used to skip releases for infrastructure-only changes. Classification rules are configured in `pyproject.toml` under `[tool.devx.classify]`. ```bash devx ci classify-changes --base origin/master --head HEAD devx ci classify-changes --base origin/master --head HEAD --github-output devx ci classify-changes --quiet --check user-facing devx ci classify-changes --check ansible # custom tag from pyproject.toml ``` Options: - `--base ` — base ref (default: latest tag) - `--head ` — head ref (default: HEAD) - `--quiet` — only output true/false - `--check ` — check specific category: `all` (default), `user-facing`, or any tag name defined in `[tool.devx.classify.tags]` - `--github-output` — write results to `$GITHUB_OUTPUT` for CI workflow steps Exit code 2 indicates workflow-only changes (no release needed). ### `devx ci detect-release-commit` Detect whether the latest git commit is a release commit (`release: vX.Y.Z [skip ci]`). Writes `is-release=true` or `is-release=false` to `$GITHUB_OUTPUT` for use in CI workflow conditionals. ```bash devx ci detect-release-commit ``` ### `devx ci discover-runners` Discover available Gitea Actions runners for dynamic job distribution. Queries the Gitea API for registered runners at repository, organization, and instance (administrator) levels. Falls back to `MOLECULE_RUNNERS` repo variable or `DEFAULT_MAX_RUNNERS` (3). ```bash devx ci discover-runners --owner oblachno-oss --repo devx devx ci discover-runners --owner oblachno-oss --repo devx --count devx ci discover-runners --owner oblachno-oss --repo devx --indices ``` Options: - `--count` — print the number of available runners - `--indices` — print a JSON array `[0, 1, ..., N-1]` for use as a dynamic matrix in Gitea Actions ### `devx ci distribute-files` Distribute files across parallel runners (round-robin). Discovers files matching a glob pattern, sorts them for deterministic ordering, then assigns them round-robin to `max_runners` groups. The assigned group for `runner_index` is written to `$GITHUB_ENV`. ```bash devx ci distribute-files --pattern "tests/integration/test_*.py" \ --runner-index 1 --max-runners 3 --github-env ``` Options: - `--pattern ` — glob pattern for files to distribute - `--runner-index ` — current runner index (0-based) - `--max-runners ` — total number of runners (default: 3) - `--github-env` — write file list to `$GITHUB_ENV` - `--skip-if-excess` — skip if fewer files than runners ### `devx ci doc-coverage` Check documentation coverage for CLI commands and major modules. Parses Click commands from `cli.py` and checks if each has documentation in `docs/user/cli-commands.md`. Verifies core modules are documented in `architecture.md` and CI scripts in `ci-cd-workflow.md`. ```bash devx ci doc-coverage devx ci doc-coverage --docs-dir docs/ --source-dir src/ --fail-on-missing ``` Options: - `--docs-dir ` — path to the docs directory (default: `docs/`) - `--source-dir ` — path to the source directory (default: auto-detect) - `--fail-on-missing` — exit with non-zero status if any documentation is missing ### `devx ci lint-docs` Lint documentation files for structure, broken links, heading hierarchy, duplicate headings, TODO/FIXME markers, and trailing whitespace. ```bash devx ci lint-docs devx ci lint-docs --root . --fix devx ci lint-docs --no-check-links --no-check-stale ``` Options: - `--root ` — repository root directory (default: `.`) - `--docs-dir ` — docs directory (default: `/docs`) - `--check-links/--no-check-links` — check internal links (default: yes) - `--check-headings/--no-check-headings` — check heading hierarchy (default: yes) - `--check-todo/--no-check-todo` — check for TODO/FIXME markers (default: yes) - `--check-stale/--no-check-stale` — check for stale docs (default: no) - `--check-trailing/--no-check-trailing` — check trailing whitespace (default: yes) - `--check-duplicates/--no-check-duplicates` — check duplicate headings (default: yes) - `--fix` — auto-fix trailing whitespace ### `devx ci integration-guard` Run pytest with cross-runner failure detection. If any other integration-tests matrix runner reports failure, the current pytest subprocess is killed and this runner exits early with code 1. ```bash devx ci integration-guard -- test_a.py test_b.py devx ci integration-guard -- -x -v --tb=short test_a.py ``` Environment variables: - `GITEA_URL` — base URL of the Gitea instance - `CI_GITEA_TOKEN` — API token with repo access - `RUN_ID` — workflow run ID (`GITHUB_RUN_ID`) - `JOB_NAME` — base job name (`GITHUB_JOB`) - `MATRIX_INDEX` — current matrix index (runner-index) - `GITEA_REPOSITORY` — repository in `owner/repo` format ### `devx ci notify-failure` Create a Gitea issue when a CI workflow fails. Uses the tea CLI for issue creation with a `bug` label if available. ```bash devx ci notify-failure --repo oblachno-oss/devx --run-id 123 \ --workflow ci --commit abc123def456 devx ci notify-failure --repo oblachno-oss/devx --run-id 123 \ --workflow post-merge/release --commit abc123def456 --auto-login ``` Options: - `--repo ` — repository (required) - `--run-id ` — CI run ID (required) - `--workflow ` — workflow name (required) - `--commit ` — commit SHA (required) - `--auto-login` — configure tea CLI login from `CI_GITEA_TOKEN` before creating the issue ### `devx ci post-merge` Update Vikunja task after a merge to master. Extracts the task ID from the commit message, marks the task as done, and posts a comment with the merge SHA. ```bash devx ci post-merge "DEVX-12 feat: add feature" --git-sha abc123def456 ``` ### `devx ci pr-review` Run automated PR review. Fetches the PR diff via the Gitea API and runs a series of checks, posting a structured review (`COMMENT` or `REQUEST_CHANGES`). Checks: architecture compliance, best practices, security, i18n, resource management, documentation, test coverage, and commit conventions. ```bash devx ci pr-review 42 oblachno-oss/devx ``` ### `devx ci publish` Build package, publish to Gitea PyPI registry (or standard PyPI), and create a Gitea release with git-cliff-generated notes. ```bash devx ci publish v1.0.0 oblachno-oss/devx devx ci publish v1.0.0 oblachno-oss/devx --registry-url https://git.example.com/api/packages/owner/pypi devx ci publish v1.0.0 oblachno-oss/devx --skip-build # Gitea release only ``` Options: - `--registry-url ` — Gitea PyPI registry URL. Defaults to `DEVX_PYPI_REGISTRY_URL` env var or a URL derived from `GITEA_API_URL`. When set, publishes to Gitea PyPI instead of standard PyPI (unless `PYPI_TOKEN` is also set). - `--skip-build` — skip package build and PyPI publish (for non-Python repos that only need a Gitea release) ### `devx ci push-badges` Generate badge SVG files and push them to the `badges` branch. Also updates `README.md` and `docs/index.md` on master with cache-busting `raw/commit//` URLs. ```bash devx ci push-badges devx ci push-badges --output-dir .badges/ --branch master devx ci push-badges --no-readme-update # skip README update (local testing) devx ci push-badges --retries 3 # retry on git push failures ``` Options: - `--output-dir ` — temporary directory for badge files (default: `.badges/`) - `--branch ` — branch to sync before generating badges (default: `master`) - `--no-readme-update` — skip updating README with cache-busting URLs - `--retries ` — number of attempts on git push failures (default: 1). Between attempts, fetches latest master and waits 10s. ### `devx ci release` Automated release: calculate next version, update files, tag, and push. Uses git-cliff to determine the next semver version from conventional commits. ```bash devx ci release devx ci release --dry-run # preview without making changes devx ci release --skip-tests # skip lint and tests (emergency only) devx ci release --verify # check tag/version/changelog alignment ``` Options: - `--dry-run` — show what would happen without making changes - `--skip-tests` — skip lint and test verification (NOT recommended — only for emergency releases) - `--verify` — verify tag/version/changelog alignment and exit (no changes made) ### `devx ci sync-wiki` Sync documentation from `docs/` to the Gitea wiki. Reads `docs/mapping.json` for file-to-page mapping. Pages that exist in the wiki but not in the mapping are left untouched. ```bash devx ci sync-wiki --repo oblachno-oss/devx devx ci sync-wiki --repo oblachno-oss/devx --dry-run devx ci sync-wiki --repo oblachno-oss/devx --verify devx ci sync-wiki --repo oblachno-oss/devx --strict ``` Options: - `--dry-run` — show what would happen without making changes - `--repo ` — repository (auto-detected if omitted) - `--verify` — after syncing, verify each page has non-empty content. Exit 1 if any page is empty or mismatched. - `--strict` — full integrity check: verify page count, missing pages, stale pages, and content. Implies `--verify`. ### `devx ci validate-commit-msg` Validate commit messages for conventional commit format. On feature branches: conventional commits only (no `{PREFIX}-N` prefix). On master: must have `{PREFIX}-N` prefix from auto-merge, followed by a conventional commit message. ```bash devx ci validate-commit-msg commit-msg.txt devx ci validate-commit-msg commit-msg.txt --branch master ``` Options: - `--branch ` — override branch detection (for CI use) ### `devx ci cancel-superseded-runs` Cancel in-flight CI runs for the same PR branch when a new push triggers a new run. Uses the Gitea Actions API to list running pull_request runs and cancel those with a lower run ID on the same branch. ```bash devx ci cancel-superseded-runs \ --repo "$REPOSITORY" \ --current-run-id "$GITHUB_RUN_ID" \ --head-branch "$HEAD_REF" ``` Options: - `--repo ` — repository (required) - `--current-run-id ` — current run ID, not cancelled (required) - `--head-branch ` — PR head branch name (required) - `--dry-run` — list superseded runs without cancelling - `--base-url ` — Gitea base URL (default: `GITEA_API_URL` env var) ### `devx ci check-workflow-artifact-deps` Verify that workflow jobs downloading artifacts depend on the uploading job. Prevents the class of bug where a download job runs in parallel with the upload job and fails because the artifact isn't available yet. ```bash devx ci check-workflow-artifact-deps devx ci check-workflow-artifact-deps --workflow .gitea/workflows/ci.yml ``` Options: - `--workflow ` — check a specific workflow file - `--workflows-dir ` — override workflows directory ### `devx ci check-workflow-tofu-init` Verify that workflow jobs using tofu state (tofu output/plan/apply or scripts that call them) have a tofu-init step in the same job. ```bash devx ci check-workflow-tofu-init devx ci check-workflow-tofu-init --workflow .gitea/workflows/deploy.yml ``` Options: - `--workflow ` — check a specific workflow file - `--workflows-dir ` — override workflows directory - `--state-script ` — add a script that uses tofu state (repeatable) ## Tools Commands ### `devx tools check-test-speed` Run unit tests and enforce execution-time budgets. Two quality gates: - **Total suite time** must not exceed `--max-seconds` (default: 10s) - **Per-test time** — no individual test may exceed `--max-single-seconds` (default: 0.5s, 0 to turn off) Runs `make test-unit` with `PYTEST_ADDOPTS=--durations=0` so pytest emits per-test timing lines. ```bash devx tools check-test-speed devx tools check-test-speed --max-seconds 10 devx tools check-test-speed --max-seconds 4 --max-single-seconds 0.5 ``` ### `devx tools check-test-isolation` Statically analyze test files for un-hermetic patterns that cause slow or flaky tests. Also available as a **pytest plugin** (auto-discovered via the `pytest11` entry point when devx is installed — runs automatically on every `pytest` invocation and **fails on violations**). Detected patterns (hard errors — exit non-zero): - **unpatched-subprocess**: `subprocess.run/call/Popen/check_call/check_output` called in a test function without `@patch` or `with patch(...)` - **unpatched-sleep**: `time.sleep` called without `@patch` - **unpatched-helper**: known subprocess-spawning helpers (`update_doc_versions`, `run_cmd`, `run_tests`) called without `@patch` or patching their internal deps - **excessive-iterations**: `for _ in range(N)` where N > 100 - **heavy-module-import**: `httpx`, `ansible`, etc. imported at module level - **reload-without-cleanup**: `importlib.reload()` called an odd number of times Advisory patterns (exit 0 — runtime audit is authoritative): - **transitive-subprocess**: `CliRunner.invoke(target)` where `target` transitively calls `subprocess.run` without being patched. Detected via static call-graph analysis. The runtime subprocess audit catches actual leaks — if a real subprocess runs without `@patch`, the test fails. ```bash devx tools check-test-isolation devx tools check-test-isolation --test-path tests/ devx tools check-test-isolation --categories unpatched-subprocess,transitive-subprocess devx tools check-test-isolation --max-loop-iterations 50 devx tools check-test-isolation --src-dir src/ ``` Pytest plugin options (automatic when devx is installed): - `--no-test-isolation` — turn off static analysis and runtime subprocess audit - `--test-isolation-max-loop N` — max iterations per loop (default: 100) ### `devx tools configure-repo` Configure repository: branch protection and labels via the Gitea REST API. Sets up master branch protection (required status checks, block on rejected reviews, block on outdated branch) and creates standard labels. ```bash devx tools configure-repo --repo devx --owner oblachno-oss ``` Status check contexts are read from `DEVX_STATUS_CHECKS` (comma-separated) or default to `CI / quality (pull_request)`. ### `devx tools generate-badges` Generate self-contained SVG badge files from project metrics. Runs pytest-cov, doc-coverage, lint checks, and version extraction, then writes SVG files that can be served as static files from the Gitea raw file API. Badges generated: `coverage.svg`, `tests.svg`, `docs.svg`, `quality.svg`, `version.svg`, `python.svg`. ```bash devx tools generate-badges devx tools generate-badges --output-dir .badges/ ``` ### `devx tools generate-cliff-config` Generate a `cliff.toml` configuration file with the correct task ID prefix preprocessor. Eliminates the need to manually duplicate and maintain `cliff.toml` across repos that use devx. ```bash devx tools generate-cliff-config --prefix GRM devx tools generate-cliff-config --prefix GRM --output cliff.toml devx tools generate-cliff-config --prefix GRM --force # overwrite existing ``` Options: - `--prefix ` — task ID prefix (default: `DEVX_TASK_PREFIX` env var or `DEVX`) - `--output ` — output path (default: `cliff.toml`) - `--force` — overwrite existing file ### `devx tools install-checkmake` Install checkmake (Makefile linter) if not already present. Tries `go install` first if Go is available, otherwise downloads the latest pre-built Linux binary from the official GitHub releases. ```bash devx tools install-checkmake ``` ### `devx tools install-tools` Install CI/CD development tools that are not Python packages: actionlint, git-cliff, act_runner, and tea. Each tool is installed to `~/.local/bin` if not already on PATH. Idempotent: skips tools that are already available. ```bash devx tools install-tools # install all devx tools install-tools --tool actionlint # install one devx tools install-tools --tool git-cliff --tool tea # install specific devx tools install-tools --list # list status ``` ### `devx tools setup` Project setup: install Python dependencies (editable mode with extras), Ansible Galaxy collections (if `ansible/requirements.yml` exists in the target repo), pre-commit hooks (pre-commit, commit-msg, pre-push), and configure the tea CLI login profile from `.env`. ```bash devx tools setup --bin .venv/bin devx tools setup --bin .venv/bin --extras "ci,lint" devx tools setup --bin .venv/bin --no-pre-commit --no-tea-login ``` Options: - `--bin ` — virtualenv bin directory (required) - `--extras ` — pip extras to install (default: `dev`) - `--no-pre-commit` — skip pre-commit hook installation - `--no-tea-login` — skip tea CLI login configuration ### `devx tools rebase` Rebase the current branch onto `origin/master` and force-push with `--force-with-lease`. Checks if the branch is behind master first — if up-to-date, exits without doing anything. ```bash devx tools rebase # rebase + force-push devx tools rebase -- --no-push # rebase locally only ``` Options (pass after `--`): - `--no-push` — rebase locally without pushing ### `devx tools pr-rebase` Rebase a pull request's head branch onto master via the Gitea API (server-side). This triggers a new `pull_request synchronize` event, which starts a new CI run. Useful when you don't have the branch checked out locally. ```bash devx tools pr-rebase -- --pr 42 # rebase PR #42 devx tools pr-rebase # auto-detect PR from current branch ``` Options (pass after `--`): - `--pr ` — PR number (auto-detected from current branch if omitted) ### `devx tools check-docker-init` Check that Docker Compose services with healthchecks have `init: true`. Without `init: true`, CMD-SHELL healthchecks spawn child processes that become zombies when PID 1 doesn't reap them. ```bash devx tools check-docker-init devx tools check-docker-init --path path/to/docker-compose.yml.j2 ``` Options: - `--path ` — check a specific file or directory - `--templates-dir ` — override templates directory (default: `ansible/roles/`) ### `devx tools check-ansible-set-fact-to-json` Check that Ansible `set_fact` tasks don't misuse `| to_json`. Using `to_json` in `set_fact` converts native Python types to JSON strings, causing iteration bugs (for example, iterating over characters instead of list items). ```bash devx tools check-ansible-set-fact-to-json devx tools check-ansible-set-fact-to-json --path path/to/playbook.yml ``` Options: - `--path ` — check a specific file or directory - `--ansible-dir ` — override ansible directories (repeatable) ### `devx tools check-alert-rules` Validate rendered Prometheus alert rules with `promtool check rules`. Renders a Jinja2 template with test values and validates the output. Skips (exits 0) if promtool is not on PATH. ```bash devx tools check-alert-rules \ --template-path ansible/roles/observability/templates devx tools check-alert-rules \ --template-path ansible/roles/observability/templates \ --var grafana_base_url=https://grafana.example.com ``` Options: - `--template-path ` — path to templates directory (required) - `--template-name ` — template filename (default: `alert-rules.yml.j2`) - `--var key=value` — template variables (repeatable) ## Molecule Commands Molecule commands require the `molecule` extra (`pip install devx[molecule]`). ### `devx molecule all` Run all molecule scenarios on all supported OS platforms. Sequential execution — CI uses the parallel matrix instead. ```bash devx molecule all devx molecule all --bin .venv/bin ``` ### `devx molecule discover-runners` Discover available Gitea Actions runners for molecule tests. Same logic as `devx ci discover-runners` but intended for molecule-specific workflows. ```bash devx molecule discover-runners --owner oblachno-oss --repo devx --indices ``` ### `devx molecule distribute` Distribute molecule (scenario, platform) pairs across N parallel runners. Discovers scenarios under `ansible/roles/*/molecule/` and crosses them with the supported OS platform matrix. ```bash devx molecule distribute --runner-index 1 --max-runners 3 devx molecule distribute --list # list all scenarios devx molecule distribute --list-platforms # list platforms devx molecule distribute --roles-root ansible/roles # multi-role repos ``` Options: - `--runner-index ` — current runner index (0-based) - `--max-runners ` — total number of runners (default: 3) - `--list` — list all scenarios, one per line - `--list-platforms` — list all platforms, one per line - `--roles-root ` — roles root directory for multi-role repos (default: `ansible/roles`)