Skip to content

Commit 448915b

Browse files
committed
feat(release): docs-ready flag gates stable promotions
- release docs-ready: merge origin/dev -> docs (worktree at ~/.lpb-stack/docs-preview), build site for local review (mike serve), commit DOCS_READY=<stable-version> on the docs branch + push - release status: docs verdict line (READY/MISSING/WRONG-VERSION/STALE) - release promote: refuses unless docs are READY for the release version (--force overrides); no-op releases are not gated - CI (main pipeline): new docs-publish job after tag-repos — re-verifies the flag, then mike deploy <version> latest -> gh-pages - fix(release): VERSION-only main<->dev conflict (stable strips -dev by design) is a clean merge now — merge-tree conflicts are inspected, the merge takes dev's VERSION (the strip step rewrites it right after) - tests: test_localpibox_release.py (11 tests), CLI surface tests - docs: lpb-devstack.md, repo-workflow skill, workflow phase comments
1 parent 647dfe7 commit 448915b

9 files changed

Lines changed: 734 additions & 19 deletions

File tree

.github/workflows/build-and-publish.yml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# Phase 2: build-cli — only if VERSION changed
1919
# Phase 3: build-web — only if VERSION changed
2020
# Phase 4: tag-repos — only if VERSION changed (after build)
21+
# Phase 4.5: docs-publish — main only, stable docs version (mike)
2122
# Phase 5: status — always runs
2223
# - Cron / manual dispatch always build (keep image fresh / on-demand)
2324
# - Dev pipeline (push to dev): 0.0.x-lpb-dev, images :dev-*, :{v}-*, :{sha}-*
@@ -371,6 +372,78 @@ jobs:
371372
exit 1
372373
fi
373374
375+
# ──────────────────────────────────────────────────────
376+
# Phase 3.5: Publish stable docs (main pipeline only)
377+
# Docs are gated into the release BEFORE promotion:
378+
# lpb-devstack release docs-ready (merge dev→docs, review, flag)
379+
# lpb-devstack release promote (refuses unless docs are ready)
380+
# This job re-verifies the flag (catches --force promotions), then cuts
381+
# the immutable docs version and points the `latest` alias at it.
382+
# Output: gh-pages branch (mike) → https://lpb-stack.github.io/devstack/<version>/
383+
# ──────────────────────────────────────────────────────
384+
docs-publish:
385+
name: Publish docs (mike)
386+
runs-on: ubuntu-latest
387+
timeout-minutes: 20
388+
needs: [tag-repos, VERSION_CHECK]
389+
if: ${{ github.ref_name == 'main' && github.event_name == 'push' && needs.VERSION_CHECK.outputs.changed == 'true' && needs.tag-repos.result == 'success' }}
390+
steps:
391+
- name: Checkout docs branch
392+
uses: actions/checkout@v6
393+
with:
394+
ref: docs
395+
fetch-depth: 0
396+
397+
- name: Verify docs flag
398+
run: |
399+
set -e
400+
VERSION=$(git show origin/main:VERSION | tr -d '[:space:]')
401+
FLAG=$(git show HEAD:DOCS_READY 2>/dev/null | tr -d '[:space:]' || true)
402+
if [ "$FLAG" != "$VERSION" ]; then
403+
echo "::error::docs not flagged ready for $VERSION (DOCS_READY='${FLAG:-<missing>}') — run 'lpb-devstack release docs-ready' before promoting, then re-run this job"
404+
exit 1
405+
fi
406+
echo "docs flag OK: $FLAG"
407+
408+
- name: Fetch stack repos at the release tag
409+
run: |
410+
set -e
411+
VERSION=$(git show origin/main:VERSION | tr -d '[:space:]')
412+
mkdir -p ws/git
413+
git clone --quiet https://github.com/lpb-stack/config.git ws/config
414+
for r in lpb-memory pi-subagents lemonade-pi-plugin; do
415+
git clone --quiet "https://github.com/lpb-stack/$r.git" "ws/git/$r"
416+
done
417+
git clone --quiet https://github.com/lpb-stack/pi.git ws/pi
418+
for d in ws/config ws/git/lpb-memory ws/git/pi-subagents \
419+
ws/git/lemonade-pi-plugin ws/pi; do
420+
git -C "$d" fetch --quiet --depth 1 origin tag "$VERSION"
421+
git -C "$d" checkout -q "$VERSION"
422+
done
423+
424+
- name: Install docs tooling
425+
run: python3 -m pip install --quiet "mkdocs-material==9.7.7" mike
426+
427+
- name: Prepare docs tree + version stamp
428+
env:
429+
AGENT_DIR: ${{ github.workspace }}/ws/config
430+
LPB_AGENT_GIT: ${{ github.workspace }}/ws/git
431+
LPB_WORKSPACE_ROOT: ${{ github.workspace }}/ws
432+
run: python3 scripts/generate.py --tag "$(git show origin/main:VERSION | tr -d '[:space:]')"
433+
434+
- name: Configure git identity for mike
435+
run: |
436+
git config user.name "lpb-docs"
437+
git config user.email "ci@lpb-stack.dev"
438+
439+
- name: Publish tagged docs version
440+
run: |
441+
set -e
442+
VERSION=$(git show origin/main:VERSION | tr -d '[:space:]')
443+
mike deploy "$VERSION" latest --push --update-aliases
444+
mike set-default latest --push
445+
echo "Docs version: https://lpb-stack.github.io/devstack/$VERSION/"
446+
374447
status:
375448
name: Build status
376449
needs: [build-cli, build-web]

.pi/skills/localpibox-repo-workflow/SKILL.md

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,26 @@ commits to the repo (manual tagging).
110110

111111
## Stable Release Procedure (dev → main)
112112

113+
**Docs are gated into the release**`promote` refuses until the docs
114+
branch is flagged ready for the version being released (`--force`
115+
overrides). Doc content changes on `dev` in place as usual; the one-shot
116+
docs sync + review happens at release time via `docs-ready`.
117+
113118
**`lpb-devstack release` is the tool** (there is no other local version path).
114119

115120
```bash
116-
# 1. Readiness check (all 6 repos, non-destructive, fetches first)
121+
# 0. Flag docs as reviewed for the release (merge dev→docs, build site,
122+
# review with `cd ~/.lpb-stack/docs-preview && mike serve`, confirm →
123+
# commits DOCS_READY=<stable-version> on the docs branch + pushes)
124+
lpb-devstack release docs-ready
125+
126+
# 1. Readiness check (all 6 repos + docs verdict, non-destructive, fetches first)
117127
lpb-devstack release status
118128

119129
# 2. Inspect the exact plan without changing anything
120130
lpb-devstack release promote --dry-run
121131

122-
# 3. Promote (interactive confirmation)
132+
# 3. Promote (interactive confirmation; blocked unless docs are READY)
123133
lpb-devstack release promote
124134
```
125135

@@ -150,9 +160,17 @@ lpb-devstack --tag main validate
150160
```
151161

152162
Flags: `--yes` (skip confirmation), `--dry-run` (plan only), `--rebase`
153-
(first-release mode for unrelated histories). Re-runs are safe: promoted
163+
(first-release mode for unrelated histories), `--force` (promote even if
164+
docs are not flagged ready). Re-runs are safe: promoted
154165
repos fast-forward or no-op.
155166

167+
Docs readiness verdicts (`release status`, checked by `promote`):
168+
- `READY``DOCS_READY` on the `docs` branch matches the release version
169+
and doc content matches `dev`
170+
- `MISSING` — no flag yet → run `lpb-devstack release docs-ready`
171+
- `STALE` — flag for another version, or doc content changed on `dev`
172+
after flagging → re-run `docs-ready`
173+
156174
## Shipping a Dev Image (the common case)
157175

158176
```bash
@@ -200,7 +218,7 @@ lpb-devstack bump [--minor|--major] [--set V] [--no-commit] [--push]
200218
lpb-devstack tag-repos [--branch dev|main] [--version V] [--dry-run]
201219
lpb-devstack workspace status | sync [--extensions] | ensure [--fix]
202220
lpb-devstack validate
203-
lpb-devstack release status | promote [--yes] [--dry-run] [--rebase]
221+
lpb-devstack release status | docs-ready | promote [--yes] [--dry-run] [--rebase] [--force]
204222
lpb-devstack validate-hooks # full pre-commit checks (tests included)
205223

206224
# Pipeline override (dev vs main) on any command:
@@ -282,7 +300,12 @@ Jobs:
282300
and **fails the run if any repo's tag fails** (a partially-tagged stack
283301
is a release bug — re-running the job is idempotent, 422 = already
284302
tagged). A missing branch aborts immediately.
285-
5. **status** — always runs; passes when builds were skipped (no VERSION
303+
5. **docs-publish** — main pipeline only, after tag-repos, only if VERSION
304+
changed: re-verifies the `DOCS_READY` flag on the `docs` branch matches
305+
the released VERSION (catches `--force` promotions), then
306+
`mike deploy <version> latest` + `set-default latest``gh-pages`
307+
branch. Served at `lpb-stack.github.io/devstack/<version>/`.
308+
6. **status** — always runs; passes when builds were skipped (no VERSION
286309
change), fails otherwise only on build failure
287310

288311
Images: `ghcr.io/lpb-stack/devstack` in two flavours per tag — `…-cli`

doc/lpb-devstack.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,27 @@ partially-tagged stack is a release bug.
6464

6565
| Command | Description |
6666
|---|---|
67-
| `lpb-devstack release status` | Pre-flight check: all 6 repos, non-destructive |
67+
| `lpb-devstack release status` | Pre-flight check: all 6 repos + docs flag, non-destructive |
68+
| `lpb-devstack release docs-ready [--yes]` | Flag the docs branch as reviewed for the next stable release |
6869
| `lpb-devstack release promote --dry-run` | Inspect plan without making changes |
69-
| `lpb-devstack release promote` | Promote dev → main (interactive confirmation) |
70+
| `lpb-devstack release promote` | Promote dev → main (interactive confirmation, blocked until docs are ready) |
71+
72+
**Docs are gated into the release.** The docs site (MkDocs + mike) lives on
73+
the `docs` branch; stable releases ship the docs version too. Before
74+
promoting:
75+
76+
1. `lpb-devstack release docs-ready` — merges `origin/dev``docs`, builds
77+
the site, and (after your local review via
78+
`cd ~/.lpb-stack/docs-preview && mike serve`) commits
79+
`DOCS_READY=<stable-version>` on the `docs` branch and pushes it
80+
2. `release status` shows the docs verdict: `READY` / `MISSING` /
81+
`STALE` (stale = flag for another version, or doc content changed on dev
82+
after flagging)
83+
3. `release promote` **refuses** unless docs are `READY` for the version
84+
being released — `--force` overrides with a warning
85+
4. The main pipeline re-verifies the flag, then publishes the immutable
86+
docs version (`mike deploy <version> latest`) to the `gh-pages` branch:
87+
`https://lpb-stack.github.io/devstack/<version>/`
7088

7189
`promote` does per repo (dev branch → stable branch: `dev``main` for
7290
devstack/config/lpb-memory, `lpb-dev``lpb` for pi/pi-subagents/
@@ -85,7 +103,8 @@ lemonade-pi-plugin):
85103
`0.0.58-lpb-dev``0.0.58-lpb`) and commits it
86104

87105
Flags: `--yes` (skip confirmation), `--dry-run` (plan only), `--rebase`
88-
(first-release mode).
106+
(first-release mode), `--force` (promote even if docs are not flagged
107+
ready). `docs-ready` accepts `--yes` (skip the review confirmation).
89108

90109
### Pipeline Override
91110

@@ -111,12 +130,15 @@ lpb-devstack validate
111130
## Manual Tagging Flow (stable release)
112131

113132
```bash
114-
lpb-devstack release status # readiness check
133+
lpb-devstack release docs-ready # merge dev→docs, review site, flag DOCS_READY
134+
lpb-devstack release status # readiness check (repos + docs)
115135
lpb-devstack release promote --dry-run # inspect plan
116-
lpb-devstack release promote # dev → stable + push
136+
lpb-devstack release promote # dev → stable + push (blocked until docs ready)
117137
lpb-devstack tag-repos --branch main # tag the 5 repos on stable branches
118138
lpb-devstack --tag main workspace sync-pins # pins → stable tag
119139
pi update --extensions
140+
# CI (main pipeline) then builds images, tags repos, and publishes the
141+
# stable docs version (https://lpb-stack.github.io/devstack/<version>/)
120142
```
121143

122144
## Quick Reference

scripts/docs/site/.marker

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
built

0 commit comments

Comments
 (0)