Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 100 additions & 188 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,264 +1,176 @@
---
name: CI/CD Pipeline

"on":
on:
push:
branches: [main, feature/*]
branches: [ main, develop, production-ready-implementation ]
pull_request:
branches: [main]

env:
GO_VERSION: 1.24
branches: [ main, develop ]

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'

- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
args: --timeout=5m

security:
name: Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'

- name: Run Gosec Security Scanner
uses: securego/gosec@master
with:
args: '-no-fail -fmt sarif -out results.sarif ./...'

- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif

test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ["1.23", "1.24"]

go-version: ['1.24']
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}

- name: Cache Go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-

- name: Download dependencies
run: go mod download

- name: Verify dependencies
run: go mod verify

- name: Run tests
run: go test -v -race -coverprofile=coverage.out ./...
run: go test -v -race -coverprofile=coverage.out -covermode=atomic ./internal/...

- name: Upload coverage to Codecov
if: matrix.go-version == '1.24'
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
file: ./coverage.out
files: ./coverage.out
flags: unittests
name: codecov-umbrella
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false

lint:
name: Lint
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}

- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.64.8
args: --timeout=5m
- name: Check coverage threshold
run: |
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
echo "Total coverage: ${COVERAGE}%"
if (( $(echo "${COVERAGE} < 80" | bc -l) )); then
echo "ERROR: Coverage ${COVERAGE}% is below 80%"
exit 1
fi

build:
name: Build
runs-on: ubuntu-latest
needs: [test, lint]

needs: [lint, test]
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}

- name: Cache Go modules
uses: actions/cache@v4
uses: actions/setup-go@v5
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
go-version: '1.24'

- name: Build binary
- name: Build
run: make build

- name: Upload build artifacts
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: mcp-compose-binary
name: mcp-compose-${{ github.sha }}
path: build/mcp-compose


docker:
name: Docker Build
name: Build Docker Image
runs-on: ubuntu-latest
needs: [test, lint]

needs: [lint, test, build]
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker images
run: |
docker build -f Dockerfile.proxy -t mcp-compose-proxy:latest .
docker build -f Dockerfile.stdio-bridge \
-t mcp-compose-stdio-bridge:latest .

- name: Test Docker images
run: |
# Test that the images can be created and run (basic smoke test)
docker run --rm --entrypoint="/bin/sh" mcp-compose-proxy:latest \
-c "echo 'Proxy image OK'"
docker run --rm --entrypoint="python" \
mcp-compose-stdio-bridge:latest -c "print('STDIO bridge image OK')"

integration:
name: Integration Tests
runs-on: ubuntu-latest
needs: [build]

services:
postgres:
image: postgres:13
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
- name: Log in to Docker Hub
if: github.ref == 'refs/heads/main'
uses: docker/login-action@v3
with:
go-version: ${{ env.GO_VERSION }}

- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: mcp-compose-binary
path: build/

- name: Make binary executable
run: chmod +x build/mcp-compose
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Run integration tests
env:
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
MCP_API_KEY: test-integration-key
run: |
# Test basic functionality
echo "Testing version command..."
./build/mcp-compose --version

echo "Testing config validation..."
./build/mcp-compose validate mcp-compose-quickstart.yaml

echo "Testing basic config validation..."
./build/mcp-compose validate mcp-compose-basic.yaml

# Basic integration test (start and stop quickly)
echo "Testing basic startup and shutdown..."
timeout 10s ./build/mcp-compose up \
--config mcp-compose-quickstart.yaml --dry-run || \
echo "Dry run completed"

echo "Integration tests completed successfully"

performance:
name: Performance Tests
runs-on: ubuntu-latest
needs: [build]

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v4
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
go-version: ${{ env.GO_VERSION }}

- name: Download build artifacts
uses: actions/download-artifact@v4
images: |
phildougherty/mcp-compose
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha

- name: Build and push
uses: docker/build-push-action@v6
with:
name: mcp-compose-binary
path: build/

- name: Make binary executable
run: chmod +x build/mcp-compose

- name: Run performance benchmarks
run: |
# Check if benchmark tests exist before running them
if grep -r "^func Benchmark" ./internal/; then
go test -bench=. -benchmem ./internal/protocol/ || \
echo "No benchmarks in protocol"
go test -bench=. -benchmem ./internal/server/ || \
echo "No benchmarks in server"
go test -bench=. -benchmem ./internal/config/ || \
echo "No benchmarks in config"
else
echo "No benchmark tests found - skipping performance tests"
fi
context: .
push: ${{ github.ref == 'refs/heads/main' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

release:
name: Release
name: Create Release
runs-on: ubuntu-latest
needs: [test, lint, build, docker, integration]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'

needs: [lint, test, build, docker]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
go-version: '1.24'

- name: Download build artifacts
uses: actions/download-artifact@v4
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
name: mcp-compose-binary
path: build/

- name: Create release
if: contains(github.event.head_commit.message, '[release]')
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Generate release notes
VERSION=$(date +%Y.%m.%d)
echo "Creating release version $VERSION"

# Create GitHub release
gh release create "v$VERSION" \
--title "Release v$VERSION" \
--notes "Automated release from CI/CD pipeline" \
build/mcp-compose
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ client-config/ # Client configuration examples

## Security Requirements

鈿狅笍 **CRITICAL**: This project handles sensitive credentials and API keys. Follow these security practices:
**CRITICAL**: This project handles sensitive credentials and API keys. Follow these security practices:

### Environment Variables
Always use environment variables for sensitive data:
Expand Down
Loading
Loading