name: Test and Quality Checks
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
schedule:
# Run tests every day at 2 AM UTC
- cron: '0 2 * * *'
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup 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: Run linting
run: |
if [ -f "package.json" ] && npm run lint --if-present; then
echo "Linting passed"
else
echo "No linting configuration found"
fi
- name: Build TypeScript
run: npm run build
- name: Run tests
run: |
if [ -f "package.json" ] && npm test --if-present; then
echo "Tests passed"
else
echo "No tests configured - creating basic validation"
node -e "
const fs = require('fs');
const path = require('path');
// Check if build was successful
if (!fs.existsSync('build/index.js')) {
console.error('Build failed - index.js not found');
process.exit(1);
}
// Check if all TypeScript files were compiled
const srcFiles = fs.readdirSync('src').filter(f => f.endsWith('.ts'));
const buildFiles = fs.readdirSync('build').filter(f => f.endsWith('.js'));
console.log('Source files:', srcFiles.length);
console.log('Built files:', buildFiles.length);
if (buildFiles.length === 0) {
console.error('No JavaScript files found in build directory');
process.exit(1);
}
console.log('✅ Basic validation passed');
"
fi
- name: Test Docker build
run: |
docker build -t fabric-analytics-mcp:test .
echo "✅ Docker build successful"
- name: Test health endpoints
run: |
# Start the container in background
docker run -d --name test-container -p 3001:3000 \
-e NODE_ENV=test \
-e ENABLE_HEALTH_SERVER=true \
fabric-analytics-mcp:test
# Wait for container to start
sleep 10
# Test health endpoints
curl -f http://localhost:3001/health || {
echo "Health check failed"
docker logs test-container
exit 1
}
curl -f http://localhost:3001/ready || {
echo "Readiness check failed"
docker logs test-container
exit 1
}
curl -f http://localhost:3001/metrics || {
echo "Metrics endpoint failed"
docker logs test-container
exit 1
}
echo "✅ All health endpoints working"
# Cleanup
docker stop test-container
docker rm test-container
code-quality:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Check code formatting
run: |
if [ -f ".prettierrc" ] || npm run format:check --if-present; then
echo "Code formatting check passed"
else
echo "No code formatting configuration found"
fi
- name: Type checking
run: |
npx tsc --noEmit || {
echo "TypeScript type checking failed"
exit 1
}
echo "✅ TypeScript type checking passed"
- name: Check for security vulnerabilities
run: |
npm audit --audit-level=high || {
echo "Security vulnerabilities found"
npm audit
exit 1
}
echo "✅ No high-level security vulnerabilities found"
- name: License compliance check
run: |
# Check if LICENSE file exists
if [ ! -f "LICENSE" ]; then
echo "❌ LICENSE file not found"
exit 1
fi
# Check if package.json has license field
if ! grep -q '"license"' package.json; then
echo "❌ License not specified in package.json"
exit 1
fi
echo "✅ License compliance check passed"
dependency-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: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Check for outdated dependencies
run: |
npm outdated || echo "Some dependencies may be outdated"
echo "✅ Dependency check completed"
- name: Check bundle size
run: |
npm run build
# Check if build directory size is reasonable
BUILD_SIZE=$(du -sh build | cut -f1)
echo "Build size: $BUILD_SIZE"
# Count number of files
FILE_COUNT=$(find build -type f | wc -l)
echo "Number of built files: $FILE_COUNT"
if [ "$FILE_COUNT" -eq 0 ]; then
echo "❌ No files in build directory"
exit 1
fi
echo "✅ Build size check passed"
documentation-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check documentation completeness
run: |
# Check for required documentation files
REQUIRED_FILES=("README.md" "CONTRIBUTING.md" "SECURITY.md" "LICENSE")
for file in "${REQUIRED_FILES[@]}"; do
if [ ! -f "$file" ]; then
echo "❌ Required file missing: $file"
exit 1
else
echo "✅ Found: $file"
fi
done
# Check if README has basic sections
if ! grep -q "Installation" README.md; then
echo "❌ README.md missing Installation section"
exit 1
fi
if ! grep -q "Usage" README.md || ! grep -q "Example" README.md; then
echo "❌ README.md missing Usage or Examples section"
exit 1
fi
echo "✅ Documentation completeness check passed"
- name: Check links in documentation
run: |
# Simple check for broken internal links in README
if grep -o '\[.*\](\..*\.md)' README.md | while read link; do
file=$(echo "$link" | sed 's/.*](\.\///;s/)//')
if [ ! -f "$file" ]; then
echo "❌ Broken link in README.md: $file"
exit 1
fi
done; then
echo "✅ Internal links check passed"
fi
integration-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: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Start services with Docker Compose
run: |
# Check if Docker Compose V2 is available, fallback to V1 if needed
if command -v docker &> /dev/null; then
if docker compose version &> /dev/null; then
echo "Using Docker Compose V2"
DOCKER_COMPOSE_CMD="docker compose"
elif command -v docker-compose &> /dev/null; then
echo "Using Docker Compose V1"
DOCKER_COMPOSE_CMD="docker-compose"
else
echo "Installing Docker Compose V1 as fallback"
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
DOCKER_COMPOSE_CMD="docker-compose"
fi
else
echo "Docker not available"
exit 1
fi
# Start only the main service for testing
${DOCKER_COMPOSE_CMD} up -d fabric-mcp
# Wait for service to be ready
timeout 60 bash -c 'until curl -f http://localhost:3000/health; do sleep 2; done'
echo "✅ Service started successfully"
- name: Run integration tests
run: |
# Test all health endpoints
curl -f http://localhost:3000/health
curl -f http://localhost:3000/ready
curl -f http://localhost:3000/metrics
# Test MCP server basic functionality
if [ -f "scripts/validate-deployment.sh" ]; then
chmod +x scripts/validate-deployment.sh
./scripts/validate-deployment.sh --url http://localhost:3000 --skip-auth
fi
echo "✅ Integration tests passed"
- name: Cleanup
if: always()
run: |
# Use the same Docker Compose command detection
if docker compose version &> /dev/null; then
DOCKER_COMPOSE_CMD="docker compose"
elif command -v docker-compose &> /dev/null; then
DOCKER_COMPOSE_CMD="docker-compose"
else
echo "Docker Compose not available for cleanup"
exit 0
fi
${DOCKER_COMPOSE_CMD} down -v
docker system prune -f