DEVX-36: docs: comprehensive documentation rewrite
This commit is contained in:
+519
-47
@@ -1,85 +1,557 @@
|
||||
# CI/CD Workflow
|
||||
|
||||
devx uses Gitea Actions for CI/CD automation. The workflow replicates GRM's automated pipeline but without molecule tests.
|
||||
devx uses Gitea Actions for CI/CD automation. Three workflows implement a
|
||||
complete pipeline: pull request validation, post-merge release automation, and
|
||||
tag-triggered publishing.
|
||||
|
||||
## Workflows
|
||||
## Workflow overview
|
||||
|
||||
### CI (`ci.yml`)
|
||||
```
|
||||
PR opened/synchronized ──► CI (ci.yml)
|
||||
│ ├── quality
|
||||
│ ├── detect-changes
|
||||
│ ├── release-dry-run (if user-facing)
|
||||
│ ├── pr-review
|
||||
│ └── auto-merge ──► squash-merge to master
|
||||
│ │
|
||||
▼ ▼
|
||||
Push to master ──► Post-merge (post-merge.yml)
|
||||
├── detect-type
|
||||
├── validate-commit-msg
|
||||
├── release ──► tag vX.Y.Z
|
||||
├── sync-wiki │
|
||||
├── badges │
|
||||
├── vikunja │
|
||||
└── configure-repo │
|
||||
│
|
||||
▼
|
||||
Tag push (v*) ──► Publish (publish.yml)
|
||||
└── publish ──► Gitea PyPI registry + Gitea release
|
||||
```
|
||||
|
||||
Runs on pull requests. Jobs:
|
||||
## CI workflow (`ci.yml`)
|
||||
|
||||
1. **quality** — lint (ruff, pyright, bandit, actionlint), unit tests with 100% coverage, test speed check, doc coverage, translation check, dependency scan
|
||||
2. **detect-changes** — classify changes as user-facing or workflow-only
|
||||
3. **release-dry-run** — dry-run the release script (only if user-facing changes)
|
||||
4. **pr-review** — automated PR review
|
||||
5. **auto-merge** — squash-merge PR when all checks pass
|
||||
Runs on pull requests (opened and synchronize) and manual dispatch.
|
||||
|
||||
### Post-merge (`post-merge.yml`)
|
||||
### Jobs
|
||||
|
||||
Runs on every push to master. Jobs:
|
||||
#### `quality`
|
||||
|
||||
1. **detect-type** — check if commit is a release commit
|
||||
2. **validate-commit-msg** — validate conventional commit format
|
||||
3. **release** — calculate next version, update changelog, tag, push
|
||||
4. **sync-wiki** — sync docs to Gitea wiki
|
||||
5. **badges** — generate and push quality badges
|
||||
6. **vikunja** — mark Vikunja task as done
|
||||
7. **configure-repo** — ensure branch protection and labels
|
||||
The main quality gate. Runs on every PR:
|
||||
|
||||
### Publish (`publish.yml`)
|
||||
1. **Lint all** — ruff check, ruff format check, pyright, bandit, actionlint
|
||||
(via `make lint-all`)
|
||||
2. **Unit tests with 100% coverage** — `make pytest-cov`
|
||||
3. **Check unit test speed** — `python -m devx.tools.check_test_speed
|
||||
--max-seconds 4 --max-single-seconds 0.5`
|
||||
4. **Documentation coverage check** — `python -m devx.ci.doc_coverage
|
||||
--fail-on-missing`
|
||||
5. **Translation completeness check** — `python -m devx.ci.check_translations`
|
||||
6. **Dependency security scan** — `pip-audit --desc --skip-editable`
|
||||
(best-effort, non-blocking)
|
||||
7. **Workflow dry-run validation** — `make workflow-dryrun` via act_runner
|
||||
(best-effort, skipped if act_runner is not installed)
|
||||
|
||||
Runs on tag pushes (`v*`). Builds the package, publishes to Gitea PyPI registry, and creates a Gitea release.
|
||||
#### `detect-changes`
|
||||
|
||||
## CI Scripts
|
||||
Classifies changes between `origin/master` and the PR head as user-facing or
|
||||
workflow-only using `python -m devx.ci.classify_changes --github-output`.
|
||||
Writes `user-facing-changed=true|false` to the job output for use by
|
||||
downstream jobs.
|
||||
|
||||
### auto_merge.py
|
||||
#### `release-dry-run`
|
||||
|
||||
Auto-merge PR when all CI checks pass. Reads task ID from `.taskid`, validates PR title format, checks Vikunja task exists, squash-merges with `DEVX-N <conventional commit>` title.
|
||||
Depends on `quality` and `detect-changes`. Only runs if user-facing changes
|
||||
are detected. Runs `python -m devx.ci.release --dry-run` to validate that
|
||||
the release script can calculate the next version and generate the changelog
|
||||
without making changes. Non-blocking (uses `|| true`).
|
||||
|
||||
### release.py
|
||||
#### `pr-review`
|
||||
|
||||
Automated release using git-cliff. Calculates next semver version from conventional commits, updates `__version__` in `__init__.py`, updates `CHANGELOG.md`, runs lint and tests, commits with `release: vX.Y.Z [skip ci]`, creates annotated tag, pushes.
|
||||
Runs on every pull request. Executes `python -m devx.ci.pr_review` with the
|
||||
PR number and repository. Fetches the PR diff via the Gitea API and runs
|
||||
automated checks, posting a structured review:
|
||||
|
||||
### publish.py
|
||||
- `COMMENT` — no issues found
|
||||
- `REQUEST_CHANGES` — issues found that must be addressed
|
||||
|
||||
Builds package with `python -m build`, publishes to Gitea PyPI registry via twine, creates Gitea release with git-cliff-generated notes.
|
||||
Checks performed:
|
||||
1. Architecture compliance — no subprocess in CLI, no hardcoded URLs
|
||||
2. Best practices — no `print()`, no bare `except`, no `TODO`/`FIXME`,
|
||||
no functions > 50 lines
|
||||
3. Security — no hardcoded secrets, no `shell=True`, no `eval`/`exec`
|
||||
4. i18n — no raw strings in `click.echo()` without `_()` wrapper
|
||||
5. Resource management — no `open()` without `with`, no `Popen()` without
|
||||
cleanup
|
||||
6. Documentation — source changes must include doc updates
|
||||
7. Test coverage — source changes must include test updates
|
||||
8. Commit conventions — conventional commit format on PR commits
|
||||
|
||||
### pr_review.py
|
||||
#### `auto-merge`
|
||||
|
||||
Automated PR review. Checks architecture compliance, best practices, security, i18n, resource management, documentation, test coverage, and commit conventions. Posts inline comments and structured review.
|
||||
Depends on `quality`, `detect-changes`, and `pr-review`. The final job in the
|
||||
CI workflow. Runs `python -m devx.ci.auto_merge` with the branch name, PR
|
||||
title, repository, and PR number:
|
||||
|
||||
### notify_failure.py
|
||||
1. **Read task ID** from branch name (e.g., `DEVX-12-fix-foo` → `DEVX-12`),
|
||||
falling back to `.taskid` file for branches without a task ID prefix
|
||||
2. **Validate PR title format** — must be `{PREFIX}-N: <vikunja task title>`
|
||||
3. **Validate PR title matches Vikunja task** — fetches the Vikunja task and
|
||||
compares the title
|
||||
4. **Extract conventional commit message** from PR commits (newest matching
|
||||
conventional format)
|
||||
5. **Squash-merge** with title `{PREFIX}-N <conventional commit message>`
|
||||
6. If the head branch is behind master (HTTP 405), automatically pulls master,
|
||||
rebases, force-pushes, and retries the merge
|
||||
|
||||
Creates a Gitea issue when a CI workflow fails. Uses tea CLI for issue creation with failure labels.
|
||||
The merge commit push to master triggers the post-merge workflow.
|
||||
|
||||
### post_merge.py
|
||||
### Smart CI: user-facing vs workflow-only changes
|
||||
|
||||
Updates Vikunja task after a merge to master. Extracts task ID from commit message, marks task as done, posts a comment with the merge SHA.
|
||||
Not all changes require a new release. The `detect-changes` job classifies
|
||||
changes using `python -m devx.ci.classify_changes`:
|
||||
|
||||
### classify_changes.py
|
||||
**Workflow-only paths** (infrastructure — no release needed):
|
||||
- `.gitea/**` — Gitea Actions workflows
|
||||
- `tests/**` — Test files
|
||||
- `AGENTS.md`, `README.md`, `CHANGELOG.md` — Project docs
|
||||
- `Makefile`, `cliff.toml`, `.pre-commit-config.yaml` — Config
|
||||
- `.env.example`, `.gitignore` — Config
|
||||
- `hooks/**` — Git hooks
|
||||
- `src/devx/__init__.py` — Only contains `__version__` (release artifact)
|
||||
|
||||
Classifies git changes as user-facing or workflow-only. Used to skip releases for infrastructure-only changes. Patterns are configurable.
|
||||
**User-facing paths** (tool changes — release needed) — everything else:
|
||||
- `src/devx/**` — Python package source (except `__init__.py`)
|
||||
- `pyproject.toml` — Package metadata
|
||||
- Any new file type not in the allowlist
|
||||
|
||||
### discover_runners.py
|
||||
Classification is configured in `pyproject.toml` under
|
||||
`[tool.devx.classify]`. The framework provides `DEFAULT_INFRASTRUCTURE` — a
|
||||
curated list of paths that are infrastructure for any Python project. Projects
|
||||
inherit these automatically and only specify what is different.
|
||||
|
||||
Discovers available Gitea Actions runners at repo, org, and instance levels. Generates a dynamic matrix for parallel job distribution.
|
||||
Rule priority (first match wins):
|
||||
1. `user_facing_overrides` — safety override (highest priority)
|
||||
2. `infrastructure_overrides` — explicit per-file
|
||||
3. `infrastructure` — DEFAULT_INFRASTRUCTURE + project-specific patterns
|
||||
4. Default: user-facing (safe — any unknown file triggers release)
|
||||
|
||||
### detect_release_commit.py
|
||||
## Post-merge workflow (`post-merge.yml`)
|
||||
|
||||
Detects whether the latest git commit is a release commit. Writes `is-release=true` or `is-release=false` to GitHub output.
|
||||
Runs on every push to master. A single workflow with conditional jobs
|
||||
replaces separate workflows for release, wiki sync, badges, and Vikunja task
|
||||
updates.
|
||||
|
||||
### push_badges.py
|
||||
### Job dependency graph
|
||||
|
||||
Generates SVG badge files from project metrics (tests, coverage, quality, version). Pushes to `badges` branch and updates README with cache-busting commit SHA URLs.
|
||||
```
|
||||
detect-type ──┬── validate-commit-msg (skip if release commit)
|
||||
├── release (skip if release commit)
|
||||
│ │
|
||||
│ ├── sync-wiki (needs release)
|
||||
│ ├── badges (needs release, ALWAYS runs)
|
||||
│ └── vikunja (needs release)
|
||||
└── configure-repo (independent, skip if release commit)
|
||||
```
|
||||
|
||||
### distribute_molecule.py
|
||||
`sync-wiki` and `vikunja` depend on `release` succeeding so that the wiki and
|
||||
task tracker are only updated when the code is actually released. If release
|
||||
fails, they are skipped to avoid leaving the wiki or Vikunja in an
|
||||
inconsistent state.
|
||||
|
||||
Distributes molecule (scenario, platform) pairs across N parallel runners. Discovers scenarios under `ansible/roles/*/molecule/`.
|
||||
The `badges` job uses `if: always()` with no is-release condition so it runs
|
||||
on every push to master, including release commits. This ensures badges
|
||||
(tests, coverage, version, etc.) are always current.
|
||||
|
||||
### molecule_ci_guard.py
|
||||
When `release` creates a `release: vX.Y.Z` commit, the release commit's
|
||||
post-merge run still updates badges (the version badge picks up the new
|
||||
version). Other jobs skip. The tag push triggers `publish.yml`.
|
||||
|
||||
Runs molecule tests sequentially while polling Gitea for other runner failures. Aborts if another runner fails the same job.
|
||||
### Jobs
|
||||
|
||||
### validate_commit_msg.py
|
||||
#### `detect-type`
|
||||
|
||||
Validates commit messages. On feature branches: conventional commits only (no `DEVX-N` prefix). On master: must have `DEVX-N` prefix from auto-merge.
|
||||
Checks if the latest commit is a release commit (`release: vX.Y.Z [skip ci]`)
|
||||
using `python -m devx.ci.detect_release_commit`. Writes `is-release=true` or
|
||||
`is-release=false` to the job output. All subsequent jobs use this to
|
||||
conditionally skip for release commits.
|
||||
|
||||
#### `validate-commit-msg`
|
||||
|
||||
Depends on `detect-type`. Skips for release commits. Validates the latest
|
||||
commit message using `python -m devx.ci.validate_commit_msg --branch master`.
|
||||
On master, commits must follow `{PREFIX}-N: <conventional commit>` format
|
||||
(added by auto-merge).
|
||||
|
||||
#### `release`
|
||||
|
||||
Depends on `detect-type`. Skips for release commits. The core release
|
||||
automation job. Runs `python -m devx.ci.release`:
|
||||
|
||||
1. **Classify changes** — calls `classify_changes.py` to check for user-facing
|
||||
changes. If only infrastructure files changed, exits without releasing.
|
||||
2. **Calculate next version** — uses git-cliff to determine the next semver
|
||||
version from conventional commits since the last tag
|
||||
3. **Update version file** — updates `__version__` in `src/devx/__init__.py`
|
||||
4. **Update changelog** — prepends the new version section to `CHANGELOG.md`
|
||||
using git-cliff output
|
||||
5. **Run tests** — executes `make lint-ruff` and `make pytest-cov` to verify
|
||||
the release is healthy. If either fails, the release is aborted — no
|
||||
commit, no tag. Use `--skip-tests` only for emergency releases.
|
||||
6. **Commit** — stages the version file and changelog, commits with
|
||||
`release: vX.Y.Z [skip ci]` (uses `--no-verify` to bypass the commit-msg
|
||||
hook since release commits are a special case)
|
||||
7. **Create tag** — creates an annotated tag `vX.Y.Z` with the changelog as
|
||||
the tag message
|
||||
8. **Push** — pushes both the commit and tag to master
|
||||
|
||||
The script is idempotent: if there are no new conventional commits since the
|
||||
last tag, it exits without doing anything. If the tag already exists (e.g.,
|
||||
from a partial previous run), it skips tag creation and only pushes.
|
||||
|
||||
**Tag consistency**: Before releasing, the script fetches remote tags and
|
||||
verifies all existing tags point to commits whose message matches the tag
|
||||
version. This prevents duplicate release commits and ensures
|
||||
tag/version/commit alignment.
|
||||
|
||||
**Version bumping rules** (git-cliff):
|
||||
|
||||
| Commit type | Version bump |
|
||||
|-------------|-------------|
|
||||
| `feat:` | minor (0.X.0) |
|
||||
| `fix:` | patch (0.0.X) |
|
||||
| `feat!:` or `BREAKING CHANGE` | minor (pre-1.0) |
|
||||
| `chore:`, `ci:`, `docs:` | no bump (excluded by cliff.toml) |
|
||||
|
||||
On failure, the `notify_failure` step creates a Gitea issue via
|
||||
`python -m devx.ci.notify_failure`.
|
||||
|
||||
#### `sync-wiki`
|
||||
|
||||
Depends on `detect-type` and `release`. Skips for release commits. Syncs
|
||||
documentation from `docs/` to the Gitea wiki using
|
||||
`python -m devx.ci.sync_wiki --repo <owner/repo> --strict`:
|
||||
|
||||
1. Reads `docs/mapping.json` to map file paths to wiki page titles
|
||||
2. Lists existing wiki pages via the Gitea API
|
||||
3. For each mapped file, reads content and creates or updates the wiki page
|
||||
4. `--strict` runs a full integrity check: verifies page count, missing
|
||||
pages, stale pages, and content match. Fails if any page is empty or
|
||||
content doesn't match.
|
||||
|
||||
Pages that exist in the wiki but not in the mapping are left untouched (not
|
||||
deleted).
|
||||
|
||||
On failure, the `notify_failure` step creates a Gitea issue.
|
||||
|
||||
#### `badges`
|
||||
|
||||
Depends on `detect-type` and `release`. Uses `if: always()` so it runs on
|
||||
every push to master, including release commits. Generates and pushes quality
|
||||
badges using `python -m devx.ci.push_badges`:
|
||||
|
||||
1. **Fetch latest master** — `git fetch origin master && git reset --hard
|
||||
origin/master` (ensures the version badge reflects the current state,
|
||||
even if the release job just pushed a new version)
|
||||
2. **Generate badges** — calls `devx.tools.generate_badges` which runs
|
||||
pytest-cov, doc-coverage, lint checks, and version extraction, then writes
|
||||
SVG files: `coverage.svg`, `tests.svg`, `docs.svg`, `quality.svg`,
|
||||
`version.svg`, `python.svg`
|
||||
3. **Push to badges branch** — creates an orphan `badges` branch, copies SVG
|
||||
files, commits, and force-pushes
|
||||
4. **Update README/docs** — switches back to master, replaces
|
||||
`raw/branch/badges/<name>.svg` URLs with `raw/commit/<sha>/<name>.svg`
|
||||
URLs (cache-busting — Gitea caches `raw/branch/` URLs for 6 hours),
|
||||
commits, and pushes
|
||||
|
||||
Supports `--retries` for retrying on git push failures (fetches latest master
|
||||
and waits 10s between attempts).
|
||||
|
||||
On failure, the `notify_failure` step creates a Gitea issue.
|
||||
|
||||
#### `vikunja`
|
||||
|
||||
Depends on `detect-type` and `release`. Skips for release commits. Updates
|
||||
the Vikunja task after a merge using `python -m devx.ci.post_merge --git-sha
|
||||
<sha>`:
|
||||
|
||||
1. Extracts the task ID from the first line of the commit message
|
||||
2. Marks the corresponding Vikunja task as done
|
||||
3. Posts a comment with the merge SHA
|
||||
|
||||
On failure, the `notify_failure` step creates a Gitea issue.
|
||||
|
||||
#### `configure-repo`
|
||||
|
||||
Depends on `detect-type`. Skips for release commits. Ensures branch
|
||||
protection and labels are configured using
|
||||
`python -m devx.tools.configure_repo --repo <name> --owner <owner>`:
|
||||
|
||||
- Sets up master branch protection (required status checks, block on rejected
|
||||
reviews, block on outdated branch)
|
||||
- Creates standard labels
|
||||
- Status check contexts read from `DEVX_STATUS_CHECKS` or default to
|
||||
`CI / quality (pull_request)`
|
||||
|
||||
On failure, the `notify_failure` step creates a Gitea issue.
|
||||
|
||||
## Publish workflow (`publish.yml`)
|
||||
|
||||
Runs on tag pushes matching `v*`. Triggered by the `release` job in the
|
||||
post-merge workflow when it creates and pushes a new version tag.
|
||||
|
||||
### Job: `publish`
|
||||
|
||||
1. **Install dependencies** — build, twine, requests, python-dotenv, click,
|
||||
and the project itself
|
||||
2. **Install CI tools** — git-cliff and tea via
|
||||
`python -m devx.tools.install_tools`
|
||||
3. **Configure tea login** — `tea login add` using `REPO_TOKEN`
|
||||
4. **Build and publish** — `python -m devx.ci.publish <tag> <owner/repo>`:
|
||||
- Build the package with `python -m build`
|
||||
- Publish to the Gitea PyPI registry (default) using `twine upload
|
||||
--repository-url <url> -u <token> -p <token>`
|
||||
- OR publish to standard PyPI if `PYPI_TOKEN` is set
|
||||
- OR skip publishing if `--skip-build` is passed (non-Python repos)
|
||||
- Create a Gitea release with git-cliff-generated release notes via
|
||||
`tea create release`
|
||||
|
||||
Publishing destination resolution (checked in order):
|
||||
1. **Gitea PyPI registry** — if `--registry-url` is given, or
|
||||
`DEVX_PYPI_REGISTRY_URL` env var is set, or derived from `GITEA_API_URL`
|
||||
2. **Standard PyPI** — if `PYPI_TOKEN` is set (takes precedence over Gitea
|
||||
registry)
|
||||
3. **Skip** — if neither is configured, only the Gitea release is created
|
||||
|
||||
On failure, the `notify_failure` step creates a Gitea issue.
|
||||
|
||||
## CI scripts
|
||||
|
||||
### `auto_merge.py`
|
||||
|
||||
Auto-merge PR when all CI checks pass. Reads task ID from the branch name
|
||||
(e.g., `DEVX-12-fix-foo` → `DEVX-12`), falling back to `.taskid` file for
|
||||
branches without a task ID prefix. Validates PR title format, checks the
|
||||
Vikunja task exists and the title matches, extracts the conventional commit
|
||||
message from PR commits, and squash-merges with
|
||||
`{PREFIX}-N <conventional commit>` title.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.auto_merge <branch> <pr_title> <owner/repo> <pr_number>
|
||||
```
|
||||
|
||||
### `release.py`
|
||||
|
||||
Automated release using git-cliff. Calculates next semver version from
|
||||
conventional commits, updates `__version__` and `CHANGELOG.md`, runs lint and
|
||||
tests, commits with `release: vX.Y.Z [skip ci]`, creates annotated tag, and
|
||||
pushes. Idempotent — exits if no unreleased changes.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.release [--dry-run] [--skip-tests] [--verify]
|
||||
```
|
||||
|
||||
- `--dry-run` — preview without making changes
|
||||
- `--skip-tests` — skip lint and test verification (emergency only)
|
||||
- `--verify` — check tag/version/changelog alignment and exit
|
||||
|
||||
### `publish.py`
|
||||
|
||||
Builds package, publishes to Gitea PyPI registry or standard PyPI, and
|
||||
creates a Gitea release with git-cliff-generated notes.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.publish <tag> <owner/repo> [--registry-url <url>] [--skip-build]
|
||||
```
|
||||
|
||||
### `pr_review.py`
|
||||
|
||||
Automated PR review. Fetches the PR diff via the Gitea API, runs automated
|
||||
checks (architecture, best practices, security, i18n, resource management,
|
||||
documentation, test coverage, commit conventions), and posts a structured
|
||||
review with inline comments.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.pr_review <pr_number> <owner/repo>
|
||||
```
|
||||
|
||||
### `notify_failure.py`
|
||||
|
||||
Creates a Gitea issue when a CI workflow fails. Uses the tea CLI for issue
|
||||
creation with failure labels. Supports `--auto-login` to configure the tea
|
||||
CLI login profile from `REPO_TOKEN`.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.notify_failure --repo <owner/repo> --run-id <id> \
|
||||
--workflow <name> --commit <sha> [--auto-login]
|
||||
```
|
||||
|
||||
### `post_merge.py`
|
||||
|
||||
Updates Vikunja task after a merge to master. Extracts task ID from the
|
||||
commit message, marks the task as done, and posts a comment with the merge SHA.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.post_merge <commit_msg> [--commit-sha <sha>] [--git-sha <sha>]
|
||||
```
|
||||
|
||||
### `classify_changes.py`
|
||||
|
||||
Classifies git changes as user-facing or workflow-only. Uses a layered rule
|
||||
system configured in `pyproject.toml`. Safe-by-default: any unknown file
|
||||
defaults to user-facing.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.classify_changes [--base <ref>] [--head <ref>] \
|
||||
[--quiet] [--check <category>] [--github-output]
|
||||
```
|
||||
|
||||
### `discover_runners.py`
|
||||
|
||||
Discovers available Gitea Actions runners at repository, organization, and
|
||||
instance levels. Falls back to `MOLECULE_RUNNERS` repo variable or
|
||||
`DEFAULT_MAX_RUNNERS` (3).
|
||||
|
||||
```bash
|
||||
python -m devx.ci.discover_runners --owner <owner> --repo <repo> [--count] [--indices]
|
||||
```
|
||||
|
||||
### `detect_release_commit.py`
|
||||
|
||||
Detects whether the latest git commit is a release commit. Writes
|
||||
`is-release=true|false` to `$GITHUB_OUTPUT`.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.detect_release_commit
|
||||
```
|
||||
|
||||
### `push_badges.py`
|
||||
|
||||
Generates SVG badge files, pushes them to the `badges` branch, and updates
|
||||
README.md and docs/index.md with cache-busting `raw/commit/<sha>/` URLs.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.push_badges [--output-dir <dir>] [--branch <branch>] \
|
||||
[--no-readme-update] [--retries <n>]
|
||||
```
|
||||
|
||||
### `distribute_molecule.py`
|
||||
|
||||
Distributes molecule (scenario, platform) pairs across N parallel runners.
|
||||
Discovers scenarios under `ansible/roles/*/molecule/`.
|
||||
|
||||
```bash
|
||||
python -m devx.molecule.distribute_molecule --runner-index <i> --max-runners <n>
|
||||
python -m devx.molecule.distribute_molecule --list
|
||||
python -m devx.molecule.distribute_molecule --list-platforms
|
||||
```
|
||||
|
||||
### `molecule_ci_guard.py`
|
||||
|
||||
Runs molecule tests sequentially while polling the Gitea API for other runner
|
||||
failures. Aborts early if another runner fails the same job. Generates JUnit
|
||||
XML when `--junit-output` is provided.
|
||||
|
||||
```bash
|
||||
python -m devx.molecule.molecule_ci_guard [--roles-root <dir>] \
|
||||
[--junit-output <file>] pair1 pair2 ...
|
||||
```
|
||||
|
||||
### `validate_commit_msg.py`
|
||||
|
||||
Validates commit messages. 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
|
||||
python -m devx.ci.validate_commit_msg <commit_msg_file> [--branch <branch>]
|
||||
```
|
||||
|
||||
### `sync_wiki.py`
|
||||
|
||||
Syncs documentation from `docs/` to the Gitea wiki via the API. Reads
|
||||
`docs/mapping.json` for file-to-page mapping. Supports `--dry-run`,
|
||||
`--verify`, and `--strict` (full integrity check).
|
||||
|
||||
```bash
|
||||
python -m devx.ci.sync_wiki [--dry-run] [--repo <owner/repo>] [--verify] [--strict]
|
||||
```
|
||||
|
||||
### `check_translations.py`
|
||||
|
||||
Validates translation files against the Python source code. Checks for
|
||||
missing keys, dead keys, and missing languages.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.check_translations [--translations <file>]...
|
||||
```
|
||||
|
||||
### `doc_coverage.py`
|
||||
|
||||
Checks documentation coverage for CLI commands and major modules. Parses
|
||||
Click commands from `cli.py` and verifies documentation exists.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.doc_coverage [--docs-dir <dir>] [--fail-on-missing]
|
||||
```
|
||||
|
||||
### `distribute_files.py`
|
||||
|
||||
Distributes files matching a glob pattern across N parallel runners
|
||||
(round-robin). Writes the assigned file list to `$GITHUB_ENV`.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.distribute_files --pattern <glob> --runner-index <i> \
|
||||
--max-runners <n> [--github-env] [--skip-if-excess]
|
||||
```
|
||||
|
||||
### `merge_junit.py`
|
||||
|
||||
Merges JUnit XML reports from parallel matrix runners into a single
|
||||
consolidated report. Exit code is non-zero if any merged suite reports
|
||||
failures.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.merge_junit --pattern <glob> --output <file>
|
||||
```
|
||||
|
||||
### `integration_guard.py`
|
||||
|
||||
Runs 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.
|
||||
|
||||
```bash
|
||||
python -m devx.ci.integration_guard --junit-output <file> -- <pytest args>
|
||||
```
|
||||
|
||||
## Release process summary
|
||||
|
||||
The complete release process from PR to published package:
|
||||
|
||||
1. **PR merged** — `auto-merge` squash-merges the PR to master with
|
||||
`{PREFIX}-N <conventional commit>` title
|
||||
2. **Post-merge triggers** — the merge push triggers `post-merge.yml`
|
||||
3. **detect-type** — confirms the commit is not a release commit
|
||||
4. **release** — `release.py` calculates the next version, updates files,
|
||||
runs tests, commits `release: vX.Y.Z [skip ci]`, creates tag `vX.Y.Z`,
|
||||
and pushes to master
|
||||
5. **Tag push triggers publish** — the tag push triggers `publish.yml`
|
||||
6. **publish** — `publish.py` builds the package, publishes to the Gitea PyPI
|
||||
registry, and creates a Gitea release with git-cliff notes
|
||||
7. **sync-wiki** — documentation is synced to the Gitea wiki
|
||||
8. **badges** — quality badges are regenerated and pushed to the `badges`
|
||||
branch; README and docs/index.md are updated with cache-busting URLs
|
||||
9. **vikunja** — the corresponding Vikunja task is marked as done
|
||||
10. **configure-repo** — branch protection and labels are ensured
|
||||
|
||||
The release commit's post-merge run skips all jobs except `badges` (which
|
||||
picks up the new version number). This prevents infinite loops.
|
||||
|
||||
## Failure handling
|
||||
|
||||
Every job in the post-merge and publish workflows has a `notify_failure` step
|
||||
that runs `if: failure()`. This creates a Gitea issue with the workflow name,
|
||||
run ID, and commit SHA, ensuring failures that would otherwise go unnoticed
|
||||
in the Actions tab are surfaced as issues. The issue is created via the tea
|
||||
CLI with a `bug` label if available.
|
||||
|
||||
Reference in New Issue
Block a user