Skip to content

Give the realm-server session refresher the same floor and backoff as the per-realm one #3346

Give the realm-server session refresher the same floor and backoff as the per-realm one

Give the realm-server session refresher the same floor and backoff as the per-realm one #3346

Workflow file for this run

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"