mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
fix(ci): narrow workflow scope and reuse setup steps (#2708)
* fix(ci): narrow workflow scope and reuse setup steps * fix(ci): narrow workflow scope and reuse setup steps Repair Nix fixed-output hashes for the filtered daemon and web source trees. Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * fix(ci): narrow workflow scope and reuse setup steps Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * fix(ci): narrow workflow scope and reuse setup steps Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * fix(ci): repair daemon and nix checks Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)
This commit is contained in:
parent
1b908a8481
commit
a5b47c5f76
10 changed files with 275 additions and 415 deletions
34
.github/actions/setup-playwright/action.yml
vendored
Normal file
34
.github/actions/setup-playwright/action.yml
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
name: Setup Playwright
|
||||
description: Restore Playwright browser cache and install browsers
|
||||
|
||||
inputs:
|
||||
package-json-path:
|
||||
description: Path to package.json containing @playwright/test or playwright devDependency
|
||||
required: true
|
||||
install-command:
|
||||
description: Command used to install browsers
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Resolve Playwright version
|
||||
id: playwright-version
|
||||
shell: bash
|
||||
run: |
|
||||
version=$(node -p "const pkg = require('./${{ inputs.package-json-path }}'); const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) }; (deps['@playwright/test'] || deps.playwright || '').replace(/[^0-9.]/g,'')")
|
||||
if [ -z "$version" ]; then
|
||||
echo "Could not resolve Playwright version from ${{ inputs.package-json-path }}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Playwright browser binaries
|
||||
uses: actions/cache@v5.0.5
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
|
||||
|
||||
- name: Install Playwright browsers
|
||||
shell: bash
|
||||
run: ${{ inputs.install-command }}
|
||||
41
.github/actions/setup-workspace/action.yml
vendored
Normal file
41
.github/actions/setup-workspace/action.yml
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
name: Setup workspace
|
||||
description: Restore pnpm cache and install dependencies
|
||||
|
||||
inputs:
|
||||
node-version:
|
||||
description: Node.js version to install
|
||||
required: false
|
||||
default: '24'
|
||||
pnpm-version:
|
||||
description: pnpm version to install
|
||||
required: false
|
||||
default: '10.33.2'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
with:
|
||||
version: ${{ inputs.pnpm-version }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache pnpm store
|
||||
uses: actions/cache@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: pnpm install --frozen-lockfile
|
||||
363
.github/workflows/ci.yml
vendored
363
.github/workflows/ci.yml
vendored
|
|
@ -73,7 +73,7 @@ jobs:
|
|||
if [[ "$file" == "tools/pack/"* || "$file" == "apps/packaged/"* || "$file" == "apps/desktop/"* || "$file" == "packages/host/"* || "$file" == "packages/platform/"* || "$file" == "packages/sidecar/"* || "$file" == "packages/sidecar-proto/"* ]]; then
|
||||
tools_pack_tests_required=true
|
||||
fi
|
||||
if [[ "$file" == "package.json" || "$file" == "apps/"*/"package.json" || "$file" == "packages/"*/"package.json" || "$file" == "tools/"*/"package.json" || "$file" == "e2e/package.json" || "$file" == "pnpm-lock.yaml" || "$file" == "pnpm-workspace.yaml" || "$file" == ".github/workflows/ci.yml" ]]; then
|
||||
if [[ "$file" == "package.json" || "$file" == "apps/daemon/package.json" || "$file" == "apps/web/package.json" || "$file" == "apps/desktop/package.json" || "$file" == "apps/packaged/package.json" || "$file" == "packages/"*/"package.json" || "$file" == "tools/"*/"package.json" || "$file" == "e2e/package.json" || "$file" == "pnpm-lock.yaml" || "$file" == "pnpm-workspace.yaml" || "$file" == ".github/workflows/ci.yml" ]]; then
|
||||
daemon_tests_required=true
|
||||
web_tests_required=true
|
||||
tools_dev_tests_required=true
|
||||
|
|
@ -106,6 +106,15 @@ jobs:
|
|||
|| [ "$tools_pack_tests_required" = "true" ]; then
|
||||
workspace_validation_required=true
|
||||
fi
|
||||
elif [ "${{ github.event_name }}" = "push" ]; then
|
||||
daemon_tests_required=true
|
||||
web_tests_required=true
|
||||
tools_dev_tests_required=true
|
||||
tools_pack_tests_required=true
|
||||
# Main already runs .github/workflows/nix-check.yml, so keep this
|
||||
# workflow's push path focused on the non-Nix workspace signal.
|
||||
nix_validation_required=false
|
||||
workspace_validation_required=true
|
||||
else
|
||||
daemon_tests_required=true
|
||||
web_tests_required=true
|
||||
|
|
@ -155,30 +164,8 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Setup workspace
|
||||
uses: ./.github/actions/setup-workspace
|
||||
|
||||
# `scripts/postinstall.mjs` only prebuilds package/tool entrypoints that
|
||||
# are needed immediately after install for linked bins and shared
|
||||
|
|
@ -212,8 +199,8 @@ jobs:
|
|||
- name: Check i18n structure
|
||||
run: pnpm i18n:check
|
||||
|
||||
core_tests:
|
||||
name: Core package tests
|
||||
workspace_unit_tests:
|
||||
name: Workspace unit tests
|
||||
needs: [change_scopes]
|
||||
if: ${{ needs.change_scopes.outputs.workspace_validation_required == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -223,77 +210,16 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
with:
|
||||
version: 10.33.2
|
||||
- name: Setup workspace
|
||||
uses: ./.github/actions/setup-workspace
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Core package tests
|
||||
- name: Workspace unit tests
|
||||
run: |
|
||||
pnpm --filter @open-design/contracts test
|
||||
pnpm --filter @open-design/host test
|
||||
pnpm --filter @open-design/platform test
|
||||
pnpm --filter @open-design/sidecar test
|
||||
pnpm --filter @open-design/sidecar-proto test
|
||||
|
||||
tools_workspace_tests:
|
||||
name: Tools workspace tests
|
||||
needs: [change_scopes]
|
||||
if: ${{ needs.change_scopes.outputs.tools_dev_tests_required == 'true' || needs.change_scopes.outputs.tools_pack_tests_required == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Tools workspace smoke tests
|
||||
run: |
|
||||
if [ "${{ needs.change_scopes.outputs.tools_dev_tests_required }}" = "true" ]; then
|
||||
pnpm --filter @open-design/tools-dev test
|
||||
fi
|
||||
|
|
@ -302,50 +228,24 @@ jobs:
|
|||
fi
|
||||
|
||||
daemon_workspace_tests:
|
||||
name: Daemon workspace tests (${{ matrix.shard }}/2)
|
||||
name: Daemon workspace tests
|
||||
needs: [change_scopes]
|
||||
if: ${{ needs.change_scopes.outputs.daemon_tests_required == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
shard: [1, 2]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Setup workspace
|
||||
uses: ./.github/actions/setup-workspace
|
||||
|
||||
- name: Prebuild daemon entrypoint declarations
|
||||
run: pnpm --filter @open-design/daemon build
|
||||
|
||||
- name: Daemon workspace tests
|
||||
run: pnpm --filter @open-design/daemon exec vitest run -c vitest.config.ts --shard=${{ matrix.shard }}/2
|
||||
run: pnpm --filter @open-design/daemon test
|
||||
|
||||
web_workspace_tests:
|
||||
name: Web workspace tests
|
||||
|
|
@ -358,30 +258,8 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Setup workspace
|
||||
uses: ./.github/actions/setup-workspace
|
||||
|
||||
- name: Prebuild web sidecar declarations
|
||||
run: pnpm --filter @open-design/web build:sidecar
|
||||
|
|
@ -389,164 +267,26 @@ jobs:
|
|||
- name: Web workspace tests
|
||||
run: pnpm --filter @open-design/web test
|
||||
|
||||
app_tests:
|
||||
name: App workspace tests
|
||||
browser_tests:
|
||||
name: Browser tests
|
||||
needs:
|
||||
- change_scopes
|
||||
- tools_workspace_tests
|
||||
- daemon_workspace_tests
|
||||
- web_workspace_tests
|
||||
if: ${{ always() && needs.change_scopes.result == 'success' && (needs.change_scopes.outputs.tools_dev_tests_required == 'true' || needs.change_scopes.outputs.tools_pack_tests_required == 'true' || needs.change_scopes.outputs.daemon_tests_required == 'true' || needs.change_scopes.outputs.web_tests_required == 'true') }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
- name: Check app workspace test jobs
|
||||
env:
|
||||
NEEDS_JSON: ${{ toJSON(needs) }}
|
||||
TOOLS_REQUIRED: ${{ needs.change_scopes.outputs.tools_dev_tests_required == 'true' || needs.change_scopes.outputs.tools_pack_tests_required == 'true' }}
|
||||
DAEMON_REQUIRED: ${{ needs.change_scopes.outputs.daemon_tests_required }}
|
||||
WEB_REQUIRED: ${{ needs.change_scopes.outputs.web_tests_required }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "$NEEDS_JSON" | jq .
|
||||
failures=()
|
||||
if [ "$TOOLS_REQUIRED" = "true" ] && [ "$(echo "$NEEDS_JSON" | jq -r '.tools_workspace_tests.result')" != "success" ]; then
|
||||
failures+=("tools_workspace_tests=$(echo "$NEEDS_JSON" | jq -r '.tools_workspace_tests.result')")
|
||||
fi
|
||||
if [ "$DAEMON_REQUIRED" = "true" ] && [ "$(echo "$NEEDS_JSON" | jq -r '.daemon_workspace_tests.result')" != "success" ]; then
|
||||
failures+=("daemon_workspace_tests=$(echo "$NEEDS_JSON" | jq -r '.daemon_workspace_tests.result')")
|
||||
fi
|
||||
if [ "$WEB_REQUIRED" = "true" ] && [ "$(echo "$NEEDS_JSON" | jq -r '.web_workspace_tests.result')" != "success" ]; then
|
||||
failures+=("web_workspace_tests=$(echo "$NEEDS_JSON" | jq -r '.web_workspace_tests.result')")
|
||||
fi
|
||||
if [ "${#failures[@]}" -gt 0 ]; then
|
||||
printf 'App workspace validation failed:\n'
|
||||
printf '%s\n' "${failures[@]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
e2e_vitest:
|
||||
name: E2E vitest
|
||||
needs: [change_scopes]
|
||||
if: ${{ needs.change_scopes.outputs.workspace_validation_required == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
# Some Vitest-based smoke tests drive the browser directly through
|
||||
# @playwright/test. Restore browser binaries without saving from CI runs;
|
||||
# the key follows the @playwright/test version so browser revisions
|
||||
# update with package bumps.
|
||||
- name: Resolve Playwright version
|
||||
id: playwright-version
|
||||
run: |
|
||||
version=$(node -p "require('./e2e/package.json').devDependencies['@playwright/test'].replace(/[^0-9.]/g,'')")
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore Playwright browser cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
|
||||
|
||||
- name: Install Playwright browsers
|
||||
run: pnpm -C e2e exec playwright install --with-deps chromium
|
||||
|
||||
- name: E2E vitest
|
||||
run: pnpm --filter @open-design/e2e test
|
||||
|
||||
ui_e2e_critical:
|
||||
name: Playwright critical (${{ matrix.group }})
|
||||
needs: [change_scopes]
|
||||
if: ${{ needs.change_scopes.outputs.workspace_validation_required == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- group: core
|
||||
grep_flag: --grep-invert
|
||||
grep_pattern: home starters|home hero
|
||||
- group: starters
|
||||
grep_flag: --grep
|
||||
grep_pattern: home starters|home hero
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
- name: Setup workspace
|
||||
uses: ./.github/actions/setup-workspace
|
||||
|
||||
- name: Setup Playwright
|
||||
uses: ./.github/actions/setup-playwright
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
# Restore Playwright browser binaries without saving from CI runs. The
|
||||
# key follows the @playwright/test version so browser revisions update
|
||||
# with package bumps.
|
||||
- name: Resolve Playwright version
|
||||
id: playwright-version
|
||||
run: |
|
||||
version=$(node -p "require('./e2e/package.json').devDependencies['@playwright/test'].replace(/[^0-9.]/g,'')")
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore Playwright browser cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
|
||||
|
||||
- name: Install Playwright browsers
|
||||
run: pnpm -C e2e exec playwright install --with-deps chromium
|
||||
package-json-path: e2e/package.json
|
||||
install-command: pnpm -C e2e exec playwright install --with-deps chromium
|
||||
|
||||
- name: Prebuild workspace type declarations
|
||||
run: |
|
||||
|
|
@ -554,10 +294,13 @@ jobs:
|
|||
pnpm --filter @open-design/desktop build
|
||||
pnpm --filter @open-design/web build:sidecar
|
||||
|
||||
- name: E2E vitest
|
||||
run: pnpm --filter @open-design/e2e test
|
||||
|
||||
- name: Playwright critical
|
||||
run: |
|
||||
pnpm -C e2e exec tsx scripts/playwright.ts clean
|
||||
pnpm -C e2e exec playwright test -c playwright.config.ts ${{ matrix.grep_flag }} '${{ matrix.grep_pattern }}' ui/critical-smoke.test.ts ui/entry-chrome-flows.test.ts
|
||||
pnpm -C e2e exec playwright test -c playwright.config.ts ui/critical-smoke.test.ts ui/entry-chrome-flows.test.ts
|
||||
|
||||
build_workspaces:
|
||||
name: Build workspaces
|
||||
|
|
@ -570,30 +313,8 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v6.0.8
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Resolve pnpm store path
|
||||
id: pnpm-store
|
||||
shell: bash
|
||||
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store cache
|
||||
uses: actions/cache/restore@v5.0.5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Setup workspace
|
||||
uses: ./.github/actions/setup-workspace
|
||||
|
||||
- name: Prebuild workspace type declarations
|
||||
run: |
|
||||
|
|
@ -615,10 +336,10 @@ jobs:
|
|||
- change_scopes
|
||||
- preflight
|
||||
- nix_validation
|
||||
- core_tests
|
||||
- app_tests
|
||||
- e2e_vitest
|
||||
- ui_e2e_critical
|
||||
- workspace_unit_tests
|
||||
- daemon_workspace_tests
|
||||
- web_workspace_tests
|
||||
- browser_tests
|
||||
- build_workspaces
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
32
.github/workflows/landing-page-ci.yml
vendored
32
.github/workflows/landing-page-ci.yml
vendored
|
|
@ -61,37 +61,17 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v5
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Setup workspace
|
||||
uses: ./.github/actions/setup-workspace
|
||||
|
||||
# Cache the Playwright browser binaries between runs. The cache key
|
||||
# is pinned to the playwright version we depend on (kept in
|
||||
# apps/landing-page/package.json) so a bump invalidates correctly.
|
||||
- name: Resolve Playwright version
|
||||
id: playwright-version
|
||||
run: |
|
||||
version=$(node -p "require('./apps/landing-page/package.json').devDependencies.playwright.replace(/[^0-9.]/g,'')")
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Playwright browsers
|
||||
uses: actions/cache@v4
|
||||
- name: Setup Playwright
|
||||
uses: ./.github/actions/setup-playwright
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
|
||||
|
||||
- name: Install Playwright Chromium
|
||||
run: pnpm --filter @open-design/landing-page exec playwright install --with-deps chromium
|
||||
package-json-path: apps/landing-page/package.json
|
||||
install-command: pnpm --filter @open-design/landing-page exec playwright install --with-deps chromium
|
||||
|
||||
- name: Typecheck landing page
|
||||
run: pnpm --filter @open-design/landing-page typecheck
|
||||
|
|
|
|||
48
flake.nix
48
flake.nix
|
|
@ -21,9 +21,53 @@
|
|||
dream2nix,
|
||||
home-manager,
|
||||
}: let
|
||||
filterProjectSource = includePaths:
|
||||
nixpkgs.lib.cleanSourceWith {
|
||||
src = self;
|
||||
filter = path: type: let
|
||||
root = toString self;
|
||||
pathStr = toString path;
|
||||
rel = nixpkgs.lib.removePrefix (root + "/") pathStr;
|
||||
matches = includePath:
|
||||
rel == includePath
|
||||
|| nixpkgs.lib.hasPrefix (includePath + "/") rel
|
||||
|| (type == "directory" && nixpkgs.lib.hasPrefix (rel + "/") includePath);
|
||||
in
|
||||
rel == ""
|
||||
|| builtins.any matches includePaths;
|
||||
};
|
||||
|
||||
perSystem = flake-utils.lib.eachDefaultSystem (system: let
|
||||
pkgs = import nixpkgs {inherit system;};
|
||||
nodejs = pkgs.nodejs_24;
|
||||
daemonSrc = filterProjectSource [
|
||||
"package.json"
|
||||
"pnpm-lock.yaml"
|
||||
"pnpm-workspace.yaml"
|
||||
"tsconfig.json"
|
||||
"scripts"
|
||||
"assets"
|
||||
"plugins"
|
||||
"skills"
|
||||
"design-systems"
|
||||
"design-templates"
|
||||
"craft"
|
||||
"prompt-templates"
|
||||
"apps/daemon"
|
||||
"packages"
|
||||
];
|
||||
webSrc = filterProjectSource [
|
||||
"package.json"
|
||||
"pnpm-lock.yaml"
|
||||
"pnpm-workspace.yaml"
|
||||
"tsconfig.json"
|
||||
"apps/web"
|
||||
"packages/contracts"
|
||||
"packages/host"
|
||||
"packages/platform"
|
||||
"packages/sidecar"
|
||||
"packages/sidecar-proto"
|
||||
];
|
||||
|
||||
# nixpkgs ships pnpm 10.33.0; the repo's package.json declares
|
||||
# `engines.pnpm: ">=10.33.2 <11"` and pnpm refuses to install
|
||||
|
|
@ -47,11 +91,11 @@
|
|||
|
||||
daemon = pkgs.callPackage ./nix/package-daemon.nix {
|
||||
inherit dream2nix nixpkgs system nodejs pnpm_10;
|
||||
src = self;
|
||||
src = daemonSrc;
|
||||
};
|
||||
web = pkgs.callPackage ./nix/package-web.nix {
|
||||
inherit dream2nix nixpkgs system nodejs pnpm_10;
|
||||
src = self;
|
||||
src = webSrc;
|
||||
};
|
||||
in {
|
||||
packages = {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ let
|
|||
pname = "open-design-daemon";
|
||||
version = (lib.importJSON ../package.json).version;
|
||||
|
||||
pnpmDepsHash = (import ./pnpm-deps.nix).hash;
|
||||
pnpmDepsHash = (import ./pnpm-deps.nix).daemonHash;
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
inherit pname version src;
|
||||
|
|
@ -153,6 +153,20 @@ in
|
|||
# just apps/daemon.
|
||||
cp -r . $out/lib/open-design/
|
||||
|
||||
# Root devDependencies expose tool workspaces via pnpm symlinks, but the
|
||||
# daemon derivation intentionally filters tools/ out of src because they
|
||||
# are not needed at runtime. Prune the dangling symlinks from the copied
|
||||
# node_modules tree so Nix fixup does not fail on broken links.
|
||||
rm -f \
|
||||
$out/lib/open-design/node_modules/@open-design/tools-dev \
|
||||
$out/lib/open-design/node_modules/@open-design/tools-pack \
|
||||
$out/lib/open-design/node_modules/@open-design/tools-pr \
|
||||
$out/lib/open-design/node_modules/@open-design/tools-serve \
|
||||
$out/lib/open-design/node_modules/.bin/tools-dev \
|
||||
$out/lib/open-design/node_modules/.bin/tools-pack \
|
||||
$out/lib/open-design/node_modules/.bin/tools-pr \
|
||||
$out/lib/open-design/node_modules/.bin/tools-serve
|
||||
|
||||
chmod +x $out/lib/open-design/apps/daemon/dist/cli.js
|
||||
|
||||
makeWrapper ${nodejs}/bin/node $out/bin/od \
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ let
|
|||
pname = "open-design-web";
|
||||
version = (lib.importJSON ../package.json).version;
|
||||
|
||||
pnpmDepsHash = (import ./pnpm-deps.nix).hash;
|
||||
pnpmDepsHash = (import ./pnpm-deps.nix).webHash;
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
inherit pname version src;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
{
|
||||
# Vendored pnpm store for the workspace packages built by the flake.
|
||||
# Vendored pnpm store hashes for the workspace packages built by the flake.
|
||||
#
|
||||
# Refresh this hash whenever pnpm-lock.yaml changes:
|
||||
# The daemon and web derivations now build from different filtered source
|
||||
# trees, so each fetchPnpmDeps invocation needs its own fixed-output hash.
|
||||
# Refresh a hash whenever pnpm-lock.yaml or that derivation's source filter
|
||||
# changes:
|
||||
# 1. Temporarily set the consuming `hash = lib.fakeHash;`
|
||||
# 2. Run the relevant nix build/flake check
|
||||
# 3. Copy the expected hash printed by Nix into `hash` below
|
||||
hash = "sha256-l87ATTkJYpX7OHHxmA/CxvJHdaaN/9RPi6AYI4DRn/I=";
|
||||
# 3. Copy the expected hash printed by Nix into the matching field below
|
||||
daemonHash = "sha256-X64KXAuSKE9ARcKHkgilAj7Nlej/MyAF/tiKsX4AEgg=";
|
||||
webHash = "sha256-74loUCL+WcaZO4AAMnSpNeBhDz1Y9TMgFRPbyaOfPAk=";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"description": "Official Open Design plugin registry seed. The generated public catalog is served from open-design.ai/marketplace.",
|
||||
"version": "0.1.0",
|
||||
"generatedFrom": "plugins/_official",
|
||||
"bundledPreinstallCount": 400
|
||||
"bundledPreinstallCount": 401
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,79 +4,101 @@ import process from "node:process";
|
|||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const repoRoot = path.resolve(import.meta.dirname, "..");
|
||||
const consumerPath = path.join(repoRoot, "nix/package-web.nix");
|
||||
const sharedHashPath = path.join(repoRoot, "nix/pnpm-deps.nix");
|
||||
|
||||
const consumerHashLine = " hash = pnpmDepsHash;";
|
||||
const fakeHashLine = " hash = lib.fakeHash;";
|
||||
const nixCommand = ["build", ".#web", "--print-build-logs"];
|
||||
const maxNixOutputBufferBytes = 32 * 1024 * 1024;
|
||||
|
||||
const consumers = [
|
||||
{
|
||||
hashKey: "daemonHash",
|
||||
consumerPath: path.join(repoRoot, "nix/package-daemon.nix"),
|
||||
nixCommand: ["build", ".#daemon", "--print-build-logs"],
|
||||
},
|
||||
{
|
||||
hashKey: "webHash",
|
||||
consumerPath: path.join(repoRoot, "nix/package-web.nix"),
|
||||
nixCommand: ["build", ".#web", "--print-build-logs"],
|
||||
},
|
||||
] as const;
|
||||
|
||||
function extractExpectedHash(output: string): string | null {
|
||||
const matches = [...output.matchAll(/got:\s*(sha256-[A-Za-z0-9+/=]+)/g)];
|
||||
return matches.at(-1)?.[1] ?? null;
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const originalConsumer = await readFile(consumerPath, "utf8");
|
||||
if (!originalConsumer.includes(consumerHashLine)) {
|
||||
throw new Error(
|
||||
`Expected to find \`${consumerHashLine.trim()}\` in ${path.relative(repoRoot, consumerPath)}`,
|
||||
);
|
||||
const updates: string[] = [];
|
||||
|
||||
for (const consumer of consumers) {
|
||||
const originalConsumer = await readFile(consumer.consumerPath, "utf8");
|
||||
if (!originalConsumer.includes(consumerHashLine)) {
|
||||
throw new Error(
|
||||
`Expected to find \`${consumerHashLine.trim()}\` in ${path.relative(repoRoot, consumer.consumerPath)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const fakeHashConsumer = originalConsumer.replace(consumerHashLine, fakeHashLine);
|
||||
|
||||
await writeFile(consumer.consumerPath, fakeHashConsumer, "utf8");
|
||||
|
||||
try {
|
||||
const result = spawnSync("nix", consumer.nixCommand, {
|
||||
cwd: repoRoot,
|
||||
encoding: "utf8",
|
||||
maxBuffer: maxNixOutputBufferBytes,
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
throw new Error(`Failed to execute nix: ${result.error.message}`);
|
||||
}
|
||||
|
||||
if (result.status === 0) {
|
||||
throw new Error(
|
||||
`nix ${consumer.nixCommand.join(" ")} unexpectedly succeeded after replacing the fixed-output hash with lib.fakeHash.`,
|
||||
);
|
||||
}
|
||||
|
||||
const combinedOutput = `${result.stdout}${result.stderr}`;
|
||||
const nextHash = extractExpectedHash(combinedOutput);
|
||||
if (!nextHash) {
|
||||
throw new Error(
|
||||
"nix build failed without reporting a fixed-output hash mismatch (`got: sha256-...`). " +
|
||||
`Refusing to update ${path.relative(repoRoot, sharedHashPath)}.\n\n${combinedOutput}`,
|
||||
);
|
||||
}
|
||||
|
||||
const originalSharedHash = await readFile(sharedHashPath, "utf8");
|
||||
const hashPattern = new RegExp(`${consumer.hashKey} = \"sha256-[A-Za-z0-9+/=]+\";`);
|
||||
if (!hashPattern.test(originalSharedHash)) {
|
||||
throw new Error(
|
||||
`Expected to find \`${consumer.hashKey} = \"sha256-...\";\` in ${path.relative(repoRoot, sharedHashPath)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const updatedSharedHash = originalSharedHash.replace(
|
||||
hashPattern,
|
||||
`${consumer.hashKey} = "${nextHash}";`,
|
||||
);
|
||||
|
||||
if (updatedSharedHash === originalSharedHash) {
|
||||
updates.push(`${consumer.hashKey} already pins ${nextHash}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await writeFile(sharedHashPath, updatedSharedHash, "utf8");
|
||||
updates.push(`${consumer.hashKey} -> ${nextHash}`);
|
||||
} finally {
|
||||
await writeFile(consumer.consumerPath, originalConsumer, "utf8");
|
||||
}
|
||||
}
|
||||
|
||||
const fakeHashConsumer = originalConsumer.replace(consumerHashLine, fakeHashLine);
|
||||
|
||||
await writeFile(consumerPath, fakeHashConsumer, "utf8");
|
||||
|
||||
try {
|
||||
const result = spawnSync("nix", nixCommand, {
|
||||
cwd: repoRoot,
|
||||
encoding: "utf8",
|
||||
maxBuffer: maxNixOutputBufferBytes,
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
throw new Error(`Failed to execute nix: ${result.error.message}`);
|
||||
}
|
||||
|
||||
if (result.status === 0) {
|
||||
throw new Error(
|
||||
"nix build unexpectedly succeeded after replacing the fixed-output hash with lib.fakeHash.",
|
||||
);
|
||||
}
|
||||
|
||||
const combinedOutput = `${result.stdout}${result.stderr}`;
|
||||
const nextHash = extractExpectedHash(combinedOutput);
|
||||
if (!nextHash) {
|
||||
throw new Error(
|
||||
"nix build failed without reporting a fixed-output hash mismatch (`got: sha256-...`). " +
|
||||
`Refusing to update ${path.relative(repoRoot, sharedHashPath)}.\n\n${combinedOutput}`,
|
||||
);
|
||||
}
|
||||
|
||||
const originalSharedHash = await readFile(sharedHashPath, "utf8");
|
||||
const updatedSharedHash = originalSharedHash.replace(
|
||||
/hash = "sha256-[A-Za-z0-9+/=]+";/,
|
||||
`hash = "${nextHash}";`,
|
||||
);
|
||||
|
||||
if (updatedSharedHash === originalSharedHash) {
|
||||
process.stdout.write(
|
||||
`${path.relative(repoRoot, sharedHashPath)} already pins ${nextHash}; no update needed.\n`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await writeFile(sharedHashPath, updatedSharedHash, "utf8");
|
||||
process.stdout.write(
|
||||
`Updated ${path.relative(repoRoot, sharedHashPath)} to ${nextHash}.\n` +
|
||||
`Re-run \`nix flake check --print-build-logs --keep-going\` to confirm.\n`,
|
||||
);
|
||||
} finally {
|
||||
await writeFile(consumerPath, originalConsumer, "utf8");
|
||||
}
|
||||
process.stdout.write(
|
||||
`Updated ${path.relative(repoRoot, sharedHashPath)} (${updates.join(", ")}).\n` +
|
||||
`Re-run \`nix flake check --print-build-logs --keep-going\` to confirm.\n`,
|
||||
);
|
||||
}
|
||||
|
||||
await main();
|
||||
|
|
|
|||
Loading…
Reference in a new issue