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 updateson.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 buildname: 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.xmlname: 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.outname: 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/arm64reusable/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=maxname: 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> --logdockerfile-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.181fcbc
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.