Files
asepharyana-hub-guide/skills/ci-cd/SKILL.md
T
asepharyana 8bcccfc022 refactor: rename hub-guide → code-guide, remove project-specific content
- 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
2026-07-26 12:28:25 +07:00

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

  1. Fast feedback — failing fast is better than failing comprehensively.
  2. Deterministic — same commit = same result, same artifacts.
  3. Immutable artifacts — build once, promote through environments.
  4. Idempotent deployments — deploying the same artifact again produces the same result.
  5. 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)

  1. Lint (<1 min) — Biome/Ruff/clippy + format check
  2. Type check (<2 min) — tsc/pyright/cargo check
  3. Unit tests (<3 min) — fast, no external deps
  4. Build (<5 min) — compile/transpile, build Docker images
  5. Integration tests (<10 min) — with DB, external services
  6. Security scan (<5 min) — CodeQL, dependency audit, secret scan
  7. Deploy (<2 min) — SSH, pull, restart

Deployment Pattern

  1. SSH to deployment target
  2. Pull latest images from container registry
  3. Restart specific container (not all)
  4. Health check after restart
  5. 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 build on 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.