name: autofix.ci
on:
  pull_request:
    branches: ["main"]
  merge_group:
    branches: ["main"]
    types: [checks_requested]
  push:
    branches: ["main"]
permissions:
  contents: read

jobs:
  autofix:
    if: github.repository == 'langgenius/dify'
    runs-on: depot-ubuntu-24.04
    steps:
      - name: Complete merge group check
        if: github.event_name == 'merge_group'
        run: echo "autofix.ci updates pull request branches, not merge group refs."

      - if: github.event_name != 'merge_group'
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Check Docker Compose inputs
        if: github.event_name != 'merge_group'
        id: docker-compose-changes
        uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
        with:
          files: |
            docker/generate_docker_compose
            docker/.env.example
            docker/docker-compose-template.yaml
            docker/docker-compose.yaml
      - name: Check web inputs
        if: github.event_name != 'merge_group'
        id: web-changes
        uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
        with:
          files: |
            web/**
            packages/**
            package.json
            pnpm-lock.yaml
            pnpm-workspace.yaml
            .nvmrc
      - name: Check api inputs
        if: github.event_name != 'merge_group'
        id: api-changes
        uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
        with:
          files: |
            api/**
      - if: github.event_name != 'merge_group'
        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: "3.11"

      - if: github.event_name != 'merge_group'
        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0

      - name: Generate Docker Compose
        if: github.event_name != 'merge_group' && steps.docker-compose-changes.outputs.any_changed == 'true'
        run: |
          cd docker
          ./generate_docker_compose

      - if: github.event_name != 'merge_group' && steps.api-changes.outputs.any_changed == 'true'
        run: |
          cd api
          uv sync --dev
          # fmt first to avoid line too long
          uv run ruff format ..
          # Fix lint errors
          uv run ruff check --fix .
          # Format code
          uv run ruff format ..

      - name: count migration progress
        if: github.event_name != 'merge_group' && steps.api-changes.outputs.any_changed == 'true'
        run: |
          cd api
          ./cnt_base.sh

      - name: ast-grep
        if: github.event_name != 'merge_group' && steps.api-changes.outputs.any_changed == 'true'
        run: |
          # ast-grep exits 1 if no matches are found; allow idempotent runs.
          uvx --from ast-grep-cli ast-grep --pattern 'db.session.query($WHATEVER).filter($HERE)' --rewrite 'db.session.query($WHATEVER).where($HERE)' -l py --update-all || true
          uvx --from ast-grep-cli ast-grep --pattern 'session.query($WHATEVER).filter($HERE)' --rewrite 'session.query($WHATEVER).where($HERE)' -l py --update-all || true
          uvx --from ast-grep-cli ast-grep -p '$A = db.Column($$$B)' -r '$A = mapped_column($$$B)' -l py --update-all || true
          uvx --from ast-grep-cli ast-grep -p '$A : $T = db.Column($$$B)' -r '$A : $T = mapped_column($$$B)' -l py --update-all || true
          # Convert Optional[T] to T | None (ignoring quoted types)
          cat > /tmp/optional-rule.yml << 'EOF'
          id: convert-optional-to-union
          language: python
          rule:
            kind: generic_type
            all:
              - has:
                  kind: identifier
                  pattern: Optional
              - has:
                  kind: type_parameter
                  has:
                    kind: type
                    pattern: $T
          fix: $T | None
          EOF
          uvx --from ast-grep-cli ast-grep scan . --inline-rules "$(cat /tmp/optional-rule.yml)" --update-all
          # Fix forward references that were incorrectly converted (Python doesn't support "Type" | None syntax)
          find . -name "*.py" -type f -exec sed -i.bak -E 's/"([^"]+)" \| None/Optional["\1"]/g; s/'"'"'([^'"'"']+)'"'"' \| None/Optional['"'"'\1'"'"']/g' {} \;
          find . -name "*.py.bak" -type f -delete

      - name: Setup web environment
        if: github.event_name != 'merge_group'
        uses: ./.github/actions/setup-web

      - name: Generate API docs
        if: github.event_name != 'merge_group' && steps.api-changes.outputs.any_changed == 'true'
        run: |
          cd api
          uv run dev/generate_swagger_markdown_docs.py --swagger-dir ../packages/contracts/openapi --markdown-dir openapi/markdown --keep-swagger-json

      - name: Generate frontend contracts
        if: github.event_name != 'merge_group' && steps.api-changes.outputs.any_changed == 'true'
        run: pnpm --dir packages/contracts gen-api-contract-from-openapi

      - name: ESLint autofix
        if: github.event_name != 'merge_group' && steps.web-changes.outputs.any_changed == 'true'
        run: |
          vp exec eslint --concurrency=2 --prune-suppressions --quiet || true

      - if: github.event_name != 'merge_group'
        uses: autofix-ci/action@c5b2d67aa2274e7b5a18224e8171550871fc7e4a # v1.3.4
