Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .agents/skills/bump-version-and-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ Three workflows in `.github/workflows/` interact with `VERSION`:
### 3. `deploy_docs_from_release.yaml` — versioned docs

- **Trigger:** GitHub `release` event with `types: [published]`.
- **Behavior:** runs `mike deploy --push --update-aliases <release.tag_name> latest`, publishing the docs site under the release tag and pointing the `latest` alias at it.
- Companion workflows publish unversioned docs from `main` (default alias `main`) and `develop` (alias `develop`).
- **Behavior:** publishes the docs under the release's **MAJOR.MINOR slug** (tag `0.21.0` → `/0.21/`) titled with the full tag, points the `latest` alias at it, and makes `latest` the site default. A later hotfix republishes the same slug in place (retitled to the new patch version), so URLs never break within a minor line.
- Companion workflows publish `develop` (slug `develop`, titled `<VERSION> (unstable)`, pinned to the top of the version selector) and `main` (same MAJOR.MINOR slug mechanism as releases, so docs hotfixes go live without a release). There is no separate `main` docs version.

So the full release path is: bump `VERSION` → PR → merge to `main`/`develop` (retag unchanged images and/or rebuild changed ones + push + sign) → cut a GitHub Release matching that VERSION (versioned docs go live).

Expand Down Expand Up @@ -253,7 +253,7 @@ For a true release (dropping the pre-release suffix):
3. [ ] In the same PR, retitle the Release Notes section to `## X.Y.Z — YYYY-MM-DD` and open a fresh `## <next-version> (Unreleased)` above it.
4. [ ] Merge to `main`.
5. [ ] Wait for `docker-build.yml` to push and sign all images.
6. [ ] Create a GitHub Release with tag `X.Y.Z` (matching `VERSION` exactly). Publishing the release fires `deploy_docs_from_release.yaml`, which runs `mike deploy --push --update-aliases X.Y.Z latest` and updates the versioned docs site.
6. [ ] Create a GitHub Release with tag `X.Y.Z` (matching `VERSION` exactly). Publishing the release fires `deploy_docs_from_release.yaml`, which publishes the docs under the `X.Y` slug (titled `X.Y.Z`) and points the `latest` alias and site default at it.
7. [ ] Verify the docs site shows the new version under the version selector and that `latest` resolves to it.

## References
Expand All @@ -263,7 +263,7 @@ For a true release (dropping the pre-release suffix):
- [`/.github/workflows/check-version-increment.yml`](../../../.github/workflows/check-version-increment.yml) — the PR gate (semver regex lives here)
- [`/.github/workflows/docker-build.yml`](../../../.github/workflows/docker-build.yml) — build/push/sign on tag change
- [`/.github/workflows/deploy_docs_from_release.yaml`](../../../.github/workflows/deploy_docs_from_release.yaml) — versioned docs on release
- [`/.github/workflows/deploy_docs_from_main.yaml`](../../../.github/workflows/deploy_docs_from_main.yaml) and [`deploy_docs_from_develop.yaml`](../../../.github/workflows/deploy_docs_from_develop.yaml) — branch-tracking docs aliases
- [`/.github/workflows/deploy_docs_from_main.yaml`](../../../.github/workflows/deploy_docs_from_main.yaml) and [`deploy_docs_from_develop.yaml`](../../../.github/workflows/deploy_docs_from_develop.yaml) — branch-tracking docs deploys (main republishes the current MAJOR.MINOR slug; develop publishes the `develop` preview)
- [`/airstack.sh`](../../../airstack.sh) — defines `airstack version` and `get_VERSION` (used everywhere image tags are built)
- [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html)

Expand Down
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ PROJECT_NAME="airstack"
# If you've run ./airstack.sh setup, then this will auto-generate from the git commit hash every time a change is made
# to a Dockerfile or docker-compose.yaml file. Otherwise this can also be set explicitly to make a release version.
# auto-generated from git commit hash
VERSION="0.20.1"
VERSION="0.20.2"
# Image-tag discriminator ONLY (appears in the image tag suffix, e.g. ..._robot-x86-64_dev).
# No Dockerfile consumes it: "prebuilt" does NOT bake the built ros_ws into the image today —
# a real prebuilt (workspace-baked) stage is future work. Keep "dev" (mounted code, built live).
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/deploy_docs_from_develop.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ jobs:
run: |
VERSION=$(grep -m1 '^VERSION=' .env | cut -d= -f2- | tr -d '"')
mike deploy --push --title "${VERSION} (unstable)" develop
# mike re-sorts versions.json on every deploy ("main" sorts above
# "develop"), so pin develop — the higher, unreleased version — back
# to the top of the version selector after each deploy.
- name: Reorder version selector (develop above main)
# mike re-sorts versions.json on every deploy, so pin develop — the
# higher, unreleased version — back to the top of the version selector
# after each deploy.
- name: Reorder version selector (develop first)
run: |
git worktree add ../ghp-reorder gh-pages
python3 .github/workflows/scripts/docs_reorder_versions.py ../ghp-reorder/versions.json
Expand Down
19 changes: 13 additions & 6 deletions .github/workflows/deploy_docs_from_main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,22 @@ jobs:
run: |
git config --global user.name "Docs Deploy"
git config --global user.email "docs.deploy@example.co.uk"
# Stable docs live under a MAJOR.MINOR slug (e.g. /0.20/) — there is
# no separate "main" docs version (it duplicated the release entry in
# the version selector). A hotfix merged to main republishes the same
# slug in place and retitles the selector entry to the new patch
# version, so URLs never break within a minor line.
- name: Build Docs Website
run: |
VERSION=$(grep -m1 '^VERSION=' .env | cut -d= -f2- | tr -d '"')
mike deploy --push --title "${VERSION} (stable)" main
mike set-default main --push
# mike re-sorts versions.json on every deploy ("main" sorts above
# "develop"), so pin develop — the higher, unreleased version — back
# to the top of the version selector after each deploy.
- name: Reorder version selector (develop above main)
SLUG=$(echo "${VERSION}" | cut -d. -f1-2)
echo "Deploying main's docs: slug ${SLUG}, title ${VERSION}"
mike deploy --push --update-aliases --title "${VERSION}" "${SLUG}" latest
mike set-default latest --push
# mike re-sorts versions.json on every deploy, so pin develop — the
# higher, unreleased version — back to the top of the version selector
# after each deploy.
- name: Reorder version selector (develop first)
run: |
git worktree add ../ghp-reorder gh-pages
python3 .github/workflows/scripts/docs_reorder_versions.py ../ghp-reorder/versions.json
Expand Down
21 changes: 15 additions & 6 deletions .github/workflows/deploy_docs_from_release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,22 @@ jobs:
run: |
git config --global user.name "Docs Deploy"
git config --global user.email "docs.deploy@example.co.uk"
# Docs versions use MAJOR.MINOR slugs (e.g. tag 0.21.0 → /0.21/) so a
# later hotfix can republish the same slug in place without breaking
# URLs; the selector entry's title carries the full patch version.
- name: Build Docs Website
run: mike deploy --push --update-aliases ${{ github.event.release.tag_name }} latest
# mike re-sorts versions.json on every deploy ("main" sorts above
# "develop"), so pin develop — the higher, unreleased version — back
# to the top of the version selector after each deploy. Guarded:
# the script may be absent on release tags cut before it existed.
- name: Reorder version selector (develop above main)
env:
TAG: ${{ github.event.release.tag_name }}
run: |
SLUG=$(echo "${TAG}" | cut -d. -f1-2)
echo "Deploying release docs: slug ${SLUG}, title ${TAG}"
mike deploy --push --update-aliases --title "${TAG}" "${SLUG}" latest
mike set-default latest --push
# mike re-sorts versions.json on every deploy, so pin develop — the
# higher, unreleased version — back to the top of the version selector
# after each deploy. Guarded: the script may be absent on release tags
# cut before it existed.
- name: Reorder version selector (develop first)
run: |
if [ ! -f .github/workflows/scripts/docs_reorder_versions.py ]; then
echo "skipped: docs_reorder_versions.py not on this tag"
Expand Down
17 changes: 9 additions & 8 deletions .github/workflows/scripts/docs_reorder_versions.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#!/usr/bin/env python3
"""Pin the docs version-selector order: develop above main.
"""Pin the docs version-selector order: develop first.

mike re-sorts versions.json on every deploy, and among non-numeric
("dev") versions it sorts reverse-lexically, so "main" always lands
above "develop". We want develop (which carries the higher, unreleased
version number) listed first while main stays the set-default landing
version. Every workflow that runs `mike deploy` must re-run this script
afterwards, since any mike write restores mike's own ordering.
mike re-sorts versions.json on every deploy, and the non-numeric
"develop" version does not reliably sort above the MAJOR.MINOR release
slugs. We want develop (which carries the higher, unreleased version
number) listed first, while the `latest` alias stays the set-default
landing version. Every workflow that runs `mike deploy` must re-run
this script afterwards, since any mike write restores mike's own
ordering.

Usage: docs_reorder_versions.py <path/to/versions.json>

Expand All @@ -20,7 +21,7 @@


def reorder(entries):
pinned_names = ('develop', 'main')
pinned_names = ('develop',)
pinned = [e for name in pinned_names for e in entries
if e['version'] == name]
rest = [e for e in entries if e['version'] not in pinned_names]
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/sync-develop-from-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ jobs:
f.write(f"NEW_VERSION={new_ver}\n")
PYEOF

# Read the version from .env: GITHUB_ENV exports only apply to
# later steps, so ${NEW_VERSION} would be empty here.
NEW_VERSION=$(grep -m1 '^VERSION=' .env | cut -d= -f2- | tr -d '"')
git add .env
git commit -m "Bump VERSION to ${NEW_VERSION} after sync from main"

Expand Down
2 changes: 1 addition & 1 deletion .openhands/microagents/repo.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ AirStack/
- Uses AirLab Docker registry credentials

**Documentation Deployment**:
- **Main Branch** (`deploy_docs_from_main.yaml`): Deploys docs to main version on pushes to `main`
- **Main Branch** (`deploy_docs_from_main.yaml`): Republishes the current MAJOR.MINOR docs slug (e.g. `/0.20/`) from pushes to `main` and points `latest` at it
- **Develop Branch** (`deploy_docs_from_develop.yaml`): Deploys docs to develop version on pushes to `develop`
- **Release** (`deploy_docs_from_release.yaml`): Deploys docs to versioned release on GitHub releases
- Uses MkDocs Material with mike for versioning
Expand Down
27 changes: 17 additions & 10 deletions docs/hooks/release_notes_current_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
mike-deployed docs version should only render its own notes — the site's
version selector (and the GitHub releases page) is the archive for the rest.

At build time this hook reads the ``VERSION=`` line from the repo-root
``.env`` and drops every ``## X.Y.Z ...`` section whose base semver does not
match (pre-release suffixes like ``-dev.N`` are ignored for matching, so
``VERSION="0.21.0-dev.13"`` keeps the ``## 0.21.0 (Unreleased)`` section).
Docs versions are published under MAJOR.MINOR slugs (e.g. ``/0.20/``), with
hotfix patches republished in place. At build time this hook reads the
``VERSION=`` line from the repo-root ``.env`` and keeps every ``## X.Y.Z ...``
section sharing its MAJOR.MINOR — so a ``0.20`` build shows the ``## 0.20.0``
section plus any ``## 0.20.1`` hotfix sections, and pre-release suffixes are
ignored (``VERSION="0.21.0-dev.13"`` keeps ``## 0.21.0 (Unreleased)``).

If no section matches the current VERSION, the page is left unfiltered and a
warning is logged rather than publishing an empty page.
If no section matches the current VERSION's MAJOR.MINOR, the page is left
unfiltered and a warning is logged rather than publishing an empty page.
"""

import logging
Expand Down Expand Up @@ -47,19 +49,24 @@ def on_page_markdown(markdown, page, config, files):
)
return markdown

minor = ".".join(current.split(".")[:2]) # "0.20.2" -> "0.20"

def matches(version: str) -> bool:
return ".".join(version.split(".")[:2]) == minor

sections = list(SECTION_RE.finditer(markdown))
if not any(m.group(1) == current for m in sections):
if not any(matches(m.group(1)) for m in sections):
log.warning(
"release_notes hook: no '## %s' section in %s; "
"release_notes hook: no '## %s.x' section in %s; "
"publishing the page unfiltered",
current,
minor,
PAGE_SRC,
)
return markdown

pieces = [markdown[: sections[0].start()]]
for i, match in enumerate(sections):
if match.group(1) != current:
if not matches(match.group(1)):
continue
end = sections[i + 1].start() if i + 1 < len(sections) else len(markdown)
pieces.append(markdown[match.start() : end])
Expand Down
Loading