# devx — Reusable Development & CI/CD Tools A Python package providing reusable development and CI/CD automation tools for oblachno-oss projects. devx consolidates release management, PR automation, wiki sync, badge generation, translation checks, documentation coverage, parallel test distribution, and more into a single installable package. It was extracted from the [GRM](https://git.oblachno.oblachno.fyi/oblachno-oss/grm) project to be reusable across all oblachno-oss repositories. Any project hosted on a Gitea instance with Gitea Actions can install devx and inherit a complete, opinionated CI/CD pipeline: conventional commits, automated versioning via git-cliff, squash-merge automation, Vikunja task tracking, wiki sync, and quality badges. > An open source project from **Oblachno** (облачно means *cloudy* in Bulgarian). [![CI](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions/workflows/ci.yml/badge.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions) [![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-blue)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/src/branch/master/LICENSE) [![Coverage](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/6a22c4cbb7262cddd22a094d3c1a42619fdd8814/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions) [![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/6a22c4cbb7262cddd22a094d3c1a42619fdd8814/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions) [![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/6a22c4cbb7262cddd22a094d3c1a42619fdd8814/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki) [![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/6a22c4cbb7262cddd22a094d3c1a42619fdd8814/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions) [![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/6a22c4cbb7262cddd22a094d3c1a42619fdd8814/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases) [![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/6a22c4cbb7262cddd22a094d3c1a42619fdd8814/python.svg)](https://www.python.org/downloads/) ## Why devx? Every oblachno-oss project shares the same CI/CD needs: automated releases, PR review, task tracking, documentation sync, and quality badges. Without a shared package, each repository duplicates this logic in shell scripts and workflow YAML, leading to drift, bugs, and maintenance burden. devx solves this by providing a single, tested Python package that any oblachno-oss project can install. The project declares its configuration via environment variables and `pyproject.toml`, and devx handles the rest. Updates to the CI/CD pipeline ship as new devx releases — consumer projects pick them up by bumping their devx dependency. ### Key features - **Automated releases** — git-cliff-driven semver versioning, changelog generation, tagging, and publishing to a Gitea PyPI registry. - **PR automation** — squash-merge with task ID validation, automated PR review with inline comments, and conventional commit enforcement. - **Smart change classification** — user-facing vs workflow-only change detection so infrastructure-only changes skip releases. - **Documentation sync** — push `docs/` markdown to the Gitea wiki with integrity verification. - **Quality badges** — generate self-contained SVG badges for coverage, tests, docs, quality, version, and Python version. - **Translation checks** — validate i18n keys against source code, detect dead keys and missing languages. - **Parallel test distribution** — split test files or molecule scenarios across CI runners with cross-runner fail-fast. - **Developer tools** — environment setup, CI tool installation, test speed enforcement, repository configuration. - **i18n** — built-in translations for English, Bulgarian, German, Russian, Chinese, and Polish; projects can extend with their own keys. ## Installation devx is published to the Gitea PyPI registry at `https://git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple`. The registry is publicly readable — no authentication required to install. ### Quick install (one-off) ```bash pip install devx --index-url https://git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple ``` ### Persistent configuration (recommended) Add the registry to `~/.pip/pip.conf` so `pip install devx` works without specifying `--index-url` every time: ```ini [global] extra-index-url = https://git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple ``` ### As a dependency in another project To use devx as a dependency in your `pyproject.toml`, add the registry as an extra index and list devx in your dependencies: ```toml [project] dependencies = [ "devx>=0.49.0", ] [tool.pip] extra-index-url = "https://git.oblachno.oblachno.fyi/api/packages/oblachno-oss/pypi/simple" ``` Then install normally: ```bash pip install -e . ``` > **Note:** If your project requires a specific devx version, pin it in > `dependencies` (for example, `"devx==0.49.0"`) or use a version constraint > (for example, `"devx>=0.49.0,<0.50"`). ### Optional extras devx ships optional dependency groups for different use cases: ```bash pip install "devx[ci,lint]" # CI runners and linting (pytest, ruff, pyright, bandit, build, twine) pip install "devx[molecule]" # Molecule testing for Ansible projects pip install "devx[dev]" # Full local development (ci + lint + build + twine) ``` ## Quick start After installing devx, set the required environment variables (see [Configuration](#configuration)) and invoke modules via `python -m devx.*` or the `devx` CLI. ### CI/CD automation CI/CD modules are invoked via `python -m devx.ci.*`. Each module is also available as a `devx ci ` subcommand. ```bash # Release automation (versioning, changelog, tagging) python -m devx.ci.release python -m devx.ci.release --dry-run # preview without changes python -m devx.ci.release --verify # check tag/version/changelog alignment # Publish a release to the Gitea PyPI registry python -m devx.ci.publish v1.0.0 oblachno-oss/devx python -m devx.ci.publish v1.0.0 oblachno-oss/devx --skip-build # Gitea release only # Automated PR review (posts inline comments and structured review) python -m devx.ci.pr_review 42 oblachno-oss/devx # Auto-merge a PR (validates title, squash-merges) python -m devx.ci.auto_merge feature-branch "DEVX-12: Add feature" oblachno-oss/devx 42 # Classify changes (user-facing vs workflow-only) python -m devx.ci.classify_changes --base origin/master --head HEAD --github-output # Sync documentation to Gitea wiki python -m devx.ci.sync_wiki --repo oblachno-oss/devx --strict # Generate and push quality badges python -m devx.ci.push_badges python -m devx.ci.push_badges --retries 3 # retry on git push failures # Check translation completeness python -m devx.ci.check_translations python -m devx.ci.check_translations --translations path/to/translations.json # Documentation coverage check python -m devx.ci.doc_coverage --fail-on-missing # Documentation lint (structure, links, headings, TODOs) python -m devx.ci.lint_docs --root . # Validate a commit message python -m devx.ci.validate_commit_msg commit-msg.txt --branch master # Detect whether the latest commit is a release commit python -m devx.ci.detect_release_commit # Notify on CI failure (creates a Gitea issue) python -m devx.ci.notify_failure --repo oblachno-oss/devx --run-id 123 \ --workflow ci --commit abc123 --auto-login # Discover available Gitea Actions runners python -m devx.ci.discover_runners --owner oblachno-oss --repo devx --indices # Distribute files across parallel runners (round-robin) python -m devx.ci.distribute_files --pattern "tests/integration/test_*.py" \ --runner-index 1 --max-runners 3 --github-env # Run pytest with cross-runner fail-fast python -m devx.ci.integration_guard -- test_a.py test_b.py ``` ### Developer tools Developer tooling modules are invoked via `python -m devx.tools.*` or the `devx tools ` subcommand. ```bash # Set up a development environment (venv, deps, hooks, tea login) python -m devx.tools.setup --bin .venv/bin python -m devx.tools.setup --bin .venv/bin --extras "ci,lint" --no-pre-commit # Install CI tools (actionlint, git-cliff, act_runner, tea) python -m devx.tools.install_tools python -m devx.tools.install_tools --tool git-cliff --tool tea python -m devx.tools.install_tools --list # Install checkmake (Makefile linter) python -m devx.tools.install_checkmake # Check unit test speed python -m devx.tools.check_test_speed --max-seconds 10 python -m devx.tools.check_test_speed --max-seconds 4 --max-single-seconds 0.5 # Configure repository (branch protection, labels) python -m devx.tools.configure_repo --repo devx --owner oblachno-oss # Generate badge SVG files locally python -m devx.tools.generate_badges --output-dir .badges/ # Generate a cliff.toml with the correct task ID prefix python -m devx.tools.generate_cliff_config --prefix GRM python -m devx.tools.generate_cliff_config --prefix GRM --force # overwrite existing ``` ### Molecule testing (optional) For projects with Ansible roles, devx provides molecule testing helpers via `python -m devx.molecule.*` or `devx molecule `. ```bash # Distribute molecule scenarios across parallel runners python -m devx.molecule.distribute_molecule --runner-index 1 --max-runners 3 python -m devx.molecule.distribute_molecule --list # list all scenarios python -m devx.molecule.distribute_molecule --list-platforms # list platforms # Run all molecule scenarios locally (sequential) python -m devx.molecule.molecule_all python -m devx.molecule.molecule_all --bin .venv/bin # Discover available Gitea Actions runners for molecule tests python -m devx.molecule.discover_runners --indices # Ensure Docker is available for molecule tests in CI python -m devx.molecule.start_docker ``` ### OpenTofu helpers devx provides reusable functions for extracting values from `tofu output`: ```python from devx.opentofu import get_tofu_output, get_tofu_vm_ip, get_tofu_vm_field vms = get_tofu_output("customer_vms", cwd="tofu/environments/staging", env={"HCLOUD_TOKEN": token}) ip = get_tofu_vm_ip("customer_vms", "oblachno", cwd="tofu/environments/staging", env={"HCLOUD_TOKEN": token}) ``` ## CLI commands overview devx provides a `devx` CLI command with three command groups: ```bash devx --help devx --version ``` ### `devx ci` — CI/CD automation | Command | Description | |---------|-------------| | `devx ci auto-merge` | Squash-merge a PR with task ID validation | | `devx ci check-translations` | Check translation files for gaps and dead keys | | `devx ci classify-changes` | Classify git changes as user-facing or workflow-only | | `devx ci detect-release-commit` | Detect whether the latest commit is a release commit | | `devx ci discover-runners` | Discover available Gitea Actions runners | | `devx ci distribute-files` | Distribute files across parallel runners (round-robin) | | `devx ci doc-coverage` | Check documentation coverage for CLI commands and modules | | `devx ci integration-guard` | Run pytest with cross-runner fail-fast | | `devx ci notify-failure` | Create a Gitea issue when a CI workflow fails | | `devx ci post-merge` | Update Vikunja task after a merge to master | | `devx ci pr-review` | Run automated PR review | | `devx ci publish` | Build package, publish to registry, create Gitea release | | `devx ci push-badges` | Generate badge SVG files and push to the badges branch | | `devx ci release` | Automated release: version, changelog, tag, push | | `devx ci sync-wiki` | Sync documentation from docs/ to the Gitea wiki | | `devx ci validate-commit-msg` | Validate commit messages for conventional format | ### `devx tools` — Developer tools | Command | Description | |---------|-------------| | `devx tools check-test-speed` | Run unit tests and enforce execution-time budgets | | `devx tools configure-repo` | Configure branch protection and labels via Gitea API | | `devx tools generate-badges` | Generate self-contained SVG badge files | | `devx tools generate-cliff-config` | Generate a cliff.toml with the correct task ID prefix | | `devx tools install-checkmake` | Install checkmake (Makefile linter) | | `devx tools install-tools` | Install actionlint, git-cliff, act_runner, tea | | `devx tools setup` | Project setup: install deps, hooks, tea login | ### `devx molecule` — Molecule testing (optional) | Command | Description | |---------|-------------| | `devx molecule all` | Run all molecule scenarios on all supported platforms | | `devx molecule discover-runners` | Discover available Gitea Actions runners | | `devx molecule distribute` | Distribute molecule test pairs across parallel runners | See [CLI Commands](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki/CLI-Commands) in the wiki for full command documentation with examples. ## Configuration devx reads configuration from environment variables with `.env` file fallback. The config system loads `.env` automatically via `python-dotenv`. ### DEVX_ environment variables | Variable | Default | Description | |----------|---------|-------------| | `DEVX_GITEA_API_URL` | `https://git.oblachno.oblachno.fyi/api/v1` | Gitea API base URL | | `DEVX_VIKUNJA_API_URL` | `https://work.oblachno.oblachno.fyi/api/v1` | Vikunja API base URL | | `DEVX_REPO_OWNER` | **(none — must be set)** | Repository owner for API calls | | `DEVX_REPO_NAME` | **(none — must be set)** | Repository name (or `owner/repo`) | | `DEVX_TASK_PREFIX` | `DEVX` | Task ID prefix (GRM, OBL-INFRA, etc.) | | `DEVX_VIKUNJA_PROJECT_ID` | `6` | Vikunja project ID | | `DEVX_LANG` | `en` | Language for i18n (en, bg, de, ru, zh, pl) | | `DEVX_TRANSLATIONS_PATH` | — | Path to a custom JSON translations file | | `DEVX_VERSION_FILE` | `src/devx/__init__.py` | Version source file (used by release) | | `DEVX_DOCS_DIR` | `docs` | Documentation directory (used by sync_wiki) | | `DEVX_STATUS_CHECKS` | `CI / quality (pull_request)` | Comma-separated status check contexts | | `DEVX_PYPI_REGISTRY_URL` | — | Gitea PyPI registry URL (used by publish) | | `CI_GITEA_TOKEN` | — | Gitea API token (see scopes below) | | `CI_GITEA_USERNAME` | — | Gitea username for registry authentication | | `VIKUNJA_TOKEN` | — | Vikunja API token | | `PYPI_TOKEN` | — | Standard PyPI token (takes precedence over Gitea registry) | #### CI_GITEA_TOKEN scopes The `CI_GITEA_TOKEN` is a single Gitea Personal Access Token used across all workflows. It requires these scopes: | Scope | Purpose | |-------|---------| | `read:repository` | Read repos, PRs, issues, branches | | `write:repository` | Push commits, merge PRs, create tags/releases, create issues, set branch protection, push wiki | | `read:package` | Pull packages from Gitea PyPI registry, pull Docker images | | `write:package` | Publish packages to Gitea PyPI registry, push Docker images | | `read:organization` | Query org-level runners for molecule test distribution | ### Per-project overrides Projects using devx can override the default API URLs and language by setting `DEVX_*` environment variables or entries in their `.env` file. Copy `.env.example` to `.env` and fill in your tokens: ```bash cp .env.example .env ``` ### Change classification Projects configure which file paths are infrastructure (no release needed) vs user-facing (release needed) in `pyproject.toml`: ```toml [tool.devx.classify] # Merge with DEFAULT_INFRASTRUCTURE (CI workflows, tests, docs, config) # use_defaults = true # (default) # Project-specific infrastructure paths (merged with defaults) infrastructure = [] # Files that would default to user-facing but are actually infrastructure infrastructure_overrides = [ "src/myproject/__init__.py", # example only — only contains __version__ ] # Safety override for broad infrastructure patterns user_facing_overrides = [] # Tag patterns for CI conditional execution (orthogonal to release impact) [tool.devx.classify.tags] # ansible = ["ansible/**"] ``` ## Development ```bash git clone https://git.oblachno.oblachno.fyi/oblachno-oss/devx.git cd devx make setup # Create venv, install deps, hooks, CI tools make lint-all # ruff + pyright + bandit + actionlint make pytest-cov # Unit tests with 100% coverage make test-unit # Unit tests without coverage make workflow-check # Static + dry-run validation of workflow YAML make clean # Remove caches, build artifacts, coverage data ``` `make setup` automatically installs all development tools: - **Python deps** via `python -m devx.tools.setup` (pip install -e .[dev], pre-commit hooks) - **actionlint, git-cliff, act_runner, tea** via `python -m devx.tools.install_tools` - **tea CLI login** via `python -m devx.tools.setup` (configures `tea login` from `.env`) ### Make targets | Target | Description | |--------|-------------| | `make setup` | Full local development setup (venv, deps, hooks, CI tools) | | `make setup-ci` | Lean setup for CI jobs (pytest + lint + runtime deps) | | `make setup-quality` | Setup for quality job (lint + test deps, actionlint) | | `make setup-release` | Setup for release jobs (git-cliff, tea, lint tools) | | `make install-tools` | Install actionlint, git-cliff, act_runner, tea | | `make install-hooks` | Install git hooks (pre-commit, pre-push) | | `make lint` | ruff check + ruff format check + pyright + bandit | | `make lint-ruff` | ruff check only | | `make lint-format` | ruff format check only | | `make typecheck` | pyright only | | `make lint-bandit` | bandit security scan only | | `make lint-all` | lint + workflow-lint (actionlint) | | `make lint-deps` | pip-audit dependency vulnerability scan | | `make test-unit` | Unit tests without coverage | | `make pytest-cov` | Unit tests with 100% coverage enforcement | | `make workflow-lint` | actionlint on `.gitea/workflows/*.yml` | | `make workflow-dryrun` | act_runner exec --dryrun on all workflows | | `make workflow-check` | workflow-lint + workflow-dryrun | | `make clean` | Remove caches, build artifacts, coverage data | See [AGENTS.md](AGENTS.md) for full project conventions, PR workflow, and architecture details. ## Architecture overview devx is a self-contained Python package under `src/devx/`. It never imports from scripts outside the package. All tools are invoked via `python -m devx.ci.*`, `python -m devx.tools.*`, or `python -m devx.molecule.*`. ```text src/devx/ ├── __init__.py # Version (single source of truth, read by setuptools) ├── cli.py # Click-based CLI entry point (devx command) ├── config.py # Configuration system (DEVX_ env vars, .env loading) ├── api_clients.py # GiteaClient, VikunjaClient — HTTP API wrappers ├── gitea_cli.py # TeaCLI — wrapper around tea CLI with JSON parsing ├── i18n.py # Translation system (gettext-based, translations.json) ├── exceptions.py # Custom exception types (DevxError, APIError) ├── opentofu.py # OpenTofu output helpers ├── translations.json # Translation strings (en, bg, de, ru, zh, pl) ├── ci/ # CI/CD automation modules (run by workflows) ├── tools/ # Developer tooling modules (run locally or by CI) └── molecule/ # Optional molecule testing helpers (for Ansible projects) ``` ### Design principles - **Self-contained package** — `src/devx/` never imports from scripts outside the package - **Module-based invocation** — All tools invoked via `python -m devx.ci.*` or `python -m devx.tools.*` - **PYTHONPATH: src** — Workflows set `PYTHONPATH: src` (not `.:src` since there are no scripts at repo root) - **Config via env vars** — `DEVX_*` environment variables with `.env` file fallback - **100% test coverage** — enforced by `--cov-fail-under=100` - **i18n by default** — all user-facing strings wrapped in `_()` for translation See [Architecture](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki/Architecture) and [CI/CD Workflow](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki/CI-CD-Workflow) in the wiki for detailed documentation. ## Links - **Wiki**: [https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki) - **Releases**: [https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases) - **Actions**: [https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions) - **Source**: [https://git.oblachno.oblachno.fyi/oblachno-oss/devx](https://git.oblachno.oblachno.fyi/oblachno-oss/devx) - **GRM (origin project)**: [https://git.oblachno.oblachno.fyi/oblachno-oss/grm](https://git.oblachno.oblachno.fyi/oblachno-oss/grm) ## License GPL-3.0 — see [LICENSE](LICENSE).