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
Comment thread
itsharshvb marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
api-path-removed-without-deprecation: ERR
api-path-removed-before-sunset: ERR
api-removed-without-deprecation: ERR
api-removed-before-sunset: ERR
api-operation-id-removed: ERR
api-tag-removed: WARN
request-body-became-enum: ERR
request-body-became-optional: INFO
request-body-became-required: ERR
request-body-max-length-decreased: ERR
request-body-max-length-increased: INFO
request-body-min-length-increased: ERR
request-body-min-length-decreased: INFO
request-body-type-changed: ERR
request-property-became-not-nullable: ERR
request-property-became-nullable: INFO
request-property-became-optional: INFO
request-property-became-required: ERR
request-property-default-value-changed: WARN
request-property-enum-value-removed: ERR
request-property-enum-value-added: INFO
request-property-max-decreased: ERR
request-property-max-increased: INFO
request-property-max-length-decreased: ERR
request-property-max-length-increased: INFO
request-property-min-increased: ERR
request-property-min-decreased: INFO
request-property-min-length-increased: ERR
request-property-min-length-decreased: INFO
request-property-pattern-changed: ERR
request-property-pattern-removed: INFO
request-property-removed: ERR
request-property-type-changed: ERR
request-property-x-extensible-enum-value-removed: ERR
response-header-became-optional: ERR
response-property-default-value-changed: WARN
response-property-enum-value-added: INFO
response-property-pattern-changed: ERR
response-property-pattern-removed: INFO
response-property-type-changed: ERR
request-parameter-became-optional: INFO
request-parameter-became-required: ERR
request-parameter-default-value-changed: WARN
request-parameter-enum-value-removed: ERR
request-parameter-enum-value-added: INFO
request-parameter-max-decreased: ERR
request-parameter-max-increased: INFO
request-parameter-max-length-decreased: ERR
request-parameter-max-length-increased: INFO
request-parameter-min-increased: ERR
request-parameter-min-decreased: INFO
request-parameter-min-length-increased: ERR
request-parameter-min-length-decreased: INFO
request-parameter-pattern-changed: ERR
request-parameter-pattern-removed: INFO
request-parameter-type-changed: ERR
request-parameter-x-extensible-enum-value-removed: ERR
request-parameter-deprecated: WARN
api-schema-removed: INFO
endpoint-deprecated: WARN
endpoint-reactivated: INFO
14 changes: 14 additions & 0 deletions .github/api-migration-compatibility/.oasdiff-warn-ignore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
response-property-max-length-increased
response-property-min-length-decreased
response-property-max-increased
response-property-min-decreased
request-parameter-max-length-increased
request-parameter-min-length-decreased
request-parameter-max-increased
request-parameter-min-decreased
api-tag-added
response-property-enum-value-added
request-property-enum-value-added
request-parameter-enum-value-added
response-media-type-added
request-body-media-type-added
108 changes: 108 additions & 0 deletions .github/api-migration-compatibility/migration-rules.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Migration Rules Configuration
# This file defines SQL patterns that are considered breaking changes or warnings
# for database migrations, with folder-specific rule application.

# Define reusable rule patterns
rule_patterns:
drop_table:
pattern: 'DROP\s+TABLE\s+'
description: "Dropping a table removes data and breaks existing queries"

drop_column:
pattern: 'DROP\s+COLUMN\s+'
description: "Dropping a column breaks applications expecting it"

delete_data:
pattern: 'DELETE\s+FROM\s+'
description: "Deleting data can break application logic"

truncate_table:
pattern: 'TRUNCATE\s+'
description: "Truncating removes all data from a table"

rename_table:
pattern: 'RENAME\s+TO\s+'
description: "Renaming a table breaks existing queries and code references"

rename_column:
pattern: 'RENAME\s+COLUMN\s+'
description: "Renaming a column breaks applications using the old name"

set_not_null:
pattern: 'ALTER\s+COLUMN\s+.*\s+SET\s+NOT\s+NULL'
description: "Making an existing nullable column NOT NULL can fail with existing NULL data"

add_column_not_null_no_default:
Comment thread
itsharshvb marked this conversation as resolved.
pattern: 'ALTER\s+TABLE\s+.*\s+ADD\s+COLUMN\s+(?!.*DEFAULT).*NOT\s+NULL'
description: "Adding a NOT NULL column without a DEFAULT to an existing table will fail"

alter_column_type:
pattern: '(ALTER\s+COLUMN\s+.*\s+TYPE|ALTER\s+COLUMN\s+.*\s+SET\s+DATA\s+TYPE)'
description: "Changing column type may cause data loss or conversion issues"

drop_index:
pattern: 'DROP\s+INDEX\s+'
description: "Dropping an index can significantly impact query performance"

drop_constraint:
pattern: 'DROP\s+CONSTRAINT\s+'
description: "Dropping a constraint may allow invalid data"

alter_default:
pattern: '(SET\s+DEFAULT|DROP\s+DEFAULT)'
description: "Changing defaults affects new rows only, may cause inconsistency"

# Apply rules per migration folder
# Each folder can have its own set of breaking and warning rules
folder_rules:
# V1 migrations
migrations:
breaking:
- drop_table
- drop_column
- delete_data
- truncate_table
- rename_table
- rename_column
- set_not_null
- add_column_not_null_no_default
- alter_column_type
Comment thread
itsharshvb marked this conversation as resolved.
warnings:
- drop_index
- drop_constraint
- alter_default

# V2 migrations
v2_migrations:
breaking:
- drop_table
- drop_column
- delete_data
- truncate_table
- rename_table
- rename_column
- set_not_null
- add_column_not_null_no_default
- alter_column_type
warnings:
- drop_index
- drop_constraint
- alter_default

# V2 compatible migrations
v2_compatible_migrations:
breaking:
- drop_table
- drop_column
- delete_data
- truncate_table
- rename_table
- rename_column
- set_not_null
- add_column_not_null_no_default
- alter_column_type
warnings:
- drop_index
- drop_constraint
- alter_default

81 changes: 81 additions & 0 deletions .github/scripts/validate_migrations.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/bin/bash

# validate_migrations.sh
# Validates database migrations for breaking changes and warnings
# Usage: ./validate_migrations.sh <migration_folder>

set -euo pipefail

MIGRATION_FOLDER="${1:-migrations}"
BASE_REF="${BASE_REF:-origin/main}"
RULES_FILE="${RULES_FILE:-.github/api-migration-compatibility/migration-rules.yaml}"

echo "Validating migrations in: $MIGRATION_FOLDER"

# Check if migration directory exists
if [[ ! -d "$MIGRATION_FOLDER" ]]; then
echo "breaking_changes=0" >> "$GITHUB_OUTPUT"
echo "warnings=0" >> "$GITHUB_OUTPUT"
echo "Directory $MIGRATION_FOLDER does not exist, skipping validation"
exit 0
fi

# Find new migrations
NEW_MIGRATIONS=$(git diff --name-only --diff-filter=AM "$BASE_REF"...HEAD -- "$MIGRATION_FOLDER/**/up.sql" 2>/dev/null || echo "")

if [[ -z "$NEW_MIGRATIONS" ]]; then
echo "breaking_changes=0" >> "$GITHUB_OUTPUT"
echo "warnings=0" >> "$GITHUB_OUTPUT"
echo "No new migrations found in $MIGRATION_FOLDER"
exit 0
fi

# Extract breaking rule patterns
BREAKING_PATTERNS=$(
for rule in $(yq ".folder_rules.${MIGRATION_FOLDER}.breaking[]" "$RULES_FILE" 2>/dev/null || echo ""); do
if [[ -n "$rule" ]]; then
yq ".rule_patterns.$rule.pattern" "$RULES_FILE"
fi
done | paste -sd'|' -
)

# Extract warning rule patterns
WARNING_PATTERNS=$(
for rule in $(yq ".folder_rules.${MIGRATION_FOLDER}.warnings[]" "$RULES_FILE" 2>/dev/null || echo ""); do
if [[ -n "$rule" ]]; then
yq ".rule_patterns.$rule.pattern" "$RULES_FILE"
fi
done | paste -sd'|' -
)

BREAKING=0
WARNINGS=0

while IFS= read -r file; do
[[ -z "$file" ]] && continue

# Check for breaking changes
if grep --ignore-case --extended-regexp --quiet "$BREAKING_PATTERNS" "$file" 2>/dev/null; then
echo "BREAKING: $file"
MATCH_COUNT=$(grep --ignore-case --count --extended-regexp "$BREAKING_PATTERNS" "$file" 2>/dev/null || echo "0")
grep --ignore-case --line-number --extended-regexp "$BREAKING_PATTERNS" "$file" 2>/dev/null | sed 's/^/ /' || true
BREAKING=$((BREAKING + MATCH_COUNT))
fi

# Check for warnings
if grep --ignore-case --extended-regexp --quiet "$WARNING_PATTERNS" "$file" 2>/dev/null; then
echo "WARNING: $file"
MATCH_COUNT=$(grep --ignore-case --count --extended-regexp "$WARNING_PATTERNS" "$file" 2>/dev/null || echo "0")
grep --ignore-case --line-number --extended-regexp "$WARNING_PATTERNS" "$file" 2>/dev/null | sed 's/^/ /' || true
WARNINGS=$((WARNINGS + MATCH_COUNT))
fi
done <<< "$NEW_MIGRATIONS"

echo "breaking_changes=$BREAKING" >> "$GITHUB_OUTPUT"
echo "warnings=$WARNINGS" >> "$GITHUB_OUTPUT"

if [[ $BREAKING -gt 0 ]]; then
echo "::error::Breaking changes detected in $MIGRATION_FOLDER database migrations."
echo "::error::Found $BREAKING breaking change(s)."
exit 1
fi
Loading
Loading