name: Enhanced AGR MCP Server CI/CD
on:
push:
branches: [ main, develop ]
tags: [ 'v*' ]
pull_request:
branches: [ main, develop ]
schedule:
# Run nightly at 2 AM UTC
- cron: '0 2 * * *'
env:
NODE_VERSION: '20'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Code Quality and Testing
quality:
name: Code Quality & Testing
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 21]
fail-fast: false
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- 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 ESLint
run: npm run lint
- name: Check code formatting
run: npm run format -- --check
- name: Run type checking (if TypeScript)
run: npm run type-check || echo "No TypeScript checking configured"
continue-on-error: true
- name: Run tests
run: npm run test:coverage
env:
CI: true
NODE_ENV: test
LOG_LEVEL: silent
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
flags: unittests
name: node-${{ matrix.node-version }}
fail_ci_if_error: false
- name: Run security audit
run: npm audit --audit-level high
continue-on-error: true
- name: Cache test results
uses: actions/cache@v3
with:
path: |
coverage/
test-results/
key: test-results-${{ runner.os }}-node${{ matrix.node-version }}-${{ github.sha }}
# Performance Testing
performance:
name: Performance Testing
runs-on: ubuntu-latest
needs: quality
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'
- name: Install dependencies
run: npm ci
- name: Run health check
run: npm run health-check
timeout-minutes: 2
- name: Run performance benchmark
run: timeout 300 npm run benchmark || echo "Benchmark completed"
timeout-minutes: 6
- name: Upload benchmark results
uses: actions/upload-artifact@v3
with:
name: benchmark-results
path: benchmark-results/
if: always()
# Security Scanning
security:
name: Security Scanning
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'
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --audit-level moderate
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
continue-on-error: true
- name: Run CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
languages: javascript
continue-on-error: true
# Build and Docker
build:
name: Build & Docker
runs-on: ubuntu-latest
needs: [quality, performance]
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Container Registry
if: github.event_name != 'pull_request'
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=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,prefix={{branch}}-
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ github.ref_name }}
BUILD_DATE=${{ github.run_number }}
- name: Test Docker image
run: |
docker run --rm -d --name test-container -p 3000:3000 ${{ steps.meta.outputs.tags }}
sleep 10
# Add health check here if available
docker stop test-container
# Integration Testing
integration:
name: Integration Testing
runs-on: ubuntu-latest
needs: build
if: github.event_name != 'pull_request'
services:
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
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'
- name: Install dependencies
run: npm ci
- name: Run integration tests
run: npm run test:integration || echo "No integration tests configured"
env:
CI: true
NODE_ENV: test
REDIS_URL: redis://localhost:6379
RUN_INTEGRATION_TESTS: true
continue-on-error: true
- name: Test with docker-compose
run: |
docker-compose -f docker-compose.yml up -d
sleep 30
# Add API health check
docker-compose logs
docker-compose down
# Deployment
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
needs: [build, integration, security]
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
environment: staging
steps:
- name: Deploy to staging
run: |
echo "๐ Deploying to staging environment..."
echo "Image: ${{ needs.build.outputs.image-tag }}"
echo "Digest: ${{ needs.build.outputs.image-digest }}"
# Add actual deployment commands here
- name: Run smoke tests
run: |
echo "๐งช Running smoke tests on staging..."
# Add smoke tests here
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [build, integration, security]
if: startsWith(github.ref, 'refs/tags/v')
environment: production
steps:
- name: Deploy to production
run: |
echo "๐ Deploying to production environment..."
echo "Version: ${{ github.ref_name }}"
echo "Image: ${{ needs.build.outputs.image-tag }}"
# Add actual production deployment commands here
- name: Run production health check
run: |
echo "๐ฅ Running production health check..."
# Add production health check
# Release
release:
name: Create Release
runs-on: ubuntu-latest
needs: [deploy-production]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate changelog
id: changelog
run: |
# Generate changelog from commits
echo "changelog<<EOF" >> $GITHUB_OUTPUT
git log --pretty=format:"- %s (%h)" $(git describe --tags --abbrev=0 HEAD^)..HEAD >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref_name }}
release_name: Enhanced AGR MCP Server ${{ github.ref_name }}
body: |
## Changes in ${{ github.ref_name }}
${{ steps.changelog.outputs.changelog }}
## Docker Image
```
docker pull ${{ needs.build.outputs.image-tag }}
```
## Quick Start
```bash
git clone https://github.com/${{ github.repository }}
cd agr-mcp-server-js
./setup.sh
npm start
```
draft: false
prerelease: contains(github.ref_name, '-')
# Notification
notify:
name: Notify
runs-on: ubuntu-latest
needs: [quality, performance, security, build]
if: always()
steps:
- name: Notify on success
if: needs.quality.result == 'success' && needs.performance.result == 'success'
run: |
echo "โ
Pipeline completed successfully!"
echo "Quality: ${{ needs.quality.result }}"
echo "Performance: ${{ needs.performance.result }}"
echo "Security: ${{ needs.security.result }}"
echo "Build: ${{ needs.build.result }}"
- name: Notify on failure
if: contains(needs.*.result, 'failure')
run: |
echo "โ Pipeline failed!"
echo "Quality: ${{ needs.quality.result }}"
echo "Performance: ${{ needs.performance.result }}"
echo "Security: ${{ needs.security.result }}"
echo "Build: ${{ needs.build.result }}"
# Workflow permissions
permissions:
contents: read
packages: write
security-events: write
actions: read