Repository navigation
Give the realm-server session refresher the same floor and backoff as the per-realm one #3346
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: Lint Catalog | |
| # The catalog (cardstack/boxel-catalog) type-checks and lints its cards against | |
| # boxel, so a platform change can break the catalog's lint while everything in | |
| # boxel passes. This lints the catalog against each change, the way the | |
| # catalog's own CI Lint does, and fails on the errors the change introduces, | |
| # including the ones it would leave catalog main with behind a paired catalog | |
| # pull request that isn't ready to follow it. See packages/catalog/README.md. | |
| # | |
| # Production deploys a boxel commit with the catalog at the revision it pins in | |
| # packages/catalog/test-subset.json, so this also lints the whole catalog at | |
| # the pin against each change, and fails on every error the change adds there. | |
| # | |
| # A pull request declares its catalog pair in its description, so editing the | |
| # description re-runs this. | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| types: [opened, synchronize, reopened, edited] | |
| # Observability-only changes skip linting, as they do in CI Lint. | |
| paths-ignore: | |
| - "packages/observability/**" | |
| # Pull requests: a new push or description edit cancels the run in progress | |
| # for the same branch. Pushes to main share one group and never cancel a run in | |
| # progress, so a burst of merges runs the commit in progress and then the | |
| # newest. The main group is `push:main` because `:` cannot appear in a branch | |
| # name, so no pull request's head_ref can land in it. | |
| concurrency: | |
| group: lint-catalog-${{ github.head_ref || (github.event_name == 'push' && github.ref == 'refs/heads/main' && 'push:main') || github.run_id }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| permissions: | |
| contents: read | |
| jobs: | |
| catalog: | |
| name: Lint Catalog | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| # A pull request checks out its merge commit, whose first parent is | |
| # the base branch the catalog may also be linted against below. | |
| fetch-depth: 2 | |
| - uses: ./.github/actions/init | |
| # boxel-catalog's production deploy runs this script from boxel main. | |
| - name: Test the catalog deploy check | |
| run: pnpm --dir packages/catalog test:deploy-check | |
| # The catalog change a pull request depends on, or that follows it, is | |
| # the one its description pairs it with (scripts/pairing.ts). Lint that | |
| # pull request's head in place of main, and catalog main as well below. | |
| # Production deploys the catalog at the revision boxel pins, so a catalog | |
| # pull request this change merges after must be in the pin once it has | |
| # merged. | |
| - name: Read the catalog pairing | |
| id: pairing | |
| if: github.event_name == 'pull_request' | |
| env: | |
| PR_BODY: ${{ github.event.pull_request.body }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| PR_BASE: ${{ github.event.pull_request.base.ref }} | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| node packages/catalog/scripts/pairing.ts \ | |
| --repository="$GITHUB_REPOSITORY" \ | |
| --number="$PR_NUMBER" \ | |
| --base="$PR_BASE" \ | |
| --counterpart=cardstack/boxel-catalog \ | |
| --pin=packages/catalog/test-subset.json \ | |
| --out="$RUNNER_TEMP/catalog-pairing.json" | |
| # An open pair this change merges after is what it builds on, and | |
| # lands first; otherwise an open pair it merges before is the | |
| # catalog fix that follows it. | |
| sha=$(jq -r '[.pairs[] | select(.merged | not)] | |
| | (map(select(.key == "merges-after")) + map(select(.key == "merges-before"))) | |
| | .[0].headSha // empty' "$RUNNER_TEMP/catalog-pairing.json") | |
| if [ -n "$sha" ]; then | |
| echo "catalog_ref=$sha" >> "$GITHUB_OUTPUT" | |
| echo "paired=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "catalog_ref=main" >> "$GITHUB_OUTPUT" | |
| echo "paired=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Test the pairing check | |
| if: always() | |
| run: pnpm --dir packages/catalog test:pairing | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| repository: cardstack/boxel-catalog | |
| ref: ${{ steps.pairing.outputs.catalog_ref || 'main' }} | |
| path: packages/catalog/contents | |
| # Restore only: the base-branch step below can rebuild boxel-icons from | |
| # the base tree, which must not be saved under this change's key. | |
| - name: Restore boxel-icons build cache | |
| id: icons-cache | |
| uses: ./.github/actions/restore-icons-cache | |
| with: | |
| save: "false" | |
| - name: Build Boxel Icons | |
| if: steps.icons-cache.outputs.cache-hit != 'true' | |
| run: pnpm run build | |
| working-directory: packages/boxel-icons | |
| # The catalog's CI Lint builds Boxel UI before linting, so its type check | |
| # reads Boxel UI's declarations; build it here to check the same thing. | |
| - name: Build Boxel UI | |
| run: pnpm run build | |
| working-directory: packages/boxel-ui | |
| - name: Lint the catalog against this change | |
| id: head | |
| working-directory: packages/catalog | |
| run: | | |
| node scripts/lint-sweep.ts --record="$RUNNER_TEMP/catalog-lint-head.json" | |
| echo "errors=$(jq '.diagnostics | length' "$RUNNER_TEMP/catalog-lint-head.json")" >> "$GITHUB_OUTPUT" | |
| # The base branch's tree may not have these scripts. lint-sweep.ts | |
| # imports pairing.ts, so the two go together. | |
| cp scripts/lint-sweep.ts scripts/pairing.ts "$RUNNER_TEMP/" | |
| # A paired change is linted with its catalog pull request's head, but | |
| # catalog main is what gets linted against it from its merge until the | |
| # catalog pull request's. So lint catalog main against the change too, | |
| # then put the paired head back for the base-branch step. | |
| - name: Lint catalog main against this change | |
| id: main | |
| if: steps.pairing.outputs.paired == 'true' | |
| working-directory: packages/catalog | |
| run: | | |
| paired=$(git -C contents rev-parse HEAD) | |
| git -C contents fetch --quiet --depth=1 origin main | |
| git -C contents checkout --quiet --detach FETCH_HEAD | |
| echo "revision=$(git -C contents rev-parse HEAD)" >> "$GITHUB_OUTPUT" | |
| node scripts/lint-sweep.ts --record="$RUNNER_TEMP/catalog-main-lint-head.json" | |
| echo "errors=$(jq '.diagnostics | length' "$RUNNER_TEMP/catalog-main-lint-head.json")" >> "$GITHUB_OUTPUT" | |
| git -C contents checkout --quiet --detach "$paired" | |
| # Production deploys this boxel with the catalog at its pin, so the | |
| # whole catalog at the pin has to work with the change, not only the | |
| # subset files boxel's tests load. When the pin is a revision a step | |
| # above already linted against the change, that recording is reused. | |
| # It is still reported again below, as the pin, against the base | |
| # branch's pin: the reports above compare a revision only with itself. | |
| - name: Lint the catalog at this change's pin | |
| id: pin | |
| working-directory: packages/catalog | |
| env: | |
| MAIN_REVISION: ${{ steps.main.outputs.revision }} | |
| run: | | |
| pin=$(jq -r .revision test-subset.json) | |
| linted=$(git -C contents rev-parse HEAD) | |
| echo "revision=$pin" >> "$GITHUB_OUTPUT" | |
| if [ "$pin" = "$linted" ]; then | |
| cp "$RUNNER_TEMP/catalog-lint-head.json" "$RUNNER_TEMP/catalog-pin-lint-head.json" | |
| elif [ "$pin" = "$MAIN_REVISION" ]; then | |
| cp "$RUNNER_TEMP/catalog-main-lint-head.json" "$RUNNER_TEMP/catalog-pin-lint-head.json" | |
| else | |
| git -C contents fetch --quiet --depth=1 origin "$pin" | |
| git -C contents checkout --quiet --detach FETCH_HEAD | |
| node scripts/lint-sweep.ts --record="$RUNNER_TEMP/catalog-pin-lint-head.json" | |
| git -C contents checkout --quiet --detach "$linted" | |
| fi | |
| echo "errors=$(jq '.diagnostics | length' "$RUNNER_TEMP/catalog-pin-lint-head.json")" >> "$GITHUB_OUTPUT" | |
| # Errors the catalog also has against the base branch are not this | |
| # change's doing: the catalog may already be broken against boxel main. | |
| # So when this change's lint finds errors, lint the same catalog revision | |
| # against the base branch, and the report counts only the difference. | |
| # Catalog main, when it was linted above, gets the same comparison. The | |
| # catalog at the pin is compared with the base branch's own pin linted | |
| # against the base branch, since a change that moves the pin is answerable | |
| # for the errors the new pin brings too. | |
| # A push to main has no base to compare with, so every error counts. | |
| - name: Lint the catalog against the base branch | |
| id: base | |
| if: github.event_name == 'pull_request' && (steps.head.outputs.errors != '0' || (steps.main.outputs.errors || '0') != '0' || (steps.pin.outputs.errors || '0') != '0') | |
| env: | |
| HEAD_ERRORS: ${{ steps.head.outputs.errors }} | |
| MAIN_ERRORS: ${{ steps.main.outputs.errors || '0' }} | |
| MAIN_REVISION: ${{ steps.main.outputs.revision }} | |
| PIN_ERRORS: ${{ steps.pin.outputs.errors || '0' }} | |
| PIN_REVISION: ${{ steps.pin.outputs.revision }} | |
| run: | | |
| head=$(git rev-parse HEAD) | |
| git checkout --detach HEAD^1 | |
| pnpm install --frozen-lockfile | |
| # This change's builds stay in place when the base builds the same. | |
| if ! git diff --quiet HEAD "$head" -- packages/boxel-icons packages/boxel-ui pnpm-lock.yaml; then | |
| (cd packages/boxel-icons && pnpm run build) | |
| (cd packages/boxel-ui && pnpm run build) | |
| fi | |
| cd packages/catalog | |
| if [ "$HEAD_ERRORS" != 0 ]; then | |
| node "$RUNNER_TEMP/lint-sweep.ts" --record="$RUNNER_TEMP/catalog-lint-base.json" | |
| fi | |
| if [ "$MAIN_ERRORS" != 0 ]; then | |
| git -C contents checkout --quiet --detach "$MAIN_REVISION" | |
| node "$RUNNER_TEMP/lint-sweep.ts" --record="$RUNNER_TEMP/catalog-main-lint-base.json" | |
| fi | |
| if [ "$PIN_ERRORS" != 0 ]; then | |
| base_pin=$(jq -r '.revision // empty' test-subset.json 2>/dev/null || true) | |
| git -C contents fetch --quiet --depth=1 origin "${base_pin:-$PIN_REVISION}" | |
| git -C contents checkout --quiet --detach FETCH_HEAD | |
| node "$RUNNER_TEMP/lint-sweep.ts" --record="$RUNNER_TEMP/catalog-pin-lint-base.json" | |
| fi | |
| # Unpaired, this is catalog main, and errors the change adds to it fail | |
| # with how to declare a pair. Paired, this is the catalog pull request's | |
| # head, and its errors are for that pull request to fix. A failed catalog | |
| # main lint skips the base step, and without its baseline this report | |
| # would count errors the catalog already has as new ones. | |
| - name: Report catalog lint errors | |
| if: ${{ !cancelled() && steps.head.outcome == 'success' && steps.main.outcome != 'failure' && steps.pin.outcome != 'failure' && steps.base.outcome != 'failure' }} | |
| run: | | |
| args=(--report="$RUNNER_TEMP/catalog-lint-head.json") | |
| if [ -f "$RUNNER_TEMP/catalog-lint-base.json" ]; then | |
| args+=(--baseline="$RUNNER_TEMP/catalog-lint-base.json") | |
| fi | |
| if [ -f "$RUNNER_TEMP/catalog-pairing.json" ]; then | |
| args+=(--pairing="$RUNNER_TEMP/catalog-pairing.json") | |
| fi | |
| node "$RUNNER_TEMP/lint-sweep.ts" "${args[@]}" | |
| # Errors a paired change adds to catalog main stay there from its merge | |
| # until the catalog pull request's, so they pass only while a catalog | |
| # pull request this change merges before is approved, to merge right | |
| # after it. | |
| - name: Report what this change does to catalog main | |
| if: ${{ !cancelled() && steps.main.outcome == 'success' && steps.pin.outcome != 'failure' && steps.base.outcome != 'failure' }} | |
| run: | | |
| args=(--report="$RUNNER_TEMP/catalog-main-lint-head.json" --pairing="$RUNNER_TEMP/catalog-pairing.json") | |
| if [ -f "$RUNNER_TEMP/catalog-main-lint-base.json" ]; then | |
| args+=(--baseline="$RUNNER_TEMP/catalog-main-lint-base.json") | |
| fi | |
| node "$RUNNER_TEMP/lint-sweep.ts" "${args[@]}" | |
| # Every error the change adds to the catalog at its pin fails, paired or | |
| # not: production deploys this boxel with that catalog. A pairing only | |
| # names the catalog revision to pin instead. | |
| - name: Report what this change does to the catalog at its pin | |
| if: ${{ !cancelled() && steps.pin.outcome == 'success' && steps.base.outcome != 'failure' }} | |
| run: | | |
| args=(--report="$RUNNER_TEMP/catalog-pin-lint-head.json" --pinned) | |
| if [ -f "$RUNNER_TEMP/catalog-pin-lint-base.json" ]; then | |
| args+=(--baseline="$RUNNER_TEMP/catalog-pin-lint-base.json") | |
| fi | |
| if [ -f "$RUNNER_TEMP/catalog-pairing.json" ]; then | |
| args+=(--pairing="$RUNNER_TEMP/catalog-pairing.json") | |
| fi | |
| node "$RUNNER_TEMP/lint-sweep.ts" "${args[@]}" | |
| # A catalog pull request this change merges after has to be in the pin | |
| # before this change merges, and nothing re-runs this job when that pull | |
| # request merges. So while it is open this fails, after the lint above | |
| # has judged its head, and the push that re-pins once it merges is the | |
| # run that compares the pin with its merge commit. | |
| - name: Wait for the re-pin | |
| if: ${{ !cancelled() && steps.pairing.outcome == 'success' }} | |
| run: node packages/catalog/scripts/pairing.ts --pin-verdict="$RUNNER_TEMP/catalog-pairing.json" |