feat(standards): drop the site CI variant + require changelog reconciliation before release
- Remove the push-triggered build-and-deploy-site pipeline and every "site" reference; Type B is now a single tag-triggered service pipeline (service-docker.yaml). - Inventory now covers packages + the auth-server service only (repos.json 11 -> 9; docs/mcp are no longer part of the standard). - Versioning standard: reconcile [Unreleased] against the last tag before promoting, and always show proposed entries to the user for approval. - Update registry.py compliance/release text and list_repos types, build.py component descriptions, and rebuild the MCP bundle + lib/wiki HTML.
This commit is contained in:
@@ -769,7 +769,7 @@ chosen by what the repository produces:</p>
|
||||
<td><strong>B — Docker deployment</strong></td>
|
||||
<td><code>templates/drone/service-docker.yaml</code></td>
|
||||
<td>An image pushed to the registry and run as a container</td>
|
||||
<td><code>auth-server</code>, <code>docs</code>, <code>mcp</code></td>
|
||||
<td><code>auth-server</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -808,30 +808,25 @@ with <code>from_secret</code> — never commit credentials.</p>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="type-b-docker-deployment-service-dockeryaml">Type B — Docker deployment (<code>service-docker.yaml</code>)</h2>
|
||||
<p>For services and sites that ship a container image. The file contains <strong>two
|
||||
pipelines</strong>, each mirroring a repo family:</p>
|
||||
<ol>
|
||||
<li><strong><code>build-and-deploy-service</code></strong> — triggered on <code>tag</code> (a long-running
|
||||
API/worker service, e.g. <code>auth-server</code>):</li>
|
||||
<p>For a service that ships a container image — a long-running API/worker, e.g.
|
||||
<code>auth-server</code>. The file contains <strong>one pipeline</strong>, <code>build-and-deploy-service</code>,
|
||||
triggered on <code>tag</code>:</p>
|
||||
<ul>
|
||||
<li><code>fetch-tags</code> — resolve the latest tag into <code>LATEST_TAG.txt</code>; fail if there
|
||||
are no tags.</li>
|
||||
are no tags.</li>
|
||||
<li><code>check-version</code> — <strong>guard</strong>: fail unless <code>$DRONE_TAG</code> equals the repo-root
|
||||
<code>VERSION</code> file (see <a href="../11_versioning_and_changelog/">11 – Versioning & Changelog</a>).</li>
|
||||
<code>VERSION</code> file (see <a href="../11_versioning_and_changelog/">11 – Versioning & Changelog</a>).</li>
|
||||
<li><code>check-remote-image</code> — if <code>aetos/<app>:<tag></code> already exists locally, exit
|
||||
<code>78</code> and skip the build.</li>
|
||||
<code>78</code> and skip the build.</li>
|
||||
<li><code>quality-gate</code> — install from <code>requirements.txt</code> and run
|
||||
<code>black</code> / <code>ruff</code> / <code>mypy</code> / <code>pytest</code>.</li>
|
||||
<code>black</code> / <code>ruff</code> / <code>mypy</code> / <code>pytest</code>.</li>
|
||||
<li><code>build-image</code> — <code>docker build</code> with the private-index build args, tagged
|
||||
<code>aetos/<app>:<tag></code> and <code>:latest</code>.</li>
|
||||
<code>aetos/<app>:<tag></code> and <code>:latest</code>.</li>
|
||||
<li><code>push-image</code> — login, re-tag with <code>$REGISTRY_HOST</code>, push both tags.</li>
|
||||
<li><code>stop-old</code> — <code>docker rm -f <app></code>.</li>
|
||||
<li><code>run-container</code> — <code>docker run -d --name <app> -p <host>:<container>
|
||||
--restart always</code> with the service's <code>-e</code> environment.</li>
|
||||
<li><strong><code>build-and-deploy-site</code></strong> — triggered on <code>push</code> (a static/HTTP site, e.g.
|
||||
<code>docs</code>, <code>mcp</code>): <code>build-image</code> → <code>push-image</code> → <code>stop-old</code> → <code>run-container</code>,
|
||||
with no tag resolution, no quality gate, and no version guard (it ships
|
||||
<code>:latest</code> only).</li>
|
||||
</ol>
|
||||
--restart always</code> with the service's <code>-e</code> environment.</li>
|
||||
</ul>
|
||||
<p>Secrets: <code>PIP_REPO_URL</code>, <code>PIP_USERNAME</code>, <code>PIP_PASSWORD</code> (service build args),
|
||||
<code>REGISTRY_HOST</code>, <code>REGISTRY_USER</code>, <code>REGISTRY_PASS</code>, plus the service runtime env
|
||||
(for example <code>MONGO_*</code>, <code>JWT_SECRET</code>).</p>
|
||||
@@ -861,11 +856,6 @@ pipelines</strong>, each mirroring a repo family:</p>
|
||||
<td><code>9003:8000</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><site></code></td>
|
||||
<td>site image / container name</td>
|
||||
<td><code>docs</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><ENV_VAR></code></td>
|
||||
<td>runtime environment variable</td>
|
||||
<td><code>MONGO_HOST</code></td>
|
||||
@@ -883,8 +873,7 @@ pipelines</strong>, each mirroring a repo family:</p>
|
||||
version to equal the tag; a service needs a root <code>VERSION</code> file that equals
|
||||
the tag. See <a href="../11_versioning_and_changelog/">11 – Versioning & Changelog</a>.</li>
|
||||
<li>Do not rename the pipelines; tooling and runbooks key off
|
||||
<code>build-and-publish-pypi</code>, <code>build-and-deploy-service</code>, and
|
||||
<code>build-and-deploy-site</code>.</li>
|
||||
<code>build-and-publish-pypi</code> and <code>build-and-deploy-service</code>.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="related">Related</h2>
|
||||
|
||||
@@ -556,6 +556,21 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="The changelog">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#reconcile-before-releasing" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Reconcile before releasing
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
@@ -771,6 +786,21 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="The changelog">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#reconcile-before-releasing" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Reconcile before releasing
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
@@ -842,7 +872,7 @@
|
||||
|
||||
<h1 id="versioning-changelog">Versioning & Changelog</h1>
|
||||
<h2 id="summary">Summary</h2>
|
||||
<p>Every Aetos artifact — library, service, or site — is versioned with
|
||||
<p>Every Aetos artifact — library or service — is versioned with
|
||||
<a href="https://semver.org/spec/v2.0.0.html">Semantic Versioning</a> and documents its
|
||||
releases in a <a href="https://keepachangelog.com/en/1.1.0/">Keep a Changelog</a> file.
|
||||
The <strong>version file is the source of truth</strong>, the <strong>git tag must equal it</strong>, and
|
||||
@@ -867,7 +897,7 @@ and tag contract is exactly what those two CI shapes consume.</p>
|
||||
<td><code>check-version</code> also reads it to skip duplicates</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Service / site (Docker)</td>
|
||||
<td>Service (Docker)</td>
|
||||
<td><code>VERSION</code> file at the repo root</td>
|
||||
<td>one line, <code>x.y.z</code>; the service <strong>reads</strong> it (build-arg) — never hardcode the version</td>
|
||||
</tr>
|
||||
@@ -934,16 +964,35 @@ one open <code>[Unreleased]</code> section with the change categories that apply
|
||||
<li>Categories: <strong>Added</strong>, <strong>Changed</strong>, <strong>Deprecated</strong>, <strong>Removed</strong>, <strong>Fixed</strong>,
|
||||
<strong>Security</strong>. Omit empty categories.</li>
|
||||
<li>Security fixes get their own entry even if the change is otherwise a bug fix.</li>
|
||||
<li>Keep <code>[Unreleased]</code> current: add an entry in the same change that introduces
|
||||
the behaviour, not later.</li>
|
||||
<li>The <code>[Unreleased]</code> heading is never renamed; copy its content into the new
|
||||
version heading and clear it.</li>
|
||||
</ul>
|
||||
<h3 id="reconcile-before-releasing">Reconcile before releasing</h3>
|
||||
<p><code>[Unreleased]</code> is a <strong>draft, not the source of truth</strong>. It is only trustworthy
|
||||
when it was maintained alongside each change; a long-running branch or a change
|
||||
that skipped the changelog leaves it stale, so it can silently under-report a
|
||||
release. Verify it against the change before you promote:</p>
|
||||
<ol>
|
||||
<li>List what actually changed since the last release:
|
||||
<code>git log <last-tag>..HEAD</code> and <code>git diff --stat <last-tag>..HEAD</code>.</li>
|
||||
<li>Compare that against <code>[Unreleased]</code>; add an entry for every user-facing change
|
||||
that is missing.</li>
|
||||
<li><strong>Always show the proposed additions to the user and wait for approval</strong>
|
||||
before promoting. If an entry is ambiguous, ask rather than guess.</li>
|
||||
</ol>
|
||||
<p>Only then promote. Never cut a release with a known gap between the diff and the
|
||||
changelog.</p>
|
||||
<hr />
|
||||
<h2 id="tagging-strategy-mr-based">Tagging strategy (MR-based)</h2>
|
||||
<p>The release version is known while the change is still a merge request, so the
|
||||
bump travels with the change and only the tag is added afterwards:</p>
|
||||
<ol>
|
||||
<li><strong>In the MR</strong> — set the intended release version: <code>version</code> in
|
||||
<code>pyproject.toml</code> (or the <code>VERSION</code> file) to <code>x.y.z</code>, and promote the
|
||||
<li><strong>In the MR</strong> — reconcile <code>[Unreleased]</code> against the change (see
|
||||
<a href="#reconcile-before-releasing">Reconcile before releasing</a>) and get the user's
|
||||
approval for any additions. Then set the intended release version: <code>version</code>
|
||||
in <code>pyproject.toml</code> (or the <code>VERSION</code> file) to <code>x.y.z</code>, and promote the
|
||||
changelog (below). Changelog entries and link references name the
|
||||
<strong>version/tag</strong>, never a commit id.</li>
|
||||
<li><strong>Merge or squash</strong> the MR into <code>main</code>.</li>
|
||||
@@ -970,8 +1019,11 @@ After the user confirms the MR is merged/squashed and says to proceed:</p>
|
||||
<h2 id="release-checklist">Release checklist</h2>
|
||||
<ol>
|
||||
<li>Confirm the quality gate is green and <code>main</code> is up to date.</li>
|
||||
<li>In the MR: move every <code>[Unreleased]</code> entry under the new version heading with
|
||||
the target date (<code>## [x.y.z] - YYYY-MM-DD</code>); restore an empty <code>[Unreleased]</code>
|
||||
<li>In the MR: reconcile <code>[Unreleased]</code> against the change being released —
|
||||
<code>git log <last-tag>..HEAD</code> and <code>git diff --stat <last-tag>..HEAD</code> — add any
|
||||
missing user-facing entries, and get the user's approval for the additions.
|
||||
Then move every <code>[Unreleased]</code> entry under the new version heading with the
|
||||
target date (<code>## [x.y.z] - YYYY-MM-DD</code>) and restore an empty <code>[Unreleased]</code>
|
||||
on top.</li>
|
||||
<li>In the MR: add the two compare-link references at the bottom of the
|
||||
changelog, naming the version/tag (never a commit id).</li>
|
||||
|
||||
@@ -557,9 +557,9 @@
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#services-sites-type-b" class="md-nav__link">
|
||||
<a href="#services-type-b" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Services & sites (Type B)
|
||||
Services (Type B)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -711,9 +711,9 @@
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#services-sites-type-b" class="md-nav__link">
|
||||
<a href="#services-type-b" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Services & sites (Type B)
|
||||
Services (Type B)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -837,14 +837,13 @@ Paths are relative to the <code>aetos/</code> workspace root.</p>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="services-sites-type-b">Services & sites (Type B)</h2>
|
||||
<h2 id="services-type-b">Services (Type B)</h2>
|
||||
<p>A container image pushed to the registry and run on the Docker host. Version
|
||||
source is the <code>VERSION</code> file; Drone file is <code>service-docker.yaml</code>.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Repo</th>
|
||||
<th>Type</th>
|
||||
<th>Path</th>
|
||||
<th>Trigger</th>
|
||||
<th>Docs</th>
|
||||
@@ -853,29 +852,13 @@ source is the <code>VERSION</code> file; Drone file is <code>service-docker.yaml
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>auth-server</code></td>
|
||||
<td>service</td>
|
||||
<td><code>auth-server</code></td>
|
||||
<td>tag</td>
|
||||
<td>api, lib, wiki</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>docs</code></td>
|
||||
<td>site</td>
|
||||
<td><code>docs</code></td>
|
||||
<td>push</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>mcp</code></td>
|
||||
<td>site</td>
|
||||
<td><code>mcp</code></td>
|
||||
<td>push</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The <strong>service</strong> variant is tag-triggered and enforces <code>tag == VERSION</code>. The
|
||||
<strong>site</strong> variant is push-triggered, ships <code>:latest</code>, and has no tag guard.</p>
|
||||
<p>Tag-triggered and enforces <code>tag == VERSION</code>.</p>
|
||||
<hr />
|
||||
<h2 id="required-files-per-repo">Required files per repo</h2>
|
||||
<table>
|
||||
@@ -895,7 +878,7 @@ source is the <code>VERSION</code> file; Drone file is <code>service-docker.yaml
|
||||
<td><code>python-lib.yaml</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>service / site</td>
|
||||
<td>service</td>
|
||||
<td><code>VERSION</code></td>
|
||||
<td><code>CHANGELOG.md</code></td>
|
||||
<td><code>service-docker.yaml</code></td>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Reference in New Issue
Block a user