mirror of
https://github.com/claude-did-this/claude-hub.git
synced 2026-02-14 19:30:02 +01:00
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>
304 lines
8.6 KiB
YAML
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 |