CtrlK
BlogDocsLog inGet started
Tessl Logo

github-actions-ci

Invalid
This skill can't be scored yet
Validation errors are blocking scoring. Review and fix them to unlock Quality, Impact and Security scores. See what needs fixing →
SKILL.md
Quality
Evals
Security

GitHub Actions CI

Generate CI/CD workflow files for common stacks with matrix builds, dependency caching, Docker build+push, deploy steps, secrets management, reusable workflows, and PR checks.

Prerequisites

  • GitHub repository
  • Repository secrets configured (Settings > Secrets and variables > Actions)
  • For Docker push: container registry credentials (GHCR, DockerHub, ECR)
  • For deploy: target environment credentials

Scaffold Command

mkdir -p .github/workflows
touch .github/workflows/ci.yml
touch .github/workflows/deploy.yml

# Optional: reusable workflows
mkdir -p .github/workflows/reusable
touch .github/workflows/reusable/docker-build.yml
touch .github/workflows/reusable/run-tests.yml

Project Structure

.github/
  workflows/
    ci.yml                        # PR checks: lint, test, type-check, build
    deploy.yml                    # Deploy to staging/production
    release.yml                   # Tag-based release workflow
    reusable/
      docker-build.yml            # Reusable Docker build+push
      run-tests.yml               # Reusable test runner
  dependabot.yml                  # Automated dependency updates

Key Conventions

  • Separate CI (PR checks) from CD (deployment) workflows.
  • Use on.pull_request for CI checks, on.push to main/tags for deployments.
  • Cache dependencies aggressively (npm, pip, Go modules, Docker layers).
  • Use matrix strategy for multi-version or multi-OS testing.
  • Pin action versions to full SHA, not tags (supply chain security).
  • Use concurrency to cancel redundant runs on the same branch.
  • Secrets go in GitHub Secrets, never in workflow files.
  • Use reusable workflows (workflow_call) to avoid duplication across repos.
  • Use permissions block with least-privilege principle.

Essential Patterns

Node.js CI (ci.yml)

name: CI

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  lint-and-typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npx tsc --noEmit

  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: npm
      - run: npm ci
      - run: npm test -- --coverage
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: coverage-node-${{ matrix.node-version }}
          path: coverage/

  build:
    runs-on: ubuntu-latest
    needs: [lint-and-typecheck, test]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npm run build

Python CI

name: CI

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: pip
      - run: pip install ruff mypy
      - run: ruff check .
      - run: ruff format --check .
      - run: mypy .

  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.11", "3.12", "3.13"]
    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: testdb
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: pip
      - run: pip install -r requirements.txt -r requirements-dev.txt
      - run: pytest --cov --cov-report=xml
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/testdb
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: coverage-py${{ matrix.python-version }}
          path: coverage.xml

Go CI

name: CI

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: "1.23"
      - uses: golangci/golangci-lint-action@v6
        with:
          version: latest

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: "1.23"
      - run: go test -race -coverprofile=coverage.out ./...
      - uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage.out

Docker Build + Push to GHCR

name: Docker Build

on:
  push:
    branches: [main]
    tags: ["v*"]

permissions:
  contents: read
  packages: write

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha

      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64,linux/arm64

Reusable Workflow — Docker Build (reusable/docker-build.yml)

name: Reusable Docker Build

on:
  workflow_call:
    inputs:
      image-name:
        required: true
        type: string
      dockerfile:
        required: false
        type: string
        default: Dockerfile
      context:
        required: false
        type: string
        default: "."
    secrets:
      registry-password:
        required: true

permissions:
  contents: read
  packages: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.registry-password }}
      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: ${{ inputs.image-name }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=sha
      - uses: docker/build-push-action@v6
        with:
          context: ${{ inputs.context }}
          file: ${{ inputs.dockerfile }}
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Calling a Reusable Workflow

name: Deploy

on:
  push:
    branches: [main]

jobs:
  build-image:
    uses: ./.github/workflows/reusable/docker-build.yml
    with:
      image-name: ghcr.io/${{ github.repository }}
    secrets:
      registry-password: ${{ secrets.GITHUB_TOKEN }}

  deploy:
    needs: build-image
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - run: echo "Deploy to production"

Deploy with kubectl

deploy:
    needs: [build]
    runs-on: ubuntu-latest
    environment: production
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4

      - name: Validate required secrets
        run: |
          if [ -z "${{ secrets.AWS_ROLE_ARN }}" ]; then
            echo "::error::AWS_ROLE_ARN secret is not set"
            exit 1
          fi

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - run: aws eks update-kubeconfig --name my-cluster --region us-east-1

      - run: |
          cd k8s/overlays/production
          kustomize edit set image ghcr.io/org/myapp=ghcr.io/org/myapp:sha-${{ github.sha }}
          kubectl apply -k .
          kubectl -n myapp-prod rollout status deployment/myapp --timeout=300s

Dependabot (.github/dependabot.yml)

version: 2
updates:
  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: weekly
  - package-ecosystem: npm
    directory: /
    schedule:
      interval: weekly
    groups:
      dev-dependencies:
        dependency-type: development
      production-dependencies:
        dependency-type: production

Common Commands

# Validate workflow syntax locally
gh workflow list
gh workflow view ci.yml

# Trigger a workflow manually (if workflow_dispatch is configured)
gh workflow run ci.yml

# View recent runs
gh run list --workflow=ci.yml

# View a specific run
gh run view <run-id>

# Download artifacts from a run
gh run download <run-id>

# View workflow run logs
gh run view <run-id> --log

Integration Notes

  • Docker: Pair with dockerfile-generator skill for optimized Dockerfiles. The CI workflow builds and pushes the image.
  • Kubernetes: Pair with kubernetes-manifests skill. The deploy job applies kustomize overlays with the new image tag.
  • Terraform: Add a separate workflow for terraform plan on PR and terraform apply on merge to main.
  • Testing: Pair with stack-specific testing skills (jest, pytest, vitest). The CI workflow runs the test suite defined in the project.
  • Secrets: Use GitHub OIDC (id-token: write) for AWS/GCP/Azure instead of long-lived credentials where possible.
Repository
achreftlili/deep-dev-skills
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.