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
40 changes: 20 additions & 20 deletions .agents/skills/bump-version-and-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ If in doubt, bump. The CI gate enforces a strict increment vs. the base branch

The version-increment check still runs on every PR, but the **only** thing it requires is that VERSION be valid semver and strictly greater than the base. For documentation-only PRs you have two options:

- **Preferred:** still bump the patch (or pre-release counter) by one. It costs nothing, keeps the gate happy, and the docker-build only fires on push to `main`/`develop` *and* a VERSION change, so an extra alpha bump on a docs PR is cheap.
- **Preferred:** still bump the patch (or pre-release counter) by one. It costs nothing, keeps the gate happy, and the docker-build only fires on push to `main`/`develop` *and* a VERSION change, so an extra dev bump on a docs PR is cheap.
- **If you really want to avoid a rebuild:** the docker-build workflow only triggers when `.env` is in the changed paths AND `VERSION=` differs from `HEAD~1`. So a docs-only PR that does not touch `.env` will not rebuild — but the PR will still fail the increment check unless you bump. There is no clean way to "opt out" of the check; the simplest path is to bump the pre-release counter.

Do **not** bump for:
Expand All @@ -47,17 +47,17 @@ Three workflows in `.github/workflows/` interact with `VERSION`:

- **Trigger:** every `pull_request`.
- **Logic:** runs a Python script that reads `VERSION=` from the PR's `.env`, reads the same line from `origin/<base_ref>:.env`, and validates:
- PR version matches the regex `^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d+))?$`
- PR version is **strictly greater than** base version, with pre-release ordering `alpha < beta < rc < (no suffix / release)`
- PR version matches the regex `^(\d+)\.(\d+)\.(\d+)(?:-(dev|beta|rc)\.(\d+))?$`
- PR version is **strictly greater than** base version, with pre-release ordering `dev < beta < rc < (no suffix / release)`
- **Accepted formats** (from the workflow's own error message):
```
MAJOR.MINOR.PATCH (e.g. 1.2.3)
MAJOR.MINOR.PATCH-alpha.N (e.g. 1.3.0-alpha.1)
MAJOR.MINOR.PATCH-dev.N (e.g. 1.3.0-dev.1)
MAJOR.MINOR.PATCH-beta.N (e.g. 1.3.0-beta.2)
MAJOR.MINOR.PATCH-rc.N (e.g. 1.3.0-rc.3)
```
- **Rejected:** `1.2`, `1.2.3-rc1` (no dot before N), `1.2.3-dev`, `1.2.3+meta`, `v1.2.3`, anything with build metadata.
- **Comparison tuple:** `(major, minor, patch, pre_rank, pre_num)` where `pre_rank = alpha:0, beta:1, rc:2, release:3`. So `1.3.0-alpha.5 < 1.3.0-beta.1 < 1.3.0-rc.1 < 1.3.0`. A release version always sorts above any pre-release of the same `MAJOR.MINOR.PATCH`.
- **Rejected:** `1.2`, `1.2.3-rc1` (no dot before N), `1.2.3-dev` (missing the `.N` counter), `1.2.3-alpha.4` (the legacy `alpha` tag was replaced by `dev` in 0.20.0), `1.2.3+meta`, `v1.2.3`, anything with build metadata.
- **Comparison tuple:** `(major, minor, patch, pre_rank, pre_num)` where `pre_rank = dev:0, beta:1, rc:2, release:3`. So `1.3.0-dev.5 < 1.3.0-beta.1 < 1.3.0-rc.1 < 1.3.0`. A release version always sorts above any pre-release of the same `MAJOR.MINOR.PATCH`.

### 2. `docker-build.yml` — the publish trigger

Expand All @@ -82,36 +82,36 @@ So the full release path is: bump `VERSION` → PR → merge to `main`/`develop`

## Choosing the Bump Type

Use this decision tree on the **current** version (currently `0.18.0-alpha.7`):
Use this decision tree on the **current** version (e.g. `0.21.0-dev.7`):

```
Is this a breaking API/topic/interface change?
├── yes → bump MAJOR, reset MINOR=0, PATCH=0 (e.g. 0.18.0-alpha.7 → 1.0.0-alpha.1 if pre-1.0)
├── yes → bump MAJOR, reset MINOR=0, PATCH=0 (e.g. 0.21.0-dev.7 → 1.0.0-dev.1 if pre-1.0)
└── no
├── New feature / new module / new Docker image content?
│ └── yes → bump MINOR, reset PATCH=0 (e.g. 0.18.0 → 0.19.0)
└── Bug fix / small tweak / dependency bump?
└── yes → bump PATCH (e.g. 0.18.0 → 0.18.1)

Are you mid-cycle on a pre-release line (suffix present)?
├── Same line, more iteration → increment N (0.18.0-alpha.7 → 0.18.0-alpha.8)
├── Promoting alpha → beta → reset N to 1 (0.18.0-alpha.7 → 0.18.0-beta.1)
├── Same line, more iteration → increment N (0.21.0-dev.7 → 0.21.0-dev.8)
├── Promoting dev → beta → reset N to 1 (0.21.0-dev.7 → 0.21.0-beta.1)
├── Promoting beta → rc → reset N to 1 (0.18.0-beta.4 → 0.18.0-rc.1)
└── Promoting rc → release → drop suffix (0.18.0-rc.3 → 0.18.0)
```

Notes:

- AirStack is pre-1.0; many "breaking" changes still bump MINOR rather than MAJOR. Use judgment, and prefer pre-release suffixes (`-alpha.N`) for the active development line so feature PRs do not have to fight over MINOR numbers.
- The current pattern in git history is per-PR alpha bumps on the development line and a final un-suffixed bump at release time (e.g. `0.16.1-rc → 0.16.1`, `0.17.0-rc1 → 0.17.0` — note the older `-rc1` form predates the current validator and would be rejected today; use `-rc.1`).
- AirStack is pre-1.0; many "breaking" changes still bump MINOR rather than MAJOR. Use judgment, and prefer pre-release suffixes (`-dev.N`) for the active development line so feature PRs do not have to fight over MINOR numbers.
- The current pattern in git history is per-PR dev bumps on the development line and a final un-suffixed bump at release time. History before 0.21.0 used `-alpha.N` for this role, and even older releases used forms like `-rc1` — both predate the current validator and would be rejected today; use `-dev.N` / `-rc.N`.

## Bumping Steps

### 1. Read the current VERSION

```bash
airstack version
# → AirStack Version: 0.18.0-alpha.7
# → AirStack Version: 0.21.0-dev.7
```

(Equivalent: `grep '^VERSION=' .env`.)
Expand All @@ -121,8 +121,8 @@ airstack version
Open `/.env` and change exactly the `VERSION=` line. Keep the surrounding comments and quoting intact:

```diff
- VERSION="0.18.0-alpha.7"
+ VERSION="0.18.0-alpha.8"
- VERSION="0.21.0-dev.7"
+ VERSION="0.21.0-dev.8"
```

The validator strips surrounding `"` or `'`, so either quoting style works, but match the existing style (double quotes).
Expand All @@ -147,15 +147,15 @@ git diff .env docs/release_notes/index.md # review the diff
Optional regex preflight (mirrors the CI check):

```bash
python3 -c 'import re,sys; v=open(".env").read(); m=re.search(r"^VERSION\s*=\s*\"?([^\"#\s]+)", v, re.M); print(m.group(1)); assert re.fullmatch(r"^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d+))?$", m.group(1)), "INVALID"'
python3 -c 'import re,sys; v=open(".env").read(); m=re.search(r"^VERSION\s*=\s*\"?([^\"#\s]+)", v, re.M); print(m.group(1)); assert re.fullmatch(r"^(\d+)\.(\d+)\.(\d+)(?:-(dev|beta|rc)\.(\d+))?$", m.group(1)), "INVALID"'
```

### 5. Commit

Use a clear, conventional message:

```
Bump version to 0.18.0-alpha.8
Bump version to 0.21.0-dev.8
```

Recent commits in this repo use exactly this phrasing (`Bump version to 0.17.0`, `Bump version to 0.16.1`).
Expand Down Expand Up @@ -216,18 +216,18 @@ Layout:
Rules:

- Use the H3 sections **Added**, **Changed**, **Fixed**, **Removed**, **Deprecated**, **Security** as needed; a release may also open with a short narrative and breaking-changes subsection.
- For pre-release bumps (`-alpha.N`, `-beta.N`, `-rc.N`), keep your bullets under the current `(Unreleased)` section. Do not create a section per alpha.
- For pre-release bumps (`-dev.N`, `-beta.N`, `-rc.N`), keep your bullets under the current `(Unreleased)` section. Do not create a section per dev bump.
- For a release bump (no suffix), retitle the section to `## <VERSION> — <YYYY-MM-DD>` and open a fresh `## <next-version> (Unreleased)` above it.
- Write user-facing prose, not commit log dumps. Mention new modules, breaking changes, and notable behavior shifts, with what changed FROM what.

## Common Pitfalls

- **Forgetting the bump.** The `check-version-increment` job fails with `::error::VERSION must be strictly greater than the base branch version.` Bump and force-push the branch.
- **Invalid semver.** Forms like `1.2`, `1.2.3-rc1`, `1.2.3-dev`, `1.2.3+sha.abc`, `v1.2.3`, or empty strings fail with `::error::VERSION '<x>' does not match the required format.` The only allowed pre-release tags are exactly `alpha`, `beta`, `rc`, each followed by a literal dot and an integer (e.g. `-rc.1`, never `-rc1`).
- **Invalid semver.** Forms like `1.2`, `1.2.3-rc1`, `1.2.3-dev` (no `.N`), `1.2.3-alpha.4` (legacy tag), `1.2.3+sha.abc`, `v1.2.3`, or empty strings fail with `::error::VERSION '<x>' does not match the required format.` The only allowed pre-release tags are exactly `dev`, `beta`, `rc`, each followed by a literal dot and an integer (e.g. `-dev.1`, never `-dev1`).
- **Going backwards.** `0.18.0 → 0.18.0-rc.1` looks like progress but is a regression: release > rc. Always move forward in the comparison tuple.
- **Two PRs racing for the same number.** Whichever merges last wins; the loser's `check-version-increment` will start failing the moment the base advances past it. Rebase on the updated base branch and bump again.
- **Bumping but forgetting the Release Notes.** No CI gate enforces this, but reviewers will (and the versioned docs deploys snapshot the page per release, so missing entries become invisible history).
- **Bumping for pure docs PRs.** Wastes a registry tag. Prefer to keep docs-only changes off `.env` if possible — but if the gate is failing, an alpha bump is the path of least resistance.
- **Bumping for pure docs PRs.** Wastes a registry tag. Prefer to keep docs-only changes off `.env` if possible — but if the gate is failing, a dev bump is the path of least resistance.
- **Editing `VERSION=` quoting.** The extractor regex `^VERSION\s*=\s*["\']?([^"\'#\s]+)` handles double quotes, single quotes, or no quotes, and stops at `#`/whitespace. Don't add inline comments after the value (e.g. `VERSION="0.18.1" # bumped`) — the trailing `# bumped` will be stripped from the value but obscures intent; put comments on their own line above.
- **Touching only sub-compose `.env` files.** The check looks at the **repo-root** `.env` only. `robot/docker/.env` and friends are container env files, not the version source of truth.
- **Force-pushing after merge to fix Release Notes.** Don't. Land a follow-up PR with the correction (docs-only, so no VERSION bump needed unless the gate demands one).
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/extract-module/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ canonical-defaults launch rule, repo anatomy) defer to
- Large pinned files (model weights) → `assets:` with `url` + `sha256` +
`dest`, no Git LFS.
- `airstack_compat`: a real semver range against the trunk `VERSION` you
tested (e.g. `">=0.19.0-alpha.18 <0.20.0"`), never a branch.
tested (e.g. `">=0.21.0-dev.18 <0.22.0"`), never a branch.
- [ ] Validate:

```bash
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.0-alpha.21"
VERSION="0.20.0"
# 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
4 changes: 2 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ FYI Docs are updated via mkdocs.yml and markdown files under `docs/`. It should

<!--
1. Look at the current version on main
2. If the version ENDS WITH A LABEL ALPHA/BETA/RC followed by a number, just bump the trailing label number (0.18.0-alpha.5 -> 0.18.0-alpha.6)
2. If the version ENDS WITH A LABEL DEV/BETA/RC followed by a number, just bump the trailing label number (0.21.0-dev.5 -> 0.21.0-dev.6)
3. If the version is ONLY numbers, e.g. 0.18.3
a. if it's a new feature, consider bumping the MINOR number and adding the ALPHA label (0.18.3 -> 0.19.0-alpha.1)
a. if it's a new feature, consider bumping the MINOR number and adding the DEV label (0.20.3 -> 0.21.0-dev.1)
b. if it's a hot fix just bump the PATCH number (0.18.3 -> 0.18.4)
-->
10 changes: 5 additions & 5 deletions .github/workflows/check-version-increment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ jobs:
import sys

SEMVER_RE = re.compile(
r'^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d+))?$'
r'^(\d+)\.(\d+)\.(\d+)(?:-(dev|beta|rc)\.(\d+))?$'
)

def parse_version(v):
"""
Parse a version string into a comparable tuple.
Returns None if the format is invalid.

Pre-release ordering: alpha < beta < rc < (release)
Pre-release ordering: dev < beta < rc < (release)
Tuple: (major, minor, patch, pre_rank, pre_num)
where pre_rank: alpha=0, beta=1, rc=2, release=3
where pre_rank: dev=0, beta=1, rc=2, release=3
"""
m = SEMVER_RE.fullmatch(v)
if not m:
Expand All @@ -44,7 +44,7 @@ jobs:
patch = int(m.group(3))
pre_type = m.group(4) # None for release versions
pre_num = int(m.group(5)) if m.group(5) else 0
pre_rank = {'alpha': 0, 'beta': 1, 'rc': 2, None: 3}[pre_type]
pre_rank = {'dev': 0, 'beta': 1, 'rc': 2, None: 3}[pre_type]
return (major, minor, patch, pre_rank, pre_num)

def extract_version(content):
Expand Down Expand Up @@ -87,7 +87,7 @@ jobs:
print(f"::error::VERSION '{pr_version}' does not match the required format.")
print(" Accepted formats:")
print(" MAJOR.MINOR.PATCH (e.g. 1.2.3)")
print(" MAJOR.MINOR.PATCH-alpha.N (e.g. 1.3.0-alpha.1)")
print(" MAJOR.MINOR.PATCH-dev.N (e.g. 1.3.0-dev.1)")
print(" MAJOR.MINOR.PATCH-beta.N (e.g. 1.3.0-beta.2)")
print(" MAJOR.MINOR.PATCH-rc.N (e.g. 1.3.0-rc.3)")
failed = True
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scripts/registry_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def bump_version() -> "tuple[str, str]":
if not m:
sys.exit('.env has no VERSION="..." line')
old = m.group(1)
pre = re.fullmatch(r"(\d+\.\d+\.\d+-(?:alpha|beta|rc)\.)(\d+)", old)
pre = re.fullmatch(r"(\d+\.\d+\.\d+-(?:dev|alpha|beta|rc)\.)(\d+)", old)
if pre:
new = f"{pre.group(1)}{int(pre.group(2)) + 1}"
else:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/sync-develop-from-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
python3 << 'PYEOF'
import os, re, subprocess, sys

SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d+))?$')
SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)(?:-(dev|alpha|beta|rc)\.(\d+))?$') # alpha kept for parsing legacy versions

def parse(v):
m = SEMVER_RE.fullmatch(v)
Expand All @@ -78,11 +78,11 @@ jobs:
dM, dn, dp, dpre, dpn = parse(dev_ver)

# If main's x.y.z has caught up to (or passed) develop's base,
# develop just released — roll forward to the next minor's alpha.0.
# develop just released — roll forward to the next minor's dev.0.
# Otherwise main is a hotfix behind develop; preserve develop's
# pre-release channel and bump the counter.
if (mM, mm, mp) >= (dM, dn, dp):
new_ver = f"{mM}.{mm + 1}.0-alpha.0"
new_ver = f"{mM}.{mm + 1}.0-dev.0"
reason = "main caught up to develop's base — rolling to next minor"
else:
if dpre is None:
Expand Down
Loading
Loading