Files
claude-hub/.github/workflows/ci.yml
Jonathan cb1329d512 fix: add pre-checkout workspace cleanup for coverage permission issues
Add explicit workspace cleanup step before checkout to handle coverage
directories with restrictive permissions that prevent GitHub Actions cleanup.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-05-31 12:58:24 -05:00

304 lines
8.6 KiB
YAML

name: CI Pipeline
on:
push:
branches: [ main ]
env:
NODE_VERSION: '20'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Lint job - fast and independent
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: 'package-lock.json'
- name: Install dependencies
run: npm ci --prefer-offline --no-audit
- name: Run linter
run: npm run lint:check || echo "No lint script found, skipping"
- name: Check formatting
run: npm run format:check || echo "No format script found, skipping"
# Unit tests - fastest test suite
test-unit:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: 'package-lock.json'
- name: Install dependencies
run: npm ci --prefer-offline --no-audit
- name: Run unit tests
run: npm run test:unit
env:
NODE_ENV: test
BOT_USERNAME: '@TestBot'
GITHUB_WEBHOOK_SECRET: 'test-secret'
GITHUB_TOKEN: 'test-token'
# Integration tests - moderate complexity
test-integration:
name: Integration Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: 'package-lock.json'
- name: Install dependencies
run: npm ci --prefer-offline --no-audit
- name: Run integration tests
run: npm run test:integration || echo "No integration tests found, skipping"
env:
NODE_ENV: test
BOT_USERNAME: '@TestBot'
GITHUB_WEBHOOK_SECRET: 'test-secret'
GITHUB_TOKEN: 'test-token'
# Coverage generation - depends on unit tests
coverage:
name: Test Coverage
runs-on: ubuntu-latest
needs: [test-unit]
steps:
- name: Clean workspace
run: |
# Fix any existing coverage file permissions before checkout
sudo find . -name "coverage" -type d -exec chmod -R 755 {} \; 2>/dev/null || true
sudo rm -rf coverage 2>/dev/null || true
- name: Checkout code
uses: actions/checkout@v4
with:
clean: true
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: 'package-lock.json'
- name: Install dependencies
run: npm ci --prefer-offline --no-audit
- name: Generate test coverage
run: npm run test:ci
env:
NODE_ENV: test
BOT_USERNAME: '@TestBot'
GITHUB_WEBHOOK_SECRET: 'test-secret'
GITHUB_TOKEN: 'test-token'
- name: Fix coverage file permissions
run: |
# Fix permissions on coverage files that may be created with restricted access
find coverage -type f -exec chmod 644 {} \; 2>/dev/null || true
find coverage -type d -exec chmod 755 {} \; 2>/dev/null || true
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: intelligence-assist/claude-hub
# Security scans - run on GitHub for faster execution
security:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: 'package-lock.json'
- name: Install dependencies
run: npm ci --prefer-offline --no-audit
- name: Run npm audit
run: npm audit --audit-level=moderate
- name: Run security scan with Snyk
uses: snyk/actions/node@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
# Check if Docker-related files changed
changes:
name: Detect Changes
runs-on: ubuntu-latest
outputs:
docker: ${{ steps.changes.outputs.docker }}
src: ${{ steps.changes.outputs.src }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
docker:
- 'Dockerfile*'
- 'scripts/**'
- '.dockerignore'
- 'claude-config*'
src:
- 'src/**'
- 'package*.json'
# Docker builds - only when relevant files change
docker:
name: Docker Build & Test
runs-on: ubuntu-latest
# Only run on main branch or version tags, not on PRs
if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && github.event_name != 'pull_request' && (needs.changes.outputs.docker == 'true' || needs.changes.outputs.src == 'true')
# Only need unit tests to pass for Docker builds
needs: [test-unit, lint, changes]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Start build profiling
run: |
echo "BUILD_START_TIME=$(date +%s)" >> $GITHUB_ENV
echo "🏗️ Docker build started at $(date)"
- name: Set up Docker layer caching
run: |
# Create cache mount directories
mkdir -p /tmp/.buildx-cache-main /tmp/.buildx-cache-claude
- name: Build main Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: false
load: true
tags: claude-github-webhook:test
cache-from: |
type=gha,scope=main
type=local,src=/tmp/.buildx-cache-main
cache-to: |
type=gha,mode=max,scope=main
type=local,dest=/tmp/.buildx-cache-main-new,mode=max
platforms: linux/amd64
build-args: |
BUILDKIT_INLINE_CACHE=1
- name: Build Claude Code Docker image (parallel)
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile.claudecode
push: false
load: true
tags: claude-code-runner:test
cache-from: |
type=gha,scope=claudecode
type=local,src=/tmp/.buildx-cache-claude
cache-to: |
type=gha,mode=max,scope=claudecode
type=local,dest=/tmp/.buildx-cache-claude-new,mode=max
platforms: linux/amd64
build-args: |
BUILDKIT_INLINE_CACHE=1
- name: Rotate build caches
run: |
# Rotate caches to avoid size limits
rm -rf /tmp/.buildx-cache-main /tmp/.buildx-cache-claude
mv /tmp/.buildx-cache-main-new /tmp/.buildx-cache-main 2>/dev/null || true
mv /tmp/.buildx-cache-claude-new /tmp/.buildx-cache-claude 2>/dev/null || true
- name: Profile build performance
run: |
BUILD_END_TIME=$(date +%s)
BUILD_DURATION=$((BUILD_END_TIME - BUILD_START_TIME))
echo "🏁 Docker build completed at $(date)"
echo "⏱️ Total build time: ${BUILD_DURATION} seconds"
# Check image sizes
echo "📦 Image sizes:"
docker images | grep -E "(claude-github-webhook|claude-code-runner):test" || true
# Show cache usage
echo "💾 Cache statistics:"
du -sh /tmp/.buildx-cache-* 2>/dev/null || echo "No local caches found"
# Performance summary
if [ $BUILD_DURATION -lt 120 ]; then
echo "✅ Fast build (< 2 minutes)"
elif [ $BUILD_DURATION -lt 300 ]; then
echo "⚠️ Moderate build (2-5 minutes)"
else
echo "🐌 Slow build (> 5 minutes) - consider optimization"
fi
- name: Test Docker containers
run: |
# Test main container starts correctly
docker run --name test-webhook -d -p 3003:3002 \
-e NODE_ENV=test \
-e BOT_USERNAME=@TestBot \
-e GITHUB_WEBHOOK_SECRET=test-secret \
-e GITHUB_TOKEN=test-token \
claude-github-webhook:test
# Wait for container to start
sleep 10
# Test health endpoint
curl -f http://localhost:3003/health || exit 1
# Cleanup
docker stop test-webhook
docker rm test-webhook