Visual Regression #1498
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Visual Regression | |
| # Slash-command-driven visual regression runner. The actual mechanics live in | |
| # decentraland/explorer-automation's `run-visual-suite.yml` reusable workflow; | |
| # this file only handles trigger validation, branch matching, and dispatching | |
| # to that workflow. Build resolution and branch matching are shared with | |
| # in-world-tests.yml via .github/actions/resolve-explorer-build. | |
| # | |
| # Trigger: | |
| # Comment "/visual-tests" on a PR. Restricted to OWNER / MEMBER / | |
| # COLLABORATOR author associations — anyone else's comment is silently | |
| # ignored to keep this from becoming a free-CPU buffet for drive-by PRs. | |
| # | |
| # Branch matching: | |
| # We look up the PR's head branch in explorer-automation. If that branch | |
| # exists, we pass it as `tests_ref` so visual baselines and test fixtures | |
| # from the matching feature branch are used. Otherwise we fall back to | |
| # explorer-automation's default branch (metaforge handles the empty case | |
| # internally). | |
| # | |
| # Required secrets / vars (configure once on the repo): | |
| # | |
| # Used directly by this dispatcher: | |
| # - vars.EXPLORER_TEAM_S3_BUCKET_PUBLIC_URL Constructs the Explorer build download URL | |
| # | |
| # Inherited by the reusable workflow via `secrets: inherit` — must exist | |
| # on this repo even though the dispatcher itself doesn't reference them: | |
| # - secrets.ALTTESTER_LICENSE | |
| # - secrets.REPOS_READ_ONLY_TOKEN | |
| # - secrets.EXPLORER_TEAM_S3_BUCKET | |
| # - secrets.EXPLORER_TEAM_AWS_DEFAULT_REGION | |
| # - secrets.EXPLORER_TEAM_AWS_ACCESS_KEY_ID | |
| # - secrets.EXPLORER_TEAM_AWS_SECRET_ACCESS_KEY | |
| on: | |
| issue_comment: | |
| types: [created] | |
| permissions: | |
| # `actions: read` for the build lookup. It resolves anyway while this repo is | |
| # public — GITHUB_TOKEN keeps read access to public data whatever the block | |
| # says — but the grant should not hinge on that. | |
| actions: read | |
| contents: write | |
| pull-requests: write | |
| concurrency: | |
| group: visual-regression-${{ github.event.issue.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| resolve: | |
| name: Resolve trigger | |
| if: | | |
| github.event.issue.pull_request && | |
| startsWith(github.event.comment.body, '/visual-tests') | |
| runs-on: ubuntu-latest | |
| outputs: | |
| authorized: ${{ steps.gate.outputs.authorized }} | |
| pr_number: ${{ steps.pr.outputs.number }} | |
| build_url: ${{ steps.resolve.outputs.build-url }} | |
| tests_ref: ${{ steps.resolve.outputs.tests-ref }} | |
| head_sha: ${{ steps.pr.outputs.head_sha }} | |
| head_short_sha: ${{ steps.pr.outputs.head_short_sha }} | |
| head_ref: ${{ steps.pr.outputs.head_ref }} | |
| steps: | |
| - name: Gate by author association | |
| id: gate | |
| env: | |
| ASSOC: ${{ github.event.comment.author_association }} | |
| run: | | |
| set -euo pipefail | |
| case "$ASSOC" in | |
| OWNER|MEMBER|COLLABORATOR) | |
| echo "authorized=true" >> "$GITHUB_OUTPUT" | |
| ;; | |
| *) | |
| echo "::notice::Ignoring /visual-tests from $ASSOC ${{ github.event.comment.user.login }} — write access required." | |
| echo "authorized=false" >> "$GITHUB_OUTPUT" | |
| ;; | |
| esac | |
| - name: React to the trigger comment | |
| if: steps.gate.outputs.authorized == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh api -X POST \ | |
| "repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions" \ | |
| -f content=eyes >/dev/null | |
| - name: Resolve PR head | |
| id: pr | |
| if: steps.gate.outputs.authorized == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PR_NUMBER: ${{ github.event.issue.number }} | |
| run: | | |
| set -euo pipefail | |
| # issue_comment events don't carry the PR head in the payload. | |
| PR_JSON=$(gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}") | |
| HEAD_SHA=$(echo "$PR_JSON" | jq -r '.head.sha') | |
| HEAD_REF=$(echo "$PR_JSON" | jq -r '.head.ref') | |
| { | |
| echo "number=${PR_NUMBER}" | |
| echo "head_sha=${HEAD_SHA}" | |
| echo "head_short_sha=${HEAD_SHA:0:7}" | |
| echo "head_ref=${HEAD_REF}" | |
| } >> "$GITHUB_OUTPUT" | |
| # `uses: ./…` resolves against $GITHUB_WORKSPACE, so the action has to be | |
| # on disk. Sparse, because the full tree is ~21k files and nothing else | |
| # here is read. | |
| - name: Fetch the resolver action | |
| if: steps.gate.outputs.authorized == 'true' | |
| uses: actions/checkout@v6 | |
| with: | |
| sparse-checkout: .github/actions/resolve-explorer-build | |
| - name: Resolve build URL and tests ref | |
| id: resolve | |
| if: steps.gate.outputs.authorized == 'true' | |
| uses: ./.github/actions/resolve-explorer-build | |
| with: | |
| head-ref: ${{ steps.pr.outputs.head_ref }} | |
| head-sha: ${{ steps.pr.outputs.head_sha }} | |
| public-url-prefix: ${{ vars.EXPLORER_TEAM_S3_BUCKET_PUBLIC_URL }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| automation-token: ${{ secrets.REPOS_READ_ONLY_TOKEN }} | |
| run-suite: | |
| name: Run visual suite | |
| needs: resolve | |
| if: needs.resolve.outputs.authorized == 'true' | |
| # @main pins us to the merged version of the reusable workflow so PRs to | |
| # explorer-automation that touch run-visual-suite.yml don't accidentally | |
| # affect every unity-explorer PR's visual run. | |
| uses: decentraland/explorer-automation/.github/workflows/run-visual-suite.yml@main | |
| with: | |
| mode: test | |
| pr_number: ${{ needs.resolve.outputs.pr_number }} | |
| build_url: ${{ needs.resolve.outputs.build_url }} | |
| tests_ref: ${{ needs.resolve.outputs.tests_ref }} | |
| commit_sha: ${{ needs.resolve.outputs.head_short_sha }} | |
| branch_label: ${{ needs.resolve.outputs.head_ref }} | |
| secrets: inherit |