name: Update All Screenshots
# Updates all screenshots on an existing PR, assuming permission has been given
# to maintainers to make edits.

on:
  workflow_dispatch:
    # Allows for manual triggering on PRs.  They should be reviewed first, to
    # avoid malicious code executing in the lab.
    inputs:
      pr:
        description: "A PR number to build and test in the lab, then update all the screenshots."
        required: true

jobs:
  set-pending-status:
    name: Set Pending Status
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          ref: refs/pull/${{ inputs.pr }}/head

      - name: Set commit status to pending
        uses: ./.github/workflows/custom-actions/set-commit-status
        with:
          context: Update All Screenshots
          state: pending
          token: ${{ secrets.GITHUB_TOKEN }}

  run-lab-tests:
    name: Get Selenium Lab Screenshots
    needs: [set-pending-status]
    uses: ./.github/workflows/selenium-lab-tests.yaml
    with:
      pr: ${{ inputs.pr }}
      test_filter: layout
      ignore_test_status: true

  update-pr:
    name: Update PR
    runs-on: ubuntu-latest
    needs: [run-lab-tests]
    steps:
      - uses: actions/checkout@v3
        with:
          ref: refs/pull/${{ inputs.pr }}/head

      - name: Set commit status to pending
        uses: ./.github/workflows/custom-actions/set-commit-status
        with:
          context: Update All Screenshots
          state: pending
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Get artifacts
        uses: actions/download-artifact@v3
        with:
          path: new-screenshots

      - name: Move screenshots
        run: |
          # The download-artifact action puts zip file contents into folders by
          # the name of the artifact, so we can't have them downloaded directly
          # to the screenshots folder.  Here we move them into the correct
          # locations.
          cd new-screenshots

          # "$i" is a folder for an artifact (eg "screenshots-ChromeAndroid"),
          # and it contains a single folder with the name we use in our
          # screenshots (eg "chrome-Android").  We want the contents of that
          # inner folder to be copied to test/test/assets/screenshots/, where a
          # folder with the same name (eg "chrome-Android") already exists.
          for i in screenshots*; do
            cp -a $i/* ../test/test/assets/screenshots/
          done

      - name: Update screenshots
        run: |
          # Install prerequisites.
          npm ci

          # Update the official screenshots for any that have visibly changed.
          # This is not a byte-for-byte comparison, but based on pixel diffs.
          ./build/updateScreenshots.py

          # Emulate the actions bot.
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

          # Commit the changes.  Ignore failure, in case there are no changes.
          git add test/test/assets/screenshots/*/*.png || true
          git commit -m ':robot: Update all screenshots' || true

      - name: Update PR
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          # Update the PR.
          PR_API_URL="/repos/${{ github.repository }}/pulls/${{ inputs.pr }}"
          REMOTE=$(gh api $PR_API_URL | jq -r .head.repo.html_url)
          BRANCH=$(gh api $PR_API_URL | jq -r .head.ref)

          # If there were no changes, this will do nothing, but succeed.
          git push "$REMOTE" HEAD:"$BRANCH"

      - name: Debug
        uses: mxschmitt/action-tmate@v3.6
        with:
          limit-access-to-actor: true
        if: failure()

  set-final-status:
    name: Set Final Status
    runs-on: ubuntu-latest
    needs: [run-lab-tests, update-pr]
    # Will run on success or failure, but not if the workflow is cancelled.
    if: ${{ success() || failure() }}
    steps:
      - uses: actions/checkout@v3
        with:
          ref: refs/pull/${{ inputs.pr }}/head

      - name: Compute final status
        id: compute
        run: |
          LAB_TEST_STATUS="${{ needs.run-lab-tests.status }}"
          UPDATE_PR_STATUS="${{ needs.update-pr.status }}"

          # If run-lab-tests succeeded, use the status of update-pr, otherwise
          # use run-lab-tests (which is "failed" or "error").
          if [ "$LAB_TEST_STATUS" == "success" ]; then
            echo "status=$UPDATE_PR_STATUS" >> $GITHUB_OUTPUT
          else
            echo "status=$LAST_TEST_STATUS" >> $GITHUB_OUTPUT
          fi

      - name: Report final status
        uses: ./.github/workflows/custom-actions/set-commit-status
        with:
          context: Update All Screenshots
          state: ${{ steps.compute.outputs.status }}
          token: ${{ secrets.GITHUB_TOKEN }}
