Перейти к содержимому

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

FilePurpose
.release-please-manifest.jsonCurrent versions per package (all 0.1.0)
release-please-config.jsonMonorepo config — 4 packages, Python + Node types
.github/workflows/release-please.ymlWorkflow trigger on push main
commitlint.config.mjsReference type list (no npm dep enforcement)
CHANGELOG.md (root)Index pointing to per-package CHANGELOGs
apps/api/CHANGELOG.mdrazmakh-api changelog (auto-updated by release-please)
apps/web/CHANGELOG.md@razmakh/web changelog
apps/docs/CHANGELOG.md@razmakh/docs changelog
packages/core/CHANGELOG.mdrazmakh-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-conventional which 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 commit 99ad9c3c — release-please looks from this SHA for conventional commits
  • include-component-in-tag: true → tags like razmakh-api-v0.1.0 (not just v0.1.0)
  • include-v-in-tag: truev prefix in version part
  • bump-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

  1. On every push to main: scans commits since last release tag, groups by type
  2. Creates/updates Release PR: with CHANGELOG.md updates + version bumps in pyproject.toml / package.json
  3. 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.yml

After 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

  1. Merge F-14 commit to main → release-please workflow runs
  2. release-please creates Release PR with CHANGELOG entries grouped by type
  3. Review + merge Release PR → GitHub Releases created, tags created:
    • razmakh-api-v0.1.0
    • razmakh-web-v0.1.0 (package name: @razmakh/web)
    • razmakh-docs-v0.1.0
    • razmakh-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.