CI/CD Guide
This document describes the continuous integration and continuous deployment workflows for the MCP server and Natural Language Agents.
Overview
The project uses GitHub Actions for automated building, testing, and quality assurance.
Workflows
Build Workflow
File: .github/workflows/build.yml
Triggers:
- Push to any branch
- Pull requests
Steps:
- Checkout code
- Set up Go (versions 1.21, 1.22, 1.23)
- Download dependencies
- Build binary
- Verify binary works
Test Workflow
File: .github/workflows/test.yml
Triggers:
- Push to any branch
- Pull requests
Matrix Testing:
- Go versions: 1.21, 1.22, 1.23
- PostgreSQL versions: 14, 15, 16, 17
Steps:
- Start PostgreSQL service
- Set up Go
- Run unit tests
- Run integration tests
- Run linting (golangci-lint)
- Generate coverage report
- Upload coverage to Codecov (optional)
Test Matrix
Go Versions
| Version | Status | Notes |
|---|---|---|
| 1.21 | Supported | Minimum required version |
| 1.22 | Supported | Recommended |
| 1.23 | Supported | Latest |
PostgreSQL Versions
| Version | Status | Notes |
|---|---|---|
| 14 | Supported | |
| 15 | Supported | |
| 16 | Supported | Recommended |
| 17 | Supported | Latest |
| 13 and earlier | Best effort | Some features may not work |
Running Tests Locally
All Tests
# Run all tests
go test ./...
# With verbose output
go test -v ./...
# With coverage
go test -v -cover ./...
# With race detection
go test -v -race ./...
Specific Test Suites
# Unit tests only
go test ./internal/...
# Integration tests only
go test ./test/...
# Specific package
go test ./internal/auth/...
# Specific test
go test -v -run TestAuthTokenGeneration ./internal/auth/...
Linting
The project uses golangci-lint v1.x (NOT v2). The configuration file .golangci.yml is designed for v1.
Installation
# Install latest v1.x version
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Verify installation
golangci-lint version
# Should show: golangci-lint has version v1.x.x
The linter will be installed to $(go env GOPATH)/bin/golangci-lint.
Running Linter
# Using Makefile (recommended - handles GOPATH/bin automatically)
make lint
# Direct invocation (if in PATH)
golangci-lint run
# Using full path
$(go env GOPATH)/bin/golangci-lint run
# Auto-fix issues
golangci-lint run --fix
Linter Configuration
The .golangci.yml configuration:
- Enabled linters: errcheck, govet, ineffassign, staticcheck, unused, misspell, gocritic
- Disabled checks: Style checks that are too strict (octalLiteral, httpNoBody, paramTypeCombine, etc.)
- Test file exclusions: Test files skip errcheck and gocritic checks for better readability
Version Note
⚠️ Important: The project uses golangci-lint v1.x, not v2. If you have v2 installed, you'll see an error:
Error: you are using a configuration file for golangci-lint v2 with golangci-lint v1
To fix this, install v1.x using the command above.
Test Coverage
Viewing Coverage
# Generate coverage report
go test -coverprofile=coverage.out ./...
# View in terminal
go tool cover -func=coverage.out
# Generate HTML report
go tool cover -html=coverage.out -o coverage.html
# Open in browser
open coverage.html # macOS
xdg-open coverage.html # Linux
Coverage Targets
| Component | Target | Current |
|---|---|---|
| Overall | >80% | Check CI |
| Authentication | >90% | Check CI |
| Database | >85% | Check CI |
| MCP Protocol | >85% | Check CI |
| Tools | >80% | Check CI |
| Resources | >80% | Check CI |
Integration Testing
Prerequisites
Integration tests require:
- PostgreSQL running locally or via environment
- Connection string in
TEST_PGEDGE_POSTGRES_CONNECTION_STRING - Optional: Anthropic API key in
TEST_ANTHROPIC_API_KEY
Running Integration Tests
# With default PostgreSQL
export TEST_PGEDGE_POSTGRES_CONNECTION_STRING="postgres://localhost/postgres?sslmode=disable"
go test ./test/...
# With custom PostgreSQL
export TEST_PGEDGE_POSTGRES_CONNECTION_STRING="postgres://user:pass@host/db"
export TEST_ANTHROPIC_API_KEY="sk-ant-your-key"
go test ./test/...
# Run specific integration test
go test -v -run TestMCPServerIntegration ./test/...
Integration Test Coverage
Tests cover:
- MCP Protocol: Initialize, tools/list, resources/list
- HTTP Mode: Server startup, endpoints, authentication
- HTTPS Mode: TLS certificate handling, secure connections
- Authentication: Token validation, expiry, authorization
- Tools: All ten tools with various inputs
- Resources: All nine resources
- Error Handling: Invalid requests, missing data, timeouts
- Multi-Database: Connection switching, temporary queries
CI Environment Variables
Required
None - tests run with default settings
Optional
env:
TEST_PGEDGE_POSTGRES_CONNECTION_STRING: postgres://postgres:postgres@localhost/test
TEST_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
GitHub Actions Configuration
Build Workflow Example
name: Build
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
build:
name: Build
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.21', '1.22', '1.23']
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Build
run: go build -v -o pgedge-postgres-mcp ./cmd/pgedge-pg-mcp-svr
- name: Verify binary
run: ./pgedge-postgres-mcp -h
Test Workflow Example
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.21', '1.22', '1.23']
postgres-version: ['14', '15', '16', '17']
services:
postgres:
image: postgres:${{ matrix.postgres-version }}
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Run tests
env:
TEST_PGEDGE_POSTGRES_CONNECTION_STRING: postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable
run: go test -v -cover ./...
- name: Run lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
Pre-Commit Hooks
Setup
# Install pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
set -e
echo "Running tests..."
go test ./...
echo "Running linter..."
# Try PATH first, then GOPATH/bin
if command -v golangci-lint >/dev/null 2>&1; then
golangci-lint run
elif [ -f "$(go env GOPATH)/bin/golangci-lint" ]; then
$(go env GOPATH)/bin/golangci-lint run
else
echo "Warning: golangci-lint not found, skipping linter"
fi
echo "All checks passed!"
EOF
chmod +x .git/hooks/pre-commit
Skip Hook (When Needed)
git commit --no-verify
Release Process
Manual Release
-
Update version:
# Update version in code vim cmd/pgedge-pg-mcp-svr/main.go # Commit git commit -am "Bump version to X.Y.Z" -
Tag release:
git tag -a vX.Y.Z -m "Release version X.Y.Z" git push origin vX.Y.Z -
Build binaries:
# Build for multiple platforms GOOS=linux GOARCH=amd64 go build -o bin/pgedge-postgres-mcp-linux-amd64 ./cmd/pgedge-pg-mcp-svr GOOS=darwin GOARCH=amd64 go build -o bin/pgedge-postgres-mcp-darwin-amd64 ./cmd/pgedge-pg-mcp-svr GOOS=darwin GOARCH=arm64 go build -o bin/pgedge-postgres-mcp-darwin-arm64 ./cmd/pgedge-pg-mcp-svr GOOS=windows GOARCH=amd64 go build -o bin/pgedge-postgres-mcp-windows-amd64.exe ./cmd/pgedge-pg-mcp-svr -
Create GitHub release:
- Go to GitHub Releases
- Create new release from tag
- Upload binaries
- Add release notes
Automated Release (Future)
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.23'
- name: Build binaries
run: |
GOOS=linux GOARCH=amd64 go build -o bin/pgedge-postgres-mcp-linux-amd64 ./cmd/pgedge-pg-mcp-svr
GOOS=darwin GOARCH=amd64 go build -o bin/pgedge-postgres-mcp-darwin-amd64 ./cmd/pgedge-pg-mcp-svr
GOOS=darwin GOARCH=arm64 go build -o bin/pgedge-postgres-mcp-darwin-arm64 ./cmd/pgedge-pg-mcp-svr
GOOS=windows GOARCH=amd64 go build -o bin/pgedge-postgres-mcp-windows-amd64.exe ./cmd/pgedge-pg-mcp-svr
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: bin/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Continuous Deployment
Docker Hub (Future)
# .github/workflows/docker.yml
name: Docker
on:
push:
branches: [ main ]
tags: [ 'v*' ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: pgedge/postgres-mcp
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
push: true
tags: ${{ steps.meta.outputs.tags }}
Monitoring CI/CD
Build Status
Check build status:
- GitHub Actions tab
- README badges
- Branch protection rules
Test Failures
When tests fail:
-
Check CI logs:
- Go to Actions tab
- Click on failed workflow
- Examine step logs
-
Reproduce locally:
# Use same Go version
go test -v ./...
# Use same PostgreSQL version
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:16
export TEST_PGEDGE_POSTGRES_CONNECTION_STRING="postgres://postgres:postgres@localhost/postgres"
go test -v ./test/...
- Debug:
# Run specific test with debug output
go test -v -run TestFailingTest ./package/...
# Add debug logging in code
log.Printf("Debug: %+v", value)
Best Practices
For Contributors
-
Run tests before committing:
go test ./... golangci-lint run -
Write tests for new code:
- Unit tests for business logic
- Integration tests for API endpoints
- Table-driven tests for multiple scenarios
-
Keep builds fast:
- Mock external dependencies
- Use parallel tests where possible
- Skip slow tests in pre-commit hooks
-
Update CI config when:
- Adding new dependencies
- Changing build process
- Adding new test suites
For Maintainers
- Review CI failures promptly
- Keep dependencies updated
- Monitor test performance
- Update Go versions as released
- Maintain test coverage above targets
Troubleshooting CI/CD
Build Failures
# Dependency issues
go mod tidy
go mod verify
# Cache issues (clear locally)
go clean -cache
rm -rf ~/go/pkg/mod
# Version mismatch
go mod edit -go=1.21
go mod tidy
Test Failures
# Timing issues
# Increase timeouts in tests
# Database connection
# Check PostgreSQL service in CI config
# Random failures
# Add retries for flaky tests
# Investigate race conditions
Lint Failures
Version Mismatch Error
Error: you are using a configuration file for golangci-lint v2 with golangci-lint v1
Solution: Install golangci-lint v1.x:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
Check Linter Locally
# Using Makefile
make lint
# Direct invocation
golangci-lint run
# Using full path
$(go env GOPATH)/bin/golangci-lint run
# Auto-fix issues
golangci-lint run --fix
Update Linter Config
If you need to adjust linting rules:
# Edit config
vim .golangci.yml
# Disable specific checks in gocritic section:
# disabled-checks:
# - checkName
# Exclude specific paths or linters in issues section:
# exclude-rules:
# - path: _test\.go
# linters: [errcheck]
Related Documentation
- Testing Guide - Detailed testing procedures
- Architecture Guide - Code structure and organization
- Troubleshooting Guide - Common issues and solutions