mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
chore(ci): route release recipes through PRs and refresh release runbook
main's ruleset now rejects direct pushes, which broke 'just release' mid-flight for v0.22.0. The release/beta recipes now land the version bump via a rebase-merged release PR and tag the rebased commit (found by commit subject). Adds a changelog-on-main pre-flight check, and updates AGENTS.md and the release runbook to match, including the docs.basicmemory.com steps which still described the old src/pages site. Signed-off-by: Drew Cain <groksrc@gmail.com>
This commit is contained in:
@@ -28,7 +28,10 @@ You are an expert release manager for the Basic Memory project. When the user ru
|
||||
|
||||
#### Documentation Validation
|
||||
1. **Changelog Check**
|
||||
- CHANGELOG.md contains entry for target version
|
||||
- CHANGELOG.md contains entry for target version **already landed on `main`**
|
||||
(main only accepts changes via PR, so the changelog entry must go through
|
||||
its own PR before running the release; the recipe pre-flight-checks for a
|
||||
`## vX.Y.Z` heading)
|
||||
- Entry includes all major features and fixes
|
||||
- Breaking changes are documented
|
||||
|
||||
@@ -41,11 +44,15 @@ just release <version>
|
||||
The justfile target handles:
|
||||
- ✅ Version format validation
|
||||
- ✅ Git status and branch checks
|
||||
- ✅ Quality checks (`just check` - lint, format, type-check, tests)
|
||||
- ✅ Changelog entry check (must already be on `main`)
|
||||
- ✅ Quality checks (`just lint` + `just typecheck`)
|
||||
- ✅ Version update across all consolidated manifests via `just set-version` (Python
|
||||
package + Claude Code plugin/marketplaces + Codex plugin + Hermes + OpenClaw)
|
||||
- ✅ Automatic commit with proper message
|
||||
- ✅ Tag creation and pushing to GitHub
|
||||
- ✅ Release PR: commits the bump on a `release/vX.Y.Z` branch, opens a PR
|
||||
(`chore(core): release vX.Y.Z`), and rebase-merges it — the `main` ruleset
|
||||
rejects direct pushes and the repo disallows merge commits
|
||||
- ✅ Tags the rebased bump commit on `main` (found by commit subject, since
|
||||
the rebase rewrites the SHA) and pushes the tag
|
||||
- ✅ Release workflow trigger (automatic on tag push)
|
||||
|
||||
The GitHub Actions workflow (`.github/workflows/release.yml`) then:
|
||||
@@ -127,25 +134,30 @@ After PyPI release is published, update the MCP registry:
|
||||
- **Deploy**: Follow deployment process for basicmachines.co
|
||||
|
||||
**2. docs.basicmemory.com** (`/Users/drew/code/docs.basicmemory.com`)
|
||||
- **Goal**: Add new release notes section to the latest-releases page
|
||||
- **File**: `src/pages/latest-releases.mdx`
|
||||
- **Goal**: Add a What's New page for the release and bump the homepage badge
|
||||
- **Site shape**: Nuxt/Docus content site. The changelog page
|
||||
(`content/2.whats-new/*.changelog.md`) auto-fetches GitHub releases — no
|
||||
manual changelog update needed. See that repo's CLAUDE.md "Version Bump
|
||||
Checklist".
|
||||
- **What to do**:
|
||||
1. Pull latest from GitHub: `git pull origin main`
|
||||
2. Create release branch: `git checkout -b release/v{VERSION}`
|
||||
3. Read the existing file to understand the format and structure
|
||||
4. Read `/Users/drew/code/basic-memory/CHANGELOG.md` to get release content
|
||||
5. Add new release section **at the top** (after MDX imports, before other releases)
|
||||
6. Follow the existing pattern:
|
||||
- Heading: `## [v{VERSION}](github-link) — YYYY-MM-DD`
|
||||
- Focus statement if applicable
|
||||
- `<Info>` block with highlights (3-5 key items)
|
||||
- Sections for Features, Bug Fixes, Breaking Changes, etc.
|
||||
- Link to full changelog at the end
|
||||
- Separator `---` between releases
|
||||
7. Commit changes: `git commit -m "docs: add v{VERSION} release notes"`
|
||||
8. Push branch: `git push origin release/v{VERSION}`
|
||||
- **Source content**: Extract and format sections from CHANGELOG.md for this version
|
||||
- **Deploy**: Follow deployment process for docs.basicmemory.com
|
||||
3. Read `/Users/drew/code/basic-memory/CHANGELOG.md` to get release content
|
||||
4. **New minor/major release**: add `content/2.whats-new/1.v{VERSION}.md`
|
||||
modeled on the previous version page (frontmatter title/description,
|
||||
headline feature first, then sections, then an Upgrading note) and
|
||||
renumber the existing what's-new pages down one slot (URLs don't
|
||||
change — Nuxt strips the numeric prefixes)
|
||||
5. **Patch release**: append a short note to the current version's page
|
||||
instead of creating a new one
|
||||
6. Update the homepage version badge in `content/index.md` (the
|
||||
`v0.XX →` button text and its `to: /whats-new/v{VERSION}` link)
|
||||
7. If the release adds user-facing features, update the relevant guide
|
||||
and reference pages (`content/3.cloud/`, `content/9.reference/`)
|
||||
8. Commit: `git commit -s -m "docs: add v{VERSION} release notes"`
|
||||
9. Push branch and open a PR; merge after the release is tagged
|
||||
- **Deploy**: push to main auto-deploys to development; production requires
|
||||
manual workflow dispatch via GitHub Actions
|
||||
|
||||
**4. Announce Release**
|
||||
- Post to Discord community if significant changes
|
||||
|
||||
@@ -300,7 +300,9 @@ See SPEC-16 for full context manager refactor details.
|
||||
|
||||
### Release Process
|
||||
|
||||
Releases are driven by `just release` / `just beta` — never by a bare `git tag`. The recipes bump version metadata, run pre-flight checks, commit, tag, and push. GitHub Actions then publishes to PyPI and updates the Homebrew formula.
|
||||
Releases are driven by `just release` / `just beta` — never by a bare `git tag`. The recipes bump version metadata, run pre-flight checks, land the bump on `main` through a release PR, tag, and push the tag. GitHub Actions then publishes to PyPI and updates the Homebrew formula.
|
||||
|
||||
**Main requires PRs.** The `main` ruleset rejects direct pushes ("Changes must be made through a pull request") and the repo disallows merge commits, so the recipes push a `release/vX.Y.Z` branch, open a PR titled `chore(core): release vX.Y.Z`, rebase-merge it with `gh pr merge --rebase`, then tag the rebased bump commit on `main` (located by its commit subject, since rebasing rewrites the SHA) and push the tag. The CHANGELOG entry for the version must already be on `main` — land it via a normal PR before running the recipe (it pre-flight-checks for a `## vX.Y.Z` heading).
|
||||
|
||||
**Stable release:**
|
||||
|
||||
@@ -308,7 +310,7 @@ Releases are driven by `just release` / `just beta` — never by a bare `git tag
|
||||
just release v0.21.3
|
||||
```
|
||||
|
||||
The recipe runs `just lint` + `just typecheck`, then updates every release manifest through `scripts/update_versions.py`: `src/basic_memory/__init__.py`, `server.json`, the root Claude marketplace, the Claude Code plugin manifest and local marketplace, the Hermes `plugin.yaml`, and the OpenClaw `package.json`. It commits as `chore: update version to X.Y.Z for vX.Y.Z release`, creates the `vX.Y.Z` tag, and pushes both the commit and the tag to `origin/main`. After the tag lands, the `Release` workflow builds the Python package, publishes to PyPI, creates the GitHub release with auto-generated notes, publishes the OpenClaw npm package, and updates the Homebrew formula. The recipe finishes by printing the post-release tasks the workflow doesn't cover.
|
||||
The recipe runs `just lint` + `just typecheck`, then updates every release manifest through `scripts/update_versions.py`: `src/basic_memory/__init__.py`, `server.json`, the root Claude marketplace, the Claude Code plugin manifest and local marketplace, the Hermes `plugin.yaml`, and the OpenClaw `package.json`. It commits as `chore: update version to X.Y.Z for vX.Y.Z release` on a `release/vX.Y.Z` branch, lands it on `main` via a rebase-merged PR, then tags the rebased commit and pushes the tag. After the tag lands, the `Release` workflow builds the Python package, publishes to PyPI, creates the GitHub release with auto-generated notes, publishes the OpenClaw npm package, and updates the Homebrew formula. The recipe finishes by printing the post-release tasks the workflow doesn't cover.
|
||||
|
||||
**Beta release:** `just beta v0.21.3b1` — same flow with a beta-suffixed tag. PyPI consumers install with `pip install basic-memory --pre`.
|
||||
|
||||
@@ -319,7 +321,7 @@ The recipe runs `just lint` + `just typecheck`, then updates every release manif
|
||||
**Do not tag releases by hand.** A bare `git tag vX.Y.Z` skips the in-code version bump. Package metadata is still correct (uv-dynamic-versioning derives it from the git tag) but `basic-memory --version` reports the previous release, which is what happened with v0.21.2 → v0.21.3.
|
||||
|
||||
**Post-release tasks** the recipe surfaces but doesn't run:
|
||||
- `docs.basicmemory.com` — add notes to `src/pages/latest-releases.mdx`
|
||||
- `docs.basicmemory.com` — add a What's New page under `content/2.whats-new/` and bump the version badge in `content/index.md` (the changelog page auto-fetches GitHub releases; see that repo's CLAUDE.md version-bump checklist)
|
||||
- `basicmachines.co` — bump version in `src/components/sections/hero.tsx`
|
||||
- MCP Registry — `mcp-publisher publish` from the repo root
|
||||
|
||||
|
||||
@@ -383,17 +383,31 @@ release version:
|
||||
echo "❌ Tag {{version}} already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Changelog must already be on main (land it via a normal PR first)
|
||||
if ! grep -q "^## {{version}} " CHANGELOG.md; then
|
||||
echo "❌ CHANGELOG.md has no entry for {{version}}. Land one via PR first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run quality checks
|
||||
echo "🔍 Running lint checks..."
|
||||
just lint
|
||||
just typecheck
|
||||
|
||||
|
||||
# Update all package manifests to the one Basic Memory product version.
|
||||
echo "📝 Updating consolidated package versions..."
|
||||
just set-version "{{version}}"
|
||||
|
||||
# Commit version update
|
||||
# Trigger: main's ruleset rejects direct pushes ("Changes must be made
|
||||
# through a pull request").
|
||||
# Why: the version bump must land on main before the tag is cut, so it
|
||||
# rides a release PR that is rebase-merged (the repo disallows merge
|
||||
# commits).
|
||||
# Outcome: the bump commit gets a new SHA on main; the tag is created on
|
||||
# that rebased commit, found by its commit subject.
|
||||
COMMIT_SUBJECT="chore: update version to $VERSION_NUM for {{version}} release"
|
||||
git checkout -b "release/{{version}}"
|
||||
git add \
|
||||
src/basic_memory/__init__.py \
|
||||
server.json \
|
||||
@@ -404,22 +418,35 @@ release version:
|
||||
integrations/hermes/plugin.yaml \
|
||||
integrations/hermes/__init__.py \
|
||||
integrations/openclaw/package.json
|
||||
git commit -s -m "chore: update version to $VERSION_NUM for {{version}} release"
|
||||
|
||||
# Create and push tag
|
||||
echo "🏷️ Creating tag {{version}}..."
|
||||
git tag "{{version}}"
|
||||
|
||||
echo "📤 Pushing to GitHub..."
|
||||
git push origin main
|
||||
git commit -s -m "$COMMIT_SUBJECT"
|
||||
|
||||
echo "📤 Opening release PR..."
|
||||
git push -u origin "release/{{version}}"
|
||||
gh pr create --title "chore(core): release {{version}}" \
|
||||
--body "Version bump for {{version}}. See CHANGELOG.md for release notes."
|
||||
gh pr merge "release/{{version}}" --rebase --delete-branch
|
||||
|
||||
git checkout main
|
||||
git pull --ff-only origin main
|
||||
|
||||
# Tag the rebased bump commit, wherever it landed on main
|
||||
TAG_COMMIT=$(git log origin/main --fixed-strings --grep "$COMMIT_SUBJECT" --format='%H' -1)
|
||||
if [[ -z "$TAG_COMMIT" ]]; then
|
||||
echo "❌ Could not find the version bump commit on main. Tag manually."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🏷️ Creating tag {{version}} at $TAG_COMMIT..."
|
||||
git tag "{{version}}" "$TAG_COMMIT"
|
||||
git push origin "{{version}}"
|
||||
|
||||
|
||||
echo "✅ Release {{version}} created successfully!"
|
||||
echo "📦 GitHub Actions will build and publish to PyPI"
|
||||
echo "🔗 Monitor at: https://github.com/basicmachines-co/basic-memory/actions"
|
||||
echo ""
|
||||
echo "📝 REMINDER: Post-release tasks:"
|
||||
echo " 1. docs.basicmemory.com - Add release notes to src/pages/latest-releases.mdx"
|
||||
echo " 1. docs.basicmemory.com - Add a What's New page under content/2.whats-new/"
|
||||
echo " and bump the badge in content/index.md (see that repo's CLAUDE.md)"
|
||||
echo " 2. basicmachines.co - Update version in src/components/sections/hero.tsx"
|
||||
echo " 3. MCP Registry - Run: mcp-publisher publish"
|
||||
echo " See: .claude/commands/release/release.md for detailed instructions"
|
||||
@@ -467,7 +494,15 @@ beta version:
|
||||
echo "📝 Updating consolidated package versions..."
|
||||
just set-version "{{version}}"
|
||||
|
||||
# Commit version update
|
||||
# Trigger: main's ruleset rejects direct pushes ("Changes must be made
|
||||
# through a pull request").
|
||||
# Why: the version bump must land on main before the tag is cut, so it
|
||||
# rides a release PR that is rebase-merged (the repo disallows merge
|
||||
# commits).
|
||||
# Outcome: the bump commit gets a new SHA on main; the tag is created on
|
||||
# that rebased commit, found by its commit subject.
|
||||
COMMIT_SUBJECT="chore: update version to $VERSION_NUM for {{version}} beta release"
|
||||
git checkout -b "release/{{version}}"
|
||||
git add \
|
||||
src/basic_memory/__init__.py \
|
||||
server.json \
|
||||
@@ -478,23 +513,36 @@ beta version:
|
||||
integrations/hermes/plugin.yaml \
|
||||
integrations/hermes/__init__.py \
|
||||
integrations/openclaw/package.json
|
||||
git commit -s -m "chore: update version to $VERSION_NUM for {{version}} beta release"
|
||||
|
||||
# Create and push tag
|
||||
echo "🏷️ Creating tag {{version}}..."
|
||||
git tag "{{version}}"
|
||||
|
||||
echo "📤 Pushing to GitHub..."
|
||||
git push origin main
|
||||
git commit -s -m "$COMMIT_SUBJECT"
|
||||
|
||||
echo "📤 Opening release PR..."
|
||||
git push -u origin "release/{{version}}"
|
||||
gh pr create --title "chore(core): release {{version}}" \
|
||||
--body "Version bump for {{version}} beta."
|
||||
gh pr merge "release/{{version}}" --rebase --delete-branch
|
||||
|
||||
git checkout main
|
||||
git pull --ff-only origin main
|
||||
|
||||
# Tag the rebased bump commit, wherever it landed on main
|
||||
TAG_COMMIT=$(git log origin/main --fixed-strings --grep "$COMMIT_SUBJECT" --format='%H' -1)
|
||||
if [[ -z "$TAG_COMMIT" ]]; then
|
||||
echo "❌ Could not find the version bump commit on main. Tag manually."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🏷️ Creating tag {{version}} at $TAG_COMMIT..."
|
||||
git tag "{{version}}" "$TAG_COMMIT"
|
||||
git push origin "{{version}}"
|
||||
|
||||
|
||||
echo "✅ Beta release {{version}} created successfully!"
|
||||
echo "📦 GitHub Actions will build and publish to PyPI as pre-release"
|
||||
echo "🔗 Monitor at: https://github.com/basicmachines-co/basic-memory/actions"
|
||||
echo "📥 Install with: uv tool install basic-memory --pre"
|
||||
echo ""
|
||||
echo "📝 REMINDER: For stable releases, update documentation sites:"
|
||||
echo " 1. docs.basicmemory.com - Add release notes to src/pages/latest-releases.mdx"
|
||||
echo " 1. docs.basicmemory.com - Add a What's New page under content/2.whats-new/"
|
||||
echo " and bump the badge in content/index.md (see that repo's CLAUDE.md)"
|
||||
echo " 2. basicmachines.co - Update version in src/components/sections/hero.tsx"
|
||||
echo " See: .claude/commands/release/release.md for detailed instructions"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user