From 07934225814029a100870121550d941106b4cab6 Mon Sep 17 00:00:00 2001 From: Fusion Date: Tue, 12 May 2026 14:17:47 -0700 Subject: [PATCH] feat(FN-4100): refactor ci workflows to use reusable setup-node-pnpm compos Refactors GitHub Actions workflow setup into a reusable composite action, consolidating repeated setup logic across CI, mobile, release, test-release, and version workflows (176 lines removed). Adds corresponding tests for the workflow configuration. Fusion-Task-Id: FN-4100 --- .github/actions/setup-node-pnpm/action.yml | 10 +++ .github/workflows/ci.yml | 48 ++--------- .github/workflows/mobile.yml | 84 ++----------------- .github/workflows/release.yml | 20 +---- .github/workflows/test-release.yml | 20 +---- .github/workflows/version.yml | 17 +--- .../cli/src/__tests__/ci-workflow.test.ts | 30 +++++-- .../app/components/PluginManager.css | 4 + 8 files changed, 57 insertions(+), 176 deletions(-) diff --git a/.github/actions/setup-node-pnpm/action.yml b/.github/actions/setup-node-pnpm/action.yml index 980f11634..f2c0f9022 100644 --- a/.github/actions/setup-node-pnpm/action.yml +++ b/.github/actions/setup-node-pnpm/action.yml @@ -9,6 +9,14 @@ inputs: description: Arguments passed to pnpm install required: false default: "--frozen-lockfile" + registry-url: + description: Optional npm registry URL passed to actions/setup-node + required: false + default: "" + skip-install: + description: Set to 'true' to skip the pnpm install step; caller runs install themselves + required: false + default: "false" runs: using: composite steps: @@ -20,7 +28,9 @@ runs: with: node-version: ${{ inputs.node-version }} cache: pnpm + registry-url: ${{ inputs.registry-url }} - name: Install dependencies + if: ${{ inputs.skip-install != 'true' }} shell: bash run: pnpm install ${{ inputs.install-args }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a037c428..897bfd5ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,20 +10,8 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile + - name: Setup Node and install dependencies + uses: ./.github/actions/setup-node-pnpm - name: Lint run: pnpm lint @@ -37,20 +25,8 @@ jobs: shard: [1, 2, 3] steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile + - name: Setup Node and install dependencies + uses: ./.github/actions/setup-node-pnpm - name: Install Bun uses: oven-sh/setup-bun@v2 @@ -64,20 +40,8 @@ jobs: needs: [lint, test-shards] steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile + - name: Setup Node and install dependencies + uses: ./.github/actions/setup-node-pnpm - name: Build workspace run: pnpm build diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml index 74075785f..6d9a411b4 100644 --- a/.github/workflows/mobile.yml +++ b/.github/workflows/mobile.yml @@ -10,32 +10,8 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - with: - node-version: "24" - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - node-version: "24" - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm - - - name: Cache pnpm store - uses: actions/cache@v4 - with: - path: ~/.pnpm-store - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - - name: Install dependencies - run: pnpm install --frozen-lockfile + - name: Setup Node and install dependencies + uses: ./.github/actions/setup-node-pnpm - name: Build dashboard client run: pnpm --filter @fusion/dashboard build @@ -53,29 +29,8 @@ jobs: needs: build-web steps: - - name: Checkout - uses: actions/checkout@v4 - with: - node-version: "24" - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - node-version: "24" - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm - - - name: Cache pnpm store - uses: actions/cache@v4 - with: - path: ~/.pnpm-store - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- + - name: Setup Node and install dependencies + uses: ./.github/actions/setup-node-pnpm - name: Cache iOS DerivedData uses: actions/cache@v4 @@ -85,9 +40,6 @@ jobs: restore-keys: | ${{ runner.os }}-derived-data- - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: Download dashboard artifact uses: actions/download-artifact@v4 with: @@ -147,21 +99,8 @@ jobs: needs: build-web steps: - - name: Checkout - uses: actions/checkout@v4 - with: - node-version: "24" - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - node-version: "24" - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm + - name: Setup Node and install dependencies + uses: ./.github/actions/setup-node-pnpm - name: Setup Java 17 uses: actions/setup-java@v4 @@ -169,14 +108,6 @@ jobs: distribution: temurin java-version: "17" - - name: Cache pnpm store - uses: actions/cache@v4 - with: - path: ~/.pnpm-store - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - name: Cache Android Gradle caches uses: actions/cache@v4 with: @@ -185,9 +116,6 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: Download dashboard artifact uses: actions/download-artifact@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3410384b6..fd879070c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,28 +40,14 @@ jobs: binary: fn-windows-x64.exe steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Setup Node and install dependencies + uses: ./.github/actions/setup-node-pnpm with: - node-version: "24" - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - node-version: "24" - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm + install-args: "" - name: Install Bun uses: oven-sh/setup-bun@v2 - - name: Install dependencies - run: pnpm install - - name: Build run: pnpm build diff --git a/.github/workflows/test-release.yml b/.github/workflows/test-release.yml index 20eb9715b..9264ffd14 100644 --- a/.github/workflows/test-release.yml +++ b/.github/workflows/test-release.yml @@ -31,28 +31,12 @@ jobs: binary: fn-windows-x64.exe steps: - - name: Checkout - uses: actions/checkout@v4 - with: - node-version: "24" - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - node-version: "24" - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm + - name: Setup Node and install dependencies + uses: ./.github/actions/setup-node-pnpm - name: Install Bun uses: oven-sh/setup-bun@v2 - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: Build run: pnpm build diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index de4c87747..508bcd276 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -20,22 +20,11 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Setup Node and pnpm + uses: ./.github/actions/setup-node-pnpm with: - node-version: "24" - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - node-version: "24" - - - name: Setup Node.js - uses: actions/setup-node@v5 - with: - node-version: "24" - cache: pnpm registry-url: "https://registry.npmjs.org" + skip-install: "true" - name: Ensure modern npm (OIDC support) run: npm install -g npm@11.6.4 diff --git a/packages/cli/src/__tests__/ci-workflow.test.ts b/packages/cli/src/__tests__/ci-workflow.test.ts index dff6852a8..a5fe2d932 100644 --- a/packages/cli/src/__tests__/ci-workflow.test.ts +++ b/packages/cli/src/__tests__/ci-workflow.test.ts @@ -5,8 +5,8 @@ import { parse } from "yaml"; const workspaceRoot = join(import.meta.dirname!, "..", "..", "..", ".."); -function loadWorkflow(name: string): any { - const path = join(workspaceRoot, ".github", "workflows", name); +function loadYamlFile(...pathParts: string[]): any { + const path = join(workspaceRoot, ...pathParts); const content = readFileSync(path, "utf-8"); const parsed = parse(content) as Record; @@ -19,9 +19,18 @@ function loadWorkflow(name: string): any { return { content, parsed }; } +function loadWorkflow(name: string): any { + return loadYamlFile(".github", "workflows", name); +} + +function findCompositeSetupStep(steps: any[]) { + return steps.find((step) => step.uses === "./.github/actions/setup-node-pnpm"); +} + describe("CI workflow (.github/workflows/ci.yml)", () => { let workflow: any; let content: string; + let compositeAction: any; let buildSteps: any[]; let testShardJob: any; let contributingContent: string; @@ -35,6 +44,7 @@ describe("CI workflow (.github/workflows/ci.yml)", () => { const result = loadWorkflow("ci.yml"); workflow = result.parsed; content = result.content; + compositeAction = loadYamlFile(".github", "actions", "setup-node-pnpm", "action.yml").parsed; buildSteps = workflow.jobs?.build?.steps ?? []; testShardJob = workflow.jobs?.["test-shards"]; contributingContent = readFileSync(join(workspaceRoot, "docs", "contributing.md"), "utf-8"); @@ -72,9 +82,13 @@ describe("CI workflow (.github/workflows/ci.yml)", () => { }); it("pins dependency bootstrap to frozen lockfile", () => { - expect(content).toContain("run: pnpm install --frozen-lockfile"); + const jobs = [workflow.jobs?.lint, workflow.jobs?.["test-shards"], workflow.jobs?.build]; + for (const job of jobs) { + expect(findCompositeSetupStep(job?.steps ?? [])).toBeDefined(); + } expect(content).not.toContain("run: pnpm install\n"); expect(content).not.toContain("--no-frozen-lockfile"); + expect(compositeAction.inputs?.["install-args"]?.default).toBe("--frozen-lockfile"); }); it("uses deterministic test sharding and keeps lint/build as explicit jobs", () => { @@ -286,8 +300,8 @@ describe("Version & Release workflow (.github/workflows/version.yml)", () => { it("configures npm registry-url", () => { const steps = workflow.jobs.release.steps; - const nodeStep = steps.find((s: any) => s.uses?.includes("actions/setup-node")); - expect(nodeStep?.with?.["registry-url"]).toBe("https://registry.npmjs.org"); + const compositeStep = findCompositeSetupStep(steps); + expect(compositeStep?.with?.["registry-url"]).toBe("https://registry.npmjs.org"); }); }); @@ -397,8 +411,10 @@ describe("Test-release workflow (.github/workflows/test-release.yml)", () => { }); it("uses frozen-lockfile install in every matrix job", () => { - const matches = content.match(/run:\s*pnpm install --frozen-lockfile/g) ?? []; - expect(matches.length).toBeGreaterThanOrEqual(1); + const steps = workflow.jobs["build-binaries"].steps ?? []; + const compositeStep = findCompositeSetupStep(steps); + expect(compositeStep).toBeDefined(); + expect(compositeStep.with?.["install-args"] ?? "--frozen-lockfile").toBe("--frozen-lockfile"); expect(content).not.toContain("run: pnpm install\n"); expect(content).not.toContain("--no-frozen-lockfile"); }); diff --git a/packages/dashboard/app/components/PluginManager.css b/packages/dashboard/app/components/PluginManager.css index d9db8b326..765733989 100644 --- a/packages/dashboard/app/components/PluginManager.css +++ b/packages/dashboard/app/components/PluginManager.css @@ -179,6 +179,10 @@ .plugin-error-text--detail { max-width: min(100%, 32rem); + overflow: visible; + text-overflow: clip; + white-space: normal; + overflow-wrap: anywhere; } .plugin-detail-content {