feat: initial Claude Code configuration scaffold
Comprehensive Claude Code guidance system with: - 5 agents: tdd-guardian, code-reviewer, security-scanner, refactor-scan, dependency-audit - 18 skills covering languages (Python, TypeScript, Rust, Go, Java, C#), infrastructure (AWS, Azure, GCP, Terraform, Ansible, Docker/K8s, Database, CI/CD), testing (TDD, UI, Browser), and patterns (Monorepo, API Design, Observability) - 3 hooks: secret detection, auto-formatting, TDD git pre-commit - Strict TDD enforcement with 80%+ coverage requirements - Multi-model strategy: Opus for planning, Sonnet for execution (opusplan) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
599
.claude/skills/infrastructure/cicd/SKILL.md
Normal file
599
.claude/skills/infrastructure/cicd/SKILL.md
Normal file
@@ -0,0 +1,599 @@
|
||||
---
|
||||
name: cicd-pipelines
|
||||
description: CI/CD pipeline patterns for Jenkins, GitHub Actions, and GitLab CI. Use when setting up continuous integration or deployment pipelines.
|
||||
---
|
||||
|
||||
# CI/CD Pipelines Skill
|
||||
|
||||
## Jenkins
|
||||
|
||||
### Declarative Pipeline
|
||||
```groovy
|
||||
// Jenkinsfile
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
REGISTRY = 'myregistry.azurecr.io'
|
||||
IMAGE_NAME = 'myapp'
|
||||
COVERAGE_THRESHOLD = '80'
|
||||
}
|
||||
|
||||
options {
|
||||
timeout(time: 30, unit: 'MINUTES')
|
||||
disableConcurrentBuilds()
|
||||
buildDiscarder(logRotator(numToKeepStr: '10'))
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage('Install Dependencies') {
|
||||
parallel {
|
||||
stage('Python') {
|
||||
when {
|
||||
changeset "apps/backend/**"
|
||||
}
|
||||
steps {
|
||||
sh 'uv sync'
|
||||
}
|
||||
}
|
||||
stage('Node') {
|
||||
when {
|
||||
changeset "apps/frontend/**"
|
||||
}
|
||||
steps {
|
||||
sh 'npm ci'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Lint & Type Check') {
|
||||
parallel {
|
||||
stage('Python Lint') {
|
||||
when {
|
||||
changeset "apps/backend/**"
|
||||
}
|
||||
steps {
|
||||
sh 'uv run ruff check apps/backend/'
|
||||
sh 'uv run mypy apps/backend/'
|
||||
}
|
||||
}
|
||||
stage('TypeScript Lint') {
|
||||
when {
|
||||
changeset "apps/frontend/**"
|
||||
}
|
||||
steps {
|
||||
sh 'npm run lint --workspace=frontend'
|
||||
sh 'npm run typecheck --workspace=frontend'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Test') {
|
||||
parallel {
|
||||
stage('Backend Tests') {
|
||||
when {
|
||||
changeset "apps/backend/**"
|
||||
}
|
||||
steps {
|
||||
sh """
|
||||
uv run pytest apps/backend/ \
|
||||
--cov=apps/backend/src \
|
||||
--cov-report=xml \
|
||||
--cov-fail-under=${COVERAGE_THRESHOLD} \
|
||||
--junitxml=test-results/backend.xml
|
||||
"""
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'test-results/backend.xml'
|
||||
publishCoverage adapters: [coberturaAdapter('coverage.xml')]
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Frontend Tests') {
|
||||
when {
|
||||
changeset "apps/frontend/**"
|
||||
}
|
||||
steps {
|
||||
sh """
|
||||
npm run test --workspace=frontend -- \
|
||||
--coverage \
|
||||
--coverageThreshold='{"global":{"branches":${COVERAGE_THRESHOLD},"functions":${COVERAGE_THRESHOLD},"lines":${COVERAGE_THRESHOLD}}}' \
|
||||
--reporter=junit \
|
||||
--outputFile=test-results/frontend.xml
|
||||
"""
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit 'test-results/frontend.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Security Scan') {
|
||||
steps {
|
||||
sh 'trivy fs --severity HIGH,CRITICAL --exit-code 1 .'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'main'
|
||||
branch 'release/*'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
def version = sh(script: 'git describe --tags --always', returnStdout: true).trim()
|
||||
sh """
|
||||
docker build -t ${REGISTRY}/${IMAGE_NAME}:${version} .
|
||||
docker tag ${REGISTRY}/${IMAGE_NAME}:${version} ${REGISTRY}/${IMAGE_NAME}:latest
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Push') {
|
||||
when {
|
||||
branch 'main'
|
||||
}
|
||||
steps {
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: 'registry-credentials',
|
||||
usernameVariable: 'REGISTRY_USER',
|
||||
passwordVariable: 'REGISTRY_PASS'
|
||||
)]) {
|
||||
sh """
|
||||
echo \$REGISTRY_PASS | docker login ${REGISTRY} -u \$REGISTRY_USER --password-stdin
|
||||
docker push ${REGISTRY}/${IMAGE_NAME}:${version}
|
||||
docker push ${REGISTRY}/${IMAGE_NAME}:latest
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy to Staging') {
|
||||
when {
|
||||
branch 'main'
|
||||
}
|
||||
steps {
|
||||
sh 'kubectl apply -f k8s/staging/'
|
||||
sh 'kubectl rollout status deployment/myapp -n staging'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy to Production') {
|
||||
when {
|
||||
branch 'release/*'
|
||||
}
|
||||
input {
|
||||
message "Deploy to production?"
|
||||
ok "Deploy"
|
||||
}
|
||||
steps {
|
||||
sh 'kubectl apply -f k8s/production/'
|
||||
sh 'kubectl rollout status deployment/myapp -n production'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
slackSend(
|
||||
channel: '#deployments',
|
||||
color: 'good',
|
||||
message: "Build ${env.BUILD_NUMBER} succeeded: ${env.BUILD_URL}"
|
||||
)
|
||||
}
|
||||
failure {
|
||||
slackSend(
|
||||
channel: '#deployments',
|
||||
color: 'danger',
|
||||
message: "Build ${env.BUILD_NUMBER} failed: ${env.BUILD_URL}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Shared Library
|
||||
```groovy
|
||||
// vars/pythonPipeline.groovy
|
||||
def call(Map config = [:]) {
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh "uv run pytest ${config.testPath ?: 'tests/'} --cov --cov-fail-under=${config.coverage ?: 80}"
|
||||
}
|
||||
}
|
||||
stage('Lint') {
|
||||
steps {
|
||||
sh "uv run ruff check ${config.srcPath ?: 'src/'}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Usage in Jenkinsfile
|
||||
@Library('my-shared-library') _
|
||||
|
||||
pythonPipeline(
|
||||
testPath: 'apps/backend/tests/',
|
||||
srcPath: 'apps/backend/src/',
|
||||
coverage: 85
|
||||
)
|
||||
```
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
### Complete Workflow
|
||||
```yaml
|
||||
# .github/workflows/ci.yml
|
||||
name: CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, 'release/*']
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
detect-changes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
backend: ${{ steps.changes.outputs.backend }}
|
||||
frontend: ${{ steps.changes.outputs.frontend }}
|
||||
infrastructure: ${{ steps.changes.outputs.infrastructure }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
backend:
|
||||
- 'apps/backend/**'
|
||||
- 'packages/shared/**'
|
||||
frontend:
|
||||
- 'apps/frontend/**'
|
||||
- 'packages/shared/**'
|
||||
infrastructure:
|
||||
- 'infrastructure/**'
|
||||
|
||||
backend-test:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.backend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
env:
|
||||
POSTGRES_USER: test
|
||||
POSTGRES_PASSWORD: test
|
||||
POSTGRES_DB: test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync
|
||||
|
||||
- name: Lint
|
||||
run: |
|
||||
uv run ruff check apps/backend/
|
||||
uv run mypy apps/backend/
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
DATABASE_URL: postgresql://test:test@localhost:5432/test
|
||||
run: |
|
||||
uv run pytest apps/backend/ \
|
||||
--cov=apps/backend/src \
|
||||
--cov-report=xml \
|
||||
--cov-fail-under=80
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: coverage.xml
|
||||
flags: backend
|
||||
|
||||
frontend-test:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Lint & Type Check
|
||||
run: |
|
||||
npm run lint --workspace=frontend
|
||||
npm run typecheck --workspace=frontend
|
||||
|
||||
- name: Test
|
||||
run: npm run test --workspace=frontend -- --coverage
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
files: apps/frontend/coverage/lcov.info
|
||||
flags: frontend
|
||||
|
||||
security-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
exit-code: '1'
|
||||
|
||||
- name: Run Gitleaks
|
||||
uses: gitleaks/gitleaks-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build-and-push:
|
||||
needs: [backend-test, frontend-test, security-scan]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Log in to Container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=sha
|
||||
type=ref,event=branch
|
||||
|
||||
- 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
|
||||
|
||||
deploy-staging:
|
||||
needs: build-and-push
|
||||
runs-on: ubuntu-latest
|
||||
environment: staging
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Deploy to staging
|
||||
run: |
|
||||
kubectl apply -f k8s/staging/
|
||||
kubectl rollout status deployment/myapp -n staging
|
||||
|
||||
deploy-production:
|
||||
needs: deploy-staging
|
||||
runs-on: ubuntu-latest
|
||||
environment: production
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Deploy to production
|
||||
run: |
|
||||
kubectl apply -f k8s/production/
|
||||
kubectl rollout status deployment/myapp -n production
|
||||
```
|
||||
|
||||
### Reusable Workflow
|
||||
```yaml
|
||||
# .github/workflows/python-ci.yml
|
||||
name: Python CI
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
python-version:
|
||||
required: false
|
||||
type: string
|
||||
default: '3.12'
|
||||
working-directory:
|
||||
required: true
|
||||
type: string
|
||||
coverage-threshold:
|
||||
required: false
|
||||
type: number
|
||||
default: 80
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: astral-sh/setup-uv@v4
|
||||
|
||||
- run: uv sync
|
||||
|
||||
- run: uv run ruff check .
|
||||
|
||||
- run: uv run pytest --cov --cov-fail-under=${{ inputs.coverage-threshold }}
|
||||
```
|
||||
|
||||
## GitLab CI
|
||||
|
||||
```yaml
|
||||
# .gitlab-ci.yml
|
||||
stages:
|
||||
- test
|
||||
- build
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
REGISTRY: registry.gitlab.com
|
||||
IMAGE_NAME: $CI_PROJECT_PATH
|
||||
|
||||
.python-base:
|
||||
image: python:3.12
|
||||
before_script:
|
||||
- pip install uv
|
||||
- uv sync
|
||||
|
||||
.node-base:
|
||||
image: node:22
|
||||
before_script:
|
||||
- npm ci
|
||||
|
||||
test:backend:
|
||||
extends: .python-base
|
||||
stage: test
|
||||
script:
|
||||
- uv run ruff check apps/backend/
|
||||
- uv run pytest apps/backend/ --cov --cov-fail-under=80
|
||||
rules:
|
||||
- changes:
|
||||
- apps/backend/**
|
||||
|
||||
test:frontend:
|
||||
extends: .node-base
|
||||
stage: test
|
||||
script:
|
||||
- npm run lint --workspace=frontend
|
||||
- npm run test --workspace=frontend -- --coverage
|
||||
rules:
|
||||
- changes:
|
||||
- apps/frontend/**
|
||||
|
||||
build:
|
||||
stage: build
|
||||
image: docker:24
|
||||
services:
|
||||
- docker:24-dind
|
||||
script:
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
- docker build -t $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA .
|
||||
- docker push $REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHA
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
|
||||
deploy:staging:
|
||||
stage: deploy
|
||||
script:
|
||||
- kubectl apply -f k8s/staging/
|
||||
environment:
|
||||
name: staging
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
|
||||
deploy:production:
|
||||
stage: deploy
|
||||
script:
|
||||
- kubectl apply -f k8s/production/
|
||||
environment:
|
||||
name: production
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
when: manual
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Pipeline Design Principles
|
||||
|
||||
1. **Fail Fast** - Run quick checks (lint, type check) before slow ones (tests)
|
||||
2. **Parallelize** - Run independent jobs concurrently
|
||||
3. **Cache** - Cache dependencies between runs
|
||||
4. **Change Detection** - Only run what's affected
|
||||
5. **Immutable Artifacts** - Tag images with commit SHA
|
||||
6. **Environment Parity** - Same process for all environments
|
||||
7. **Secrets Management** - Never hardcode, use CI/CD secrets
|
||||
|
||||
### Quality Gates
|
||||
|
||||
```yaml
|
||||
# Minimum checks before merge
|
||||
- Lint passes
|
||||
- Type check passes
|
||||
- Unit tests pass
|
||||
- Coverage threshold met (80%+)
|
||||
- Security scan passes
|
||||
- No secrets detected
|
||||
```
|
||||
|
||||
### Deployment Strategies
|
||||
|
||||
```yaml
|
||||
# Rolling update (default)
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
|
||||
# Blue-green (via service switch)
|
||||
# Deploy new version alongside old
|
||||
# Switch service selector when ready
|
||||
|
||||
# Canary (gradual rollout)
|
||||
# Route percentage of traffic to new version
|
||||
# Monitor metrics before full rollout
|
||||
```
|
||||
Reference in New Issue
Block a user