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:
102
standards/src/lib/10_drone_pipelines.md
Normal file
102
standards/src/lib/10_drone_pipelines.md
Normal 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)
|
||||
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user