Skip to content

refactor(trends): extract buildDerivedConfigs helper + perf fixes #57905

refactor(trends): extract buildDerivedConfigs helper + perf fixes

refactor(trends): extract buildDerivedConfigs helper + perf fixes #57905

name: Migration & Service Separation Check
on:
pull_request:
merge_group:
permissions:
contents: read
pull-requests: read
jobs:
check-migration-service-separation:
name: Check migrations and service changes are not in same PR
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
with:
client-id: ${{ secrets.GH_APP_POSTHOG_PATHS_FILTER_APP_ID }}
private-key: ${{ secrets.GH_APP_POSTHOG_PATHS_FILTER_PRIVATE_KEY }}
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: filter
with:
token: ${{ steps.app-token.outputs.token || github.token }}
filters: |
migrations:
- 'posthog/migrations/*.py'
- 'posthog/clickhouse/migrations/*.py'
- 'products/*/backend/migrations/*.py'
- 'ee/migrations/*.py'
sqlx_migrations:
- 'rust/persons_migrations/*.sql'
- 'rust/behavioral_cohorts_migrations/*.sql'
- 'rust/cyclotron-core/migrations/*.sql'
nodejs:
- 'nodejs/**'
# Separate step with predicate-quantifier: 'every' so that the
# negative patterns actually exclude migration directories.
# The default quantifier is 'some' (OR logic), which means a file
# matching ANY pattern (including the positive rust/**) passes the
# filter — the ! patterns are silently ignored.
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: rust-filter
with:
token: ${{ steps.app-token.outputs.token || github.token }}
predicate-quantifier: 'every'
filters: |
rust_services:
- 'rust/**'
- '!rust/persons_migrations/**'
- '!rust/behavioral_cohorts_migrations/**'
- '!rust/cyclotron-core/migrations/**'
- name: Check for conflicting changes
id: check
env:
MIGRATIONS_CHANGED: ${{ steps.filter.outputs.migrations }}
NODEJS_CHANGED: ${{ steps.filter.outputs.nodejs }}
SQLX_MIGRATIONS_CHANGED: ${{ steps.filter.outputs.sqlx_migrations }}
RUST_SERVICES_CHANGED: ${{ steps.rust-filter.outputs.rust_services }}
run: |
has_error=false
error_messages=""
# Check nodejs + Django migrations
if [ "$MIGRATIONS_CHANGED" == "true" ] && [ "$NODEJS_CHANGED" == "true" ]; then
error_messages="${error_messages}❌ Found both Django migration and nodejs changes\n"
has_error=true
fi
# Check nodejs + sqlx migrations
if [ "$SQLX_MIGRATIONS_CHANGED" == "true" ] && [ "$NODEJS_CHANGED" == "true" ]; then
error_messages="${error_messages}❌ Found both sqlx migration and nodejs changes\n"
has_error=true
fi
# Check rust services + sqlx migrations
if [ "$SQLX_MIGRATIONS_CHANGED" == "true" ] && [ "$RUST_SERVICES_CHANGED" == "true" ]; then
error_messages="${error_messages}❌ Found both sqlx migration and rust service changes\n"
has_error=true
fi
if [ "$has_error" == "true" ]; then
echo "error=true" >> $GITHUB_OUTPUT
echo -e "$error_messages"
else
echo "error=false" >> $GITHUB_OUTPUT
echo "✅ No conflicting changes detected"
fi
- name: Fail if conflicting changes detected
if: steps.check.outputs.error == 'true'
run: |
echo "::error::This PR contains both migration files and service changes. These must be separated into different PRs."
echo ""
echo "Why? Migration jobs are not orchestrated with service deployments. If you merge"
echo "service code that depends on new database schema alongside the migration, your"
echo "service may deploy before the migration runs, causing failures."
echo ""
echo "Solution: Split into two PRs:"
echo " 1. First PR: Migration changes only (merge and wait for it to deploy)"
echo " 2. Second PR: Service code changes (merge after migration is deployed)"
exit 1