Drone Pipelines
Summary
Every Aetos repository ships a Drone CI definition at .drone.yml. There is
exactly one standard per repository, and there are three 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 — npm package | templates/drone/npm-lib.yaml |
A package published to the private npm registry | doc-weaver, react-auth, react-openapi |
| C — Docker deployment | templates/drone/service-docker.yaml |
An image pushed to the registry and run as a container | auth-server, vet |
All templates run on platform: linux / arm64 with the workspace at
/drone/src. Copy the matching template to <repo>/.drone.yml; the Type A and
Type B files need no edits, the Type C file needs its placeholders filled in
(below).
Conventions:
.drone.yml(not.yaml), one file per repo, secrets injected withfrom_secret— never commit credentials.
Type A — PyPI package (python-lib.yaml)
For internal Python libraries. The file contains two pipelines:
build-and-publish-pypi— triggered ontag:check-version— guard: fail unless$DRONE_TAGequals the version inpyproject.toml; then readname/versionand query$PIP_REPO_URL/simple/<package>/; if that version already exists, exit78and skip the whole build (see 91 – Versioning & Changelog).quality-gate— install the package with its[dev]extras from the private index, thenblack --check,ruff check,mypy,pydoclint,pytest.build-package—python -m buildintodist/.upload-to-private-pypi—twine uploadto$PIP_REPO_URL.backfill-pypi-from-tags— triggered oncustom:fetch-tags—git fetch --tags --force.build-and-upload-missing— walk every tag in version order, skip the ones already on the index,git checkoutthe rest, verifytag == pyproject versionat that commit, 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 — npm package (npm-lib.yaml)
For internal npm libraries (the React packages). One pipeline,
build-and-publish-npm, triggered on tag:
check-version— guard: fail unless$DRONE_TAGequals the version inpackage.json; query$NPM_REPO_URLforname@version; if it already exists, exit78and skip the whole build.quality-gate— write.npmrcfrom the secrets,npm install, thennpm run quality-gate.build-package—npm install && npm run buildintodist/.publish-to-private-npm—npm publish --access restrictedto$NPM_REPO_URL.
Secrets: NPM_REPO_URL, NPM_USERNAME, NPM_PASSWORD. Auth is a generated
.npmrc (registry= + _auth= base64 of user:pass) written from secrets at
runtime — the committed .npmrc in a repo only points at the registry URL.
- Ship as-is. Name and version come from
package.json, so the same file is reused verbatim across every npm package.
Type C — Docker deployment (service-docker.yaml)
For a service that ships a container image — a long-running API/worker, e.g.
auth-server. The file contains one pipeline, build-and-deploy-service,
triggered on tag:
fetch-tags— resolve the latest tag intoLATEST_TAG.txt; fail if there are no tags.check-version— guard: fail unless$DRONE_TAGequals the repo-rootVERSIONfile (see 91 – Versioning & Changelog).check-remote-image— ifaetos/<app>:<tag>already exists locally, exit78and skip the build.quality-gate— install fromrequirements.txtand runblack/ruff/mypy/pytest.build-image—docker buildwith the private-index build args, taggedaetos/<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 alwayswith the service's-eenvironment.
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 |
<ENV_VAR> |
runtime environment variable | MONGO_HOST |
What not to do
- Do not hand-roll a fourth shape. A repo is exactly one of Type A, B, or C, never combinations.
- Do not inline secrets; always use
from_secret. - Do not drop the
check-version/check-remote-imageskip — it guards the index and the running container against duplicate publishes. - Do not drop the tag↔version guard. A Python package needs its
pyproject.tomlversion to equal the tag; an npm package needs itspackage.jsonversion; a service needs a rootVERSIONfile. See 91 – Versioning & Changelog. - Do not rename the pipelines; tooling and runbooks key off
build-and-publish-pypi,build-and-publish-npm, andbuild-and-deploy-service.