Metadata-Version: 2.4
Name: devx
Version: 0.50.1
Summary: Reusable development and CI/CD tools for oblachno-oss projects
License: GPL-3.0
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests==2.34.2
Requires-Dist: python-dotenv==1.2.2
Requires-Dist: click==8.4.2
Requires-Dist: tenacity==9.1.4
Requires-Dist: jinja2==3.1.6
Requires-Dist: pyyaml==6.0.3
Provides-Extra: ci
Requires-Dist: pytest==9.1.1; extra == "ci"
Requires-Dist: pytest-cov==7.1.0; extra == "ci"
Requires-Dist: pytest-xdist==3.8.0; extra == "ci"
Provides-Extra: lint
Requires-Dist: ruff==0.15.21; extra == "lint"
Requires-Dist: pyright==1.1.411; extra == "lint"
Requires-Dist: bandit==1.9.4; extra == "lint"
Requires-Dist: pip-audit==2.10.1; extra == "lint"
Requires-Dist: pre-commit==4.6.0; extra == "lint"
Provides-Extra: release
Requires-Dist: build==1.5.1; extra == "release"
Requires-Dist: twine==6.2.0; extra == "release"
Provides-Extra: molecule
Requires-Dist: molecule==26.6.0; extra == "molecule"
Requires-Dist: molecule-docker==2.1.0; extra == "molecule"
Requires-Dist: ansible-lint==26.6.0; extra == "molecule"
Requires-Dist: ansible-core==2.21.1; extra == "molecule"
Provides-Extra: deploy
Requires-Dist: ansible-core==2.21.1; extra == "deploy"
Requires-Dist: boto3==1.43.44; extra == "deploy"
Requires-Dist: docker==7.1.0; extra == "deploy"
Requires-Dist: cryptography==50.0.0; extra == "deploy"
Requires-Dist: bcrypt==5.0.0; extra == "deploy"
Requires-Dist: PyJWT==2.13.0; extra == "deploy"
Provides-Extra: dev
Requires-Dist: devx[ci,lint,molecule,release]; extra == "dev"
Requires-Dist: build==1.5.1; extra == "dev"
Requires-Dist: twine==6.2.0; extra == "dev"
Dynamic: license-file

# 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/a506e1130cab09747bb881e0fe98093e6bcd8110/coverage.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Tests](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/a506e1130cab09747bb881e0fe98093e6bcd8110/tests.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Docs](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/a506e1130cab09747bb881e0fe98093e6bcd8110/docs.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
[![Code Quality](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/a506e1130cab09747bb881e0fe98093e6bcd8110/quality.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
[![Version](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/a506e1130cab09747bb881e0fe98093e6bcd8110/version.svg)](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
[![Python](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/raw/commit/a506e1130cab09747bb881e0fe98093e6bcd8110/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.50.1",
]

[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.50.1"`) or use a version constraint
> (for example, `"devx>=0.50.1,<0.51"`).

### 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 <command>` 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 <command>` 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 <command>`.

```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).
