diff --git a/.github/CI.md b/.github/CI.md index 271311ede03..c5f13305e5f 100644 --- a/.github/CI.md +++ b/.github/CI.md @@ -1,7 +1,11 @@ # CI selection and acceptance ownership +GitHub-hosted jobs restore their event-specific dependency caches first. Trusted PRs also try the default branch's push caches, so a new PR can reuse installed dependencies before it has saved a cache of its own. The `node_modules` fallback requires the identical lockfile hash. Saves stay in the event-specific namespace, fork PRs do not receive the fallback, and push jobs never restore PR caches. Blacksmith sticky disks keep their existing event-scoped keys. Dependency installation still validates the frozen lockfile after every restore. Explicit save steps run immediately after installation, while the composite action's path inputs are available, so later test failures do not prevent dependency-cache population. + The `changes` job runs Turborepo 2.9.14's `affectedTasks` query before installing application dependencies or provisioning services. `turbo.json` records package dependency propagation; `apps/sim/turbo.json` partitions the app into shared runtime, server, workspace UI, and acceptance tasks. `.github/ci-suites.json` turns those tasks into job matrices. The uploaded `ci-plan` artifact names changed files, selected tasks, attribution reasons, and any fallback. +The integration matrix's `push/db` job owns dependency-cache uploads; the other integration jobs only restore. Exact hits skip uploads. This avoids concurrently compressing the same dependency trees across all shards merely to lose the shared-key reservation race. + A PR compares its merge base with the checked-out merge commit. Main/staging pushes execute all checks; the parent `ci` workflow skips checks on `dev` pushes, while PRs targeting `dev` still run checks. A manual `checks` run executes all checks unless supplied a full base commit SHA to reproduce a scoped plan. Missing history, an empty diff, unknown files outside the workspace graph, root script/CI changes, or a planner error run every check. Missing selection outputs fail the aggregate gate. The gate also rejects an omitted dependency, any failed/cancelled job, and any skip that its explicit selection flag did not authorize. | Change | Expensive checks selected | diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 575623a6fb9..4e94e99ded9 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -18,10 +18,13 @@ inputs: description: npm registry to write an .npmrc for, so `npm publish` reads NODE_AUTH_TOKEN. Empty writes none. required: false default: '' + save-dependency-cache: + description: Save GitHub dependency caches after installation. Parallel matrices can elect one writer. + required: false + default: 'true' -# Cache keys are scoped by event name, and fork PRs get their own namespace on -# top: untrusted fork runs must never share a cache with push runs (whose caches -# feed production image builds) or with trusted internal-PR runs. +# Writes stay scoped by event and fork status. Trusted GitHub PRs can read the +# default branch's push caches; push jobs never read PR caches. # # node_modules also keys on the lockfile hash: a sticky disk is a mutable volume, # and `bun install --frozen-lockfile` adds what the lockfile needs without @@ -45,6 +48,7 @@ runs: registry-url: ${{ inputs.registry-url }} - name: Mount Bun cache + if: inputs.provider == '' || inputs.provider == 'blacksmith' uses: ./.github/actions/cache with: provider: ${{ inputs.provider }} @@ -52,20 +56,51 @@ runs: path: ~/.bun/install/cache - name: Mount node_modules + if: inputs.provider == '' || inputs.provider == 'blacksmith' uses: ./.github/actions/cache with: provider: ${{ inputs.provider }} key: ${{ github.repository }}-node-modules-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ hashFiles('bun.lock') }} path: ./node_modules + - name: Restore Bun cache + id: bun-cache + if: inputs.provider != '' && inputs.provider != 'blacksmith' + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 + with: + key: ${{ github.repository }}-bun-cache-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ github.run_id }} + restore-keys: | + ${{ github.repository }}-bun-cache-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}- + ${{ github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork && format('{0}-bun-cache-push-', github.repository) || '' }} + path: ~/.bun/install/cache + + - name: Restore node_modules + id: node-modules-cache + if: inputs.provider != '' && inputs.provider != 'blacksmith' + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 + with: + key: ${{ github.repository }}-node-modules-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ hashFiles('bun.lock') }}-${{ github.run_id }} + restore-keys: | + ${{ github.repository }}-node-modules-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ hashFiles('bun.lock') }}- + ${{ github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork && format('{0}-node-modules-push-{1}-', github.repository, hashFiles('bun.lock')) || '' }} + path: ./node_modules + - name: Mount Turbo cache - if: inputs.turbo-cache-key != '' + if: inputs.turbo-cache-key != '' && (inputs.provider == '' || inputs.provider == 'blacksmith') uses: ./.github/actions/cache with: provider: ${{ inputs.provider }} key: ${{ github.repository }}-${{ inputs.turbo-cache-key }}-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }} path: ./.turbo + - name: Restore and save Turbo cache + if: inputs.turbo-cache-key != '' && inputs.provider != '' && inputs.provider != 'blacksmith' + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 + with: + key: ${{ github.repository }}-${{ inputs.turbo-cache-key }}-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ github.run_id }} + restore-keys: ${{ github.repository }}-${{ inputs.turbo-cache-key }}-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}- + path: ./.turbo + # Bun retries a failed request itself, but a registry connection that stalls # without failing leaves `bun install` waiting until the job's own timeout # cancels it, the whole budget spent on one hung step. Healthy installs finish @@ -83,3 +118,17 @@ runs: done echo "::error title=bun install stalled::both attempts ran past 3 minutes" exit 1 + + - name: Save Bun cache + if: inputs.provider != '' && inputs.provider != 'blacksmith' && inputs.save-dependency-cache == 'true' && steps.bun-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 + with: + key: ${{ github.repository }}-bun-cache-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ github.run_id }} + path: ~/.bun/install/cache + + - name: Save node_modules + if: inputs.provider != '' && inputs.provider != 'blacksmith' && inputs.save-dependency-cache == 'true' && steps.node-modules-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 + with: + key: ${{ github.repository }}-node-modules-${{ github.event_name }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-${{ hashFiles('bun.lock') }}-${{ github.run_id }} + path: ./node_modules diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index bd202022778..caf192bc274 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -136,6 +136,7 @@ jobs: uses: ./.github/actions/setup with: provider: github + save-dependency-cache: ${{ matrix.provision == 'push' && matrix.shard == 'db' }} - name: Provision a fresh database through the supported command working-directory: packages/db