CI/CD Integration Guide
This guide covers how to integrate CVT into your CI/CD pipelines for automated contract testing, consumer registration, and deployment safety checks.
Overview
A typical CVT-enabled pipeline includes:
- Contract tests - Validate interactions against OpenAPI schemas
- Consumer registration - Register your service's API dependencies after tests pass
- Deployment safety checks - Run
can-i-deploybefore deploying schema changes
For PR checks that detect breaking changes when your OpenAPI spec file changes, see the Breaking Changes CI/CD section.
Recommended Workflow
CVT works best when each team has a clear role. The producer owns the schema, the consumer validates against it, and CVT is the shared infrastructure that connects them.
┌──────────────────────────────┐
│ Producer CI/CD │
│ │
│ 1. Build & test API │
│ 2. Register schema with CVT │◄── Producer owns the OpenAPI spec
│ 3. can-i-deploy check │
│ 4. Deploy │
└──────────────┬───────────────┘
│
▼
┌──────────────────────────────┐
│ CVT Server (shared) │
│ │
│ • Registered schemas │◄── Central source of truth
│ • Consumer registrations │
│ • Validation engine │
└──────────────┬───────────────┘
│
▼
┌──────────────────────────────┐
│ Consumer CI/CD │
│ │
│ 1. Run contract tests │◄── Validates against producer's schema
│ 2. Register as consumer │
│ 3. Deploy │
└──────────────────────────────┘
| Step | Who | What | When |
|---|---|---|---|
| Register schema | Producer | Publishes OpenAPI spec to CVT | On merge to main |
| Validate interactions | Consumer | Tests requests/responses against schema | On every CI run |
| Register consumer | Consumer | Records which endpoints are used | After tests pass on main |
| can-i-deploy | Producer | Checks if schema changes break consumers | Before deploying |
The producer should register their schema in CVT — not the consumer. If consumers register schemas independently, you risk stale or inconsistent contracts. In local development, consumers may register schemas for convenience, but in CI/CD the producer's pipeline should be the single source of truth.
GitHub Actions
Consumer Contract Tests
name: Contract Tests
on: [push, pull_request]
jobs:
contract-tests:
runs-on: ubuntu-latest
services:
cvt:
image: ghcr.io/sahina/cvt:latest
ports:
- 9550:9550
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm ci
- name: Run contract tests
run: npm test
- name: Register consumer
if: github.ref == 'refs/heads/main'
run: |
npm run register-consumer -- \
--id my-service \
--version ${{ github.sha }} \
--schema petstore \
--env staging
The published CVT server image is available at ghcr.io/sahina/cvt:latest. You can also:
- Build your own image:
docker build -t cvt . - Use
make upto run CVT locally - Host CVT as a shared service in your infrastructure
Producer Deployment Safety
name: Deploy API
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run contract tests
run: npm test
- name: Check deployment safety
run: |
cvt can-i-deploy \
--schema ${{ env.SCHEMA_ID }} \
--version ${{ env.VERSION }} \
--env prod \
--server ${{ secrets.CVT_SERVER }}
- name: Deploy
if: success()
run: ./deploy.sh
Pre-Deploy Safety Check
deploy:
needs: [contract-tests]
steps:
- name: Check if upstream is safe
run: |
# This checks if any upstream dependencies have breaking changes
cvt can-i-deploy \
--schema petstore \
--version ${{ env.SCHEMA_VERSION }} \
--env prod \
--json > check.json
if [ "$(jq '.safe_to_deploy' check.json)" != "true" ]; then
echo "Upstream API has breaking changes!"
jq '.affected_consumers[] | select(.will_break == true) | .consumer_id' check.json
exit 1
fi
GitLab CI
The can-i-deploy job requires the cvt CLI and jq to be available. Either use a base image with these tools pre-installed, or add installation steps to your before_script.
Consumer Contract Tests
stages:
- test
- deploy
variables:
CVT_SERVER: "localhost:9550"
contract-tests:
stage: test
services:
- name: ghcr.io/sahina/cvt:latest
alias: cvt
variables:
CVT_SERVER: "cvt:9550"
script:
- npm ci
- npm test
artifacts:
reports:
junit: test-results.xml
register-consumer:
stage: deploy
only:
- main
script:
- |
npm run register-consumer -- \
--id my-service \
--version $CI_COMMIT_SHA \
--schema petstore \
--env staging
can-i-deploy:
stage: deploy
only:
- main
script:
- |
cvt can-i-deploy \
--schema petstore \
--version $SCHEMA_VERSION \
--env prod \
--json > check.json
if [ "$(jq '.safe_to_deploy' check.json)" != "true" ]; then
echo "Breaking changes detected!"
jq '.affected_consumers[] | select(.will_break == true)' check.json
exit 1
fi
Producer Deployment Safety
stages:
- test
- safety-check
- deploy
contract-tests:
stage: test
script:
- npm test
deployment-safety:
stage: safety-check
script:
- cvt can-i-deploy --schema $SCHEMA_ID --version $VERSION --env prod --json
allow_failure: false
deploy:
stage: deploy
script:
- ./deploy.sh
only:
- main
Jenkins
This example uses readJSON from the Pipeline Utility Steps plugin.
Consumer Contract Tests
pipeline {
agent any
environment {
CVT_SERVER = 'cvt.internal:9550'
}
stages {
stage('Start CVT') {
steps {
sh 'docker-compose up -d cvt-server'
sh 'cvt wait --server localhost:9550 --timeout 60'
}
}
stage('Contract Tests') {
steps {
sh 'npm ci'
sh 'npm test'
}
post {
always {
junit 'test-results.xml'
}
}
}
stage('Register Consumer') {
when {
branch 'main'
}
steps {
sh """
npm run register-consumer -- \\
--id my-service \\
--version ${env.GIT_COMMIT} \\
--schema petstore \\
--env staging
"""
}
}
stage('Can I Deploy') {
when {
branch 'main'
}
steps {
script {
def result = sh(
script: """
cvt can-i-deploy \\
--schema petstore \\
--version ${env.SCHEMA_VERSION} \\
--env prod \\
--json
""",
returnStdout: true
).trim()
def json = readJSON text: result
if (!json.safe_to_deploy) {
error "Breaking changes detected! Affected consumers: ${json.affected_consumers}"
}
}
}
}
}
post {
always {
sh 'docker-compose down'
}
}
}
Next Steps
- Consumer Testing Guide - Test your API integrations
- Producer Testing Guide - Validate your own APIs
- Breaking Changes Guide - Schema compatibility and can-i-deploy
- Configuration Reference - Environment variables and settings