git clone https://github.com/ComeOnOliver/skillshub
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/cicd-pipeline" ~/.claude/skills/comeonoliver-skillshub-cicd-pipeline && rm -rf "$T"
skills/TerminalSkills/skills/cicd-pipeline/SKILL.mdCI/CD Pipeline
Overview
Generate production-ready CI/CD pipeline configurations for automated testing, building, and deploying applications. This skill creates well-structured workflows with proper caching, matrix testing, environment separation, and deployment strategies for GitHub Actions, GitLab CI, and CircleCI.
Instructions
When a user asks to create or improve a CI/CD pipeline, follow these steps:
Step 1: Analyze the project
Detect the project type and requirements:
# Determine language and framework ls package.json pyproject.toml Gemfile go.mod Cargo.toml pom.xml build.gradle 2>/dev/null # Check for existing CI config ls .github/workflows/*.yml .gitlab-ci.yml .circleci/config.yml 2>/dev/null # Detect test commands cat package.json | grep -A5 '"scripts"' 2>/dev/null cat Makefile 2>/dev/null | grep -E "^test|^lint|^build"
Identify:
- Language/runtime: Node.js, Python, Go, Rust, Java
- Package manager: npm, pnpm, yarn, pip, poetry
- Test framework: Jest, Pytest, Go test, etc.
- Build output: Docker image, static site, binary, package
- Deploy target: Vercel, AWS, Docker registry, npm registry
Step 2: Choose the CI/CD platform
Default to GitHub Actions unless the user specifies otherwise or the repo is on GitLab.
Step 3: Generate the pipeline configuration
Create the workflow file with these standard stages:
GitHub Actions — Node.js example:
# .github/workflows/ci.yml name: CI on: push: branches: [main] pull_request: branches: [main] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: lint: 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 test: runs-on: ubuntu-latest strategy: matrix: node-version: [18, 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: matrix.node-version == 20 with: name: coverage path: coverage/ build: runs-on: ubuntu-latest needs: [lint, test] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' - run: npm ci - run: npm run build - uses: actions/upload-artifact@v4 with: name: build path: dist/
GitHub Actions — Python example:
name: CI on: push: branches: [main] pull_request: jobs: test: runs-on: ubuntu-latest strategy: matrix: python-version: ['3.10', '3.11', '3.12'] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' - run: pip install -e '.[dev]' - run: pytest --cov=src --cov-report=xml - uses: codecov/codecov-action@v4 if: matrix.python-version == '3.12' with: file: coverage.xml
GitLab CI example:
# .gitlab-ci.yml stages: - lint - test - build - deploy variables: NODE_VERSION: "20" .node-cache: cache: key: ${CI_COMMIT_REF_SLUG} paths: - node_modules/ lint: stage: lint extends: .node-cache image: node:${NODE_VERSION} script: - npm ci - npm run lint test: stage: test extends: .node-cache image: node:${NODE_VERSION} script: - npm ci - npm test -- --coverage coverage: '/All files.*\|.*\s+([\d\.]+)/' artifacts: reports: coverage_report: coverage_format: cobertura path: coverage/cobertura-coverage.xml build: stage: build extends: .node-cache image: node:${NODE_VERSION} script: - npm ci - npm run build artifacts: paths: - dist/ only: - main
Step 4: Add deployment stage if requested
Deploy to Vercel:
deploy: needs: [build] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - uses: amondnet/vercel-action@v25 with: vercel-token: ${{ secrets.VERCEL_TOKEN }} vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} vercel-args: '--prod'
Deploy Docker image:
deploy: needs: [test] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - uses: docker/build-push-action@v5 with: push: true tags: ghcr.io/${{ github.repository }}:latest cache-from: type=gha cache-to: type=gha,mode=max
Step 5: Add release workflow if needed
# .github/workflows/release.yml name: Release on: push: tags: ['v*'] jobs: release: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 registry-url: 'https://registry.npmjs.org' - run: npm ci && npm run build - run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - uses: softprops/action-gh-release@v1 with: generate_release_notes: true
Examples
Example 1: Full CI/CD for a Next.js app deploying to Vercel
User request: "Set up CI/CD for my Next.js project with tests, linting, and Vercel deploy"
Actions taken:
- Detected: Next.js 14, npm, Vitest, ESLint
- Created
with lint, test, build jobs.github/workflows/ci.yml - Added Vercel deployment on main branch pushes
- Configured concurrency to cancel outdated runs
Result:
Created: .github/workflows/ci.yml - Lint job: ESLint + Prettier check - Test job: Vitest with coverage upload (Node 18/20 matrix) - Build job: next build (depends on lint + test passing) - Deploy job: Vercel production deploy (main branch only) Estimated run time: ~3 minutes Required secrets: VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID
Example 2: GitLab CI for a Python Django API with Docker
User request: "Create a GitLab CI pipeline for my Django app with Docker deployment"
Actions taken:
- Detected: Django 4.2, Poetry, Pytest, PostgreSQL dependency
- Created
with lint, test (with Postgres service), build, deploy stages.gitlab-ci.yml - Added Postgres service container for integration tests
- Configured Docker image build and push to GitLab Container Registry
Result:
Created: .gitlab-ci.yml Stages: lint → test → build → deploy - lint: ruff + mypy type checking - test: pytest with PostgreSQL 16 service container - build: Docker image build, pushed to $CI_REGISTRY_IMAGE - deploy: SSH deploy to production (manual trigger) Required variables: DEPLOY_HOST, DEPLOY_USER, SSH_PRIVATE_KEY
Guidelines
- Always use
and the latest stable action versions.actions/checkout@v4 - Enable dependency caching (
,cache: 'npm'
) to speed up runs.cache: 'pip' - Use
withconcurrency
to avoid wasted compute on PRs.cancel-in-progress: true - Pin action versions to major tags (e.g.,
) not@v4
or commit SHAs for readability.@main - Use matrix strategy for testing across multiple runtime versions.
- Separate CI (runs on every PR) from CD (runs only on main/tags).
- Store secrets in repository/organization secrets, never in workflow files.
- Add
to deployment jobs to prevent accidental deploys from PRs.if: github.ref == 'refs/heads/main' - For monorepos, use path filters to only run relevant pipelines:
.paths: ['packages/api/**'] - Include a status badge in README:
.