Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/CI.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CI selection and acceptance ownership

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 `changes` job runs Turborepo 2.11.10'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.

A PR compares the checked-out GitHub merge commit with its first parent: the actual target revision tested by that merge. The PR event's base SHA can become stale when the target advances. Scoping requires a matching GitHub merge ref and SHA, exactly two merge parents, and a usable target parent; otherwise every check runs. This works with the existing depth-two checkout without fetching older ancestry. 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.

Expand All @@ -24,7 +24,7 @@ Integration also depends on workspace UI because the desktop executor integratio

SEO depends on workspace UI and server code: landing pages reuse workspace pricing and preview components, provider models/pricing, and the block registry. These directory boundaries are not isolated application dependency graphs.

`affectedTasks` already uses task inputs. Do not enable `futureFlags.affectedUsingTaskInputs` just for this planner: that flag also changes pruning, which can pull CI-only cross-app task dependencies into production Docker contexts.
`affectedTasks` matches task inputs only under a task-level future flag; without one it reports every task of an affected package. The root `turbo.json` enables `futureFlags.filterUsingTasks`, which CI's package-name `--filter` calls are unaffected by. Do not use `futureFlags.affectedUsingTaskInputs` instead: that flag also changes pruning, which pulls CI-only cross-app task dependencies into production Docker contexts. `affectedTasks.items` also lists the prerequisites of affected tasks, so the planner selects `docs#build` through its own task filter, which applies before prerequisites are added.

Affected type-checks follow the package graph too; repository audits and lint run whenever the checks workflow runs. Workspace-only unit jobs use a free GitHub runner and do not start the app test shards.

Expand Down
6 changes: 6 additions & 0 deletions .github/scripts/ci-plan.gql
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ query($base: String!, $head: String!) {
}
}
}
# `items` also lists the prerequisites of affected tasks, and docs#build is one for
# ci:e2e-docs-platform. The task filter applies before prerequisites are added, so this
# selection holds docs#build only when the docs site itself changed.
docsSite: affectedTasks(base: $base, head: $head, tasks: ["docs#build"]) {
items { fullName }
}
}
4 changes: 2 additions & 2 deletions apps/sim/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"inputs": [
"$TURBO_DEFAULT$",
"!app/workspace/**",
"!app/(landing)/**",
"!app/[(]landing[)]/**",
"!app/api/**",
"!content/**",
"!public/library/**",
Expand Down Expand Up @@ -157,7 +157,7 @@
"ci:e2e-seo": {
"dependsOn": ["ci:server", "ci:ui"],
"inputs": [
"app/(landing)/**",
"app/[(]landing[)]/**",
"content/**",
"public/library/**",
"scripts/test-landing-seo-e2e.ts"
Expand Down
16 changes: 8 additions & 8 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
"remark-gfm": "4.0.1",
"remark-parse": "11.0.0",
"sharp": "0.35.5",
"turbo": "2.9.14",
"turbo": "2.11.10",
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Resolved
"unified": "11.0.5",
"unist-util-visit": "5.2.0",
"vitest": "^5.1.0",
Expand Down
12 changes: 12 additions & 0 deletions scripts/ci-changes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,18 @@ describe('CI task attribution through real Turborepo', () => {
e2e_build: true,
})
})
it('keeps landing route-group edits on the rendering and SEO path', () => {
const plan = classifyFiles(['apps/sim/app/(landing)/pricing/page.tsx'])
expect(plan.fallback).toBeUndefined()
expect(groups(plan)).toEqual(['seo'])
expect(plan.flags).toMatchObject({
integration: false,
desktop_live: false,
test_app: true,
build: true,
e2e_build: true,
})
})
it.each(['delete', 'move'])('keeps SEO coverage when library media is removed: %s', (change) => {
const { repo } = fixture()
const media = 'apps/sim/public/library/example/cover.jpg'
Expand Down
6 changes: 5 additions & 1 deletion scripts/ci-plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface QueryResult {
data?: {
packages: { items: { name: string; path: string }[] }
affectedTasks: { items: ChangedTask[] }
docsSite: { items: { fullName: string }[] }
}
}
const root = process.cwd()
Expand All @@ -29,6 +30,7 @@ const suites: { http: Suite[]; production: Suite[] } = JSON.parse(
const sourceBase = process.argv[2]
let files: string[] = []
let tasks: ChangedTask[] = []
let docsSiteChanged = false
let base = sourceBase
let fallback: string | undefined

Expand Down Expand Up @@ -80,6 +82,7 @@ try {
if (
result.errors?.length ||
!Array.isArray(result.data?.affectedTasks?.items) ||
!Array.isArray(result.data?.docsSite?.items) ||
!Array.isArray(result.data?.packages?.items)
)
throw new Error('Turborepo did not return a complete task plan')
Expand All @@ -98,6 +101,7 @@ try {
)
)
throw new Error('Malformed task attribution')
docsSiteChanged = result.data.docsSite.items.some((task) => task.fullName === 'docs#build')
} catch (error) {
fallback = String(error)
}
Expand All @@ -108,7 +112,7 @@ const http = suites.http.filter((suite) => affected(suite.task))
const production = suites.production.filter((suite) => affected(suite.task))
const desktopLive = affected('ci:desktop-live')
const appTest = affected('test')
const docsSite = fallback !== undefined || selected.has('docs#build')
const docsSite = fallback !== undefined || docsSiteChanged
const docsPlatform = affected('ci:e2e-docs-platform')
const docsGroups = docsSite
? ['http', 'corpus', 'chromium', 'webkit']
Expand Down
9 changes: 8 additions & 1 deletion turbo.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
{
"$schema": "https://v2-9-12.turborepo.dev/schema.json",
"$schema": "https://v2-11-10.turborepo.dev/schema.json",
"envMode": "loose",
// CI planning (`.github/scripts/ci-plan.gql`) needs `affectedTasks` to match changed files
// against each task's `inputs`; without a task-level flag Turborepo reports every task of an
// affected package. `filterUsingTasks` opts into that, and CI's `--filter` calls only name
// packages, so it selects the same tasks. `affectedUsingTaskInputs` would also do it, but it
// makes `turbo prune` keep packages reached only through `pkg#task` dependencies, which pulls
// desktop, docs, and realtime into the app image.
"futureFlags": { "filterUsingTasks": true },
// Local cache eviction is opt-in until Turborepo 3.0, so without these the
// filesystem cache grows forever. In CI each cache dir is a Blacksmith sticky
// disk that is mounted many times a day, so it never goes idle long enough for
Expand Down
Loading