name: Migration Tests

on:
  pull_request:
    paths:
      - ".github/workflows/migration-tests.yml"
      - "migrations/**"
  push:
    branches:
      - main
      - stable
    paths:
      - ".github/workflows/migration-tests.yml"
      - "migrations/**"

concurrency:
  group: migration-tests-${{ format('{0}-{1}', github.head_ref || github.run_number, github.job) }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  tests:
    if: github.event_name == 'pull_request' || github.repository != 'discourse/discourse-private-mirror'
    name: Tests
    runs-on: ${{ (github.repository_owner == 'discourse' && 'cdck-linux-8-core') || 'ubuntu-latest' }}
    container: discourse/discourse_test:release
    timeout-minutes: 20

    env:
      RAILS_ENV: test
      PGUSER: discourse
      PGPASSWORD: discourse
      LOAD_PLUGINS: 1

    steps:
      - name: Set working directory owner
        run: chown root:root .

      - uses: actions/checkout@v6
        with:
          fetch-depth: 1

      - name: Setup Git
        run: |
          git config --global user.email "ci@ci.invalid"
          git config --global user.name "Discourse CI"

      - name: Start redis
        run: |
          redis-server /etc/redis/redis.conf &

      - name: Start Postgres
        run: |
          chown -R postgres /var/run/postgresql
          sudo -E -u postgres script/start_test_db.rb
          sudo -u postgres psql -c "CREATE ROLE $PGUSER LOGIN SUPERUSER PASSWORD '$PGPASSWORD';"

      - name: Symlink vendor/bundle from image
        run: |
          ln -s /var/www/discourse/vendor/bundle vendor/bundle

      - name: Setup gems
        run: |
          bundle config --local path vendor/bundle
          bundle config --local deployment true
          bundle config --local without development
          bundle config --local with migrations
          bundle install --jobs $(($(nproc) - 1))

      - name: pnpm install
        run: pnpm install --frozen-lockfile

      - name: Get CPU cores
        id: cpu-info
        run: echo "cpu-cores=$(nproc)" >> $GITHUB_OUTPUT

      - name: Fetch app state cache
        uses: actions/cache@v5
        id: app-cache
        with:
          path: tmp/app-cache
          key: >-
            ${{ runner.os }}-
            ${{ steps.cpu-info.outputs.cpu-cores }}-
            ${{ hashFiles('.github/workflows/migration-tests.yml') }}-
            ${{ hashFiles('db/**/*', 'plugins/**/db/**/*') }}-
            ${{ hashFiles('config/environments/test.rb') }}

      - name: Restore database from cache
        if: steps.app-cache.outputs.cache-hit == 'true'
        run: script/silence_successful_output psql --quiet -o /dev/null -f tmp/app-cache/cache.sql postgres

      - name: Restore uploads from cache
        if: steps.app-cache.outputs.cache-hit == 'true'
        run: rm -rf public/uploads && cp -r tmp/app-cache/uploads public/uploads

      - name: Create and migrate database
        if: steps.app-cache.outputs.cache-hit != 'true'
        run: |
          bin/rake db:create
          script/silence_successful_output bin/rake db:migrate

      - name: Dump database for cache
        if: steps.app-cache.outputs.cache-hit != 'true'
        run: mkdir -p tmp/app-cache && pg_dumpall > tmp/app-cache/cache.sql

      - name: Dump uploads for cache
        if: steps.app-cache.outputs.cache-hit != 'true'
        run: rm -rf tmp/app-cache/uploads && cp -r public/uploads tmp/app-cache/uploads

      - name: Validate IntermediateDB schema
        run: |
          # Show structured differences between DSL config and database
          migrations/bin/cli schema diff --db=intermediate_db || true

          # Regenerate schema from DSL config
          migrations/bin/cli schema generate --db=intermediate_db

          # Check if generated output matches what's committed
          if [ ! -z "$(git status --porcelain migrations/db/intermediate_db_schema/ migrations/lib/database/intermediate_db/ migrations/lib/database/intermediate_db/enums/)" ]; then
            echo ""
            echo "=========================================="
            echo "IntermediateDB schema is not up to date."
            echo "=========================================="
            echo ""
            echo "The generated schema files differ from what is committed."
            echo "This usually means the schema DSL config or the database"
            echo "structure changed without regenerating."
            echo ""
            echo "To fix:"
            echo "  1. Run: migrations/bin/cli schema diff"
            echo "     to see what changed between config and database"
            echo "  2. Update config files in migrations/config/schema/intermediate_db/"
            echo "     - New tables: migrations/bin/cli schema add <table>"
            echo "     - Ignore tables: migrations/bin/cli schema ignore <table> --reason '...'"
            echo "     - New columns: add to the table's include list or ignore with reason"
            echo "  3. Run: migrations/bin/cli schema generate"
            echo "  4. Commit the updated config and generated files"
            echo ""
            echo "Generated file diff:"
            git -c color.ui=always diff -- migrations/db/intermediate_db_schema/ migrations/lib/database/intermediate_db/ migrations/lib/database/intermediate_db/enums/
            exit 1
          fi

      - name: RSpec
        run: bin/rspec --default-path migrations/spec
