name: Demo PR changes

on:
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  demo:
    # Headless Junie executes repository code. Run only trusted, same-repository PRs.
    if: >-
      !github.event.pull_request.draft &&
      github.event.pull_request.head.repo.full_name == github.repository &&
      github.actor != 'dependabot[bot]'
    runs-on: ubuntu-latest
    timeout-minutes: 35
    permissions:
      contents: read
      pull-requests: write
    defaults:
      run:
        shell: bash
    env:
      JUNIE_API_KEY: ${{ secrets.JUNIE_API_KEY }}
      BASE_SHA: ${{ github.event.pull_request.base.sha }}
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 0
          persist-credentials: false

      - name: Check prerequisites
        run: |
          test -n "$JUNIE_API_KEY" || { echo "::error::Add the JUNIE_API_KEY repository secret."; exit 1; }
          docker info > /dev/null
          if [[ ! -s .junie/demo.md || ! -d .junie/vms ]]; then
            echo "::error::Set up /demo locally and commit .junie/demo.md and .junie/vms/."
            exit 1
          fi
          find .junie/vms -name Dockerfile -type f -print -quit | grep -q .
          mkdir -p demo-output
          printf '%s\n' "${GITHUB_SHA}" > demo-output/workflow-sha.txt
          git rev-parse HEAD > demo-output/tested-sha.txt

      - name: Install Junie
        # Install the public Junie CLI release.
        run: |
          curl -fsSL --retry 3 https://junie.jetbrains.com/install.sh \
            -o "$RUNNER_TEMP/install-junie.sh"
          bash "$RUNNER_TEMP/install-junie.sh"
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Decide whether the PR needs a demo
        id: classify
        run: |
          task="Inspect git diff ${BASE_SHA}...HEAD for changes that can be demonstrated
          through the running application's UI, including a browser or terminal UI.
          Do not launch a demo or change application code.
          Write exactly YES or NO to demo-output/decision.txt.
          Use NO only when there is clearly no demonstrable behavior change; if unsure, use YES.
          Explain the decision in demo-output/reason.md."
          junie --auth="$JUNIE_API_KEY" --skip-update-check -p . \
            --output-format json --json-output-file demo-output/classify.json --task "$task"
          decision=$(<demo-output/decision.txt)
          decision=${decision%$'\r'}
          case "$decision" in
            YES|NO) echo "decision=$decision" >> "$GITHUB_OUTPUT" ;;
            *) echo "::error::Junie did not return a valid classification."; exit 1 ;;
          esac
          printf 'Demo needed: %s\n' "$decision" >> "$GITHUB_STEP_SUMMARY"
          if [[ -f demo-output/reason.md ]]; then
            cat demo-output/reason.md >> "$GITHUB_STEP_SUMMARY"
          fi

      - name: Demonstrate the PR changes
        if: steps.classify.outputs.decision == 'YES'
        run: |
          task="Demonstrate the user-visible changes in git diff ${BASE_SHA}...HEAD.
          Follow .junie/demo.md to build and launch this checked-out revision.
          Read the diff before planning, list its user-visible changes, and demonstrate each one.
          Use the actual UI and report observed behavior, failures, and anything you could not verify.
          Do not modify or fix application code. Do not commit or push.
          Write a concise assessment to demo-output/assessment.md."
          junie --auth="$JUNIE_API_KEY" --skip-update-check --demo -p . \
            --output-format json --json-output-file demo-output/demo.json --task "$task"

      - name: Collect recordings and reports
        if: ${{ !cancelled() }}
        run: |
          mkdir -p demo-output/runs
          shopt -s nullglob
          for run_dir in "$HOME"/.junie/sessions/*/demo/*; do
            [[ -d "$run_dir" ]] || continue
            session=$(basename "$(dirname "$(dirname "$run_dir")")")
            mkdir -p "demo-output/runs/$session"
            cp -R "$run_dir" "demo-output/runs/$session/"
          done
          # Copy each run intact so report.html can resolve its relative media links.
          if [[ -f demo-output/assessment.md ]]; then
            cat demo-output/assessment.md >> "$GITHUB_STEP_SUMMARY"
          fi

      - name: Upload demo artifacts
        id: upload
        if: ${{ !cancelled() }}
        uses: actions/upload-artifact@v4
        with:
          name: demo-pr-${{ github.event.pull_request.number }}-${{ github.run_attempt }}
          path: demo-output/
          if-no-files-found: warn
          retention-days: 14

      - name: Link the demo from the PR
        if: ${{ !cancelled() && steps.classify.outputs.decision == 'YES' && steps.upload.outputs.artifact-url != '' }}
        env:
          GH_TOKEN: ${{ github.token }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          ARTIFACT_URL: ${{ steps.upload.outputs.artifact-url }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
        run: |
          run_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
          body_file="$RUNNER_TEMP/demo-comment.md"
          {
            printf '### Junie demo\n\nRevision: `%s`\n\n' "$HEAD_SHA"
            printf '[Download report and available recordings](%s) · [View run](%s)\n\n' "$ARTIFACT_URL" "$run_url"
            printf 'Unzip the artifact and open a report.html inside runs/. Review the report for the actual result; failed runs may contain only diagnostic output.\n'
          } > "$body_file"
          gh pr comment "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --body-file "$body_file"
