infrastructure/github-actions-ci/SKILL.md
--- name: github-actions-ci description: > 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. category: infrastructure agent-type: devops compatibility: GitHub repository, Repository secrets configured, For Docker push: container registry credentials, For deploy: target environment credentials --- # GitHub Actions CI > Generate CI/CD workflow files for common stack
npx skillsauth add achreftlili/deep-dev-skills infrastructure/github-actions-ciInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
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
.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
on.pull_request for CI checks, on.push to main/tags for deployments.concurrency to cancel redundant runs on the same branch.workflow_call) to avoid duplication across repos.permissions block with least-privilege principle.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
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
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
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/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
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:
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
.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
# 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
dockerfile-generator skill for optimized Dockerfiles. The CI workflow builds and pushes the image.kubernetes-manifests skill. The deploy job applies kustomize overlays with the new image tag.terraform plan on PR and terraform apply on merge to main.id-token: write) for AWS/GCP/Azure instead of long-lived credentials where possible.testing
Set up Vitest 2.x with TypeScript for unit and component testing using test/describe/it, vi.fn/vi.mock/vi.spyOn, component testing with Testing Library, coverage (v8/istanbul), workspace config, and snapshot testing.
testing
Set up pytest 8.x with Python for unit and integration testing using fixtures (scope, autouse, parametrize), async tests (pytest-asyncio), mocking (unittest.mock, pytest-mock), coverage (pytest-cov), conftest.py patterns, and markers.
testing
Set up Playwright 1.49+ with TypeScript for E2E testing using page object model, fixtures, test.describe/test blocks, assertions, selectors, network mocking, CI configuration, and trace viewer.
testing
Set up Jest 30+ with TypeScript for unit tests, integration tests, mocking (jest.fn, jest.mock, jest.spyOn), coverage configuration, custom matchers, snapshot testing, and setup/teardown patterns.