F-14: Release-please automated release pipeline
Context
Foundation F-01..F-13 complete. Production live at razmakh.ru. Next step — automate version bumping and GitHub Release creation via Conventional Commits → release-please.
What was implemented
Files created
| File | Purpose |
|---|---|
.release-please-manifest.json | Current versions per package (all 0.1.0) |
release-please-config.json | Monorepo config — 4 packages, Python + Node types |
.github/workflows/release-please.yml | Workflow trigger on push main |
commitlint.config.mjs | Reference type list (no npm dep enforcement) |
CHANGELOG.md (root) | Index pointing to per-package CHANGELOGs |
apps/api/CHANGELOG.md | razmakh-api changelog (auto-updated by release-please) |
apps/web/CHANGELOG.md | @razmakh/web changelog |
apps/docs/CHANGELOG.md | @razmakh/docs changelog |
packages/core/CHANGELOG.md | razmakh-core changelog |
lefthook.yml (updated) | Added conventional commits validation в commit-msg hook |
Architecture decisions
Conventional commits enforcement via regex (not @commitlint/cli):
- Rationale: zero new npm dependencies. commitlint requires
npm install @commitlint/cli @commitlint/config-conventionalwhich adds ~15MB to devDeps and complicates pnpm workspace. - Solution: bash regex in lefthook commit-msg hook. Same allowed types as commitlint.config.mjs.
- Trade-off: less detailed error messages than commitlint, but good enough for single-dev workflow.
release-please-action@v4 manifest mode:
- 4 packages: apps/api (python), apps/web (node), apps/docs (node), packages/core (python)
bootstrap-sha: initial commit99ad9c3c— release-please looks from this SHA for conventional commitsinclude-component-in-tag: true→ tags likerazmakh-api-v0.1.0(not justv0.1.0)include-v-in-tag: true→vprefix in version partbump-minor-pre-major: true+bump-patch-for-minor-pre-major: true— while < 1.0.0, feat→minor, fix→patch (sane pre-1.0 behavior)
GITHUB_TOKEN (default) — no extra secrets needed. release-please uses it for PR creation + GitHub Release.
Two separate workflows:
ci.yml— runs on PR + push main (test/lint/security/deploy)release-please.yml— runs on push main only (after CI green, parallel)- They don’t conflict — release-please creates a PR, CI validates that PR
Conventional commits hook (lefthook update)
New valid-message command in commit-msg section:
# Allows: feat(api): add endpoint | fix: correct RLS | chore: release# Blocks: WIP: stuff | bad message | fix broken# Skips: Merge branch ... | Revert "..." (git auto-generated)Regex pattern: ^(feat|fix|chore|docs|refactor|test|ci|perf|build|revert)(\([a-z0-9_/-]+\))?\!?: .{10,100}$
What release-please does automatically
- On every push to main: scans commits since last release tag, groups by type
- Creates/updates Release PR: with CHANGELOG.md updates + version bumps in pyproject.toml / package.json
- On Release PR merge: creates GitHub Release + version tag per package
How to verify
Test invalid commit (should be blocked by lefthook):
git commit -m "bad message"# Expected: COMMIT BLOCKED: Commit message does not follow Conventional Commits format.Test valid commit:
git commit -m "chore: trigger release-please initial run"# Expected: Commit message OK: chore: trigger...View release-please workflow:
gh workflow view release-please.ymlAfter first push: release-please opens PR titled “chore: release razmakh-api 0.1.0” (or “no release needed” if all commits are hidden types like chore/test/ci).
First release flow
- Merge F-14 commit to main → release-please workflow runs
- release-please creates Release PR with CHANGELOG entries grouped by type
- Review + merge Release PR → GitHub Releases created, tags created:
razmakh-api-v0.1.0razmakh-web-v0.1.0(package name:@razmakh/web)razmakh-docs-v0.1.0razmakh-core-v0.1.0
Note: release-please may say “no release needed” for first run if all commits since bootstrap-sha use hidden types (chore/ci/test). To trigger a real release, the next non-hidden commit (feat/fix/perf) will open the Release PR.
Deferred (Phase 1.5+)
- Signed tags (GPG) — need to set up signing key as GitHub secret
- PyPI publishing — after Phase 1 packages are public-ready
- NPM publishing — @razmakh/web, @razmakh/docs (unlikely — internal only)
- Telegram notification on release — commented-out in release-please.yml, enable in Phase 1.5
- @commitlint/cli — if multi-developer team joins, replace regex with proper commitlint
F-15 + F-16 note
F-15 (Caddy + DNS + first deploy) and F-16 (lessons/decisions structure) were effectively completed as part of F-08 (FastAPI + Caddy) + F-11 (Next.js deploy) + F-13 (docs deploy):
- razmakh.ru, razmakh.ru/admin, docs.razmakh.ru — all LIVE with TLS
- lessons/ + TEMPLATE.md created in F-09/F-10
- F-15 + F-16 in plan still have unresolved items (off-site backup, sync script) — NOT moved to done
Actual time
Plan: 1 день (8h). Actual: ~1.5h. Speedup: ~5x (consistent with Foundation baseline).
Speedup factors: existing CI structure (ci.yml) made integration obvious; no Docker/VPS work needed; release-please is well-documented. Main time: reading research (AK) + writing lesson.