feat(standards): add Drone CI standard (PyPI package + Docker deployment)

Document the two `.drone.yml` shapes used across the org, derived from the
repos:

- Type A `python-lib.yaml`: build-and-publish-pypi + backfill-pypi-from-tags
- Type B `service-docker.yaml`: build-and-deploy-service + build-and-deploy-site

- add reference page `10_drone_pipelines`
- vendor `src/templates/drone/` into the MCP bundle (`drone.json`)
- expose `registry://drone` + `list_drone_templates` / `get_drone_template`
- wire `build.py` to vendor drone templates; rebuild nav/index (14 modules)
This commit is contained in:
2026-10-15 00:52:38 +05:30
parent 18d52bdb7c
commit a754366901
14 changed files with 1133 additions and 2 deletions

View File

@@ -0,0 +1,102 @@
# Drone Pipelines
## Summary
Every Aetos repository ships a Drone CI definition at `.drone.yml`. There is
exactly **one standard per repository**, and there are **two types of file**,
chosen by what the repository produces:
| Type | File | Produces | Repos |
|------|------|----------|-------|
| **A — PyPI package** | `templates/drone/python-lib.yaml` | A wheel + sdist on the private index | `dagpipe`, `doc-forge`, `hexa`, `mail-intake`, `mongo-ops`, `omniread`, `openapi-first`, `py-jwt` |
| **B — Docker deployment** | `templates/drone/service-docker.yaml` | An image pushed to the registry and run as a container | `auth-server`, `docs`, `mcp` |
Both templates run on `platform: linux / arm64` with the workspace at
`/drone/src`. Copy the matching template to `<repo>/.drone.yml`; the Type A file
needs no edits, the Type B file needs its placeholders filled in (below).
> Conventions: `.drone.yml` (not `.yaml`), one file per repo, secrets injected
> with `from_secret` — never commit credentials.
---
## Type A — PyPI package (`python-lib.yaml`)
For internal libraries. The file contains **two pipelines**:
1. **`build-and-publish-pypi`** — triggered on `tag`:
- `check-version` — read `name` / `version` from `pyproject.toml` and query
`$PIP_REPO_URL/simple/<package>/`; if that version already exists, exit
`78` and skip the whole build.
- `quality-gate` — install the package with its `[dev]` extras from the
private index, then `black --check`, `ruff check`, `mypy`, `pydoclint`,
`pytest`.
- `build-package` — `python -m build` into `dist/`.
- `upload-to-private-pypi` — `twine upload` to `$PIP_REPO_URL`.
2. **`backfill-pypi-from-tags`** — triggered on `custom`:
- `fetch-tags` — `git fetch --tags --force`.
- `build-and-upload-missing` — walk every tag in version order, skip the ones
already on the index, `git checkout` the rest, build, and upload. This is
the disaster-recovery / replay path.
Secrets: `PIP_REPO_URL`, `PIP_USERNAME`, `PIP_PASSWORD`.
- **Ship as-is.** Package name and version come from `pyproject.toml`, so the
same file is reused verbatim across every library.
---
## Type B — Docker deployment (`service-docker.yaml`)
For services and sites that ship a container image. The file contains **two
pipelines**, each mirroring a repo family:
1. **`build-and-deploy-service`** — triggered on `tag` (a long-running
API/worker service, e.g. `auth-server`):
- `fetch-tags` — resolve the latest tag into `LATEST_TAG.txt`; fail if there
are no tags.
- `check-remote-image` — if `aetos/<app>:<tag>` already exists locally, exit
`78` and skip the build.
- `quality-gate` — install from `requirements.txt` and run
`black` / `ruff` / `mypy` / `pytest`.
- `build-image` — `docker build` with the private-index build args, tagged
`aetos/<app>:<tag>` and `:latest`.
- `push-image` — login, re-tag with `$REGISTRY_HOST`, push both tags.
- `stop-old` — `docker rm -f <app>`.
- `run-container` — `docker run -d --name <app> -p <host>:<container>
--restart always` with the service's `-e` environment.
2. **`build-and-deploy-site`** — triggered on `push` (a static/HTTP site, e.g.
`docs`, `mcp`): `build-image` → `push-image` → `stop-old` → `run-container`,
with no tag resolution and no quality gate.
Secrets: `PIP_REPO_URL`, `PIP_USERNAME`, `PIP_PASSWORD` (service build args),
`REGISTRY_HOST`, `REGISTRY_USER`, `REGISTRY_PASS`, plus the service runtime env
(for example `MONGO_*`, `JWT_SECRET`).
Placeholders to fill in per repo:
| Placeholder | Meaning | Example |
|-------------|---------|---------|
| `<app>` | service image / container name | `auth-server` |
| `aetos/<app>` | image repository on the registry | `aetos/auth-server` |
| `<host-port>` / `<container-port>` | published : in-image port | `9003:8000` |
| `<site>` | site image / container name | `docs` |
| `<ENV_VAR>` | runtime environment variable | `MONGO_HOST` |
---
## What not to do
- Do not hand-roll a third shape. A repo is either Type A or Type B, never both.
- Do not inline secrets; always use `from_secret`.
- Do not drop the `check-version` / `check-remote-image` skip — it guards the
index and the running container against duplicate publishes.
- Do not rename the pipelines; tooling and runbooks key off
`build-and-publish-pypi`, `build-and-deploy-service`, and
`build-and-deploy-site`.
---
## Related
- [01 – Build Recipe](01_build_recipe.md) · [09 – Infra Adapters](09_infra_adaptors.md) · [13 – Library Registry](13_library_registry.md)

View File

@@ -14,6 +14,7 @@ patterns, and the internal library catalog that agents consult while coding.
- **Worker & Progress** — queued work, progress reporting, and visibility.
- **Human-in-the-Loop** — guardrails and approvals inside automations.
- **Infra Adapters** — how infrastructure connects without leaking into domain.
- **Drone Pipelines** — the two CI shapes: a PyPI package or a Docker deployment.
- **Genericity Matrix** — what is library-backed, template-provided, or authored.
- **Auth Integration** — consuming the shared auth-server service (spec-driven,
no auth code).