diff --git a/.circleci/config.yml b/.circleci/config.yml index 58465fd2d66d..250ef2f5abe3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,6 +45,15 @@ commands: echo "No relevance flag found; failing open (continuing job)." fi + restore-yarn-cache: + # The workspace skips the yarn cache (~130 MiB) to keep setup's upload + # short; only jobs that re-resolve dependencies (`yarn up`/`add`) need it. + steps: + - restore_cache: + keys: + - v16-dependencies-{{ checksum ".ci-deps-key" }} + - v16-dependencies- + jobs: setup: executor: node @@ -132,11 +141,13 @@ jobs: npm pkg set 'workspaces[]'='examples/todo-app' npm pkg set 'workspaces[]'='examples/github-app' npm pkg set 'workspaces[]'='examples/normalizr-relationships' - - restore_cache: - keys: - - v14-dependencies-{{ checksum "yarn.lock" }}-{{ checksum "examples/github-app/package.json" }}-{{ checksum "examples/todo-app/package.json" }} - # fallback to using the latest cache if no exact match is found - - v14-dependencies- + - run: + # Hash the manifests before trimming and `yarn up` rewrite them, + # so the same key restores and saves. + name: Compute dependency cache key + command: | + git show HEAD:package.json HEAD:yarn.lock HEAD:examples/todo-app/package.json HEAD:examples/github-app/package.json HEAD:examples/normalizr-relationships/package.json | sha256sum > .ci-deps-key + - restore-yarn-cache - run: name: yarn install command: | @@ -144,8 +155,7 @@ jobs: - save_cache: paths: - .yarn/cache - - .yarn/install-state.gz - key: v14-dependencies-{{ checksum "yarn.lock" }}-{{ checksum "examples/github-app/package.json" }}-{{ checksum "examples/todo-app/package.json" }} + key: v16-dependencies-{{ checksum ".ci-deps-key" }} - run: # These are independent (babel/rollup compile from src, not tsc output), # so run them concurrently to shorten the critical path. Legacy types @@ -162,7 +172,11 @@ jobs: root: ~/ paths: # explicitly list so we can ignore some directories that are not needed - - project/.yarn + # .yarn/cache is left out; see restore-yarn-cache + - project/.yarn/releases + - project/.yarn/plugins + - project/.yarn/install-state.gz + - project/.ci-deps-key - project/__tests__ - project/examples/todo-app - project/examples/github-app @@ -220,6 +234,12 @@ jobs: flag: tests - attach_workspace: at: ~/ + - unless: + # `latest` uses the installed React as-is + condition: + equal: ["latest", << parameters.react-version >>] + steps: + - restore-yarn-cache - run: name: Installing React Version command: | @@ -276,6 +296,7 @@ jobs: flag: tests - attach_workspace: at: ~/ + - restore-yarn-cache - run: command: | node --version @@ -301,6 +322,7 @@ jobs: flag: esmodule - attach_workspace: at: ~/ + - restore-yarn-cache - run: name: Install TypeScript Version command: | diff --git a/.cursor/rules/ci-config.mdc b/.cursor/rules/ci-config.mdc index c3a1f356b2d0..9c18a97e2be6 100644 --- a/.cursor/rules/ci-config.mdc +++ b/.cursor/rules/ci-config.mdc @@ -21,12 +21,14 @@ alwaysApply: false - `typecheck` also runs `yarn check:typeperf` ([scripts/typeperf](../../scripts/typeperf/README.md)), which reads the `ci:build:types` output from `setup`'s workspace. - Never `git fetch --depth` the base branch in the relevance check: a shallow fetch severs the merge base and the three-dot diff fails. - Changing root `package.json` `workspaces` requires updating the `setup` job's workspace trimming step. +- `setup`'s workspace leaves out the yarn cache (`.yarn/cache`) to keep its upload short. Jobs that re-resolve dependencies (`yarn up`/`add`) run `restore-yarn-cache`, keyed on `.ci-deps-key`, a hash of the manifests as committed (taken before trimming and `yarn up` rewrite them). ## GitHub Actions (`.github/workflows/`) - Workflows install only needed workspaces via `./scripts/ci-install.sh [extra-workspace ...]`. - `skills.yml` `paths` must cover every input of `website/framework-docs/skillReferences.mjs` (docs, skill manifests, the generator and its deps). - `editor-types.yml` reruns `yarn copy:websitetypes` and fails if `website/src/components/Playground/editor-types` changes. It needs the `website` workspace (for deps like `bignumber.js`), which CircleCI's `setup` drops. Its `paths` must cover every input of `scripts/copywebsitetypes.sh`. +- `site-preview.yml` runs one `build` job (one install for the typecheck and the build). It builds the site directly (no Vercel CLI, only the packages it imports via `ci:build:website`, `VERCEL_ENV=preview` to include drafts), restores Docusaurus' webpack cache (only master pushes save it, so PRs share one entry), and fails on any `[WARNING]`/`[ERROR]` line. Broken links are `warn` in `docusaurus.config.ts` so this check catches them without failing Vercel deploys. - `site-preview.yml`/`site-release.yml` `paths` (`website/**`, `docs/{core,rest,graphql}/**`) must match `SITE_PATHS` in `website/scripts/vercel-ignore.sh`. - `benchmark-react.yml` caches Playwright browsers keyed on the resolved `playwright` version from `examples/benchmark-react`; bumping playwright invalidates the cache automatically. - Benchmark workflows (`benchmark.yml`, `benchmark-react.yml`) tune the host (CPU governor, swapoff) and pin CPUs with `taskset` — they must run directly on the runner, not in a `container:`. diff --git a/.github/workflows/site-preview.yml b/.github/workflows/site-preview.yml index 431c6c962923..3aaf10c6e148 100644 --- a/.github/workflows/site-preview.yml +++ b/.github/workflows/site-preview.yml @@ -10,13 +10,24 @@ on: - 'docs/rest/**' - 'docs/graphql/**' - '.github/workflows/site-preview.yml' + # Refreshes the webpack cache that PRs restore from + push: + branches: + - master + paths: + - 'website/**' + - 'docs/core/**' + - 'docs/rest/**' + - 'docs/graphql/**' + - '.github/workflows/site-preview.yml' concurrency: group: site-preview-${{ github.head_ref || github.ref }} cancel-in-progress: true jobs: - typecheck: + # One job so the install happens once: the typecheck is short next to it + build: runs-on: ubuntu-latest steps: - name: Checkout @@ -31,24 +42,37 @@ jobs: cache: 'yarn' - name: Install packages run: ./scripts/ci-install.sh website - - name: Build package types - run: yarn ci:build:types + - name: Build package types and the packages the website imports + run: yarn ci:build:website - name: Typecheck website run: yarn workspace rdc-website typecheck - - build: - runs-on: ubuntu-latest - env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} - steps: - - name: Checkout - uses: actions/checkout@v7 + # Docusaurus' webpack cache (~73 MiB compressed). Only master saves it, so + # PRs share one fresh entry instead of each storing their own; stale + # modules just miss. + - uses: actions/cache/restore@v6 with: - fetch-depth: 1 - - name: Install Vercel CLI - run: npm install --global vercel@latest - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + path: website/node_modules/.cache + key: website-build-${{ hashFiles('yarn.lock') }} + restore-keys: | + website-build-${{ hashFiles('yarn.lock') }}- + website-build- + - name: Build website + env: + # Build drafts like the Vercel preview does + VERCEL_ENV: preview + # explicit `shell: bash` adds pipefail, so a failed build isn't masked by tee + shell: bash + run: | + yarn workspace rdc-website build 2>&1 | tee build.log + # Warnings (broken links, webpack warnings) fail the check, but not + # the Vercel deploy, which only stops on errors + if grep -E '\[(WARNING|ERROR)\]' build.log; then + echo "::error::Website build logged warnings (listed above)" + exit 1 + fi + - if: github.event_name == 'push' + uses: actions/cache/save@v6 + with: + path: website/node_modules/.cache + # Unique per run: an existing key can't be overwritten + key: website-build-${{ hashFiles('yarn.lock') }}-${{ github.run_id }} diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000000..406d10542cd2 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,6 @@ +codecov: + # Report as soon as the coverage upload is processed, instead of holding + # the status until every other CI job has finished. + require_ci_to_pass: false + notify: + wait_for_ci: false diff --git a/package.json b/package.json index 1eeff5aa957e..bae491c170d9 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,8 @@ "ci:build:types": "yarn build:copy:ambient && tsc --build --builders 1", "ci:build:legacy-types": "yarn workspaces foreach -Wpiv --include @data-client/endpoint --include @data-client/normalizr --include @data-client/rest run build:legacy-types", "ci:build-test-lib": "yarn workspace @data-client/core run build:lib && yarn workspace @data-client/test run build:lib && yarn workspace @data-client/test run build:bundle", + "ci:build:website": "run-p ci:build:types ci:build:website-lib", + "ci:build:website-lib": "yarn workspaces foreach -WptivR --from rdc-website --no-private run build:lib", "ci:build:esmodule": "yarn workspaces foreach -WptivR --from @data-client/react --from @data-client/rest --from @data-client/graphql run build:lib && yarn workspace @data-client/normalizr run build:js:node && yarn workspace @data-client/endpoint run build:js:node", "ci:build:bundlesize": "yarn workspaces foreach -Wptiv --no-private run build:lib && yarn workspace test-bundlesize run build:sizecompare", "build:benchmark": "yarn workspaces foreach -WptivR --from @data-client/core --from @data-client/endpoint --from @data-client/normalizr run build:lib && yarn workspace example-benchmark run build", diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index 4c51fb78c658..ad066e44d0d2 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -54,7 +54,7 @@ const config: Config = { markdown: { mermaid: true, hooks: { - onBrokenMarkdownLinks: 'log', + onBrokenMarkdownLinks: 'warn', }, // Vercel preview deploys publish `draft: true` pages so PRs can review them; // production (VERCEL_ENV=production) and local builds still drop them. @@ -225,7 +225,7 @@ const config: Config = { customFields: { repoUrl: 'https://github.com/reactive/data-client', }, - onBrokenLinks: 'log', + onBrokenLinks: 'warn', future: { // Generated Vue mirror pages have no git history; read their source's experimental_vcs: {