CI/CD Integration Guide
Rails Migration Guard provides robust CI/CD integration to prevent orphaned migrations from reaching production. This guide covers how to integrate migration checks into your continuous integration pipeline.
Quick Start
Add this to your CI pipeline to check for migration issues:
# Basic CI check
bundle exec rails db:migration:ci
# Strict mode (fails on any issues)
bundle exec rails db:migration:ci STRICT=true
# JSON output for machine processing
bundle exec rails db:migration:ci FORMAT=json
For GitHub Actions users, see our dedicated GitHub Actions guide for ready-to-use workflow files, reusable composite actions, PR comment integration, and matrix build examples.
The rails db:migration:ci
Command
The CI command is specifically designed for automated environments. It:
0=success, 1=warnings, 2=errors
Both human-readable and machine-readable output
Even when MigrationGuard is disabled
With recommended fixes
Exit Codes
Exit Code | Meaning | Description |
---|---|---|
0 | Success | No migration issues found |
1 | Warning | Issues found but not critical (default behavior) |
2 | Error | Critical issues found or strict mode triggered |
Strictness Levels
Control how the CI command responds to migration issues:
Level | Orphaned Migrations | Missing Migrations | Exit Code |
---|---|---|---|
permissive | Warning (1) | Warning (1) | 1 |
warning (default) | Warning (1) | Warning (1) | 1 |
strict | Error (2) | Error (2) | 2 |
# Set strictness level
bundle exec rails db:migration:ci STRICTNESS=strict
bundle exec rails db:migration:ci STRICTNESS=warning
bundle exec rails db:migration:ci STRICTNESS=permissive
# Legacy strict flag (equivalent to STRICTNESS=strict)
bundle exec rails db:migration:ci STRICT=true
Output Formats
Text Format (Default)
Human-readable output perfect for logs and developer review
$ bundle exec rails db:migration:ci
✅ Migration Guard CI Check (feature/user-profiles → main)
🔍 Orphaned Migrations Found:
• 20240115123456 (feature/user-profiles) - alice@example.com
💡 Recommended Actions:
1. Roll back orphaned migrations:
rails db:migration:rollback_specific VERSION=20240115123456
2. Or commit migration files if they should be included
📊 Summary:
Orphaned: 1
Missing: 0
Strictness: warning
Exit code: 1
JSON Format
Machine-readable output for CI integration and tooling
$ bundle exec rails db:migration:ci FORMAT=json
{
"migration_guard": {
"version": "0.1.0",
"status": "warning",
"summary": {
"total_orphaned": 1,
"total_missing": 0,
"issues_found": 1,
"main_branch": "main",
"current_branch": "feature/user-profiles"
},
"orphaned_migrations": [
{
"version": "20240115123456",
"file": "20240115123456_*.rb",
"branch": "feature/user-profiles",
"author": "alice@example.com",
"created_at": "2024-01-15T12:34:56Z"
}
],
"missing_migrations": [],
"branch_info": {
"current": "feature/user-profiles",
"main": "main",
"ahead_count": 0,
"behind_count": 0
},
"timestamp": "2024-01-15T13:00:00Z",
"exit_code": 1,
"strictness": "warning"
}
}
CI Platform Examples
GitHub Actions
See our comprehensive GitHub Actions guide for detailed setup instructions, reusable actions, and advanced configurations.
GitHub Actions
Basic example:
# .github/workflows/migration_guard.yml
name: Migration Guard Check
on:
pull_request:
paths:
- 'db/migrate/**'
- 'db/schema.rb'
jobs:
check-migrations:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:14
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for proper branch comparison
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Setup Database
run: |
bundle exec rails db:setup
env:
RAILS_ENV: test
DATABASE_URL: postgresql://postgres:postgres@localhost/test
- name: Check for migration issues
run: |
bundle exec rails db:migration:ci --strict
env:
RAILS_ENV: test
DATABASE_URL: postgresql://postgres:postgres@localhost/test
GitLab CI
# .gitlab-ci.yml
stages:
- test
migration_guard:
stage: test
image: ruby:3.1
services:
- postgres:14
variables:
POSTGRES_DB: test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
DATABASE_URL: postgresql://postgres:postgres@postgres/test
RAILS_ENV: test
before_script:
- bundle install
- bundle exec rails db:setup
script:
- bundle exec rails db:migration:ci STRICTNESS=strict FORMAT=json
only:
changes:
- db/migrate/**/*
- db/schema.rb
CircleCI
# .circleci/config.yml
version: 2.1
jobs:
migration_guard:
docker:
- image: cimg/ruby:3.1
- image: cimg/postgres:14.0
environment:
POSTGRES_DB: test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
steps:
- checkout
- run:
name: Install dependencies
command: bundle install
- run:
name: Setup database
command: |
bundle exec rails db:setup
environment:
RAILS_ENV: test
DATABASE_URL: postgresql://postgres@localhost/test
- run:
name: Check migrations
command: |
bundle exec rails db:migration:ci STRICT=true
environment:
RAILS_ENV: test
DATABASE_URL: postgresql://postgres@localhost/test
workflows:
version: 2
test:
jobs:
- migration_guard:
filters:
branches:
ignore: main
Jenkins
// Jenkinsfile
pipeline {
agent any
environment {
RAILS_ENV = 'test'
DATABASE_URL = 'postgresql://postgres:postgres@localhost/test'
}
stages {
stage('Setup') {
steps {
sh 'bundle install'
sh 'bundle exec rails db:setup'
}
}
stage('Migration Guard Check') {
steps {
script {
def result = sh(
script: 'bundle exec rails db:migration:ci FORMAT=json STRICTNESS=strict',
returnStatus: true
)
if (result != 0) {
error("Migration issues detected. Check logs for details.")
}
}
}
}
}
post {
always {
// Archive migration check results
archiveArtifacts artifacts: 'log/migration_guard.log', allowEmptyArchive: true
}
}
}
Environment Variables
The CI command supports these environment variables:
Variable | Values | Default | Description |
---|---|---|---|
FORMAT | text, json | text | Output format |
STRICT | true, false | false | Legacy strict mode flag |
STRICTNESS | permissive, warning, strict | warning | Strictness level |
Case-insensitive variants are also supported (format
, strict
, strictness
).
Integration Tips
1. Run Only on Migration Changes
Configure your CI to run migration checks only when migration-related files change:
# GitHub Actions
on:
pull_request:
paths:
- 'db/migrate/**'
- 'db/schema.rb'
- 'Gemfile*'
2. Parallel Builds
The CI command is fast (typically < 5 seconds) and can run in parallel with other checks:
jobs:
tests:
# ... your existing tests
migration_guard:
runs-on: ubuntu-latest
# ... migration guard setup
3. Custom Strictness by Branch
Adjust strictness based on the target branch:
# Strict for main/production branches
if [[ "$TARGET_BRANCH" == "main" ]]; then
bundle exec rails db:migration:ci STRICTNESS=strict
else
bundle exec rails db:migration:ci STRICTNESS=warning
fi
4. Artifact Collection
Save migration check results for debugging:
- name: Save migration check results
if: failure()
run: |
bundle exec rails db:migration:ci FORMAT=json > migration_check.json
- uses: actions/upload-artifact@v3
if: failure()
with:
name: migration-check-results
path: migration_check.json
Troubleshooting
Common Issues
Exit code 2 in CI but local tests pass
- Ensure your CI environment has the same database state as local
- Check that all migration files are committed
- Verify git history is complete (
fetch-depth: 0
in GitHub Actions)
"MigrationGuard is not enabled" message
- This is normal and returns exit code 0
- MigrationGuard automatically disables in production and can be configured for other environments
JSON parsing errors
- Ensure you're using
FORMAT=json
notFORMAT=JSON
- Check for mixed output (some gems may output to stdout)
Debug Mode
For detailed debugging, enable verbose logging:
# Add to your CI environment
export MIGRATION_GUARD_LOG_LEVEL=debug
bundle exec rails db:migration:ci
Best Practices
Use appropriate strictness
Start with warning
and move to strict
as your team adapts
Run early in pipeline
Catch issues before expensive test suites
Cache dependencies
Bundle and gem caching significantly speeds up CI
Monitor trends
Track migration issues over time to identify patterns
Team education
Ensure developers understand the migration workflow