From 7e3a53a9444843d8aab70ddc69019a6e16a67a48 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 06:48:45 +0100 Subject: [PATCH 01/22] chore(cli): Add tests for building workspace packages --- packages/cli/src/commands/build.js | 2 +- .../{ => build}/__tests__/build.test.js | 5 +- .../src/commands/{ => build}/buildHandler.js | 67 +++---------------- .../src/commands/build/buildPackagesTask.js | 60 +++++++++++++++++ 4 files changed, 71 insertions(+), 63 deletions(-) rename packages/cli/src/commands/{ => build}/__tests__/build.test.js (96%) rename packages/cli/src/commands/{ => build}/buildHandler.js (75%) create mode 100644 packages/cli/src/commands/build/buildPackagesTask.js diff --git a/packages/cli/src/commands/build.js b/packages/cli/src/commands/build.js index 3ff49faf64..9fb3e48606 100644 --- a/packages/cli/src/commands/build.js +++ b/packages/cli/src/commands/build.js @@ -87,6 +87,6 @@ export const builder = (yargs) => { } export const handler = async (options) => { - const { handler } = await import('./buildHandler.js') + const { handler } = await import('./build/buildHandler.js') return handler(options) } diff --git a/packages/cli/src/commands/__tests__/build.test.js b/packages/cli/src/commands/build/__tests__/build.test.js similarity index 96% rename from packages/cli/src/commands/__tests__/build.test.js rename to packages/cli/src/commands/build/__tests__/build.test.js index 20abc0cd0e..bb8ef297a5 100644 --- a/packages/cli/src/commands/__tests__/build.test.js +++ b/packages/cli/src/commands/build/__tests__/build.test.js @@ -8,7 +8,7 @@ vi.mock('@cedarjs/telemetry', () => { } }) -vi.mock('@cedarjs/project-config', async () => { +vi.mock('@cedarjs/project-config', () => { return { getPaths: () => { return { @@ -35,7 +35,7 @@ vi.mock('@cedarjs/project-config', async () => { } }) -vi.mock('node:fs', async () => { +vi.mock('node:fs', () => { return { default: { existsSync: (path) => { @@ -53,7 +53,6 @@ vi.mock('node:fs', async () => { return JSON.stringify({ workspaces: ['api', 'web', 'packages/*'], }) - // } }, }, } diff --git a/packages/cli/src/commands/buildHandler.js b/packages/cli/src/commands/build/buildHandler.js similarity index 75% rename from packages/cli/src/commands/buildHandler.js rename to packages/cli/src/commands/build/buildHandler.js index 89bc18513e..780db19483 100644 --- a/packages/cli/src/commands/buildHandler.js +++ b/packages/cli/src/commands/build/buildHandler.js @@ -2,7 +2,6 @@ import fs from 'node:fs' import { createRequire } from 'node:module' import path from 'node:path' -import concurrently from 'concurrently' import execa from 'execa' import { Listr } from 'listr2' import { terminalLink } from 'termi-link' @@ -12,11 +11,12 @@ import { buildApi, cleanApiBuild } from '@cedarjs/internal/dist/build/api' import { generate } from '@cedarjs/internal/dist/generate/generate' import { loadAndValidateSdls } from '@cedarjs/internal/dist/validateSchema' import { detectPrerenderRoutes } from '@cedarjs/prerender/detection' -import { timedTelemetry, errorTelemetry } from '@cedarjs/telemetry' +import { timedTelemetry } from '@cedarjs/telemetry' -import { exitWithError } from '../lib/exit.js' -import { generatePrismaCommand } from '../lib/generatePrismaClient.js' -import { getPaths, getConfig } from '../lib/index.js' +import { generatePrismaCommand } from '../../lib/generatePrismaClient.js' +import { getPaths, getConfig } from '../../lib/index.js' + +import { buildPackagesTask } from './buildPackagesTask.js' export const handler = async ({ workspace = ['api', 'web', 'packages/*'], @@ -48,7 +48,7 @@ export const handler = async ({ const packageJsonPath = path.join(cedarPaths.base, 'package.json') const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) const packageJsonWorkspaces = packageJson.workspaces - const restWorkspaces = + const nonApiWebWorkspaces = Array.isArray(packageJsonWorkspaces) && packageJsonWorkspaces.length > 2 ? workspace.filter((w) => w !== 'api' && w !== 'web') : [] @@ -72,60 +72,9 @@ export const handler = async ({ }) }, }, - restWorkspaces.length > 0 && { + nonApiWebWorkspaces.length > 0 && { title: 'Building Packages...', - task: async () => { - // fs.globSync requires forward slashes as path separators in patterns, - // even on Windows. - const globPattern = path - .join(cedarPaths.packages, '*') - .replaceAll('\\', '/') - const allPackagePaths = await Array.fromAsync( - fs.promises.glob(globPattern), - ) - - // restWorkspaces can be ['packages/*'] or - // ['@my-org/pkg-one', '@my-org/pkg-two', 'packages/pkg-three', etc] - // We need to map that to filesystem paths - const workspacePaths = restWorkspaces.some((w) => w === 'packages/*') - ? allPackagePaths - : restWorkspaces.map((w) => { - const workspacePath = path.join( - cedarPaths.packages, - w.split('/').at(-1), - ) - - if (!fs.existsSync(workspacePath)) { - throw new Error(`Workspace not found: ${workspacePath}`) - } - - return workspacePath - }) - - const { result } = concurrently( - workspacePaths.map((workspacePath) => { - return { - command: `yarn build`, - name: workspacePath.split('/').at(-1), - cwd: workspacePath, - } - }), - { - prefix: '{name} |', - timestampFormat: 'HH:mm:ss', - }, - ) - - await result.catch((e) => { - if (e?.message) { - errorTelemetry( - process.argv, - `Error concurrently building sides: ${e.message}`, - ) - exitWithError(e) - } - }) - }, + task: () => buildPackagesTask(nonApiWebWorkspaces), }, // If using GraphQL Fragments or Trusted Documents, then we need to use // codegen to generate the types needed for possible types and the trusted diff --git a/packages/cli/src/commands/build/buildPackagesTask.js b/packages/cli/src/commands/build/buildPackagesTask.js new file mode 100644 index 0000000000..75b7dbf4a8 --- /dev/null +++ b/packages/cli/src/commands/build/buildPackagesTask.js @@ -0,0 +1,60 @@ +import fs from 'node:fs' +import path from 'node:path' + +import concurrently from 'concurrently' + +import { errorTelemetry } from '@cedarjs/telemetry' + +import { exitWithError } from '../../lib/exit.js' +import { getPaths } from '../../lib/index.js' + +export async function buildPackagesTask(nonApiWebWorkspaces) { + const cedarPaths = getPaths() + + // fs.globSync requires forward slashes as path separators in patterns, + // even on Windows. + const globPattern = path.join(cedarPaths.packages, '*').replaceAll('\\', '/') + const allPackagePaths = await Array.fromAsync(fs.promises.glob(globPattern)) + + // restWorkspaces can be ['packages/*'] or + // ['@my-org/pkg-one', '@my-org/pkg-two', 'packages/pkg-three', etc] + // We need to map that to filesystem paths + const workspacePaths = nonApiWebWorkspaces.some((w) => w === 'packages/*') + ? allPackagePaths + : nonApiWebWorkspaces.map((w) => { + const workspacePath = path.join( + cedarPaths.packages, + w.split('/').at(-1), + ) + + if (!fs.existsSync(workspacePath)) { + throw new Error(`Workspace not found: ${workspacePath}`) + } + + return workspacePath + }) + + const { result } = concurrently( + workspacePaths.map((workspacePath) => { + return { + command: `yarn build`, + name: workspacePath.split('/').at(-1), + cwd: workspacePath, + } + }), + { + prefix: '{name} |', + timestampFormat: 'HH:mm:ss', + }, + ) + + await result.catch((e) => { + if (e?.message) { + errorTelemetry( + process.argv, + `Error concurrently building sides: ${e.message}`, + ) + exitWithError(e) + } + }) +} From bd232da23966b04c88fed4eb2141ff2c8c152de8 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 07:44:30 +0100 Subject: [PATCH 02/22] tests --- .../commands/build/__tests__/build.test.js | 34 ++++- .../build/__tests__/buildPackagesTask.test.js | 127 ++++++++++++++++++ .../src/commands/build/buildPackagesTask.js | 3 +- 3 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js diff --git a/packages/cli/src/commands/build/__tests__/build.test.js b/packages/cli/src/commands/build/__tests__/build.test.js index bb8ef297a5..2795a63777 100644 --- a/packages/cli/src/commands/build/__tests__/build.test.js +++ b/packages/cli/src/commands/build/__tests__/build.test.js @@ -1,4 +1,3 @@ -// mock Telemetry for CLI commands so they don't try to spawn a process vi.mock('@cedarjs/telemetry', () => { return { errorTelemetry: () => vi.fn(), @@ -58,6 +57,39 @@ vi.mock('node:fs', () => { } }) +// Aggressively mocking a lot of modules here to speed up test +// Without these mocks the "collect" phase of the tests took around 2s +// With these mocks it's down to ~250ms + +vi.mock('@cedarjs/internal/dist/build/api', () => ({ + buildApi: vi.fn(), + cleanApiBuild: vi.fn(), +})) + +vi.mock('@cedarjs/internal/dist/generate/generate', () => ({ + generate: vi.fn(), +})) + +vi.mock('@cedarjs/internal/dist/validateSchema', () => ({ + loadAndValidateSdls: vi.fn(), +})) + +vi.mock('@cedarjs/cli-helpers', () => ({ + recordTelemetryAttributes: vi.fn(), +})) + +vi.mock('termi-link', () => ({ + terminalLink: vi.fn((text, _url) => text), +})) + +vi.mock('../../lib/generatePrismaClient.js', () => ({ + generatePrismaCommand: vi.fn(() => ({ cmd: 'echo', args: [] })), +})) + +vi.mock('./buildPackagesTask.js', () => ({ + buildPackagesTask: vi.fn(), +})) + import { Listr } from 'listr2' import { vi, afterEach, test, expect } from 'vitest' diff --git a/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js b/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js new file mode 100644 index 0000000000..dc8832490c --- /dev/null +++ b/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js @@ -0,0 +1,127 @@ +vi.mock('node:fs', () => { + return { + default: { + existsSync: (_path) => { + return true + }, + readFileSync: () => { + // Reading /mocked/project/package.json + // It just needs a workspace config section + return JSON.stringify({ + workspaces: ['api', 'web', 'packages/*'], + }) + }, + promises: { + glob: vi.fn(() => { + return [ + '/mocked/project/packages/foo', + '/mocked/project/packages/bar', + '/mocked/project/packages/baz', + ] + }), + }, + }, + } +}) + +vi.mock('concurrently', () => ({ + default: vi.fn(() => ({ result: Promise.resolve() })), +})) + +vi.mock('../../../lib/index.js', () => { + return { + getPaths: () => { + return { + base: '/mocked/project', + api: { + dist: '/mocked/project/api/dist', + prismaConfig: '/mocked/project/api/prisma.config.js', + }, + packages: '/mocked/project/packages', + web: { + dist: '/mocked/project/web/dist', + routes: '/mocked/project/web/Routes.tsx', + }, + } + }, + } +}) + +vi.mock('@cedarjs/telemetry', () => { + return { + errorTelemetry: () => vi.fn(), + timedTelemetry: (_argv, _options, callback) => { + return callback() + }, + } +}) + +vi.mock('../../lib/exit.js', () => ({ + exitWithError: vi.fn(), +})) + +import fs from 'node:fs' + +import concurrently from 'concurrently' +import { vi, afterEach, describe, it, expect } from 'vitest' + +import { buildPackagesTask } from '../buildPackagesTask' + +afterEach(() => { + vi.clearAllMocks() +}) + +describe('buildPackagesTask', async () => { + it('expands packages/* to all packages', async () => { + await buildPackagesTask(['packages/*']) + + expect(vi.mocked(fs).promises.glob).toHaveBeenCalledOnce() + expect(vi.mocked(concurrently)).toHaveBeenCalledWith( + [ + { + command: 'yarn build', + name: 'foo', + cwd: '/mocked/project/packages/foo', + }, + { + command: 'yarn build', + name: 'bar', + cwd: '/mocked/project/packages/bar', + }, + { + command: 'yarn build', + name: 'baz', + cwd: '/mocked/project/packages/baz', + }, + ], + { + prefix: '{name} |', + timestampFormat: 'HH:mm:ss', + }, + ) + }) + + it('builds specific workspaces', async () => { + await buildPackagesTask(['@my-org/pkg-one', 'pkg-two']) + + expect(vi.mocked(fs).promises.glob).not.toHaveBeenCalled() + expect(vi.mocked(concurrently)).toHaveBeenCalledWith( + [ + { + command: 'yarn build', + name: 'pkg-one', + cwd: '/mocked/project/packages/pkg-one', + }, + { + command: 'yarn build', + name: 'pkg-two', + cwd: '/mocked/project/packages/pkg-two', + }, + ], + { + prefix: '{name} |', + timestampFormat: 'HH:mm:ss', + }, + ) + }) +}) diff --git a/packages/cli/src/commands/build/buildPackagesTask.js b/packages/cli/src/commands/build/buildPackagesTask.js index 75b7dbf4a8..cff9f9ab19 100644 --- a/packages/cli/src/commands/build/buildPackagesTask.js +++ b/packages/cli/src/commands/build/buildPackagesTask.js @@ -14,13 +14,12 @@ export async function buildPackagesTask(nonApiWebWorkspaces) { // fs.globSync requires forward slashes as path separators in patterns, // even on Windows. const globPattern = path.join(cedarPaths.packages, '*').replaceAll('\\', '/') - const allPackagePaths = await Array.fromAsync(fs.promises.glob(globPattern)) // restWorkspaces can be ['packages/*'] or // ['@my-org/pkg-one', '@my-org/pkg-two', 'packages/pkg-three', etc] // We need to map that to filesystem paths const workspacePaths = nonApiWebWorkspaces.some((w) => w === 'packages/*') - ? allPackagePaths + ? await Array.fromAsync(fs.promises.glob(globPattern)) : nonApiWebWorkspaces.map((w) => { const workspacePath = path.join( cedarPaths.packages, From 923513f99b9f7321c64bceb77f2950469102d88b Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 10:57:10 +0100 Subject: [PATCH 03/22] try fixing tests on Windows --- .../build/__tests__/buildPackagesTask.test.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js b/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js index dc8832490c..12c5d4dae6 100644 --- a/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js +++ b/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js @@ -61,6 +61,7 @@ vi.mock('../../lib/exit.js', () => ({ })) import fs from 'node:fs' +import path from 'node:path' import concurrently from 'concurrently' import { vi, afterEach, describe, it, expect } from 'vitest' @@ -81,17 +82,17 @@ describe('buildPackagesTask', async () => { { command: 'yarn build', name: 'foo', - cwd: '/mocked/project/packages/foo', + cwd: '/mocked/project/packages/foo'.split('/').join(path.sep), }, { command: 'yarn build', name: 'bar', - cwd: '/mocked/project/packages/bar', + cwd: '/mocked/project/packages/bar'.split('/').join(path.sep), }, { command: 'yarn build', name: 'baz', - cwd: '/mocked/project/packages/baz', + cwd: '/mocked/project/packages/baz'.split('/').join(path.sep), }, ], { @@ -110,12 +111,12 @@ describe('buildPackagesTask', async () => { { command: 'yarn build', name: 'pkg-one', - cwd: '/mocked/project/packages/pkg-one', + cwd: '/mocked/project/packages/pkg-one'.split('/').join(path.sep), }, { command: 'yarn build', name: 'pkg-two', - cwd: '/mocked/project/packages/pkg-two', + cwd: '/mocked/project/packages/pkg-two'.split('/').join(path.sep), }, ], { From 64340def10180ffbfed713e0ccbdd65605cb2956 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 14:26:58 +0100 Subject: [PATCH 04/22] Add workspace packages to test-fixture project --- .../src/pages/ContactUsPage/ContactUsPage.tsx | 15 +++- tasks/test-project/codemods/contactUsPage.js | 22 +++++- .../rebuild-test-project-fixture.ts | 72 +++++++++++++++++-- 3 files changed, 99 insertions(+), 10 deletions(-) diff --git a/__fixtures__/test-project/web/src/pages/ContactUsPage/ContactUsPage.tsx b/__fixtures__/test-project/web/src/pages/ContactUsPage/ContactUsPage.tsx index de6488e1a7..dd0d47fb3f 100644 --- a/__fixtures__/test-project/web/src/pages/ContactUsPage/ContactUsPage.tsx +++ b/__fixtures__/test-project/web/src/pages/ContactUsPage/ContactUsPage.tsx @@ -14,6 +14,8 @@ import { useBlocker } from '@cedarjs/router' import { useMutation } from '@cedarjs/web' import { toast, Toaster } from '@cedarjs/web/toast' +import { validateEmail } from '@my-org/validators' + const CREATE_CONTACT = gql` mutation CreateContactMutation($input: CreateContactInput!) { createContact(input: $input) { @@ -94,9 +96,16 @@ const ContactUsPage = () => { name="email" validation={{ required: true, - pattern: { - value: /[^@]+@[^.]+..+/, - message: 'Please enter a valid email address', + validate: (value) => { + if (!value) { + return 'Email is required' + } + + if (!validateEmail(value)) { + return 'Please enter a valid email address' + } + + return true }, }} className="rounded-sm border px-2 py-1" diff --git a/tasks/test-project/codemods/contactUsPage.js b/tasks/test-project/codemods/contactUsPage.js index 6f21dce2fc..6b90251b9d 100644 --- a/tasks/test-project/codemods/contactUsPage.js +++ b/tasks/test-project/codemods/contactUsPage.js @@ -39,9 +39,16 @@ const body = ` name="email" validation={{ required: true, - pattern: { - value: /[^@]+@[^.]+\..+/, - message: 'Please enter a valid email address', + validate: (value) => { + if (!value) { + return 'Email is required' + } + + if (!validateEmail(value)) { + return 'Please enter a valid email address' + } + + return true }, }} className="border rounded-sm px-2 py-1" @@ -157,6 +164,15 @@ export default (file, api) => { ], j.stringLiteral('@cedarjs/router'), ), + j.importDeclaration( + [ + j.importSpecifier( + j.identifier('validateEmail'), + j.identifier('validateEmail'), + ), + ], + j.stringLiteral('@my-org/validators'), + ), ] // Remove the `{ Link, routes }` imports that are generated and unused diff --git a/tasks/test-project/rebuild-test-project-fixture.ts b/tasks/test-project/rebuild-test-project-fixture.ts index 32c91917a3..1677822e5f 100755 --- a/tasks/test-project/rebuild-test-project-fixture.ts +++ b/tasks/test-project/rebuild-test-project-fixture.ts @@ -13,7 +13,7 @@ import { addFrameworkDepsToProject, copyFrameworkPackages, } from './frameworkLinking' -import { webTasks, apiTasks } from './tui-tasks' +import { webTasks, apiTasks } from './tui-tasks.js' import { isAwaitable, isTuiError } from './typing' import type { TuiTaskDef } from './typing' import { @@ -498,6 +498,70 @@ async function runCommand() { await tuiTask({ step: 10, + title: 'Add workspace packages', + task: async () => { + await exec( + 'yarn cedar g package @my-org/validators', + [], + getExecaOptions(OUTPUT_PROJECT_PATH), + ) + + const packagePath = path.join( + OUTPUT_PROJECT_PATH, + 'packages', + 'validators', + ) + + fs.writeFileSync( + path.join(packagePath, 'validator.ts'), + "import { contacts } from 'api/src/services/contacts/contacts'\n" + + '\n' + + 'export function validateEmail(email: string) {\n' + + " return email.includes('@') &&\n" + + " email.includes('.') &&\n" + + " email.lastIndexOf('.') > email.indexOf('@') + 1\n" + + '}\n\n', + ) + + // Verify that `yarn cedar ` works inside package directories + // Starting with `yarn cedar info` + // TODO: Enable code below + // const info = await exec( + // 'yarn cedar info', + // [], + // getExecaOptions(OUTPUT_PROJECT_PATH), + // ) + + // if ( + // !info.stdout.includes('Binaries:') || + // !info.stdout.includes('Node:') || + // !info.stdout.includes('npmPackages:') || + // !info.stdout.includes('@cedarjs/core') + // ) { + // console.error('yarn cedar info output', info.stdout, info.stderr) + + // throw new Error('Unexpected output from `yarn cedar info`') + // } + + // Continue testing `yarn cedar ` by running `yarn cedar test` + // const test = await exec( + // 'yarn cedar test @my-org/validators', + // [], + // getExecaOptions(OUTPUT_PROJECT_PATH), + // ) + + // Validate that only the tests for this package ran + // Verify that all tests passed + // TODO: Implement functionality according to the comment above + + // The package we've generated (@my-org/validators) is used in the test + // project on both the web and the api side and is further tested by our + // playwright tests that trigger the files that import the package. + }, + }) + + await tuiTask({ + step: 11, title: 'Running prisma migrate reset', task: () => { return exec( @@ -509,7 +573,7 @@ async function runCommand() { }) await tuiTask({ - step: 11, + step: 12, title: 'Lint --fix all the things', task: async () => { try { @@ -540,7 +604,7 @@ async function runCommand() { }) await tuiTask({ - step: 12, + step: 13, title: 'Replace and Cleanup Fixture', task: async () => { // @TODO: This only works on UNIX, we should use path.join everywhere @@ -595,7 +659,7 @@ async function runCommand() { }) await tuiTask({ - step: 13, + step: 14, title: 'All done!', task: () => { console.log('-'.repeat(30)) From ca1bd9846936573a0ed9f0ae4c4ce173d3b35a70 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 15:49:15 +0100 Subject: [PATCH 05/22] update fixture --- .../packages/validators/README.md | 15 +++++++++++++++ .../packages/validators/package.json | 15 +++++++++++++++ .../packages/validators/src/index.ts | 5 +++++ .../validators/src/validators.test.ts | 7 +++++++ .../packages/validators/tsconfig.json | 16 ++++++++++++++++ __fixtures__/test-project/redwood.toml | 3 +++ .../src/pages/ContactUsPage/ContactUsPage.tsx | 3 +-- .../rebuild-test-project-fixture-esm.ts | 4 ++-- .../rebuild-test-project-fixture.ts | 19 ++++++++++++------- 9 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 __fixtures__/test-project/packages/validators/README.md create mode 100644 __fixtures__/test-project/packages/validators/package.json create mode 100644 __fixtures__/test-project/packages/validators/src/index.ts create mode 100644 __fixtures__/test-project/packages/validators/src/validators.test.ts create mode 100644 __fixtures__/test-project/packages/validators/tsconfig.json diff --git a/__fixtures__/test-project/packages/validators/README.md b/__fixtures__/test-project/packages/validators/README.md new file mode 100644 index 0000000000..91976d7de2 --- /dev/null +++ b/__fixtures__/test-project/packages/validators/README.md @@ -0,0 +1,15 @@ +# Shared Package '@my-org/validators' + +Use code in this package by adding it to the dependencies on the side you want +to use it, with the special `workspace:*` version. After that you can import it +into your code: + +```json + "dependencies": { + "@my-org/validators": "workspace:*" + } +``` + +```javascript +import { validators } from '@my-org/validators'; +``` diff --git a/__fixtures__/test-project/packages/validators/package.json b/__fixtures__/test-project/packages/validators/package.json new file mode 100644 index 0000000000..eb30b49e92 --- /dev/null +++ b/__fixtures__/test-project/packages/validators/package.json @@ -0,0 +1,15 @@ +{ + "name": "@my-org/validators", + "version": "0.0.0", + "private": true, + "type": "module", + "main": "dist/index.js", + "scripts": { + "build": "tsc", + "watch": "tsc --watch" + }, + "devDependencies": { + "@cedarjs/testing": "2.2.1", + "typescript": "5.9.3" + } +} diff --git a/__fixtures__/test-project/packages/validators/src/index.ts b/__fixtures__/test-project/packages/validators/src/index.ts new file mode 100644 index 0000000000..22aefe648c --- /dev/null +++ b/__fixtures__/test-project/packages/validators/src/index.ts @@ -0,0 +1,5 @@ +export function validateEmail(email: string) { + return email.includes('@') && + email.includes('.') && + email.lastIndexOf('.') > email.indexOf('@') + 1 +} diff --git a/__fixtures__/test-project/packages/validators/src/validators.test.ts b/__fixtures__/test-project/packages/validators/src/validators.test.ts new file mode 100644 index 0000000000..b9fbd98dc9 --- /dev/null +++ b/__fixtures__/test-project/packages/validators/src/validators.test.ts @@ -0,0 +1,7 @@ +import { validators } from './index.js' + +describe('validators', () => { + it('should not throw any errors', async () => { + expect(validators()).not.toThrow() + }) +}) diff --git a/__fixtures__/test-project/packages/validators/tsconfig.json b/__fixtures__/test-project/packages/validators/tsconfig.json new file mode 100644 index 0000000000..a2e259fee3 --- /dev/null +++ b/__fixtures__/test-project/packages/validators/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "composite": true, + "target": "ES2023", + "module": "Node20", + "esModuleInterop": true, + "skipLibCheck": true, + "baseUrl": ".", + "rootDir": "src", + "outDir": "dist", + "sourceMap": true, + "declaration": true, + "declarationMap": true, + }, + "include": ["src"], +} diff --git a/__fixtures__/test-project/redwood.toml b/__fixtures__/test-project/redwood.toml index fd4787af4b..5d80e61f18 100644 --- a/__fixtures__/test-project/redwood.toml +++ b/__fixtures__/test-project/redwood.toml @@ -19,3 +19,6 @@ open = true [notifications] versionUpdates = ["latest"] + +[experimental.packagesWorkspace] + enabled = true diff --git a/__fixtures__/test-project/web/src/pages/ContactUsPage/ContactUsPage.tsx b/__fixtures__/test-project/web/src/pages/ContactUsPage/ContactUsPage.tsx index dd0d47fb3f..3f523f7717 100644 --- a/__fixtures__/test-project/web/src/pages/ContactUsPage/ContactUsPage.tsx +++ b/__fixtures__/test-project/web/src/pages/ContactUsPage/ContactUsPage.tsx @@ -1,5 +1,6 @@ import { useState } from 'react' +import { validateEmail } from '@my-org/validators' import { useForm } from 'react-hook-form' import { @@ -14,8 +15,6 @@ import { useBlocker } from '@cedarjs/router' import { useMutation } from '@cedarjs/web' import { toast, Toaster } from '@cedarjs/web/toast' -import { validateEmail } from '@my-org/validators' - const CREATE_CONTACT = gql` mutation CreateContactMutation($input: CreateContactInput!) { createContact(input: $input) { diff --git a/tasks/test-project/rebuild-test-project-fixture-esm.ts b/tasks/test-project/rebuild-test-project-fixture-esm.ts index a413ba0609..da0055e727 100755 --- a/tasks/test-project/rebuild-test-project-fixture-esm.ts +++ b/tasks/test-project/rebuild-test-project-fixture-esm.ts @@ -318,10 +318,10 @@ async function runCommand() { await tuiTask({ step: 1, title: '[link] Building Cedar framework', - content: 'yarn build:clean && yarn build', + content: 'yarn clean && yarn build', task: async () => { return exec( - 'yarn build:clean && yarn build', + 'yarn clean && yarn build', [], getExecaOptions(RW_FRAMEWORK_PATH), ) diff --git a/tasks/test-project/rebuild-test-project-fixture.ts b/tasks/test-project/rebuild-test-project-fixture.ts index 1677822e5f..10a82f66f9 100755 --- a/tasks/test-project/rebuild-test-project-fixture.ts +++ b/tasks/test-project/rebuild-test-project-fixture.ts @@ -315,10 +315,10 @@ async function runCommand() { await tuiTask({ step: 1, title: '[link] Building Cedar framework', - content: 'yarn build:clean && yarn build', + content: 'yarn clean && yarn build', task: async () => { return exec( - 'yarn build:clean && yarn build', + 'yarn clean && yarn build', [], getExecaOptions(RW_FRAMEWORK_PATH), ) @@ -500,6 +500,13 @@ async function runCommand() { step: 10, title: 'Add workspace packages', task: async () => { + const tomlPath = path.join(OUTPUT_PROJECT_PATH, 'redwood.toml') + const redwoodToml = fs.readFileSync(tomlPath, 'utf-8') + const newRedwoodToml = + redwoodToml + '\n[experimental.packagesWorkspace]\n enabled = true\n' + + fs.writeFileSync(tomlPath, newRedwoodToml) + await exec( 'yarn cedar g package @my-org/validators', [], @@ -513,14 +520,12 @@ async function runCommand() { ) fs.writeFileSync( - path.join(packagePath, 'validator.ts'), - "import { contacts } from 'api/src/services/contacts/contacts'\n" + - '\n' + - 'export function validateEmail(email: string) {\n' + + path.join(packagePath, 'src', 'index.ts'), + 'export function validateEmail(email: string) {\n' + " return email.includes('@') &&\n" + " email.includes('.') &&\n" + " email.lastIndexOf('.') > email.indexOf('@') + 1\n" + - '}\n\n', + '}\n', ) // Verify that `yarn cedar ` works inside package directories From a3f2537223390d63d5d6ed51a2a5fae3bdd9f699 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 17:13:50 +0100 Subject: [PATCH 06/22] concurrentlyOptions --- packages/cli/src/commands/build/buildPackagesTask.js | 6 +++++- tasks/test-project/rebuild-test-project-fixture.ts | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/build/buildPackagesTask.js b/packages/cli/src/commands/build/buildPackagesTask.js index cff9f9ab19..f4c9ad485b 100644 --- a/packages/cli/src/commands/build/buildPackagesTask.js +++ b/packages/cli/src/commands/build/buildPackagesTask.js @@ -35,11 +35,15 @@ export async function buildPackagesTask(nonApiWebWorkspaces) { const { result } = concurrently( workspacePaths.map((workspacePath) => { - return { + const concurrentlyOptions = { command: `yarn build`, name: workspacePath.split('/').at(-1), cwd: workspacePath, } + + console.log('concurrentlyOptions', concurrentlyOptions) + + return concurrentlyOptions }), { prefix: '{name} |', diff --git a/tasks/test-project/rebuild-test-project-fixture.ts b/tasks/test-project/rebuild-test-project-fixture.ts index 10a82f66f9..6a79462d75 100755 --- a/tasks/test-project/rebuild-test-project-fixture.ts +++ b/tasks/test-project/rebuild-test-project-fixture.ts @@ -528,6 +528,18 @@ async function runCommand() { '}\n', ) + const build = await exec( + 'yarn cedar build', + [], + getExecaOptions(OUTPUT_PROJECT_PATH), + ) + + // TODO: Update this when we refine the build process + if (!build.stdout.includes('yarn build exited with code 0')) { + console.error('yarn cedar build output', build.stdout, build.stderr) + throw new Error('Unexpected output from `yarn cedar build`') + } + // Verify that `yarn cedar ` works inside package directories // Starting with `yarn cedar info` // TODO: Enable code below From f07c1f863b56e3efc0a8e04e69fd38c60723ba5b Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 19:07:12 +0100 Subject: [PATCH 07/22] pkgJson deps --- .../__snapshots__/package.test.ts.snap | 9 ++-- .../package/templates/README.md.template | 2 +- .../package/templates/tsconfig.json.template | 1 + .../rebuild-test-project-fixture.ts | 44 ++++++++++++++++++- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap b/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap index 1d4b4c62e6..a4112a06ff 100644 --- a/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap +++ b/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap @@ -14,7 +14,7 @@ into your code: \`\`\` \`\`\`javascript -import { formValidators } from '@my-camel-case-app/form-validators'; +import { formValidators } from '@my-camel-case-app/form-validators' \`\`\` " `; @@ -51,7 +51,7 @@ into your code: \`\`\` \`\`\`javascript -import { formValidators } from '@my-camel-case-app/form-validators'; +import { formValidators } from '@my-camel-case-app/form-validators' \`\`\` " `; @@ -114,7 +114,7 @@ into your code: \`\`\` \`\`\`javascript -import { formValidatorsPkg } from '@my-org/form-validators-pkg'; +import { formValidatorsPkg } from '@my-org/form-validators-pkg' \`\`\` " `; @@ -144,7 +144,7 @@ into your code: \`\`\` \`\`\`javascript -import { foo } from '@my-cedar-app/foo'; +import { foo } from '@my-cedar-app/foo' \`\`\` " `; @@ -202,6 +202,7 @@ exports[`packageHandler > files > single word package name > infers package scop "declarationMap": true, }, "include": ["src"], + "exclude": ["*.test.ts"], } " `; diff --git a/packages/cli/src/commands/generate/package/templates/README.md.template b/packages/cli/src/commands/generate/package/templates/README.md.template index 716a69a85a..716fe7aacc 100644 --- a/packages/cli/src/commands/generate/package/templates/README.md.template +++ b/packages/cli/src/commands/generate/package/templates/README.md.template @@ -11,5 +11,5 @@ into your code: ``` ```javascript -import { ${camelName} } from '${packageName}'; +import { ${camelName} } from '${packageName}' ``` diff --git a/packages/cli/src/commands/generate/package/templates/tsconfig.json.template b/packages/cli/src/commands/generate/package/templates/tsconfig.json.template index a2e259fee3..1803c714a7 100644 --- a/packages/cli/src/commands/generate/package/templates/tsconfig.json.template +++ b/packages/cli/src/commands/generate/package/templates/tsconfig.json.template @@ -13,4 +13,5 @@ "declarationMap": true, }, "include": ["src"], + "exclude": ["*.test.ts"], } diff --git a/tasks/test-project/rebuild-test-project-fixture.ts b/tasks/test-project/rebuild-test-project-fixture.ts index 6a79462d75..095e7c74d1 100755 --- a/tasks/test-project/rebuild-test-project-fixture.ts +++ b/tasks/test-project/rebuild-test-project-fixture.ts @@ -528,12 +528,50 @@ async function runCommand() { '}\n', ) + fs.writeFileSync( + path.join(packagePath, 'src', 'validators.test.ts'), + "import { validateEmail } from './index.js'\n" + + '\n' + + "describe('validators', () => {\n" + + " it('should not throw any errors', async () => {\n" + + " expect(validateEmail('valid@email.com')).not.toThrow()\n" + + ' })\n' + + '})\n', + ) + + const webPackageJson = JSON.parse( + fs.readFileSync( + path.join(OUTPUT_PROJECT_PATH, 'web', 'package.json'), + 'utf8', + ), + ) + + webPackageJson.dependencies['@my-org/validators'] = 'workspace:*' + + fs.writeFileSync( + path.join(OUTPUT_PROJECT_PATH, 'web', 'package.json'), + JSON.stringify(webPackageJson, null, 2), + ) + + await exec('yarn install', [], getExecaOptions(OUTPUT_PROJECT_PATH)) + const build = await exec( 'yarn cedar build', [], getExecaOptions(OUTPUT_PROJECT_PATH), ) + const distFiles = fs.readdirSync( + path.join(OUTPUT_PROJECT_PATH, 'packages', 'validators', 'dist'), + ) + + if (distFiles.some((file) => file.includes('test'))) { + console.error('distFiles', distFiles) + throw new Error( + 'Unexpected test file in validators package dist directory', + ) + } + // TODO: Update this when we refine the build process if (!build.stdout.includes('yarn build exited with code 0')) { console.error('yarn cedar build output', build.stdout, build.stderr) @@ -623,6 +661,7 @@ async function runCommand() { await tuiTask({ step: 13, title: 'Replace and Cleanup Fixture', + skip: Math.random() < 5, task: async () => { // @TODO: This only works on UNIX, we should use path.join everywhere // remove all .gitignore @@ -648,8 +687,9 @@ async function runCommand() { await rimraf(`${OUTPUT_PROJECT_PATH}/.nx`) await rimraf(`${OUTPUT_PROJECT_PATH}/tarballs`) - // Copy over package.json from template, so we remove the extra dev dependencies, and cfw postinstall script - // that we added in "Adding framework dependencies to project" + // Copy over package.json from template, so we remove the extra dev + // dependencies, and cfw postinstall script that we added in "Adding + // framework dependencies to project" // There's one devDep we actually do want in there though, and that's the // prettier plugin for Tailwind CSS const rootPackageJson = JSON.parse( From 593cf0dd80d2fe9035f833d79af051bb8f93159b Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 19:47:39 +0100 Subject: [PATCH 08/22] try to fix paths for unit test --- .../build/__tests__/buildPackagesTask.test.js | 11 +++++------ packages/cli/src/commands/build/buildPackagesTask.js | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js b/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js index 12c5d4dae6..dc8832490c 100644 --- a/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js +++ b/packages/cli/src/commands/build/__tests__/buildPackagesTask.test.js @@ -61,7 +61,6 @@ vi.mock('../../lib/exit.js', () => ({ })) import fs from 'node:fs' -import path from 'node:path' import concurrently from 'concurrently' import { vi, afterEach, describe, it, expect } from 'vitest' @@ -82,17 +81,17 @@ describe('buildPackagesTask', async () => { { command: 'yarn build', name: 'foo', - cwd: '/mocked/project/packages/foo'.split('/').join(path.sep), + cwd: '/mocked/project/packages/foo', }, { command: 'yarn build', name: 'bar', - cwd: '/mocked/project/packages/bar'.split('/').join(path.sep), + cwd: '/mocked/project/packages/bar', }, { command: 'yarn build', name: 'baz', - cwd: '/mocked/project/packages/baz'.split('/').join(path.sep), + cwd: '/mocked/project/packages/baz', }, ], { @@ -111,12 +110,12 @@ describe('buildPackagesTask', async () => { { command: 'yarn build', name: 'pkg-one', - cwd: '/mocked/project/packages/pkg-one'.split('/').join(path.sep), + cwd: '/mocked/project/packages/pkg-one', }, { command: 'yarn build', name: 'pkg-two', - cwd: '/mocked/project/packages/pkg-two'.split('/').join(path.sep), + cwd: '/mocked/project/packages/pkg-two', }, ], { diff --git a/packages/cli/src/commands/build/buildPackagesTask.js b/packages/cli/src/commands/build/buildPackagesTask.js index f4c9ad485b..d2913cc9ac 100644 --- a/packages/cli/src/commands/build/buildPackagesTask.js +++ b/packages/cli/src/commands/build/buildPackagesTask.js @@ -3,6 +3,7 @@ import path from 'node:path' import concurrently from 'concurrently' +import { importStatementPath } from '@cedarjs/project-config' import { errorTelemetry } from '@cedarjs/telemetry' import { exitWithError } from '../../lib/exit.js' @@ -30,7 +31,7 @@ export async function buildPackagesTask(nonApiWebWorkspaces) { throw new Error(`Workspace not found: ${workspacePath}`) } - return workspacePath + return importStatementPath(workspacePath) }) const { result } = concurrently( From 3dde21e07da1fdc11852eccce5164ea5a776119a Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 19:59:14 +0100 Subject: [PATCH 09/22] add dep to test project fixture package json --- __fixtures__/test-project/web/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/__fixtures__/test-project/web/package.json b/__fixtures__/test-project/web/package.json index fbea5f2c21..05e3a5c76c 100644 --- a/__fixtures__/test-project/web/package.json +++ b/__fixtures__/test-project/web/package.json @@ -15,6 +15,7 @@ "@cedarjs/forms": "2.0.2", "@cedarjs/router": "2.0.2", "@cedarjs/web": "2.0.2", + "@my-org/validators": "2.0.2", "humanize-string": "2.1.0", "react": "19.2.3", "react-dom": "19.2.3" From 473e7ca75f3f252cea731fcc6fede5b1b837908e Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 20:11:36 +0100 Subject: [PATCH 10/22] Add packages/* as a workspace in test-fixture --- __fixtures__/test-project/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/__fixtures__/test-project/package.json b/__fixtures__/test-project/package.json index 8182db3296..2877da9ac3 100644 --- a/__fixtures__/test-project/package.json +++ b/__fixtures__/test-project/package.json @@ -2,7 +2,8 @@ "private": true, "workspaces": [ "api", - "web" + "web", + "packages/*" ], "devDependencies": { "@cedarjs/core": "2.0.2", From 72741193d2afeb6ba4453d7678ace777c4bf9c6f Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 21:42:55 +0100 Subject: [PATCH 11/22] test ingore pattern --- __fixtures__/test-project/packages/validators/README.md | 2 +- .../test-project/packages/validators/src/validators.test.ts | 4 ++-- __fixtures__/test-project/packages/validators/tsconfig.json | 1 + __fixtures__/test-project/web/package.json | 2 +- .../package/__tests__/__snapshots__/package.test.ts.snap | 2 +- .../generate/package/templates/tsconfig.json.template | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/__fixtures__/test-project/packages/validators/README.md b/__fixtures__/test-project/packages/validators/README.md index 91976d7de2..ecfd785633 100644 --- a/__fixtures__/test-project/packages/validators/README.md +++ b/__fixtures__/test-project/packages/validators/README.md @@ -11,5 +11,5 @@ into your code: ``` ```javascript -import { validators } from '@my-org/validators'; +import { validators } from '@my-org/validators' ``` diff --git a/__fixtures__/test-project/packages/validators/src/validators.test.ts b/__fixtures__/test-project/packages/validators/src/validators.test.ts index b9fbd98dc9..110ad35ba3 100644 --- a/__fixtures__/test-project/packages/validators/src/validators.test.ts +++ b/__fixtures__/test-project/packages/validators/src/validators.test.ts @@ -1,7 +1,7 @@ -import { validators } from './index.js' +import { validateEmail } from './index.js' describe('validators', () => { it('should not throw any errors', async () => { - expect(validators()).not.toThrow() + expect(validateEmail('valid@email.com')).not.toThrow() }) }) diff --git a/__fixtures__/test-project/packages/validators/tsconfig.json b/__fixtures__/test-project/packages/validators/tsconfig.json index a2e259fee3..a405d33430 100644 --- a/__fixtures__/test-project/packages/validators/tsconfig.json +++ b/__fixtures__/test-project/packages/validators/tsconfig.json @@ -13,4 +13,5 @@ "declarationMap": true, }, "include": ["src"], + "exclude": ["**/*.test.ts"], } diff --git a/__fixtures__/test-project/web/package.json b/__fixtures__/test-project/web/package.json index 05e3a5c76c..72c3d8e82c 100644 --- a/__fixtures__/test-project/web/package.json +++ b/__fixtures__/test-project/web/package.json @@ -15,7 +15,7 @@ "@cedarjs/forms": "2.0.2", "@cedarjs/router": "2.0.2", "@cedarjs/web": "2.0.2", - "@my-org/validators": "2.0.2", + "@my-org/validators": "workspace:*", "humanize-string": "2.1.0", "react": "19.2.3", "react-dom": "19.2.3" diff --git a/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap b/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap index a4112a06ff..ff7940350c 100644 --- a/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap +++ b/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap @@ -202,7 +202,7 @@ exports[`packageHandler > files > single word package name > infers package scop "declarationMap": true, }, "include": ["src"], - "exclude": ["*.test.ts"], + "exclude": ["**/*.test.ts"], } " `; diff --git a/packages/cli/src/commands/generate/package/templates/tsconfig.json.template b/packages/cli/src/commands/generate/package/templates/tsconfig.json.template index 1803c714a7..a405d33430 100644 --- a/packages/cli/src/commands/generate/package/templates/tsconfig.json.template +++ b/packages/cli/src/commands/generate/package/templates/tsconfig.json.template @@ -13,5 +13,5 @@ "declarationMap": true, }, "include": ["src"], - "exclude": ["*.test.ts"], + "exclude": ["**/*.test.ts"], } From ea5b67068d97f6ca42dbafad798ad54767ae8e6d Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 21:48:20 +0100 Subject: [PATCH 12/22] update root packagejson in rebuild script --- tasks/test-project/rebuild-test-project-fixture.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasks/test-project/rebuild-test-project-fixture.ts b/tasks/test-project/rebuild-test-project-fixture.ts index 095e7c74d1..cfb60d5e5f 100755 --- a/tasks/test-project/rebuild-test-project-fixture.ts +++ b/tasks/test-project/rebuild-test-project-fixture.ts @@ -692,6 +692,8 @@ async function runCommand() { // framework dependencies to project" // There's one devDep we actually do want in there though, and that's the // prettier plugin for Tailwind CSS + // We also want the `packages/*` workspace config that was added when + // adding the validators package const rootPackageJson = JSON.parse( fs.readFileSync(path.join(OUTPUT_PROJECT_PATH, 'package.json'), 'utf8'), ) @@ -704,6 +706,7 @@ async function runCommand() { ) newRootPackageJson.devDependencies['prettier-plugin-tailwindcss'] = rootPackageJson.devDependencies['prettier-plugin-tailwindcss'] + newRootPackageJson.workspaces.push('packages/*') fs.writeFileSync( path.join(OUTPUT_PROJECT_PATH, 'package.json'), JSON.stringify(newRootPackageJson, null, 2) + '\n', From 3ee23b650c3dcbd346763e480ab77cb331bd1825 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 22:25:21 +0100 Subject: [PATCH 13/22] debug cli smoketest --- .github/actions/set-up-test-project-esm/action.yaml | 2 +- .github/actions/set-up-test-project/action.yaml | 2 +- .github/actions/set-up-test-project/setUpTestProject.mjs | 2 +- .github/workflows/cli-smoke-tests.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/set-up-test-project-esm/action.yaml b/.github/actions/set-up-test-project-esm/action.yaml index f8b36dd369..0dc09524f1 100644 --- a/.github/actions/set-up-test-project-esm/action.yaml +++ b/.github/actions/set-up-test-project-esm/action.yaml @@ -2,7 +2,7 @@ name: Set up test project description: Sets up the test project fixture in CI for smoke tests and CLI checks runs: - using: node20 + using: node24 main: 'setUpTestProjectEsm.mjs' inputs: diff --git a/.github/actions/set-up-test-project/action.yaml b/.github/actions/set-up-test-project/action.yaml index 7c3528987a..baeab023c5 100644 --- a/.github/actions/set-up-test-project/action.yaml +++ b/.github/actions/set-up-test-project/action.yaml @@ -2,7 +2,7 @@ name: Set up test project description: Sets up the test project fixture in CI for smoke tests and CLI checks runs: - using: node20 + using: node24 main: 'setUpTestProject.mjs' inputs: diff --git a/.github/actions/set-up-test-project/setUpTestProject.mjs b/.github/actions/set-up-test-project/setUpTestProject.mjs index bf9d5f664d..aadc01ac7c 100644 --- a/.github/actions/set-up-test-project/setUpTestProject.mjs +++ b/.github/actions/set-up-test-project/setUpTestProject.mjs @@ -27,7 +27,7 @@ console.log() * @returns {Promise} */ async function main() { - await setUpTestProject({ canary: true }) + await setUpTestProject({ canary }) } /** diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index d162d8a39b..868327370a 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -40,7 +40,7 @@ jobs: working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar test api` - run: yarn cedar test api --no-watch + run: cat web/package.json && yarn cedar test api --no-watch working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar test web` From c60f232295e4c68117c6e08b1c0fbb24be378a0a Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 22:45:15 +0100 Subject: [PATCH 14/22] debug cli smoketest --- .github/workflows/cli-smoke-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index 868327370a..6e58c501c7 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -26,6 +26,7 @@ jobs: env: REDWOOD_DISABLE_TELEMETRY: 1 YARN_ENABLE_IMMUTABLE_INSTALLS: false + YARN_ENABLE_HARDENED_MODE: 0 - name: Run `cedar info` run: yarn cedar info From 79a83cbc521f1831c52144d445ecc38b5ccc2edc Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 23:14:19 +0100 Subject: [PATCH 15/22] cat lockfile --- .github/workflows/cli-smoke-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index 6e58c501c7..f50a1bbbe3 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -41,11 +41,11 @@ jobs: working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar test api` - run: cat web/package.json && yarn cedar test api --no-watch + run: yarn cedar test api --no-watch working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar test web` - run: yarn cedar test web --no-watch + run: cat yarn.lock | grep my-org && yarn cedar test web --no-watch working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar check` From b0fcf0625ab2b41460a4887ce59b82754d6a46b2 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 23:41:35 +0100 Subject: [PATCH 16/22] exports --- .../test-project/packages/validators/package.json | 6 ++++++ .../__tests__/__snapshots__/package.test.ts.snap | 12 ++++++++++++ .../generate/package/templates/package.json.template | 6 ++++++ 3 files changed, 24 insertions(+) diff --git a/__fixtures__/test-project/packages/validators/package.json b/__fixtures__/test-project/packages/validators/package.json index eb30b49e92..fc834676cc 100644 --- a/__fixtures__/test-project/packages/validators/package.json +++ b/__fixtures__/test-project/packages/validators/package.json @@ -4,6 +4,12 @@ "private": true, "type": "module", "main": "dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, "scripts": { "build": "tsc", "watch": "tsc --watch" diff --git a/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap b/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap index ff7940350c..6959964485 100644 --- a/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap +++ b/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap @@ -88,6 +88,12 @@ exports[`packageHandler > files > multi-word package names > uses the provided s "private": true, "type": "module", "main": "dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, "scripts": { "build": "tsc", "watch": "tsc --watch" @@ -174,6 +180,12 @@ exports[`packageHandler > files > single word package name > infers package scop "private": true, "type": "module", "main": "dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, "scripts": { "build": "tsc", "watch": "tsc --watch" diff --git a/packages/cli/src/commands/generate/package/templates/package.json.template b/packages/cli/src/commands/generate/package/templates/package.json.template index 48ed8ea96e..2b62f93635 100644 --- a/packages/cli/src/commands/generate/package/templates/package.json.template +++ b/packages/cli/src/commands/generate/package/templates/package.json.template @@ -4,6 +4,12 @@ "private": true, "type": "module", "main": "dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, "scripts": { "build": "tsc", "watch": "tsc --watch" From 5437fe075ea643009567e3aadde3050790754580 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 23:52:43 +0100 Subject: [PATCH 17/22] build before test --- .github/workflows/cli-smoke-tests.yml | 9 +++++++++ .../test-project/packages/validators/package.json | 1 + .../package/__tests__/__snapshots__/package.test.ts.snap | 2 ++ .../generate/package/templates/package.json.template | 1 + 4 files changed, 13 insertions(+) diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index f50a1bbbe3..0793a8201b 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -40,6 +40,15 @@ jobs: run: yarn cedar lint ./api/src --fix working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} + # - name: Run `cedar build` + # run: yarn cedar build + # working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} + + # TODO: Remove this and favor `yarn cedar build` when it's working + - name: Run `yarn build` + run: yarn build + working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }}/packages/validators + - name: Run `cedar test api` run: yarn cedar test api --no-watch working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} diff --git a/__fixtures__/test-project/packages/validators/package.json b/__fixtures__/test-project/packages/validators/package.json index fc834676cc..e52bec0137 100644 --- a/__fixtures__/test-project/packages/validators/package.json +++ b/__fixtures__/test-project/packages/validators/package.json @@ -4,6 +4,7 @@ "private": true, "type": "module", "main": "dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", diff --git a/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap b/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap index 6959964485..c6e3fa3fae 100644 --- a/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap +++ b/packages/cli/src/commands/generate/package/__tests__/__snapshots__/package.test.ts.snap @@ -88,6 +88,7 @@ exports[`packageHandler > files > multi-word package names > uses the provided s "private": true, "type": "module", "main": "dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", @@ -180,6 +181,7 @@ exports[`packageHandler > files > single word package name > infers package scop "private": true, "type": "module", "main": "dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", diff --git a/packages/cli/src/commands/generate/package/templates/package.json.template b/packages/cli/src/commands/generate/package/templates/package.json.template index 2b62f93635..40b481ae42 100644 --- a/packages/cli/src/commands/generate/package/templates/package.json.template +++ b/packages/cli/src/commands/generate/package/templates/package.json.template @@ -4,6 +4,7 @@ "private": true, "type": "module", "main": "dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", From 6f8952820b7a95475b7a2a0047e857518702c163 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 3 Jan 2026 23:53:56 +0100 Subject: [PATCH 18/22] ls -la --- .github/workflows/cli-smoke-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index 0793a8201b..fe8cca9475 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -54,7 +54,7 @@ jobs: working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar test web` - run: cat yarn.lock | grep my-org && yarn cedar test web --no-watch + run: cat yarn.lock | grep my-org && ls -la packages/validators && ls -la packages/validators/dist && yarn cedar test web --no-watch working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar check` From f99141a9a88d4a0cd1fa72bb440e168485e09153 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sun, 4 Jan 2026 00:04:32 +0100 Subject: [PATCH 19/22] only ls --- .github/workflows/cli-smoke-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index fe8cca9475..72463f9ad9 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -54,7 +54,7 @@ jobs: working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar test web` - run: cat yarn.lock | grep my-org && ls -la packages/validators && ls -la packages/validators/dist && yarn cedar test web --no-watch + run: cat yarn.lock | grep my-org && ls packages/validators && ls packages/validators/dist && yarn cedar test web --no-watch working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar check` From 2a35e77506f99384eb3c33aaf22ab02535768bfd Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sun, 4 Jan 2026 13:26:58 +0100 Subject: [PATCH 20/22] revert cli-smoke-tests.yml --- .github/workflows/cli-smoke-tests.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index 72463f9ad9..8b9fbf7573 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -40,15 +40,6 @@ jobs: run: yarn cedar lint ./api/src --fix working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - # - name: Run `cedar build` - # run: yarn cedar build - # working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - - # TODO: Remove this and favor `yarn cedar build` when it's working - - name: Run `yarn build` - run: yarn build - working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }}/packages/validators - - name: Run `cedar test api` run: yarn cedar test api --no-watch working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} From a1382b2d9343414099f6a008d42906c0cd42a5b1 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sun, 4 Jan 2026 13:27:55 +0100 Subject: [PATCH 21/22] revert cli-smoke-tests.yml --- .github/workflows/cli-smoke-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index bbd381b50b..bfbf9e1f1a 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -49,7 +49,7 @@ jobs: working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar test web` - run: cat yarn.lock | grep my-org && ls packages/validators && ls packages/validators/dist && yarn cedar test web --no-watch + run: yarn cedar test web --no-watch working-directory: ${{ steps.set-up-test-project.outputs.test-project-path }} - name: Run `cedar check` From e52ec5533dc37781d673370ec776afa395299761 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sun, 4 Jan 2026 13:28:25 +0100 Subject: [PATCH 22/22] revert cli-smoke-tests.yml --- .github/workflows/cli-smoke-tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/cli-smoke-tests.yml b/.github/workflows/cli-smoke-tests.yml index bfbf9e1f1a..3ca87cea90 100644 --- a/.github/workflows/cli-smoke-tests.yml +++ b/.github/workflows/cli-smoke-tests.yml @@ -26,7 +26,6 @@ jobs: env: REDWOOD_DISABLE_TELEMETRY: 1 YARN_ENABLE_IMMUTABLE_INSTALLS: false - YARN_ENABLE_HARDENED_MODE: 0 - name: Run `cedar info` run: yarn cedar info