feat: full-stack MCP surface — client template, npm CI, 13 repos
- build.py: vendor templates/client into mcp/templates/client with client.json manifest (16 kinds); register drone-npm as a third CI shape (types: pypi/npm/docker); root *.py stale doc numbers fixed - registry.py: registry://client resource + list_client_components / get_client_component / get_client_template tools; build prompt gains the client scaffold step (docs://modules/ui_admin); compliance prompt covers npm packages; drone docs describe all three shapes - repos.json (+mcp): doc-weaver, react-auth, react-openapi (npm Type B, package.json version source), vet (app Type C, VERSION) - docs: 90_drone_pipelines gains Type B npm section; 91_versioning covers package.json as a version source; 94_repository_inventory gains the npm package table and services/apps Type C; lib index updated Verified: bundle regen (24 modules, client 16, drone 3, repos 13); registry client readers exercised against the vendored bundle.
This commit is contained in:
@@ -3,17 +3,19 @@
|
||||
## 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**,
|
||||
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 — Docker deployment** | `templates/drone/service-docker.yaml` | An image pushed to the registry and run as a container | `auth-server` |
|
||||
| **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` |
|
||||
|
||||
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).
|
||||
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
|
||||
> with `from_secret` — never commit credentials.
|
||||
@@ -22,7 +24,7 @@ needs no edits, the Type B file needs its placeholders filled in (below).
|
||||
|
||||
## Type A — PyPI package (`python-lib.yaml`)
|
||||
|
||||
For internal libraries. The file contains **two pipelines**:
|
||||
For internal Python libraries. The file contains **two pipelines**:
|
||||
|
||||
1. **`build-and-publish-pypi`** — triggered on `tag`:
|
||||
- `check-version` — **guard**: fail unless `$DRONE_TAG` equals the version in
|
||||
@@ -48,7 +50,30 @@ Secrets: `PIP_REPO_URL`, `PIP_USERNAME`, `PIP_PASSWORD`.
|
||||
|
||||
---
|
||||
|
||||
## Type B — Docker deployment (`service-docker.yaml`)
|
||||
## 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_TAG` equals the version in
|
||||
`package.json`; query `$NPM_REPO_URL` for `name@version`; if it already
|
||||
exists, exit `78` and skip the whole build.
|
||||
- `quality-gate` — write `.npmrc` from the secrets, `npm install`, then
|
||||
`npm run quality-gate`.
|
||||
- `build-package` — `npm install && npm run build` into `dist/`.
|
||||
- `publish-to-private-npm` — `npm publish --access restricted` to
|
||||
`$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`,
|
||||
@@ -86,15 +111,18 @@ Placeholders to fill in per repo:
|
||||
|
||||
## What not to do
|
||||
|
||||
- Do not hand-roll a third shape. A repo is either Type A or Type B, never both.
|
||||
- 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-image` skip — it guards the
|
||||
index and the running container against duplicate publishes.
|
||||
- Do not drop the tag↔version guard. A package needs its `pyproject.toml`
|
||||
version to equal the tag; a service needs a root `VERSION` file that equals
|
||||
the tag. See [91 – Versioning & Changelog](91_versioning_and_changelog.md).
|
||||
- Do not drop the tag↔version guard. A Python package needs its
|
||||
`pyproject.toml` version to equal the tag; an npm package needs its
|
||||
`package.json` version; a service needs a root `VERSION` file. See
|
||||
[91 – Versioning & Changelog](91_versioning_and_changelog.md).
|
||||
- Do not rename the pipelines; tooling and runbooks key off
|
||||
`build-and-publish-pypi` and `build-and-deploy-service`.
|
||||
`build-and-publish-pypi`, `build-and-publish-npm`, and
|
||||
`build-and-deploy-service`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ a Drone guard enforces that equality before anything is published. Releases are
|
||||
cut manually; a tag is what triggers the pipeline.
|
||||
|
||||
This page pairs with [90 – Drone Pipelines](90_drone_pipelines.md): the version
|
||||
and tag contract is exactly what those two CI shapes consume.
|
||||
and tag contract is exactly what those three CI shapes consume.
|
||||
|
||||
---
|
||||
|
||||
@@ -19,6 +19,7 @@ and tag contract is exactly what those two CI shapes consume.
|
||||
| Artifact | Source of truth | Notes |
|
||||
|----------|-----------------|-------|
|
||||
| Library (PyPI package) | `version` in `pyproject.toml` | `check-version` also reads it to skip duplicates |
|
||||
| Library (npm package) | `version` in `package.json` | `check-version` also queries the registry to skip duplicates |
|
||||
| Service (Docker) | `VERSION` file at the repo root | one line, `x.y.z`; the service **reads** it (build-arg) — never hardcode the version |
|
||||
|
||||
Rules:
|
||||
@@ -116,7 +117,8 @@ bump travels with the change and only the tag is added afterwards:
|
||||
1. **In the MR** — reconcile `[Unreleased]` against the change (see
|
||||
[Reconcile before releasing](#reconcile-before-releasing)) and get the user's
|
||||
approval for any additions. Then set the intended release version: `version`
|
||||
in `pyproject.toml` (or the `VERSION` file) to `x.y.z`, and promote the
|
||||
in `pyproject.toml` or `package.json` (or the `VERSION` file) to `x.y.z`,
|
||||
and promote the
|
||||
changelog (below). Changelog entries and link references name the
|
||||
**version/tag**, never a commit id.
|
||||
2. **Merge or squash** the MR into `main`.
|
||||
@@ -133,8 +135,10 @@ After the user confirms the MR is merged/squashed and says to proceed:
|
||||
|
||||
1. **Wait** for that explicit go-ahead.
|
||||
2. Find the commit that introduced the version bump:
|
||||
- packages:
|
||||
- Python packages:
|
||||
`git log -S 'version = "x.y.z"' -n 1 --format='%H %s' -- pyproject.toml`
|
||||
- npm packages:
|
||||
`git log -S '"version": "x.y.z"' -n 1 --format='%H %s' -- package.json`
|
||||
- services:
|
||||
`git log -S 'x.y.z' -n 1 --format='%H %s' -- VERSION`
|
||||
3. Confirm that commit's version file equals `x.y.z`, then tag **only** that
|
||||
@@ -154,13 +158,14 @@ After the user confirms the MR is merged/squashed and says to proceed:
|
||||
on top.
|
||||
3. In the MR: add the two compare-link references at the bottom of the
|
||||
changelog, naming the version/tag (never a commit id).
|
||||
4. In the MR: set the version file — `pyproject.toml` (`version = "x.y.z"`) or
|
||||
`VERSION` — to the intended release version.
|
||||
4. In the MR: set the version file — `pyproject.toml` (`version = "x.y.z"`),
|
||||
`package.json` (`"version": "x.y.z"`), or `VERSION` — to the intended
|
||||
release version.
|
||||
5. Merge or squash the MR into `main`.
|
||||
6. Create the tag on the resulting commit: lightweight `git tag x.y.z`.
|
||||
7. Push the tag (`git push origin x.y.z`). Watch Drone: Type A publishes the
|
||||
wheel/sdist, Type B builds and deploys the image; both first assert
|
||||
`tag == version`.
|
||||
wheel/sdist, Type B publishes the npm package, Type C builds and deploys
|
||||
the image; all three first assert `tag == version`.
|
||||
8. Do not reuse the tag if the run fails — fix and cut `x.y.(z+1)`.
|
||||
|
||||
---
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
The canonical list of Aetos repositories covered by the CI and versioning
|
||||
standards, with the artifact each one produces, its version source, and its
|
||||
Drone shape. Every entry maps to the contract in
|
||||
[91 – Versioning & Changelog](91_versioning_and_changelog.md) and the two CI
|
||||
[91 – Versioning & Changelog](91_versioning_and_changelog.md) and the three CI
|
||||
files in [90 – Drone Pipelines](90_drone_pipelines.md).
|
||||
|
||||
The same data is published machine-readably as the `registry://repos` MCP
|
||||
@@ -14,7 +14,7 @@ Paths are relative to the `aetos/` workspace root.
|
||||
|
||||
---
|
||||
|
||||
## Packages (Type A)
|
||||
## Packages (Type A — PyPI)
|
||||
|
||||
A wheel + sdist published to the private index. Version source is
|
||||
`pyproject.toml`; Drone file is `python-lib.yaml` (tag-triggered).
|
||||
@@ -32,14 +32,28 @@ A wheel + sdist published to the private index. Version source is
|
||||
|
||||
---
|
||||
|
||||
## Services (Type B)
|
||||
## Packages (Type B — npm)
|
||||
|
||||
A package published to the private npm registry (`npm.aetoskia.com`). Version
|
||||
source is `package.json`; Drone file is `npm-lib.yaml` (tag-triggered).
|
||||
|
||||
| Repo | Path | Docs | MCP server |
|
||||
|------|------|------|------------|
|
||||
| `doc-weaver` | `doc-weaver` | lib, wiki | `doc-weaver:8010` |
|
||||
| `react-auth` | `react/react-auth` | lib, wiki | `react-auth:8011` |
|
||||
| `react-openapi` | `react/react-openapi` | lib, wiki | `react-openapi:8012` |
|
||||
|
||||
---
|
||||
|
||||
## Services & Apps (Type C)
|
||||
|
||||
A container image pushed to the registry and run on the Docker host. Version
|
||||
source is the `VERSION` file; Drone file is `service-docker.yaml`.
|
||||
|
||||
| Repo | Path | Trigger | Docs |
|
||||
|------|------|---------|------|
|
||||
| `auth-server` | `auth-server` | tag | api, lib, wiki |
|
||||
| Repo | Path | Type | Trigger | Docs |
|
||||
|------|------|------|---------|------|
|
||||
| `auth-server` | `auth-server` | service | tag | api, lib, wiki |
|
||||
| `vet` | `react/vet` | app | tag | lib, wiki |
|
||||
|
||||
Tag-triggered and enforces `tag == VERSION`.
|
||||
|
||||
@@ -49,8 +63,9 @@ Tag-triggered and enforces `tag == VERSION`.
|
||||
|
||||
| Type | Version source | Changelog | Drone |
|
||||
|------|----------------|-----------|-------|
|
||||
| package | `pyproject.toml` | `CHANGELOG.md` | `python-lib.yaml` |
|
||||
| service | `VERSION` | `CHANGELOG.md` | `service-docker.yaml` |
|
||||
| package (PyPI) | `pyproject.toml` | `CHANGELOG.md` | `python-lib.yaml` |
|
||||
| package (npm) | `package.json` | `CHANGELOG.md` | `npm-lib.yaml` |
|
||||
| service / app | `VERSION` | `CHANGELOG.md` | `service-docker.yaml` |
|
||||
|
||||
Every covered repository must be able to satisfy `tag == version`:
|
||||
the version file (never a commit id) is bumped in the release MR, the MR is
|
||||
|
||||
@@ -44,8 +44,8 @@ and an optional pipelines layer.
|
||||
|
||||
## Delivery & Meta
|
||||
|
||||
- **Drone Pipelines** — the two CI shapes: a PyPI/npm package or a Docker
|
||||
deployment.
|
||||
- **Drone Pipelines** — the three CI shapes: a PyPI package, an npm package,
|
||||
or a Docker deployment.
|
||||
- **Versioning & Changelog** — SemVer, the tag↔version contract, and the
|
||||
release changelog.
|
||||
- **Repository Inventory** — every covered repo, its type, version source, and
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"project": "standards",
|
||||
"note": "Machine-readable repository inventory. Mirrors standards/src/lib/15_repository_inventory.md. Read it with the registry://repos resource or the list_repos tool.",
|
||||
"note": "Machine-readable repository inventory. Mirrors standards/src/lib/94_repository_inventory.md. Read it with the registry://repos resource or the list_repos tool.",
|
||||
"path_convention": "relative to the aetos/ workspace root",
|
||||
"repos": [
|
||||
{
|
||||
@@ -23,6 +23,16 @@
|
||||
"docs": ["lib", "wiki"],
|
||||
"mcp": { "server": "docforge", "port": 8001 }
|
||||
},
|
||||
{
|
||||
"name": "doc-weaver",
|
||||
"type": "package",
|
||||
"path": "doc-weaver",
|
||||
"version_source": "package.json",
|
||||
"drone": "npm-lib.yaml",
|
||||
"trigger": "tag",
|
||||
"docs": ["lib", "wiki"],
|
||||
"mcp": { "server": "doc-weaver", "port": 8010 }
|
||||
},
|
||||
{
|
||||
"name": "hexa",
|
||||
"type": "package",
|
||||
@@ -83,6 +93,26 @@
|
||||
"docs": ["lib", "wiki"],
|
||||
"mcp": { "server": "jwtlib", "port": 8005 }
|
||||
},
|
||||
{
|
||||
"name": "react-auth",
|
||||
"type": "package",
|
||||
"path": "react/react-auth",
|
||||
"version_source": "package.json",
|
||||
"drone": "npm-lib.yaml",
|
||||
"trigger": "tag",
|
||||
"docs": ["lib", "wiki"],
|
||||
"mcp": { "server": "react-auth", "port": 8011 }
|
||||
},
|
||||
{
|
||||
"name": "react-openapi",
|
||||
"type": "package",
|
||||
"path": "react/react-openapi",
|
||||
"version_source": "package.json",
|
||||
"drone": "npm-lib.yaml",
|
||||
"trigger": "tag",
|
||||
"docs": ["lib", "wiki"],
|
||||
"mcp": { "server": "react-openapi", "port": 8012 }
|
||||
},
|
||||
{
|
||||
"name": "auth-server",
|
||||
"type": "service",
|
||||
@@ -92,6 +122,16 @@
|
||||
"trigger": "tag",
|
||||
"docs": ["api", "lib", "wiki"],
|
||||
"mcp": null
|
||||
},
|
||||
{
|
||||
"name": "vet",
|
||||
"type": "app",
|
||||
"path": "react/vet",
|
||||
"version_source": "VERSION",
|
||||
"drone": "service-docker.yaml",
|
||||
"trigger": "tag",
|
||||
"docs": ["lib", "wiki"],
|
||||
"mcp": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user