diff --git a/docs/release-engineering.md b/docs/release-engineering.md new file mode 100644 index 0000000..6919b11 --- /dev/null +++ b/docs/release-engineering.md @@ -0,0 +1,478 @@ +# Release Engineering Documentation + +## Overview + +This project uses a fully automated release engineering pipeline powered by **semantic-release**, **commitlint**, and **GitHub Actions**. The pipeline handles versioning, changelog generation, Docker image publishing, and multi-environment deployments. + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Developer Workflow │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. Write code with conventional commits │ +│ 2. Push to feature branch │ +│ 3. Create PR → CI validates commits + code │ +│ 4. Merge to master → Release pipeline triggers │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ GitHub Actions Pipeline │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────────┐ ┌──────────────────────────┐ │ +│ │ CI Job │───►│ Release Job │───►│ Docker Build Job │ │ +│ │ │ │ │ │ │ │ +│ │ • Lint │ │ • Analyze │ │ • Multi-platform build │ │ +│ │ • Test │ │ commits │ │ (amd64, arm64) │ │ +│ │ • Build │ │ • Bump version │ │ • Push to Docker Hub │ │ +│ │ • Commitlint│ │ • Update │ │ • Push to GHCR │ │ +│ │ │ │ CHANGELOG │ │ │ │ +│ │ │ │ • Create tag │ │ │ │ +│ │ │ │ • GitHub release│ │ │ │ +│ └─────────────┘ └─────────────────┘ └──────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Registries │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────┐ ┌─────────────────────────────────┐ │ +│ │ Docker Hub │ │ GitHub Container Registry │ │ +│ │ │ │ │ │ +│ │ username/cv-app:latest │ │ ghcr.io/owner/cv-app:latest │ │ +│ │ username/cv-app:v1.0.0 │ │ ghcr.io/owner/cv-app:v1.0.0 │ │ +│ │ username/cv-app:staging │ │ ghcr.io/owner/cv-app:staging │ │ +│ │ username/cv-app:nightly │ │ ghcr.io/owner/cv-app:nightly │ │ +│ └─────────────────────────────┘ └─────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +## Components + +### 1. Conventional Commits + +All commits must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification: + +``` +(): + +[optional body] + +[optional footer] +``` + +#### Commit Types + +| Type | Description | Version Bump | Example | +|------|-------------|--------------|---------| +| `feat` | New feature | Minor (1.0.0 → 1.1.0) | `feat(admin): add password protection` | +| `fix` | Bug fix | Patch (1.0.0 → 1.0.1) | `fix(skills): prevent focus loss` | +| `perf` | Performance improvement | Patch | `perf(ui): lazy load images` | +| `feat!` | Breaking change | Major (1.0.0 → 2.0.0) | `feat(api)!: remove deprecated endpoints` | +| `docs` | Documentation only | None | `docs(readme): update installation` | +| `style` | Code style (formatting) | None | `style(ui): fix indentation` | +| `refactor` | Code refactoring | None | `refactor(auth): simplify token validation` | +| `test` | Adding/updating tests | None | `test(api): add auth middleware tests` | +| `build` | Build system changes | None | `build(docker): update node version` | +| `ci` | CI/CD changes | None | `ci(github): add staging workflow` | +| `chore` | Maintenance tasks | None | `chore(deps): update dependencies` | +| `revert` | Revert previous commit | Patch | `revert: remove broken feature` | + +#### Allowed Scopes + +| Scope | Description | +|-------|-------------| +| `admin` | Admin panel components | +| `api` | Backend API | +| `ui` | Frontend UI components | +| `docker` | Docker configuration | +| `ci` | CI/CD workflows | +| `deps` | Dependencies | +| `release` | Release configuration | +| `auth` | Authentication | +| `skills` | Skills section | +| `experience` | Experience section | +| `education` | Education section | +| `projects` | Projects section | +| `personal` | Personal info section | + +### 2. semantic-release + +semantic-release automates the entire release process: + +1. **Commit Analysis**: Analyzes commits since last release +2. **Version Calculation**: Determines next version based on commit types +3. **Changelog Generation**: Updates CHANGELOG.md with changes +4. **Git Operations**: Creates tags and commits version bump +5. **GitHub Release**: Creates release with notes and assets + +#### Configuration + +Located in `.releaserc.json`: + +```json +{ + "branches": ["master", { "name": "staging", "prerelease": true }], + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/changelog", + "@semantic-release/npm", + "@semantic-release/git", + "@semantic-release/github" + ] +} +``` + +### 3. commitlint + +Enforces conventional commits via: + +- **Git hook**: Validates every commit message locally +- **CI job**: Validates commits in pull requests + +Configuration in `commitlint.config.js`: +- Validates commit types +- Validates scopes +- Enforces lowercase subjects +- Limits subject length to 72 characters + +### 4. Husky Git Hooks + +| Hook | Purpose | Command | +|------|---------|---------| +| `pre-commit` | Run linting before commit | `npm run lint` | +| `commit-msg` | Validate commit message | `commitlint --edit` | + +### 5. GitHub Actions Workflows + +#### CI Workflow (`.github/workflows/ci.yml`) + +Runs on: Push to master, Pull requests to master + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ Frontend │ │ Backend │ │ Commitlint │ +│ Job │ │ Job │ │ Job │ +├─────────────┤ ├─────────────┤ ├─────────────┤ +│ • Lint │ │ • Install │ │ • Validate │ +│ • Test │ │ • Test │ │ commits │ +│ • Build │ │ │ │ │ +└─────────────┘ └─────────────┘ └─────────────┘ + │ │ │ + └────────────────┼────────────────┘ + ▼ + ┌─────────────────┐ + │ Integration │ + │ Job │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ E2E │ + │ Job │ + └─────────────────┘ +``` + +#### Release Workflow (`.github/workflows/release.yml`) + +Runs on: Push to master (excluding [skip ci] commits) + +``` +┌───────────────────────────────────────────────────────────┐ +│ Release Job │ +├───────────────────────────────────────────────────────────┤ +│ 1. Checkout (fetch-depth: 0 for full history) │ +│ 2. Setup Node.js 20 │ +│ 3. Install dependencies (root + backend) │ +│ 4. Lint │ +│ 5. Run tests (root + backend) │ +│ 6. Build │ +│ 7. semantic-release │ +│ - Analyze commits │ +│ - Bump version │ +│ - Update CHANGELOG.md │ +│ - Create git tag │ +│ - Create GitHub release │ +└───────────────────────────────────────────────────────────┘ + │ + ▼ +┌───────────────────────────────────────────────────────────┐ +│ Docker Build Job │ +├───────────────────────────────────────────────────────────┤ +│ 1. Checkout │ +│ 2. Get version from git tag │ +│ 3. Setup QEMU (for multi-platform) │ +│ 4. Setup Docker Buildx │ +│ 5. Login to Docker Hub │ +│ 6. Login to GHCR │ +│ 7. Build and push (amd64 + arm64) │ +└───────────────────────────────────────────────────────────┘ +``` + +#### Staging Workflow (`.github/workflows/staging.yml`) + +Runs on: Push to staging branch + +``` +┌───────────────────────────────────────────────────────────┐ +│ Staging Deploy Job │ +├───────────────────────────────────────────────────────────┤ +│ 1. Checkout │ +│ 2. Install + Lint + Test + Build │ +│ 3. Build Docker image (multi-platform) │ +│ 4. Push with tag: staging │ +└───────────────────────────────────────────────────────────┘ +``` + +#### Nightly Workflow (`.github/workflows/nightly.yml`) + +Runs on: Schedule (daily at 02:00 UTC) + +``` +┌───────────────────────────────────────────────────────────┐ +│ Nightly Build Job │ +├───────────────────────────────────────────────────────────┤ +│ 1. Checkout master │ +│ 2. Get current date │ +│ 3. Install + Build │ +│ 4. Build Docker image (multi-platform) │ +│ 5. Push with tags: nightly, edge, YYYY-MM-DD │ +└───────────────────────────────────────────────────────────┘ +``` + +## Docker Image Tags + +| Tag | Registry | Description | Update Frequency | +|-----|----------|-------------|------------------| +| `latest` | Both | Latest stable release | Every release | +| `v1.0.0` | Both | Specific version | Immutable | +| `1.0` | Both | Major.minor | Points to latest patch | +| `1` | Both | Major version | Points to latest minor | +| `staging` | Both | Staging environment | Every staging push | +| `nightly` | Both | Latest nightly build | Daily | +| `edge` | Both | Alias for nightly | Daily | +| `2026-02-20` | Both | Date-specific nightly | Immutable | + +### Pulling Images + +```bash +# Docker Hub +docker pull username/cv-app:latest +docker pull username/cv-app:v1.0.0 +docker pull username/cv-app:staging +docker pull username/cv-app:nightly + +# GitHub Container Registry +docker pull ghcr.io/owner/cv-app:latest +docker pull ghcr.io/owner/cv-app:v1.0.0 +``` + +## Environments + +| Environment | Branch | Trigger | Docker Tag | +|-------------|--------|---------|------------| +| Production | `master` | semantic-release (feat/fix commits) | `latest`, `vX.Y.Z` | +| Staging | `staging` | Push to branch | `staging` | +| Nightly | `master` | Daily at 02:00 UTC | `nightly`, `edge`, `YYYY-MM-DD` | + +## Release Flow Example + +``` +Developer commits: feat(admin): add export functionality + │ + ▼ + ┌─────────────────┐ + │ Git Hook Runs │ + │ (pre-commit) │ + │ • npm run lint │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Git Hook Runs │ + │ (commit-msg) │ + │ • commitlint │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Push to PR │ + │ │ + │ CI validates: │ + │ • commitlint │ + │ • lint │ + │ • test │ + │ • build │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Merge to │ + │ master │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Release Workflow│ + │ Triggers │ + └─────────────────┘ + │ + ▼ + ┌─────────────────────────────────────┐ + │ semantic-release analyzes │ + │ │ + │ Previous version: 1.0.0 │ + │ Commits since last release: │ + │ • feat(admin): add export │ + │ │ + │ Decision: MINOR release │ + │ New version: 1.1.0 │ + └─────────────────────────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Version bumped │ + │ in package.json │ + │ 1.0.0 → 1.1.0│ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ CHANGELOG.md │ + │ updated │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Git tag created │ + │ v1.1.0 │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ GitHub Release │ + │ created │ + │ with notes │ + └─────────────────┘ + │ + ▼ + ┌─────────────────────────────────┐ + │ Docker images built and │ + │ pushed to: │ + │ │ + │ • username/cv-app:latest │ + │ • username/cv-app:v1.1.0 │ + │ • ghcr.io/owner/cv-app:latest │ + │ • ghcr.io/owner/cv-app:v1.1.0 │ + └─────────────────────────────────┘ +``` + +## Required Secrets + +Configure these in GitHub repository settings → Secrets and variables → Actions: + +| Secret | Description | Required For | +|--------|-------------|--------------| +| `DOCKERHUB_USERNAME` | Docker Hub username | Docker Hub push | +| `DOCKERHUB_TOKEN` | Docker Hub access token | Docker Hub push | +| `GITHUB_TOKEN` | GitHub token (automatic) | GHCR push, releases | + +### Creating Docker Hub Token + +1. Go to Docker Hub → Account Settings → Security +2. Click "New Access Token" +3. Name: `cv-app-github-actions` +4. Permissions: Read, Write, Delete +5. Copy token and add to GitHub secrets + +## Local Development + +### Testing Commit Messages + +```bash +# Test a valid commit message +echo "feat(ui): add new button component" | npx commitlint + +# Test an invalid commit message +echo "added a button" | npx commitlint +``` + +### Skipping CI + +Add `[skip ci]` to commit message to skip CI: + +```bash +git commit -m "docs: update readme [skip ci]" +``` + +### Manual Release Trigger + +1. Go to Actions → Release workflow +2. Click "Run workflow" +3. Select branch (master) +4. Click "Run workflow" + +## Troubleshooting + +### Commit Rejected by commitlint + +**Error**: `subject must be lower-case` + +**Fix**: Use lowercase for the subject: +```bash +# Wrong +git commit -m "feat(ui): Add new button" + +# Correct +git commit -m "feat(ui): add new button" +``` + +### Release Not Triggering + +**Causes**: +1. No release-worthy commits (only docs/style/refactor/test/build/ci/chore) +2. Commit message contains `[skip ci]` +3. Workflow already running + +**Solution**: Ensure you have `feat`, `fix`, or `perf` commits since last release. + +### Docker Push Fails + +**Error**: `denied: requested access to the resource is denied` + +**Fix**: +1. Verify `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` secrets +2. Ensure Docker Hub token has Write permission +3. Check Docker Hub repository exists (or enable auto-create) + +### Version Not Bumping + +**Cause**: semantic-release requires conventional commits with proper types. + +**Fix**: Ensure commits follow: +- `feat:` for features (minor bump) +- `fix:` for bug fixes (patch bump) +- `feat!:` or `BREAKING CHANGE:` for breaking changes (major bump) + +## File Reference + +| File | Purpose | +|------|---------| +| `.releaserc.json` | semantic-release configuration | +| `commitlint.config.js` | Commitlint rules | +| `.husky/pre-commit` | Pre-commit hook (lint) | +| `.husky/commit-msg` | Commit message hook (commitlint) | +| `.github/workflows/ci.yml` | CI pipeline | +| `.github/workflows/release.yml` | Release pipeline | +| `.github/workflows/staging.yml` | Staging deployment | +| `.github/workflows/nightly.yml` | Nightly builds | +| `docker-bake.hcl` | Multi-platform Docker build config | +| `CHANGELOG.md` | Auto-generated changelog |