Provider GitHub Actions Integration
Integrating Entente provider testing into GitHub Actions ensures your API implementations are verified against real consumer interactions before deployment.
Complete Provider Workflow
Section titled “Complete Provider Workflow”Here’s the complete GitHub Actions setup from the castle-service example, covering build, test, and deployment:
Build & Test Workflow
Section titled “Build & Test Workflow”name: Castle Service - Build & Test
on: push: branches: [main] paths: - 'examples/castle-service/**' - '.github/workflows/castle-service-build-test.yml' pull_request: branches: [main] paths: - 'examples/castle-service/**' - '.github/workflows/castle-service-build-test.yml' workflow_dispatch:
jobs: build-and-test: runs-on: ubuntu-latest
steps: - name: Checkout uses: actions/checkout@v4
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20'
- name: Setup pnpm uses: pnpm/action-setup@v4
# Install published Entente packages (not local workspace packages) - name: Install published Entente packages working-directory: examples/castle-service run: pnpm add @entente/types@latest @entente/provider@latest @entente/fixtures@latest
- name: Install dependencies working-directory: examples/castle-service run: pnpm install
- name: Install Entente CLI globally run: npm install -g @entente/cli@latest
- name: Build castle-service env: ENTENTE_SERVICE_URL: ${{ vars.ENTENTE_SERVICE_URL }} ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: pnpm --filter @entente/example-castle-service build
# Register service with Entente (idempotent operation) - name: Register service with Entente env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service entente register-service \ --type provider \ --service castle-service \ --spec spec/openapi.json \ --spec-version 0.1.0 \ --environment development
# Run provider verification tests - name: Run provider verification tests env: ENTENTE_SERVICE_URL: ${{ vars.ENTENTE_SERVICE_URL }} ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: pnpm --filter @entente/example-castle-service testDeployment Workflow
Section titled “Deployment Workflow”name: Castle Service - Deploy
on: workflow_run: workflows: ["Castle Service - Build & Test"] types: - completed branches: [main] workflow_dispatch: inputs: environment: description: 'Environment to deploy to' required: true default: 'development' type: choice options: - development - staging - production
jobs: deploy-development: if: (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch') runs-on: ubuntu-latest environment: development
steps: - name: Checkout uses: actions/checkout@v4
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20'
- name: Setup pnpm uses: pnpm/action-setup@v4
- name: Install published Entente packages working-directory: examples/castle-service run: pnpm add @entente/types@latest @entente/provider@latest @entente/fixtures@latest
- name: Install dependencies working-directory: examples/castle-service run: pnpm install
- name: Install Entente CLI globally run: npm install -g @entente/cli@latest
- name: Build castle-service env: ENTENTE_SERVICE_URL: ${{ vars.ENTENTE_SERVICE_URL }} ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: pnpm --filter @entente/example-castle-service build
# Upload OpenAPI spec for this version - name: Upload OpenAPI spec env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") entente upload-spec \ --service castle-service \ --version $VERSION \ --environment development \ --spec spec/openapi.json
# Check if it's safe to deploy - name: Check deployment readiness env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") entente can-i-deploy \ --type provider \ --service castle-service \ --version $VERSION \ --environment development
# Deploy to Cloudflare Workers - name: Deploy to Cloudflare Workers (Development) uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} workingDirectory: examples/castle-service command: deploy --name castle-service-dev --env development env: ENVIRONMENT: development
# Record the deployment in Entente - name: Record deployment env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") entente deploy-service \ --service castle-service \ --version $VERSION \ --environment development \ --type provider
# Run smoke tests - name: Run smoke tests run: | sleep 10 curl -f https://castle-service-dev.${{ vars.CLOUDFLARE_WORKERS_SUBDOMAIN }}.workers.dev/health || exit 1
deploy-staging: if: needs.deploy-development.result == 'success' needs: [deploy-development] runs-on: ubuntu-latest environment: staging
steps: # ... similar steps for staging environment - name: Check deployment readiness env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") entente can-i-deploy \ --type provider \ --service castle-service \ --version $VERSION \ --environment staging
deploy-production: if: needs.deploy-staging.result == 'success' needs: [deploy-staging] runs-on: ubuntu-latest environment: production
steps: # ... similar steps for production environment - name: Check deployment readiness env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") entente can-i-deploy \ --type provider \ --service castle-service \ --version $VERSION \ --environment productionKey Integration Points
Section titled “Key Integration Points”1. Service Registration
Section titled “1. Service Registration”Register your provider service and upload the OpenAPI spec:
- name: Register service with Entente env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service entente register-service \ --type provider \ --service castle-service \ --spec spec/openapi.json \ --spec-version 0.1.0 \ --environment development2. Provider Verification
Section titled “2. Provider Verification”Run provider tests that verify against recorded consumer interactions:
- name: Run provider verification tests env: ENTENTE_SERVICE_URL: ${{ vars.ENTENTE_SERVICE_URL }} ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: pnpm --filter @entente/example-castle-service test3. Spec Upload
Section titled “3. Spec Upload”Upload your OpenAPI spec for the specific version being deployed:
- name: Upload OpenAPI spec env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") entente upload-spec \ --service castle-service \ --version $VERSION \ --environment development \ --spec spec/openapi.json4. Deployment Safety Check
Section titled “4. Deployment Safety Check”Verify it’s safe to deploy before actually deploying:
- name: Check deployment readiness env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") entente can-i-deploy \ --type provider \ --service castle-service \ --version $VERSION \ --environment development5. Deployment Recording
Section titled “5. Deployment Recording”Record the successful deployment in Entente:
- name: Record deployment env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") entente deploy-service \ --service castle-service \ --version $VERSION \ --environment development \ --type providerEnvironment Variables & Secrets
Section titled “Environment Variables & Secrets”Required Secrets
Section titled “Required Secrets”Configure these secrets in your GitHub repository:
# Entente API key for authenticationENTENTE_API_KEY=ent_your_api_key_here
# If deploying to Cloudflare WorkersCLOUDFLARE_API_TOKEN=your_cloudflare_tokenCLOUDFLARE_ACCOUNT_ID=your_account_idRequired Variables
Section titled “Required Variables”Configure these variables in your GitHub repository:
# Entente server URL (can be public)ENTENTE_SERVICE_URL=https://entente.company.com
# If using Cloudflare WorkersCLOUDFLARE_WORKERS_SUBDOMAIN=your-workers-subdomainPath-Based Triggering
Section titled “Path-Based Triggering”Only run workflows when relevant files change:
on: push: branches: [main] paths: - 'examples/castle-service/**' # Service code - '.github/workflows/castle-service-*.yml' # Workflow files pull_request: branches: [main] paths: - 'examples/castle-service/**' - '.github/workflows/castle-service-*.yml'Multi-Environment Deployment
Section titled “Multi-Environment Deployment”Deploy to multiple environments in sequence:
graph LR
A[Build & Test] --> B[Deploy Dev]
B --> C[Deploy Staging]
C --> D[Deploy Production]
A -.->|Failure| E[Stop]
B -.->|Failure| E
C -.->|Failure| E
Each environment has its own safety checks:
# Development: More permissive- name: Check deployment readiness (dev) run: | entente can-i-deploy \ --type provider \ --service castle-service \ --version $VERSION \ --environment development
# Production: Strict requirements- name: Check deployment readiness (prod) run: | entente can-i-deploy \ --type provider \ --service castle-service \ --version $VERSION \ --environment productionManual Deployment Control
Section titled “Manual Deployment Control”Allow manual deployments with environment selection:
on: workflow_dispatch: inputs: environment: description: 'Environment to deploy to' required: true default: 'development' type: choice options: - development - staging - productionError Handling
Section titled “Error Handling”Deployment Safety Failures
Section titled “Deployment Safety Failures”When can-i-deploy fails, the workflow stops:
- name: Check deployment readiness id: can-i-deploy env: ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | cd examples/castle-service VERSION=$(node -p "require('./package.json').version") if ! entente can-i-deploy \ --type provider \ --service castle-service \ --version $VERSION \ --environment development; then echo "❌ Deployment safety check failed" echo "This version cannot be safely deployed to development" echo "Check consumer compatibility before proceeding" exit 1 fiProvider Test Failures
Section titled “Provider Test Failures”When provider verification fails:
- name: Run provider verification tests env: ENTENTE_SERVICE_URL: ${{ vars.ENTENTE_SERVICE_URL }} ENTENTE_API_KEY: ${{ secrets.ENTENTE_API_KEY }} run: | if ! pnpm --filter @entente/example-castle-service test; then echo "❌ Provider verification failed" echo "Your implementation doesn't match recorded consumer expectations" echo "Check the test output for details on what failed" exit 1 fiPackage.json Scripts
Section titled “Package.json Scripts”Add convenient scripts for local development:
{ "scripts": { "test": "vitest run test/provider.test.ts", "register:provider": "entente register-service --type provider --service castle-service --spec spec/openapi.json --spec-version 0.1.0 --environment test", "upload:spec": "entente upload-spec --service castle-service --version 0.1.0 --environment test --spec spec/openapi.json", "can-i-deploy": "entente can-i-deploy --type provider --service castle-service --version 0.1.0 --environment test", "deploy:provider": "entente deploy-service --type provider --service castle-service --version 0.1.0 --environment test" }}Performance Optimization
Section titled “Performance Optimization”Dependency Caching
Section titled “Dependency Caching”Cache dependencies between workflow runs:
- name: Setup pnpm uses: pnpm/action-setup@v4 with: run_install: false
- name: Get pnpm store directory shell: bash run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache uses: actions/cache@v3 with: path: ${{ env.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store-Conditional Steps
Section titled “Conditional Steps”Skip unnecessary work when possible:
- name: Check if provider files changed uses: dorny/paths-filter@v3 id: changes with: filters: | provider: - 'examples/castle-service/**'
- name: Run provider tests if: steps.changes.outputs.provider == 'true' run: pnpm testMonitoring & Notifications
Section titled “Monitoring & Notifications”Deployment Notifications
Section titled “Deployment Notifications”Notify teams about deployment status:
- name: Notify deployment success if: success() run: | curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} \ -H 'Content-type: application/json' \ --data '{"text":"✅ castle-service deployed to development successfully"}'
- name: Notify deployment failure if: failure() run: | curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} \ -H 'Content-type: application/json' \ --data '{"text":"❌ castle-service deployment to development failed"}'Contract Test Reports
Section titled “Contract Test Reports”Generate test reports for visibility:
- name: Generate verification report if: always() run: | echo "## Provider Verification Report" >> $GITHUB_STEP_SUMMARY echo "Service: castle-service" >> $GITHUB_STEP_SUMMARY echo "Version: $(node -p 'require(\"./package.json\").version')" >> $GITHUB_STEP_SUMMARY echo "Environment: development" >> $GITHUB_STEP_SUMMARYSecurity Best Practices
Section titled “Security Best Practices”API Key Management
Section titled “API Key Management”- Store
ENTENTE_API_KEYas a repository secret - Use environment-specific API keys when possible
- Rotate API keys regularly
Least Privilege Access
Section titled “Least Privilege Access”- Limit GitHub Actions permissions:
permissions: contents: read deployments: write actions: readNext Steps
Section titled “Next Steps”- State Management - Advanced patterns for test data management
- Troubleshooting - Common CI/CD issues and solutions
- Monitoring - Track provider verification health over time
The GitHub Actions integration ensures your provider implementations are thoroughly tested against real consumer usage before reaching production, giving you confidence in every deployment.