- Rename all references from hub-guide to code-guide - Remove project-specific hub-guide skill (100% Asepharyana Hub specific) - Genericize examples in monorepo, docker, ci-cd, engineering-principles skills - Use generic service names (frontend, api, worker instead of hub, scraper) - Use generic registry paths instead of ghcr.io/asepharyana/asepharyana-hub - Remove project-specific deployment and infrastructure references
4.9 KiB
4.9 KiB
name, description
| name | description |
|---|---|
| ci-cd | CI/CD best practices — GitHub Actions, pipeline design, Docker build + push, deployment workflows, testing in CI, and environment management. Use when designing CI/CD pipelines, debugging workflow failures. Triggers from project files and configuration, not just keyword matching." |
CI/CD Best Practices
Pipeline Design Principles
- Fast feedback — failing fast is better than failing comprehensively.
- Deterministic — same commit = same result, same artifacts.
- Immutable artifacts — build once, promote through environments.
- Idempotent deployments — deploying the same artifact again produces the same result.
- Security gates — scan dependencies, secrets, and code before production.
GitHub Actions Structure
.github/workflows/
├── lint.yml # Quick checks — runs in <2 min
├── docker-build-push.yml # Build + push images
├── deploy-docker.yml # Deploy to VPS
├── security.yml # CodeQL + dependency scan
├── update-submodule.yml # Update submodule pointer
└── ...other workflows
Workflow Patterns
Lint (fast — gates everything else)
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run ci # Biome lint + format
Build + Push (on push to main)
name: Build Docker
on:
push:
branches: [main]
paths: ['apps/**', 'infra/**']
repository_dispatch:
types: [build]
jobs:
build:
strategy:
matrix:
service: [frontend, api]
steps:
- uses: actions/checkout@v4
- run: |
docker build \
-f infra/docker/${{ matrix.service }}.Dockerfile \
-t ghcr.io/myorg/myproject/${{ matrix.service }}:sha-${{ github.sha }} \
-t ghcr.io/myorg/myproject/${{ matrix.service }}:latest \
.
- run: docker push --all-tags ghcr.io/myorg/myproject/${{ matrix.service }}
Deploy (after build)
name: Deploy
on:
workflow_run:
workflows: ['Build Docker']
types: [completed]
push:
branches: [main]
paths: ['infra/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd ${{ secrets.VPS_TARGET_DIR }}
docker compose pull <service>
docker compose up -d <service>
Key Patterns
Matrix Builds
jobs:
build:
strategy:
matrix:
service: [frontend, api, worker]
fail-fast: false # Let others complete even if one fails
Conditional Jobs
jobs:
deploy:
if: github.event.workflow_run.conclusion == 'success'
Caching
- uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
Secrets
# All secrets in GitHub Secrets, never in code
secrets:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
VPS_HOST: ${{ secrets.VPS_HOST }}
ENV_FILE_PRODUCTION: ${{ secrets.ENV_FILE_PRODUCTION }}
Environment Strategy
| Environment | Purpose | Deploy Method |
|---|---|---|
development |
Local dev | Manual docker compose up |
staging |
Pre-production | Auto-deploy from PR branches |
production |
Live | Auto-deploy from main |
Quality Gates (run order)
- Lint (<1 min) — Biome/Ruff/clippy + format check
- Type check (<2 min) — tsc/pyright/cargo check
- Unit tests (<3 min) — fast, no external deps
- Build (<5 min) — compile/transpile, build Docker images
- Integration tests (<10 min) — with DB, external services
- Security scan (<5 min) — CodeQL, dependency audit, secret scan
- Deploy (<2 min) — SSH, pull, restart
Deployment Pattern
- SSH to deployment target
- Pull latest images from container registry
- Restart specific container (not all)
- Health check after restart
- Rollback if health check fails
Anti-patterns
- ❌ Large CI configs — extract repeated blocks into actions. Use YAML anchors.
- ❌ Building in deployment — build once in CI, deploy artifact. Avoid
docker compose buildon production. - ❌ Hardcoded values — use env vars, secrets, and GitHub variables.
- ❌ Skipping lint — lint should run first and gate everything.
- ❌ No caching — each run fetches deps fresh = 2x+ slower.
- ❌ Manual deployment steps — automate everything. If it's manual, it will be wrong.
- ❌ Deploying untested artifacts — run tests before build, not after.