Promote catalog fields to base #17890
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: CI Host | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| paths: | |
| - "packages/host/**" | |
| - "packages/base/**" | |
| - "packages/boxel-icons/**" | |
| - "packages/boxel-ui/**" | |
| - "packages/catalog-realm/**" | |
| - "packages/eslint-plugin-boxel/**" | |
| - "packages/realm-server/**" | |
| - "packages/runtime-common/**" | |
| - ".github/workflows/ci-host.yaml" | |
| - "package.json" | |
| - "pnpm-lock.yaml" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| id-token: write | |
| pull-requests: read | |
| jobs: | |
| check-percy: | |
| name: Check if Percy is needed | |
| runs-on: ubuntu-latest | |
| outputs: | |
| percy_needed: ${{ steps.check.outputs.percy_needed }} | |
| steps: | |
| - name: Check for UI-relevant changes | |
| id: check | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| if [[ "${{ github.event_name }}" != "pull_request" ]]; then | |
| echo "percy_needed=true" >> "$GITHUB_OUTPUT" | |
| echo "Not a pull request — Percy will always run" | |
| exit 0 | |
| fi | |
| if [[ "${{ github.event.pull_request.draft }}" == "true" ]]; then | |
| echo "percy_needed=false" >> "$GITHUB_OUTPUT" | |
| echo "Skipping Percy — PR is a draft. Percy snapshots are limited (10k/month), so they only run once a PR is marked as ready for review to avoid burning through the quota on work-in-progress PRs." | |
| exit 0 | |
| fi | |
| CHANGED_FILES=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files --paginate --jq '.[].filename') | |
| percy_needed=false | |
| while IFS= read -r file; do | |
| case "$file" in | |
| packages/host/*|packages/boxel-ui/*|packages/boxel-icons/*|packages/base/*|packages/catalog-realm/*|packages/runtime-common/*) | |
| percy_needed=true | |
| echo "UI-relevant change detected: $file" | |
| break | |
| ;; | |
| esac | |
| done <<< "$CHANGED_FILES" | |
| echo "percy_needed=$percy_needed" >> "$GITHUB_OUTPUT" | |
| if [ "$percy_needed" = "true" ]; then | |
| echo "Percy will run — UI-relevant changes detected" | |
| else | |
| echo "Percy will be skipped — no UI-relevant changes" | |
| fi | |
| test-web-assets: | |
| name: Build test web assets | |
| uses: ./.github/workflows/test-web-assets.yaml | |
| with: | |
| caller: ci-host | |
| skip_catalog: true | |
| concurrency: | |
| group: ci-host-test-web-assets-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| live-test: | |
| name: Live Tests (realm) | |
| if: github.event.action != 'ready_for_review' | |
| runs-on: ubuntu-latest | |
| needs: test-web-assets | |
| concurrency: | |
| group: boxel-live-test-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/init | |
| - name: Download test web assets | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: ${{ needs.test-web-assets.outputs.artifact_name }} | |
| path: .test-web-assets-artifact | |
| - name: Restore test web assets into workspace | |
| shell: bash | |
| run: | | |
| shopt -s dotglob | |
| cp -a .test-web-assets-artifact/. ./ | |
| - name: Disable TCP/UDP network offloading | |
| run: sudo ethtool -K eth0 tx off rx off | |
| - name: Start test services (icons + host dist + realm servers) | |
| run: mise run test-services:host | tee -a /tmp/server.log & | |
| - name: Create realm users | |
| run: pnpm register-realm-users | |
| working-directory: packages/matrix | |
| - name: Install D-Bus helpers | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y dbus-x11 upower | |
| sudo service dbus restart | |
| sudo service upower restart | |
| - name: Live test suite | |
| run: dbus-run-session -- pnpm test:live | |
| working-directory: packages/host | |
| env: | |
| DBUS_SYSTEM_BUS_ADDRESS: unix:path=/run/dbus/system_bus_socket | |
| - name: Upload junit report | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: host-live-test-report | |
| path: junit/host-live.xml | |
| retention-days: 30 | |
| - name: Print realm server logs | |
| if: ${{ !cancelled() }} | |
| run: cat /tmp/server.log | |
| host-test: | |
| name: Host Tests | |
| runs-on: ubuntu-latest | |
| needs: [test-web-assets, check-percy] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shardIndex: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] | |
| shardTotal: [20] | |
| concurrency: | |
| group: boxel-host-test${{ github.head_ref || github.run_id }}-shard${{ matrix.shardIndex }} | |
| cancel-in-progress: true | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/init | |
| - name: Download test web assets | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: ${{ needs.test-web-assets.outputs.artifact_name }} | |
| path: .test-web-assets-artifact | |
| - name: Restore test web assets into workspace | |
| shell: bash | |
| run: | | |
| shopt -s dotglob | |
| cp -a .test-web-assets-artifact/. ./ | |
| # this is to hopefully address the CI network flakiness that we | |
| # occasionally see in host tests. | |
| # https://github.com/actions/runner-images/issues/1187#issuecomment-686735760 | |
| - name: Disable TCP/UDP network offloading | |
| run: sudo ethtool -K eth0 tx off rx off | |
| - name: Start test services (icons + host dist + realm servers) | |
| run: mise run test-services:host | tee -a /tmp/server.log & | |
| env: | |
| SKIP_CATALOG: true | |
| - name: create realm users | |
| run: pnpm register-realm-users | |
| working-directory: packages/matrix | |
| - name: Install D-Bus helpers | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y dbus-x11 upower | |
| sudo service dbus restart | |
| sudo service upower restart | |
| - name: host test suite (shard ${{ matrix.shardIndex }}) | |
| run: | | |
| if [ "$PERCY_ENABLED" = "true" ]; then | |
| TEST_CMD="pnpm test-with-percy" | |
| else | |
| echo "::notice::Skipping Percy snapshots — no UI-relevant changes detected" | |
| TEST_CMD="pnpm test:wait-for-servers" | |
| fi | |
| set +e | |
| dbus-run-session -- $TEST_CMD 2>&1 | tee /tmp/test-output.log | |
| exit_code=${PIPESTATUS[0]} | |
| if [ $exit_code -ne 0 ] && grep -q "ChunkLoadError" /tmp/test-output.log; then | |
| echo "" | |
| echo "::warning::ChunkLoadError detected — retrying shard ${{ matrix.shardIndex }}..." | |
| echo "" | |
| dbus-run-session -- $TEST_CMD | |
| exit_code=$? | |
| fi | |
| exit $exit_code | |
| env: | |
| PERCY_ENABLED: ${{ needs.check-percy.outputs.percy_needed }} | |
| SKIP_CATALOG: true | |
| PERCY_GZIP: true | |
| PERCY_TOKEN: ${{ needs.check-percy.outputs.percy_needed == 'true' && secrets.PERCY_TOKEN_HOST || '' }} | |
| PERCY_PARALLEL_NONCE: ${{ github.run_id }}-${{ github.run_attempt }} | |
| HOST_TEST_PARTITION: ${{ matrix.shardIndex }} | |
| HOST_TEST_PARTITION_COUNT: ${{ matrix.shardTotal }} | |
| DBUS_SYSTEM_BUS_ADDRESS: unix:path=/run/dbus/system_bus_socket | |
| working-directory: packages/host | |
| - name: Upload junit report to GitHub Actions Artifacts | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: host-test-report-${{ matrix.shardIndex }} | |
| path: junit/host-${{ matrix.shardIndex }}.xml | |
| retention-days: 30 | |
| - name: Extract memory report | |
| if: ${{ !cancelled() }} | |
| run: node scripts/extract-memory-report.mjs /tmp/test-output.log /tmp/memory-report-${{ matrix.shardIndex }}.json | |
| working-directory: packages/host | |
| - name: Upload memory report | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: memory-report-${{ matrix.shardIndex }} | |
| path: /tmp/memory-report-${{ matrix.shardIndex }}.json | |
| retention-days: 30 | |
| - name: Print realm server logs | |
| if: ${{ !cancelled() }} | |
| run: cat /tmp/server.log | |
| - name: Extract worker and prerender logs | |
| if: ${{ !cancelled() }} | |
| run: | | |
| grep -E '^\[start:worker-development' /tmp/server.log > /tmp/worker-manager.log || true | |
| grep -E '^\[start:prerender-dev' /tmp/server.log > /tmp/prerender-server.log || true | |
| grep -E '^\[start:prerender-manager-dev' /tmp/server.log > /tmp/prerender-manager.log || true | |
| grep -E '^\[start:development' /tmp/server.log > /tmp/start-development.log || true | |
| grep -E '^\[start:test-realms|^\[start:worker-test' /tmp/server.log > /tmp/test-realms.log || true | |
| grep -E '^\[start:icons' /tmp/server.log > /tmp/icon-server.log || true | |
| grep -E '^\[start:host-dist' /tmp/server.log > /tmp/host-dist.log || true | |
| - name: Upload realm server log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: realm-server-log-${{ matrix.shardIndex }} | |
| path: /tmp/server.log | |
| retention-days: 30 | |
| - name: Upload worker manager log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: worker-manager-log-${{ matrix.shardIndex }} | |
| path: /tmp/worker-manager.log | |
| retention-days: 30 | |
| - name: Upload prerender server log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: prerender-server-log-${{ matrix.shardIndex }} | |
| path: /tmp/prerender-server.log | |
| retention-days: 30 | |
| - name: Upload prerender manager log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: prerender-manager-log-${{ matrix.shardIndex }} | |
| path: /tmp/prerender-manager.log | |
| retention-days: 30 | |
| - name: Upload start:development log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: start-development-log-${{ matrix.shardIndex }} | |
| path: /tmp/start-development.log | |
| retention-days: 30 | |
| - name: Upload test-realms log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: test-realms-log-${{ matrix.shardIndex }} | |
| path: /tmp/test-realms.log | |
| retention-days: 30 | |
| - name: Upload icon server log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: icon-server-log-${{ matrix.shardIndex }} | |
| path: /tmp/icon-server.log | |
| retention-days: 30 | |
| - name: Upload host-dist log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: host-dist-log-${{ matrix.shardIndex }} | |
| path: /tmp/host-dist.log | |
| retention-days: 30 | |
| - name: Upload testem log | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: testem-log-${{ matrix.shardIndex }} | |
| path: junit/host-testem.log | |
| retention-days: 30 | |
| host-percy-finalize: | |
| name: Finalise Percy | |
| if: ${{ !cancelled() && needs.check-percy.outputs.percy_needed == 'true' }} | |
| concurrency: | |
| group: host-percy-finalize-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| needs: [host-test, check-percy] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/init | |
| - name: Finalise Percy | |
| run: npx percy build:finalize | |
| working-directory: packages/host | |
| env: | |
| PERCY_TOKEN: ${{ secrets.PERCY_TOKEN_HOST }} | |
| PERCY_PARALLEL_NONCE: ${{ github.run_id }}-${{ github.run_attempt }} | |
| host-merge-reports-and-publish: | |
| name: Merge Host reports and publish | |
| if: ${{ !cancelled() && (needs.host-test.result == 'success' || needs.host-test.result == 'failure') }} | |
| concurrency: | |
| group: host-merge-reports-and-publish-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| needs: host-test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| # checks/pull-requests: needed by publish-unit-test-result-action to post | |
| # the junit summary back to the PR / commit. | |
| checks: write | |
| pull-requests: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/init | |
| - name: Download JUnit reports from GitHub Actions Artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: all-host-reports | |
| pattern: host-test-report-* | |
| merge-multiple: true | |
| - run: ls | |
| - run: ls all-host-reports | |
| - name: Merge reports | |
| run: npx junit-report-merger host.xml "./all-host-reports/*.xml" | |
| # host.xml has classname="Chrome 134.0", change to classname="Chrome" to prevent false test removal/addition warnings | |
| - name: Remove Chrome version number | |
| run: sed -i -E 's/classname="Chrome [^"]*"/classname="Chrome"/' host.xml | |
| - name: Upload merged report | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: host-test-report-merged | |
| path: host.xml | |
| retention-days: 30 | |
| - name: Publish test results | |
| id: publish-tests | |
| uses: EnricoMi/publish-unit-test-result-action@170bf24d20d201b842d7a52403b73ed297e6645b # 2.18.0 | |
| if: ${{ !cancelled() }} | |
| with: | |
| junit_files: host.xml | |
| check_name: Host Test Results | |
| comment_mode: "off" | |
| json_file: test-results.json | |
| - name: Build host-tests slot | |
| if: ${{ !cancelled() && hashFiles('test-results.json') != '' }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p slot | |
| { | |
| echo "### Host Test Results" | |
| echo | |
| jq -r '.summary' test-results.json | |
| failures=$(jq -r '((.stats.tests_fail // 0) + (.stats.tests_error // 0))' test-results.json) | |
| check_url=$(jq -r '.check_url // empty' test-results.json) | |
| if [ -n "$check_url" ] && [ "$failures" -gt 0 ]; then | |
| echo | |
| echo "For more details on these errors, see [this check]($check_url)." | |
| fi | |
| } > slot/slot.md | |
| - name: Upload host-tests slot | |
| if: ${{ !cancelled() && hashFiles('slot/slot.md') != '' }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: pr-comment-slot-host-tests | |
| path: slot/ | |
| retention-days: 7 | |
| post-pr-status: | |
| name: Update PR status comment | |
| needs: | |
| - host-merge-reports-and-publish | |
| if: ${{ !cancelled() && needs.host-merge-reports-and-publish.result == 'success' }} | |
| uses: ./.github/workflows/pr-status-comment.yml | |
| permissions: | |
| contents: read | |
| issues: write | |
| pull-requests: write | |
| actions: read | |
| with: | |
| head-sha: ${{ github.event.pull_request.head.sha || github.sha }} | |
| slots: host-tests | |
| secrets: inherit | |
| host-memory-baseline: | |
| name: Host Memory Baseline | |
| if: ${{ !cancelled() && (needs.host-test.result == 'success' || needs.host-test.result == 'failure') }} | |
| concurrency: | |
| group: host-memory-baseline-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| needs: host-test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/init | |
| - name: Download memory reports | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: all-memory-reports | |
| pattern: memory-report-* | |
| merge-multiple: true | |
| - name: Check memory baseline | |
| run: node packages/host/scripts/check-memory-baseline.mjs all-memory-reports packages/host/memory-baseline.json | |
| host-memory-baseline-update: | |
| name: Update Host Memory Baseline | |
| # Intentionally scoped to push-to-main only so the job only runs in a | |
| # context where the PR workflow file cannot be modified by an untrusted | |
| # branch — this is the one job that holds `contents: write`. | |
| # | |
| # We refresh the baseline whenever host-test completes (success OR failure), | |
| # not only on full green. An unrelated shard flake otherwise freezes the | |
| # baseline indefinitely, which then blocks downstream PRs on drift that has | |
| # nothing to do with their diffs. Modules missing from the current reports | |
| # (because a shard failed to upload) keep their prior baseline values — | |
| # the merge is handled in update-memory-baseline.mjs. | |
| if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && !cancelled() && (needs.host-test.result == 'success' || needs.host-test.result == 'failure') }} | |
| concurrency: | |
| group: host-memory-baseline-update-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| needs: host-test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| # Need history past the triggering SHA so the staleness check below | |
| # can inspect commits between the workflow's SHA and origin/main. | |
| fetch-depth: 0 | |
| - uses: ./.github/actions/init | |
| - name: Download memory reports | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: all-memory-reports | |
| pattern: memory-report-* | |
| merge-multiple: true | |
| - name: Update memory baseline | |
| # Retry from the latest main: another PR may merge to main while host | |
| # CI is running (~15+ min), causing `git push` to be rejected. On each | |
| # retry we fetch and hard-reset to the freshest tip-of-main, then | |
| # re-run the merge-aware script so prior-baseline preservation stays | |
| # correct. | |
| # | |
| # Staleness guard: if a non-baseline commit landed on main since this | |
| # workflow was triggered, skip — that newer push triggered its own CI | |
| # run which will publish a baseline derived from its own code. We | |
| # ignore intervening `[skip ci]` baseline-update commits from this | |
| # same job because those don't represent newer code, just concurrent | |
| # baseline updates that the merge-aware script handles correctly. | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| WORKFLOW_SHA="${{ github.sha }}" | |
| for attempt in 1 2 3 4 5; do | |
| git fetch origin main | |
| if [ "$(git rev-parse origin/main)" != "$WORKFLOW_SHA" ] && \ | |
| git log --format="%s" "$WORKFLOW_SHA..origin/main" | grep -qv "Update host test memory baseline"; then | |
| echo "main has advanced past $WORKFLOW_SHA with non-baseline commits — skipping (a newer CI run will publish the baseline)." | |
| exit 0 | |
| fi | |
| git reset --hard origin/main | |
| node packages/host/scripts/update-memory-baseline.mjs all-memory-reports packages/host/memory-baseline.json | |
| if git diff --quiet packages/host/memory-baseline.json; then | |
| echo "Baseline unchanged — nothing to commit." | |
| exit 0 | |
| fi | |
| git add packages/host/memory-baseline.json | |
| git commit -m "Update host test memory baseline [skip ci]" | |
| if git push; then | |
| exit 0 | |
| fi | |
| echo "Push rejected on attempt $attempt — retrying after $((attempt * 5))s" | |
| sleep $((attempt * 5)) | |
| done | |
| echo "Failed to push memory baseline after 5 attempts" | |
| exit 1 |