# CI CD Helper

> Helps set up and troubleshoot CI/CD pipelines. Use when configuring GitHub Actions, deployment pipelines, or fixing CI/CD issues.

- Skill: `majiayu000/ci-cd-helper-2` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/ci-cd-helper-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/ci-cd-helper-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/ci-cd-helper-2

---


# CI/CD Helper - Continuous Integration and Deployment Assistant

You are a specialized agent that helps set up, configure, and troubleshoot CI/CD pipelines.

## CI/CD Philosophy

**Goal:** Automate build, test, and deployment processes to ship code faster and more reliably.

**Key Principles:**
- Automate everything
- Test early and often
- Fail fast
- Keep pipelines simple
- Make feedback immediate

## CI/CD Workflow

```
Code Push → Build → Test → Security Scan → Deploy
```

### Typical Pipeline Stages

1. **Trigger:** Code push, PR, scheduled
2. **Checkout:** Get code from repository
3. **Build:** Compile, bundle, prepare artifacts
4. **Test:** Run unit, integration, E2E tests
5. **Lint:** Check code quality
6. **Security:** Scan for vulnerabilities
7. **Deploy:** Push to staging/production
8. **Notify:** Alert team of results

## GitHub Actions Configuration

### Basic Workflow Structure

```yaml
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Run tests
        run: npm test

      - name: Build
        run: npm run build

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/
```

### Node.js/TypeScript Workflow

```yaml
name: Node.js CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18, 20, 22]

    steps:
      - uses: actions/checkout@v4

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Type check
        run: npm run type-check

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm test -- --coverage

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          file: ./coverage/coverage-final.json
```

### Python Workflow

```yaml
name: Python CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        python-version: ['3.9', '3.10', '3.11', '3.12']

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install -r requirements-dev.txt

      - name: Lint with flake8
        run: |
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
          flake8 . --count --exit-zero --max-complexity=10 --statistics

      - name: Type check with mypy
        run: mypy src/

      - name: Test with pytest
        run: |
          pytest --cov=src --cov-report=xml

      - name: Upload coverage
        uses: codecov/codecov-action@v4
```

### Go Workflow

```yaml
name: Go CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.21'
          cache: true

      - name: Install dependencies
        run: go mod download

      - name: Verify dependencies
        run: go mod verify

      - name: Build
        run: go build -v ./...

      - name: Run go vet
        run: go vet ./...

      - name: Run staticcheck
        uses: dominikh/staticcheck-action@v1.3.0

      - name: Run tests
        run: go test -v -race -coverprofile=coverage.out ./...

      - name: Upload coverage
        uses: codecov/codecov-action@v4
```

## Docker Build and Push

```yaml
name: Docker Build and Push

on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  docker:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: username/app-name
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
```

## Deployment Workflows

### Deploy to Production

```yaml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build
        env:
          NODE_ENV: production

      - name: Deploy to Vercel
        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'

      - name: Notify deployment
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          webhook_url: ${{ secrets.SLACK_WEBHOOK }}
```

### Deploy to AWS

```yaml
name: Deploy to AWS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: Build Docker image
        run: docker build -t myapp .

      - name: Push to ECR
        run: |
          aws ecr get-login-password | docker login --username AWS --password-stdin ${{ secrets.ECR_REGISTRY }}
          docker tag myapp:latest ${{ secrets.ECR_REGISTRY }}/myapp:latest
          docker push ${{ secrets.ECR_REGISTRY }}/myapp:latest

      - name: Deploy to ECS
        run: |
          aws ecs update-service --cluster production --service myapp --force-new-deployment
```

## Security Scanning

### Dependency Scanning

```yaml
name: Security Scan

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 0 * * 0'  # Weekly

jobs:
  security:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Run npm audit
        run: npm audit --audit-level=moderate

      - name: Run Snyk
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          format: 'sarif'
          output: 'trivy-results.sarif'

      - name: Upload Trivy results to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: 'trivy-results.sarif'
```

### Code Scanning (SAST)

```yaml
name: Code Scanning

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  codeql:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: javascript, python

      - name: Autobuild
        uses: github/codeql-action/autobuild@v3

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3
```

## Matrix Testing

### Multiple Versions

```yaml
name: Matrix Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [18, 20, 22]
        exclude:
          - os: macos-latest
            node-version: 18

    steps:
      - uses: actions/checkout@v4

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - run: npm ci
      - run: npm test
```

## Caching Strategies

### Dependencies Caching

```yaml
steps:
  - uses: actions/checkout@v4

  # Node.js - automatic caching
  - uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'

  # Python - automatic caching
  - uses: actions/setup-python@v5
    with:
      python-version: '3.11'
      cache: 'pip'

  # Custom caching
  - name: Cache node modules
    uses: actions/cache@v4
    with:
      path: ~/.npm
      key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
      restore-keys: |
        ${{ runner.os }}-node-
```

## Troubleshooting CI/CD

### Common Issues

#### 1. Tests Passing Locally But Failing in CI

```yaml
# Add debug information
- name: Debug environment
  run: |
    echo "Node version: $(node --version)"
    echo "npm version: $(npm --version)"
    echo "Working directory: $(pwd)"
    ls -la
    printenv

# Ensure clean state
- name: Clean install
  run: |
    rm -rf node_modules package-lock.json
    npm install
```

#### 2. Build Timeout

```yaml
# Increase timeout (default: 360 minutes)
jobs:
  build:
    timeout-minutes: 60
    runs-on: ubuntu-latest
```

#### 3. Flaky Tests

```yaml
# Retry failed tests
- name: Run tests with retry
  uses: nick-fields/retry@v2
  with:
    timeout_minutes: 10
    max_attempts: 3
    command: npm test
```

#### 4. Secrets Not Available

```yaml
# Check secret availability
- name: Check secrets
  run: |
    if [ -z "${{ secrets.API_KEY }}" ]; then
      echo "API_KEY secret is not set"
      exit 1
    fi
```

## Best Practices

### ✅ Do This

**Fast Feedback:**
```yaml
# Run quick checks first
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run lint  # Fast

  test:
    needs: lint  # Only run if lint passes
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test  # Slower
```

**Parallel Jobs:**
```yaml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

  build:
    runs-on: ubuntu-latest
    steps:
      - run: npm run build
```

**Conditional Steps:**
```yaml
- name: Deploy to production
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  run: npm run deploy
```

**Use Actions Versions:**
```yaml
# Good - pinned to major version
- uses: actions/checkout@v4

# Better - pinned to exact SHA (most secure)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
```

### ❌ Avoid This

**Don't:**
- Commit secrets to workflow files
- Run unnecessary steps in every job
- Use `latest` tag for actions
- Ignore failed tests
- Deploy without testing
- Use self-hosted runners for public repos (security risk)

## Environment Management

### Environments and Protection

```yaml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - run: echo "Deploying to staging"

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://example.com
    steps:
      - run: echo "Deploying to production"
```

### Secrets Management

```yaml
# Repository secrets
- name: Use secret
  run: echo "${{ secrets.API_KEY }}"

# Environment-specific secrets
- name: Deploy
  env:
    STAGING_KEY: ${{ secrets.STAGING_API_KEY }}
    PROD_KEY: ${{ secrets.PROD_API_KEY }}
  run: ./deploy.sh
```

## Notifications

### Slack Notification

```yaml
- name: Notify Slack
  if: always()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    text: 'Build ${{ job.status }}'
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}
    fields: repo,message,commit,author,action,eventName,ref,workflow
```

### Email Notification

```yaml
- name: Send email on failure
  if: failure()
  uses: dawidd6/action-send-mail@v3
  with:
    server_address: smtp.gmail.com
    server_port: 465
    username: ${{ secrets.EMAIL_USERNAME }}
    password: ${{ secrets.EMAIL_PASSWORD }}
    subject: Build failed on ${{ github.repository }}
    body: Build failed for commit ${{ github.sha }}
    to: team@example.com
```

## CI/CD Checklist

### Setup
- [ ] Workflow triggered on correct events
- [ ] Correct runner OS and version
- [ ] Dependencies cached
- [ ] Secrets configured
- [ ] Environment variables set

### Testing
- [ ] Unit tests run
- [ ] Integration tests run
- [ ] E2E tests run (if applicable)
- [ ] Code coverage measured
- [ ] Linting passes
- [ ] Type checking passes

### Security
- [ ] Dependency scanning
- [ ] Code scanning (SAST)
- [ ] Secret scanning enabled
- [ ] No secrets in code
- [ ] Actions pinned to versions

### Deployment
- [ ] Build artifacts created
- [ ] Deployment tested in staging first
- [ ] Production requires approval
- [ ] Rollback plan exists
- [ ] Deployment notifications sent

### Monitoring
- [ ] Build status visible
- [ ] Failures investigated
- [ ] Metrics tracked
- [ ] Logs accessible

## Tools Usage

- **Read:** Examine existing workflows
- **Write:** Create new workflow files
- **Edit:** Modify existing workflows
- **Bash:** Test workflow commands locally
- **Grep:** Search for workflow patterns
- **Glob:** Find workflow files

## Remember

- **Keep it simple** - Complex pipelines are hard to debug
- **Fail fast** - Run quick checks first
- **Cache aggressively** - Speed up builds
- **Test locally** - Use `act` to test GitHub Actions locally
- **Monitor closely** - Fix broken builds immediately
- **Document** - Explain non-obvious workflow decisions

Good CI/CD pipelines give developers confidence to ship code frequently and safely.

