Skip to content
Draft
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
94 changes: 94 additions & 0 deletions .github/workflows/design-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: Design diff (advisory)

on:
pull_request_target:
types: [opened, reopened, synchronize, edited, ready_for_review]
branches: [staging]
workflow_dispatch:
inputs:
pull_request:
description: Open PR number targeting staging
required: true
type: number

permissions:
contents: read
pull-requests: read

concurrency:
group: design-diff-${{ github.event.pull_request.number || inputs.pull_request }}
cancel-in-progress: true

jobs:
analyze:
if: github.event_name == 'pull_request_target' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }}
timeout-minutes: 15
steps:
- name: Resolve immutable trusted engine and PR revisions
id: revisions
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
env:
REQUESTED_PR: ${{ inputs.pull_request }}
with:
script: |
const { owner, repo } = context.repo;
const number = context.payload.pull_request?.number ?? Number(process.env.REQUESTED_PR);
if (!Number.isSafeInteger(number) || number <= 0) throw new Error('Invalid PR number');
const pr = context.payload.pull_request ?? (await github.rest.pulls.get({ owner, repo, pull_number: number })).data;
if (pr.state !== 'open' || pr.base.ref !== 'staging' || pr.base.repo.full_name !== `${owner}/${repo}`) {
throw new Error('Expected an open PR targeting this repository staging branch');
}
const repository = (await github.rest.repos.get({ owner, repo })).data;
const engine = (await github.rest.repos.getCommit({ owner, repo, ref: repository.default_branch })).data.sha;
for (const sha of [engine, pr.base.sha, pr.head.sha]) {
if (!/^[a-f0-9]{40}$/.test(sha)) throw new Error('Invalid commit identity');
}
core.setOutput('engine', engine);
core.setOutput('base', pr.base.sha);
core.setOutput('head', pr.head.sha);
core.setOutput('pr', String(number));

- name: Checkout trusted engine only
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
ref: ${{ steps.revisions.outputs.engine }}
fetch-depth: 0
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.4.1

- name: Install trusted dependencies
run: bun install --frozen-lockfile --ignore-scripts

- name: Fetch PR source as Git objects
env:
BASE_SHA: ${{ steps.revisions.outputs.base }}
HEAD_SHA: ${{ steps.revisions.outputs.head }}
GH_TOKEN: ${{ github.token }}
run: |
AUTH_HEADER="$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')"
git -c "http.extraheader=AUTHORIZATION: basic $AUTH_HEADER" fetch --no-tags origin "$BASE_SHA" "$HEAD_SHA" >/dev/null 2>&1
test "$(git rev-parse --verify "$BASE_SHA^{commit}")" = "$BASE_SHA"
test "$(git rev-parse --verify "$HEAD_SHA^{commit}")" = "$HEAD_SHA"

- name: Analyze source
env:
BASE_SHA: ${{ steps.revisions.outputs.base }}
HEAD_SHA: ${{ steps.revisions.outputs.head }}
DESIGN_DIFF_PR: ${{ steps.revisions.outputs.pr }}
DESIGN_DIFF_ENGINE_SHA: ${{ steps.revisions.outputs.engine }}
REPORT_PATH: ${{ runner.temp }}/design-diff-${{ steps.revisions.outputs.pr }}-${{ steps.revisions.outputs.head }}.json
run: bun run design:diff --base "$BASE_SHA" --head "$HEAD_SHA" --output "$REPORT_PATH" > /dev/null 2>&1

- name: Retain JSON report
if: ${{ always() && steps.revisions.outcome == 'success' }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: design-diff-${{ steps.revisions.outputs.pr }}-${{ steps.revisions.outputs.head }}
path: ${{ runner.temp }}/design-diff-${{ steps.revisions.outputs.pr }}-${{ steps.revisions.outputs.head }}.json
retention-days: 7
if-no-files-found: error
63 changes: 42 additions & 21 deletions bun.lock

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions design-diff.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
{
"sourceRoots": ["apps/", "packages/"],
"exclude": [
"(?:^|/)(?:node_modules|__tests__|__fixtures__|fixtures|test-results|\\.source|dist|build)/",
"\\.(?:test|spec)\\.[cm]?[jt]sx?$",
"(?:^|/)next-env\\.d\\.ts$"
],
"renderedMarkdown": ["apps/docs/content/", "apps/sim/content/"],
"aliases": [
{
"from": "apps/sim/",
"prefix": "@/",
"target": "apps/sim/"
},
{
"from": "apps/docs/",
"prefix": "@/",
"target": "apps/docs/"
}
],
"themes": [
{
"roots": ["apps/sim/", "packages/emcn/", "packages/workflow-renderer/"],
"path": "apps/sim/app/_styles/globals.css"
},
{
"roots": ["apps/docs/", "packages/emcn/", "packages/workflow-renderer/"],
"path": "apps/docs/app/global.css"
}
],
"classFunctions": ["cn", "clsx", "classNames", "twMerge"],
"variantFunctions": ["cva"],
"nativeAppearance": [
"backgroundColor",
"titleBarStyle",
"titleBarOverlay",
"trafficLightPosition",
"vibrancy",
"visualEffectState",
"transparent",
"opacity",
"frame",
"roundedCorners",
"backgroundMaterial",
"width",
"height",
"minWidth",
"minHeight",
"maxWidth",
"maxHeight",
"resizable",
"fullscreen",
"autoHideMenuBar",
"icon"
],
"infrastructure": [
"(?:^|/)(?:tailwind|postcss|next|vite|electron-vite|source)\\.config\\.",
"(?:^|/)mdx-components\\.",
"(?:^|/)lib/postcss/",
"(?:^|/)lib/cn\\.ts$",
"(?:^|/)tsconfig[^/]*\\.json$"
],
"renderingDependencies": "^(?:react(?:-dom)?|next|tailwindcss|tailwind-merge|clsx|class-variance-authority|postcss|electron|framer-motion|motion|tw-animate-css|@tailwindcss/|@radix-ui/|@react-email/|fumadocs|@mdx-js/|remark-|rehype-|lucide)",
"limits": {
"fileBytes": 2097152,
"totalBytes": 268435456,
"resolutionDepth": 24,
"resolutionSteps": 5000
},
"nativeRendering": [
"apps/desktop/src/main/terminal-themes.ts",
"apps/desktop/src/main/context-menu.ts",
"apps/desktop/src/main/tray.ts"
],
"classModules": [
"clsx",
"classnames",
"tailwind-merge",
"@sim/emcn",
"@sim/emcn/lib/cn",
"@/lib/utils",
"@/lib/cn"
],
"variantModules": ["class-variance-authority"],
"mergeFontSizes": ["micro", "caption", "small", "md"],
"fileInputs": [
{
"list": "apps/docs/lib/openapi-specs.ts",
"export": "OPENAPI_SPEC_FILES",
"root": "apps/docs",
"renderer": "apps/docs/lib/openapi.ts"
}
],
"environmentAdapters": [
{
"module": "apps/sim/lib/core/config/env-capabilities.server.ts",
"export": "wireServerFallback",
"environmentModule": "apps/sim/lib/core/config/env.ts",
"environmentExport": "env",
"implementationModule": "apps/sim/lib/core/config/env-capabilities.ts",
"implementationExport": "wireFallback"
}
]
}
18 changes: 17 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@
"test:workflow-sync": "bun --no-env-file scripts/test-workflow-sync.ts",
"type-check": "turbo run type-check",
"release": "bun run scripts/create-single-release.ts",
"test:scripts": "vitest run --config scripts/vitest.config.ts"
"test:scripts": "vitest run --config scripts/vitest.config.ts",
"design:diff": "bun --no-env-file scripts/design-diff/cli.ts",
"check:design-diff-types": "tsc --noEmit --project scripts/design-diff/tsconfig.json"
},
"overrides": {
"react": "19.2.4",
Expand Down Expand Up @@ -150,9 +152,13 @@
},
"devDependencies": {
"@babel/parser": "7.29.2",
"@babel/traverse": "7.29.0",
"@babel/types": "7.29.7",
"@biomejs/biome": "2.0.6",
"@octokit/rest": "^21.0.0",
"@sim/utils": "workspace:*",
"@types/babel__traverse": "7.28.0",
"@types/node": "24.2.1",
"@types/opentype.js": "1.3.10",
"@typescript/native": "npm:typescript@^7.0.2",
"@typescript/typescript6": "^6.0.2",
Expand All @@ -165,12 +171,19 @@
"gray-matter": "4.0.3",
"husky": "9.1.7",
"json-schema-to-typescript": "15.0.4",
"jsonc-parser": "3.3.1",
"lint-staged": "16.0.0",
"opentype.js": "1.3.4",
"parse5": "7.3.0",
"postcss": "8.5.26",
"react": "19.2.4",
"remark-frontmatter": "5.0.0",
"remark-gfm": "4.0.1",
"remark-mdx": "3.1.1",
"remark-parse": "11.0.0",
"sharp": "0.35.4",
"tailwind-merge": "3.6.0",
"tailwindcss": "4.3.3",
"turbo": "2.9.14",
"unified": "11.0.5",
"unist-util-visit": "5.1.0",
Expand All @@ -189,5 +202,8 @@
"patchedDependencies": {
"@better-auth/oauth-provider@1.6.27": "patches/@better-auth%2Foauth-provider@1.6.27.patch",
"postgres@3.4.9": "patches/postgres@3.4.9.patch"
},
"imports": {
"#design-diff/*": "./scripts/design-diff/*.ts"
}
}
14 changes: 9 additions & 5 deletions scripts/check-script-test-coverage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bun
/**
* Asserts every `scripts/*.test.ts` file is collected by the scripts Vitest config.
* Asserts every root script test and nested design-diff test is collected by the scripts Vitest config.
*
* The root `test` script once chained a hand-maintained list of `test:*` entries, and a
* hand-maintained list silently drifts from the files on disk: a test added without a matching
Expand Down Expand Up @@ -57,10 +57,14 @@ const collected = new Set(
)
)

const onDisk = readdirSync(path.join(ROOT, 'scripts'))
.filter((file) => file.endsWith('.test.ts'))
.map((file) => `scripts/${file}`)
.sort()
const onDisk = [
...readdirSync(path.join(ROOT, 'scripts'))
.filter((file) => file.endsWith('.test.ts'))
.map((file) => `scripts/${file}`),
...readdirSync(path.join(ROOT, 'scripts/design-diff/tests'), { recursive: true })
.filter((file): file is string => typeof file === 'string' && file.endsWith('.test.ts'))
.map((file) => `scripts/design-diff/tests/${file.split(path.sep).join('/')}`),
].sort()

const orphaned = onDisk.filter((file) => !collected.has(file))
if (orphaned.length > 0) {
Expand Down
Loading
Loading