Implement comprehensive test suite with matrix-driven configuration validation#4
Implement comprehensive test suite with matrix-driven configuration validation#4eugenegraves wants to merge 34 commits into
Conversation
WalkthroughThis pull request introduces a comprehensive test infrastructure overhaul for the AbsoluteJS project scaffolder. It adds 20+ new functional test validators for various frameworks and databases, implements a dependency caching system for test optimization, creates a matrix-based test execution CLI, establishes behavioral test suites with database hooks, and updates code generators to support Prisma ORM and enhanced PostgreSQL/Drizzle configurations alongside existing database support. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as Test CLI
participant Matrix as Matrix Generator
participant Suite as Functional Suite
participant Scaffold as Scaffold Project
participant Deps as Install Dependencies
participant Build as Build Validator
participant Serve as Server Validator
participant Validate as Framework/DB Validator
CLI->>Matrix: createMatrix()
Matrix-->>CLI: MatrixConfig[]
CLI->>Matrix: annotateHostConstraints()
Matrix-->>CLI: annotated configs with skip/required-env
loop per suite
CLI->>Suite: runFunctionalTests()
rect rgb(200, 220, 255)
Suite->>Scaffold: scaffoldProject()
Scaffold-->>Suite: projectPath
Suite->>Deps: testDependencyInstallation()
Deps-->>Suite: DependencyInstallResult
end
rect rgb(200, 255, 220)
Suite->>Build: validateBuild()
Build-->>Suite: BuildResult
end
rect rgb(255, 220, 200)
Suite->>Serve: validateServerStartup()
Serve-->>Suite: ServerStartupResult
end
Suite-->>CLI: FunctionalTestResult
CLI->>Validate: validateFramework/Database()
Validate->>Validate: aggregate functional results
Validate-->>CLI: ValidationResult
end
sequenceDiagram
participant Test as Behavioural Test
participant Scenario as Scenario Runner
participant Scaffold as Scaffold
participant DB as Database Hooks
participant Server as Server
participant HTTP as HTTP Client
Test->>Scenario: runCountHistoryScenario()
Scenario->>Scaffold: scaffoldProject(config)
Scaffold-->>Scenario: projectPath
Scenario->>DB: beforeServerStart()
rect rgb(200, 220, 255)
DB->>DB: docker compose up
DB->>DB: wait for readiness
end
Scenario->>Server: startServer()
Server-->>Scenario: running server
Scenario->>HTTP: POST /count
HTTP-->>Scenario: { uid, count }
Scenario->>HTTP: GET /count?uid=...
HTTP-->>Scenario: history array
Scenario->>Server: server.stop()
Scenario->>DB: afterServerStop()
DB->>DB: docker compose down
Scenario-->>Test: result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas requiring extra attention:
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 24
🧹 Nitpick comments (6)
src/commands/formatProject.ts (1)
6-6: Remove unused import.The
formatNoInstallCommandsimport is no longer used after the refactoring to always useformatCommands.Apply this diff:
-import { formatCommands, formatNoInstallCommands } from '../utils/commandMaps'; +import { formatCommands } from '../utils/commandMaps';scripts/functional-tests/database-connection-tester.ts (1)
11-11: Remove unused import.The
readFileSyncimport is not used anywhere in the file.Apply this diff:
-import { existsSync, readFileSync } from 'fs'; +import { existsSync } from 'fs';scripts/functional-tests/frontend-renderer-tester.ts (4)
18-24: Consider prefixing unused parameters with underscore.The
projectPathandconfigparameters are declared but never used in the function body. To signal intentionally unused parameters and avoid linting warnings, consider prefixing them with an underscore (e.g.,_projectPath,_config) or add basic validation such as checking that the project path exists.Apply this diff to prefix unused parameters:
export async function testFrontendRendering( - projectPath: string, + _projectPath: string, serverUrl: string = 'http://localhost:3000', - config: { + _config: { frontends?: string[]; } = {} ): Promise<FrontendRendererResult> {
47-47: Use theerrorsvariable for consistency.Line 47 returns an empty array literal
errors: []instead of theerrorsvariable declared on line 25. For consistency with howwarningsis returned, use the variable.Apply this diff:
- return { passed: true, errors: [], warnings }; + return { passed: true, errors, warnings };
50-78: CLI usage is well-structured.The CLI block properly validates input presence, handles errors, and uses appropriate exit codes. The error messages are clear and helpful.
Optionally, you could add validation that the project path exists to provide earlier feedback:
import { existsSync } from 'fs'; // ... after line 58 if (!existsSync(projectPath)) { console.error(`Error: Project path "${projectPath}" does not exist`); process.exit(1); }
28-47: Placeholder always succeeds—consider test suite implications.The function returns
passed: trueregardless of actual validation, which means any tests using this helper will pass until the implementation is complete. While the warnings alert users to the incomplete state, you might consider either:
- Documenting this behavior in the function's JSDoc
- Having it fail by default with an opt-in flag for placeholder mode
- Ensuring the test suite explicitly filters out tests using this placeholder
This helps prevent false confidence in test coverage.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (54)
.gitignore(1 hunks)package.json(1 hunks)scripts/check-project-structure.ts(1 hunks)scripts/functional-tests/api-endpoint-tester.ts(1 hunks)scripts/functional-tests/auth-test-runner.ts(1 hunks)scripts/functional-tests/auth-validator.ts(1 hunks)scripts/functional-tests/build-validator.ts(1 hunks)scripts/functional-tests/cloud-provider-test-runner.ts(1 hunks)scripts/functional-tests/cloud-provider-validator.ts(1 hunks)scripts/functional-tests/database-connection-tester.ts(1 hunks)scripts/functional-tests/dependency-cache.ts(1 hunks)scripts/functional-tests/dependency-installer-tester.ts(1 hunks)scripts/functional-tests/frontend-renderer-tester.ts(1 hunks)scripts/functional-tests/functional-test-runner.ts(1 hunks)scripts/functional-tests/html-test-runner.ts(1 hunks)scripts/functional-tests/html-validator.ts(1 hunks)scripts/functional-tests/htmx-test-runner.ts(1 hunks)scripts/functional-tests/htmx-validator.ts(1 hunks)scripts/functional-tests/mongodb-test-runner.ts(1 hunks)scripts/functional-tests/mongodb-validator.ts(1 hunks)scripts/functional-tests/mysql-test-runner.ts(1 hunks)scripts/functional-tests/mysql-validator.ts(1 hunks)scripts/functional-tests/postgresql-test-runner.ts(1 hunks)scripts/functional-tests/postgresql-validator.ts(1 hunks)scripts/functional-tests/react-test-runner.ts(1 hunks)scripts/functional-tests/react-validator.ts(1 hunks)scripts/functional-tests/server-startup-validator.ts(1 hunks)scripts/functional-tests/sqlite-test-runner.ts(1 hunks)scripts/functional-tests/sqlite-validator.ts(1 hunks)scripts/functional-tests/svelte-test-runner.ts(1 hunks)scripts/functional-tests/svelte-validator.ts(1 hunks)scripts/functional-tests/test-utils.ts(1 hunks)scripts/functional-tests/vue-test-runner.ts(1 hunks)scripts/functional-tests/vue-validator.ts(1 hunks)scripts/generate-test-matrix.ts(1 hunks)scripts/verify-test-matrix.ts(1 hunks)src/commands/formatProject.ts(1 hunks)src/generators/configurations/generatePackageJson.ts(2 hunks)src/generators/configurations/scaffoldConfigurationFiles.ts(1 hunks)src/generators/db/generateHandlers.ts(1 hunks)src/generators/db/handlerTemplates.ts(2 hunks)src/generators/project/generateDBBlock.ts(3 hunks)src/generators/project/generateImportsBlock.ts(2 hunks)src/generators/project/generateRoutesBlock.ts(4 hunks)src/generators/project/generateServer.ts(1 hunks)src/generators/project/generateUseBlock.ts(1 hunks)src/questions/directoryConfiguration.ts(1 hunks)src/questions/frontendDirectoryConfigurations.ts(3 hunks)src/templates/configurations/.prettierignore(1 hunks)src/templates/configurations/.prettierrc.json(0 hunks)src/templates/configurations/drizzle.config.ts(0 hunks)src/templates/configurations/eslint.config.mjs(2 hunks)src/templates/configurations/tsconfig.example.json(1 hunks)src/utils/parseCommandLineOptions.ts(3 hunks)
💤 Files with no reviewable changes (2)
- src/templates/configurations/.prettierrc.json
- src/templates/configurations/drizzle.config.ts
🧰 Additional context used
🧬 Code graph analysis (43)
src/generators/db/generateHandlers.ts (1)
src/questions/orm.ts (1)
databaseEngine(7-28)
src/generators/configurations/scaffoldConfigurationFiles.ts (2)
src/generators/vue/scaffoldVue.ts (1)
ScaffoldVueProps(8-27)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)
src/questions/frontendDirectoryConfigurations.ts (4)
src/data.ts (1)
frontendLabels(55-62)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)src/questions/configurationType.ts (1)
directoryConfig(5-16)src/prompt.ts (2)
frontend(34-34)argumentConfiguration(18-123)
scripts/functional-tests/mongodb-validator.ts (3)
src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)
scripts/functional-tests/frontend-renderer-tester.ts (5)
src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)src/generators/svelte/scaffoldSvelte.ts (1)
ScaffoldFrontendProps(6-33)src/generators/htmx/scaffoldHTMX.ts (1)
ScaffoldFrontendProps(8-46)src/generators/html/generateHTMLPage.ts (1)
frontends(4-75)src/generators/react/scaffoldReact.ts (1)
ScaffoldFrontendProps(7-35)
scripts/functional-tests/api-endpoint-tester.ts (2)
src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)src/generators/htmx/scaffoldHTMX.ts (1)
ScaffoldFrontendProps(8-46)
scripts/functional-tests/test-utils.ts (1)
src/generators/configurations/initializeRoot.ts (1)
projectName(4-44)
scripts/functional-tests/mongodb-test-runner.ts (5)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(24-120)scripts/functional-tests/mongodb-validator.ts (1)
validateMongoDBDatabase(22-170)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)
scripts/functional-tests/database-connection-tester.ts (7)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)src/generators/configurations/generateEnv.ts (1)
GenerateEnvProps(23-44)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/questions/orm.ts (1)
databaseEngine(7-28)
scripts/functional-tests/cloud-provider-validator.ts (5)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)
scripts/verify-test-matrix.ts (3)
src/types.ts (6)
DatabaseEngine(45-47)ORM(52-52)DatabaseHost(49-49)Frontend(21-21)AuthProvider(40-40)CodeQualityTool(53-53)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
scripts/functional-tests/html-validator.ts (3)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)src/generators/html/scaffoldHTML.ts (1)
ScaffoldHTMLProps(11-41)src/generators/html/generateHTMLPage.ts (1)
frontends(4-75)
scripts/functional-tests/sqlite-test-runner.ts (4)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(24-120)scripts/functional-tests/sqlite-validator.ts (1)
validateSQLiteDatabase(23-157)
scripts/check-project-structure.ts (1)
src/generators/configurations/initializeRoot.ts (1)
projectName(4-44)
scripts/functional-tests/functional-test-runner.ts (4)
scripts/check-project-structure.ts (1)
checkProjectStructure(17-48)scripts/functional-tests/dependency-installer-tester.ts (1)
testDependencyInstallation(18-105)scripts/functional-tests/build-validator.ts (1)
validateBuild(18-109)scripts/functional-tests/server-startup-validator.ts (1)
validateServerStartup(20-109)
scripts/functional-tests/svelte-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/svelte-validator.ts (1)
validateSvelteFramework(24-162)
scripts/functional-tests/svelte-validator.ts (4)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)src/generators/svelte/scaffoldSvelte.ts (1)
ScaffoldFrontendProps(6-33)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)src/generators/svelte/generateSveltePage.ts (1)
frontends(4-218)
scripts/functional-tests/mysql-validator.ts (4)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)
scripts/functional-tests/mysql-test-runner.ts (6)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(24-120)scripts/functional-tests/mysql-validator.ts (1)
validateMySQLDatabase(23-198)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)
scripts/functional-tests/react-validator.ts (3)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)src/generators/react/scaffoldReact.ts (1)
ScaffoldFrontendProps(7-35)src/templates/react/pages/ReactExample.tsx (1)
ReactExampleProps(7-18)
scripts/functional-tests/react-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/react-validator.ts (1)
validateReactFramework(24-140)
src/generators/db/handlerTemplates.ts (1)
src/questions/authProvider.ts (1)
authProvider(5-16)
src/generators/project/generateServer.ts (5)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateEnv.ts (1)
GenerateEnvProps(23-44)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)
src/utils/parseCommandLineOptions.ts (1)
src/prompt.ts (1)
argumentConfiguration(18-123)
scripts/functional-tests/build-validator.ts (2)
src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
scripts/functional-tests/vue-validator.ts (2)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)src/generators/vue/scaffoldVue.ts (1)
ScaffoldVueProps(8-27)
scripts/functional-tests/postgresql-test-runner.ts (4)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(24-120)scripts/functional-tests/postgresql-validator.ts (1)
validatePostgreSQLDatabase(23-198)
scripts/functional-tests/htmx-validator.ts (3)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)src/generators/htmx/scaffoldHTMX.ts (1)
ScaffoldFrontendProps(8-46)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)
scripts/functional-tests/auth-validator.ts (4)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)
scripts/functional-tests/htmx-test-runner.ts (5)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/htmx-validator.ts (1)
validateHTMXFramework(24-181)src/generators/htmx/scaffoldHTMX.ts (1)
ScaffoldFrontendProps(8-46)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)
src/generators/project/generateRoutesBlock.ts (2)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateEnv.ts (1)
GenerateEnvProps(23-44)
scripts/functional-tests/dependency-installer-tester.ts (2)
src/utils/commandMaps.ts (1)
installCommands(17-22)src/commands/installDependencies.ts (1)
packageManager(8-24)
src/questions/directoryConfiguration.ts (3)
src/prompt.ts (1)
argumentConfiguration(18-123)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)
scripts/generate-test-matrix.ts (6)
src/types.ts (6)
Frontend(21-21)DatabaseEngine(45-47)ORM(52-52)DatabaseHost(49-49)AuthProvider(40-40)CodeQualityTool(53-53)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateEnv.ts (1)
GenerateEnvProps(23-44)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)
scripts/functional-tests/sqlite-validator.ts (4)
src/utils/checkSqliteInstalled.ts (7)
hasSqlite(137-159)hasSqlite(112-117)commandExists(80-110)commandExists(119-135)$(34-35)$(27-32)cmd(21-25)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)
scripts/functional-tests/postgresql-validator.ts (5)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)
scripts/functional-tests/dependency-cache.ts (2)
src/generators/project/collectDependencies.ts (2)
dependency(39-39)CollectDependenciesProps(17-48)src/commands/installDependencies.ts (1)
packageManager(8-24)
src/generators/configurations/generatePackageJson.ts (3)
src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)
scripts/functional-tests/html-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/html-validator.ts (1)
validateHTMLFramework(24-187)
scripts/functional-tests/vue-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/vue-validator.ts (1)
validateVueFramework(24-160)
scripts/functional-tests/auth-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/auth-validator.ts (1)
validateAuthConfiguration(43-178)
scripts/functional-tests/cloud-provider-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/cloud-provider-validator.ts (1)
validateCloudProvider(26-230)
src/commands/formatProject.ts (1)
src/utils/commandMaps.ts (1)
formatCommands(3-8)
🔇 Additional comments (12)
src/templates/configurations/.prettierignore (1)
1-5: Looks good.Standard Prettier ignore patterns (dependencies, build artifacts, minified files) with proper trailing newline following POSIX convention. This template is ready for scaffolding.
src/commands/formatProject.ts (2)
19-23: LGTM: Early return guard prevents hanging in non-interactive mode.The guard correctly skips formatting when dependencies aren't installed, preventing the command from hanging on bunx/npx prettier calls during non-interactive test runs.
28-28: LGTM: Command selection simplified correctly.Since the early return ensures
installDependenciesNowis true at this point, always usingformatCommands[packageManager]is safe and removes unnecessary conditional logic.scripts/functional-tests/database-connection-tester.ts (3)
1-9: Good documentation of current limitations.The header clearly communicates that this is a placeholder implementation and outlines what's needed for full functionality.
14-62: Validation logic is appropriate for a placeholder.The function correctly validates the basic project structure (db directory, schema files) and clearly communicates its limitations through warnings. The early-return pattern keeps the code readable.
64-97: CLI interface is well-structured.The command-line interface properly validates inputs, provides clear usage instructions, and formats output in a user-friendly way with appropriate exit codes.
scripts/functional-tests/frontend-renderer-tester.ts (1)
1-16: Clear documentation and appropriate result type.The header comment clearly communicates the placeholder status and outlines the future requirements. The
FrontendRendererResulttype follows a standard pattern for test results.scripts/functional-tests/api-endpoint-tester.ts (2)
8-12: LGTM: Clean result type definition.The
APIEndpointResulttype follows standard conventions for test result reporting with clear boolean pass/fail status and separate arrays for errors and warnings.
44-72: LGTM: Well-structured CLI entry point.The CLI implementation properly handles argument parsing, validation, result reporting, and exit codes. Error handling is appropriate with both promise rejection and general error catching.
Minor note: The CLI currently doesn't expose the
configparameter (auth provider, frontends) to command-line users, which is fine for this placeholder implementation but may need extension when the actual testing logic is implemented.src/templates/configurations/tsconfig.example.json (2)
3-17: Modern, clean TypeScript configuration.The simplified compilerOptions are well-chosen for a modern web project: strict type checking enabled, modern target/module settings, and sensible defaults like
noUncheckedIndexedAccess. The configuration aligns with current TypeScript best practices.
10-10: No changes required—TypeScript version is compatible.The project specifies TypeScript 5.8.3 in peerDependencies, which fully supports the
"bundler"moduleResolution mode (available since TypeScript 5.0). The example configuration aligns with the roottsconfig.json, which also uses"bundler". No fallback or modification is necessary.src/generators/project/generateUseBlock.ts (1)
34-43: Remove misleading comments and consider template literal refactoring.Verification shows no actual template literal parsing issues exist:
useBlockis interpolated normally via${}ingenerateServer.ts- The generated string contains no backticks or special characters
- No
eval()orFunction()calls process this code- TypeScript compiles the output as standard source code
The string concatenation in lines 39-43 works but is less readable than template literals, which would work identically here. The comments citing "template literal nesting issues" and "parsing issues" describe a non-existent problem. Either remove the comments or refactor to use template literals:
return `.use(absoluteAuth${pluginGeneric}(${mergedConfig}))`;Likely an incorrect or invalid review comment.
| files: ['**/*.{js,mjs,cjs,ts,tsx,jsx,json}'], | ||
| rules: { | ||
| 'absolute/explicit-object-types': 'error', | ||
| 'absolute/localize-react-props': 'error', | ||
| 'absolute/max-depth-extended': ['error', 1], | ||
| 'absolute/max-jsxnesting': ['error', 5], | ||
| 'absolute/min-var-length': [ | ||
| 'error', | ||
| { allowedVars: ['_', 'id', 'db', 'OK'], minLength: 3 } | ||
| ], | ||
| 'absolute/no-button-navigation': 'error', | ||
| 'absolute/no-explicit-return-type': 'error', | ||
| 'absolute/no-inline-prop-types': 'error', | ||
| 'absolute/no-multi-style-objects': 'error', | ||
| 'absolute/no-nested-jsx-return': 'error', | ||
| 'absolute/no-or-none-component': 'error', | ||
| 'absolute/no-transition-cssproperties': 'error', | ||
| 'absolute/no-type-cast': 'error', | ||
| 'absolute/no-unnecessary-div': 'error', | ||
| 'absolute/no-unnecessary-key': 'error', | ||
| 'absolute/no-useless-function': 'error', | ||
| 'absolute/seperate-style-files': 'error', | ||
| 'absolute/sort-exports': [ | ||
| '@typescript-eslint/no-unused-vars': [ | ||
| 'error', | ||
| { | ||
| caseSensitive: true, | ||
| natural: true, | ||
| order: 'asc', | ||
| variablesBeforeFunctions: true | ||
| } | ||
| { argsIgnorePattern: '^_' } | ||
| ], | ||
| 'absolute/sort-keys-fixable': [ | ||
| 'error', | ||
| { | ||
| caseSensitive: true, | ||
| natural: true, | ||
| order: 'asc', | ||
| variablesBeforeFunctions: true | ||
| } | ||
| ], | ||
| 'arrow-body-style': ['error', 'as-needed'], | ||
| 'consistent-return': 'error', | ||
| eqeqeq: 'error', | ||
| 'func-style': [ | ||
| 'error', | ||
| 'expression', | ||
| { allowArrowFunctions: true } | ||
| ], | ||
| 'import/no-cycle': 'error', | ||
| 'import/no-default-export': 'error', | ||
| 'import/no-relative-packages': 'error', | ||
| 'import/no-unused-modules': ['error', { missingExports: true }], | ||
| 'import/order': ['error', { alphabetize: { order: 'asc' } }], | ||
| 'no-await-in-loop': 'error', | ||
| 'no-console': ['error', { allow: ['warn', 'error'] }], | ||
| 'no-debugger': 'error', | ||
| 'no-duplicate-case': 'error', | ||
| 'no-duplicate-imports': 'error', | ||
| 'no-else-return': 'error', | ||
| 'no-empty-function': 'error', | ||
| 'no-empty-pattern': 'error', | ||
| 'no-empty-static-block': 'error', | ||
| 'no-fallthrough': 'error', | ||
| 'no-floating-decimal': 'error', | ||
| 'no-global-assign': 'error', | ||
| 'no-implicit-coercion': 'error', | ||
| 'no-implicit-globals': 'error', | ||
| 'no-loop-func': 'error', | ||
| 'no-magic-numbers': [ | ||
| 'warn', | ||
| { detectObjects: false, enforceConst: true, ignore: [0, 1] } | ||
| ], | ||
| 'no-misleading-character-class': 'error', | ||
| 'no-nested-ternary': 'error', | ||
| 'no-new-native-nonconstructor': 'error', | ||
| 'no-new-wrappers': 'error', | ||
| 'no-param-reassign': 'error', | ||
| 'no-restricted-imports': [ | ||
| 'error', | ||
| { | ||
| paths: [ | ||
| { | ||
| importNames: ['default'], | ||
| message: | ||
| 'Import only named React exports for tree-shaking.', | ||
| name: 'react' | ||
| }, | ||
| { | ||
| importNames: ['default'], | ||
| message: 'Import only the required Bun exports.', | ||
| name: 'bun' | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| 'no-return-await': 'error', | ||
| 'no-shadow': 'error', | ||
| 'no-undef': 'error', | ||
| 'no-unneeded-ternary': 'error', | ||
| 'no-unreachable': 'error', | ||
| 'no-useless-assignment': 'error', | ||
| 'no-useless-concat': 'error', | ||
| 'no-useless-return': 'error', | ||
| 'no-var': 'error', | ||
| 'prefer-arrow-callback': 'error', | ||
| 'prefer-const': 'error', | ||
| 'prefer-destructuring': [ | ||
| 'error', | ||
| { array: true, object: true }, | ||
| { enforceForRenamedProperties: false } | ||
| ], | ||
| 'prefer-template': 'error', | ||
| 'promise/always-return': 'warn', | ||
| 'promise/avoid-new': 'warn', | ||
| 'promise/catch-or-return': 'error', | ||
| 'promise/no-callback-in-promise': 'warn', | ||
| 'promise/no-nesting': 'warn', | ||
| 'promise/no-promise-in-callback': 'warn', | ||
| 'promise/no-return-wrap': 'error', | ||
| 'promise/param-names': 'error' | ||
| } | ||
| }, | ||
| { | ||
| files: ['example/**/*.{js,jsx,ts,tsx}'], | ||
| plugins: { | ||
| 'jsx-a11y': jsxA11yPlugin, | ||
| react: reactPlugin, | ||
| 'react-compiler': reactCompilerPlugin, | ||
| 'react-hooks': reactHooksPlugin | ||
| }, | ||
| rules: { | ||
| 'jsx-a11y/prefer-tag-over-role': 'error', | ||
| 'react-compiler/react-compiler': 'error', | ||
| 'react-hooks/exhaustive-deps': 'warn', | ||
| 'react-hooks/rules-of-hooks': 'error', | ||
| 'react/checked-requires-onchange-or-readonly': 'error', | ||
| 'react/destructuring-assignment': ['error', 'always'], | ||
| 'react/jsx-filename-extension': ['error', { extensions: ['.tsx'] }], | ||
| 'react/jsx-no-leaked-render': 'error', | ||
| 'react/jsx-no-target-blank': 'error', | ||
| 'react/jsx-no-useless-fragment': 'error', | ||
| 'react/jsx-pascal-case': ['error', { allowAllCaps: true }], | ||
| 'react/no-multi-comp': 'error', | ||
| 'react/no-unknown-property': 'off', | ||
| 'react/react-in-jsx-scope': 'off', | ||
| 'react/self-closing-comp': 'error' | ||
| }, | ||
| settings: { | ||
| react: { version: 'detect' } | ||
| } | ||
| }, | ||
| { | ||
| files: [ | ||
| 'example/server.ts', | ||
| 'example/indexes/*.tsx', | ||
| 'example/db/migrate.ts' | ||
| ], | ||
| rules: { | ||
| 'import/no-unused-modules': 'off' | ||
| } | ||
| }, | ||
| { | ||
| files: ['example/db/migrate.ts', 'example/utils/absoluteAuthConfig.ts'], | ||
| rules: { | ||
| 'no-console': 'off' | ||
| } | ||
| }, | ||
| { | ||
| files: ['eslint.config.mjs'], | ||
| rules: { | ||
| 'no-magic-numbers': 'off' | ||
| } | ||
| }, | ||
| { | ||
| files: ['eslint.config.mjs'], | ||
| rules: { | ||
| 'import/no-default-export': 'off' | ||
| } | ||
| }, | ||
| { | ||
| files: ['example/db/schema.ts'], | ||
| rules: { | ||
| 'absolute/explicit-object-types': 'off' | ||
| 'no-console': 'warn', | ||
| 'prefer-const': 'error' | ||
| } |
There was a problem hiding this comment.
Drop .json from the rules glob or add a JSON parser
With the flat config, ESLint will run this rule set on *.json files using the default parser (espree). JSON syntax is invalid JavaScript, so every run will now fail with Parsing error: Unexpected token. Either remove .json from the files glob or wire up a JSON-capable parser (e.g. eslint-plugin-jsonc) before shipping this config.
🤖 Prompt for AI Agents
In src/templates/configurations/eslint.config.mjs around lines 35 to 43, the
config applies JS/TS rules to .json files which causes "Parsing error:
Unexpected token" with the default parser; either remove ".json" from the files
glob so ESLint won't run this rule set on JSON, or add a JSON-capable
parser/plugin and an override for JSON files (e.g., install and enable
eslint-plugin-jsonc or similar, register its processor/parser, and set an
override for files: ['**/*.json'] to use that parser and appropriate rules).
Ensure you choose one approach (remove .json from the glob OR wire up the json
parser and add an override) and update the config accordingly.
Summary after Testing Improvements
Testing
Pending: integrate the discovered local Postgres/MySQL/MongoDB template fixes in upcoming tasks. |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
scripts/functional-tests/server-startup-validator.ts (1)
69-76: Check fortypecheckscript existence before invoking it.Line 76 runs
${packageManager} run typecheckwithout verifying thatpackageJson.scripts?.typecheckexists. If the scaffold omits this script (many provide onlydevandbuild), the invocation will fail and incorrectly report the project as broken. Check for the script's presence and either skip with a warning or fall back totsc --noEmitif absent.Apply this diff to guard the typecheck invocation:
// Check 4: TypeScript compilation (most important functional check) if (!existsSync(tsconfigPath)) { warnings.push(`tsconfig.json not found - skipping compilation check`); + } else if (!packageJson.scripts?.typecheck) { + warnings.push(`No 'typecheck' script found - skipping compilation check`); } else { try { const startTime = Date.now();
🧹 Nitpick comments (8)
scripts/functional-tests/mysql-test-runner.ts (6)
44-52: Remove redundant cleanup operation.The
cleanupProjectDirectoryutility already performsrmSyncwithrecursive: trueandforce: true(as shown in test-utils.ts). The additionalrm -rfcommand is unnecessary.Apply this diff to streamline the cleanup:
- // Ensure cleanup before starting - cleanupProjectDirectory(projectPath); - - try { - const { $ } = await import('bun'); - await $`rm -rf ${projectPath}`.quiet().nothrow(); - } catch { - // Ignore cleanup errors - } + // Ensure cleanup before starting + cleanupProjectDirectory(projectPath);
107-108: Remove redundant import.The
$utility is already imported from 'bun' at line 48. This second import is unnecessary.Apply this diff:
- // Scaffold project - const { $ } = await import('bun'); - process.stdout.write(' → Scaffolding project... '); + // Scaffold project + process.stdout.write(' → Scaffolding project... ');
168-191: Consider extracting duplicate dependency fingerprint.The dependency fingerprint object is constructed twice (lines 168-176 and 179-189) with identical properties. Extracting this to a variable would reduce duplication and make the code more maintainable.
Apply this diff to extract the common fingerprint:
process.stdout.write(' → Installing dependencies... '); - const hasCache = hasCachedDependencies({ + const depFingerprint = { frontend: config.frontend, databaseEngine: config.databaseEngine, orm: config.orm, databaseHost: config.databaseHost, authProvider: config.authProvider, useTailwind: config.useTailwind, codeQualityTool: config.codeQualityTool - }); + }; + const hasCache = hasCachedDependencies(depFingerprint); try { - const { cached, installTime } = await getOrInstallDependencies( - projectPath, - { - frontend: config.frontend, - databaseEngine: config.databaseEngine, - orm: config.orm, - databaseHost: config.databaseHost, - authProvider: config.authProvider, - useTailwind: config.useTailwind, - codeQualityTool: config.codeQualityTool - }, - packageJsonPath - ); + const { cached, installTime } = await getOrInstallDependencies( + projectPath, + depFingerprint, + packageJsonPath + );
259-259: Verify the null-check logic for functionalTestResults.The variable
functionalTestResultsis declared at line 213 and will always be defined (though it may beundefinedif the try-catch assigns nothing). The condition!functionalTestResultsshould explicitly check forundefinedto clarify intent.Apply this diff:
- const passed = validationResult.passed && (!functionalTestResults || functionalTestResults.passed); + const passed = validationResult.passed && (functionalTestResults === undefined || functionalTestResults.passed);
288-292: Remove unused parameter.The
maxConcurrentparameter is defined but never used—tests run sequentially at line 312. Either implement concurrent execution or remove the parameter.Apply this diff to remove the unused parameter:
async function runMySQLTests( matrixFile: string = 'test-matrix.json', - maxConcurrent: number = 2, testSubset?: number ): Promise<void> {And update the CLI usage:
const matrixFile = process.argv[2] || 'test-matrix.json'; - const maxConcurrent = parseInt(process.argv[3] || '2', 10); - const testSubset = process.argv[4] ? parseInt(process.argv[4], 10) : undefined; + const testSubset = process.argv[3] ? parseInt(process.argv[3], 10) : undefined; - runMySQLTests(matrixFile, maxConcurrent, testSubset).catch((e) => { + runMySQLTests(matrixFile, testSubset).catch((e) => {
316-318: Extract project name generation to avoid duplication.The project name generation logic is duplicated from lines 40-42. Consider extracting this to a helper function to maintain consistency and reduce code duplication.
Add a helper function at the top of the file:
function getProjectName(config: TestMatrixEntry): string { return `test-mysql-${config.frontend}-${config.orm}-${config.authProvider === 'none' ? 'noauth' : 'auth'}-${config.databaseHost === 'none' ? 'local' : config.databaseHost}-${config.useTailwind ? 'tw' : 'notw'}`.replace(/[^a-z0-9-]/g, '-'); }Then use it at lines 41 and 317:
- const projectName = `test-mysql-${config.frontend}-${config.orm}-${config.authProvider === 'none' ? 'noauth' : 'auth'}-${config.databaseHost === 'none' ? 'local' : config.databaseHost}-${config.useTailwind ? 'tw' : 'notw'}`.replace(/[^a-z0-9-]/g, '-'); + const projectName = getProjectName(config);scripts/functional-tests/server-startup-validator.ts (1)
136-143: Consider an ESM-native entrypoint check.The file uses ESM imports but checks
require.main === module(CommonJS). While Bun likely supports this, an ESM-native approach would be more consistent. You can useimport.meta.urlcomparison or Bun's specific entrypoint detection if available.scripts/functional-tests/html-test-runner.ts (1)
293-318: Consider documenting or removing the unusedmaxConcurrentparameter.The
maxConcurrentparameter is defined and parsed from CLI args but never used to control concurrency. Tests always run sequentially (line 318). While the comment on line 317 acknowledges this, the parameter is misleading to callers.Either remove the parameter for now and add it back when implementing parallelization, or document it as reserved for future use:
async function runHTMLTests( matrixFile: string = 'test-matrix.json', - maxConcurrent: number = 2, + maxConcurrent: number = 2, // Reserved for future parallel execution testSubset?: number ): Promise<void> {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
scripts/check-project-structure.ts(1 hunks)scripts/functional-tests/api-endpoint-tester.ts(1 hunks)scripts/functional-tests/build-validator.ts(1 hunks)scripts/functional-tests/cloud-provider-test-runner.ts(1 hunks)scripts/functional-tests/cloud-provider-validator.ts(1 hunks)scripts/functional-tests/dependency-installer-tester.ts(1 hunks)scripts/functional-tests/html-test-runner.ts(1 hunks)scripts/functional-tests/htmx-validator.ts(1 hunks)scripts/functional-tests/mongodb-test-runner.ts(1 hunks)scripts/functional-tests/mysql-test-runner.ts(1 hunks)scripts/functional-tests/server-startup-validator.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- scripts/functional-tests/build-validator.ts
- scripts/functional-tests/mongodb-test-runner.ts
- scripts/functional-tests/api-endpoint-tester.ts
🧰 Additional context used
🧬 Code graph analysis (6)
scripts/functional-tests/dependency-installer-tester.ts (1)
src/utils/commandMaps.ts (1)
installCommands(17-22)
scripts/functional-tests/mysql-test-runner.ts (4)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(24-120)scripts/functional-tests/mysql-validator.ts (1)
validateMySQLDatabase(23-198)
scripts/functional-tests/cloud-provider-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/cloud-provider-validator.ts (1)
validateCloudProvider(26-231)
scripts/functional-tests/htmx-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)
scripts/functional-tests/cloud-provider-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(24-120)
scripts/functional-tests/html-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/html-validator.ts (1)
validateHTMLFramework(24-187)
🔇 Additional comments (4)
scripts/functional-tests/mysql-test-runner.ts (2)
1-31: LGTM! Clean setup and well-structured types.The imports and type definitions align with other test runners in the suite, maintaining consistency across the functional testing infrastructure.
362-372: Verify CLI entry point works in Bun/ESM context.The
require.main === modulepattern is CommonJS-specific, but this file uses ES module syntax (import statements). While Bun may support this pattern, you should verify that the CLI entry point is properly invoked when running the script directly.If this doesn't work, consider using an alternative ESM-compatible approach or ensure Bun's CommonJS compatibility is sufficient for your use case.
scripts/functional-tests/server-startup-validator.ts (1)
76-108: Timeout logic correctly kills the compiler process.The timeout mechanism now properly terminates the typecheck subprocess when the deadline expires (lines 82-85: SIGTERM → SIGKILL fallback) and clears the timeout when the process completes first (lines 97-100, 105-107). This addresses the past review concern about hung compilers clogging the test matrix.
scripts/check-project-structure.ts (1)
27-53: Good call on guarding the filesystem stat path.Wrapping both
statSynccalls in try/catch ensures the checker returns structured failures instead of crashing on IO issues. Solid hardening.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (7)
scripts/functional-tests/cloud-provider-test-runner.ts (5)
44-53: Remove redundant cleanup operations.The cleanup at line 45 (
cleanupProjectDirectory) already performs a recursive, forced removal usingrmSync. The subsequentrm -rfcommand (lines 48-53) and 100ms wait are redundant and suggest a workaround for a non-existent filesystem sync issue.Apply this diff to remove the redundancy:
// Ensure cleanup before starting cleanupProjectDirectory(projectPath); - try { - const { $ } = await import('bun'); - await $`rm -rf ${projectPath}`.quiet().nothrow(); - await new Promise(resolve => setTimeout(resolve, 100)); - } catch { - // Ignore cleanup errors - } - try {
262-266: Remove unnecessaryawaiton synchronous function.
cleanupProjectDirectoryis synchronous (returnsvoid), so theawaithas no effect.Apply this diff:
try { - await cleanupProjectDirectory(projectPath); + cleanupProjectDirectory(projectPath); } catch {
277-281: Remove unnecessaryawaiton synchronous function.Same issue as line 263 -
cleanupProjectDirectorydoesn't return a Promise.Apply this diff:
try { - await cleanupProjectDirectory(projectPath); + cleanupProjectDirectory(projectPath); } catch {
330-338: Remove redundant pre-cleanup in orchestrator.
scaffoldAndTestCloudProvideralready performs pre-cleanup at line 45, so this additional cleanup is redundant and adds unnecessary overhead to each test run.Apply this diff:
console.log(`[${i + 1}/${configsToTest.length}] Testing ${providerName} + ${config.databaseEngine} + ${config.orm} + ${config.authProvider === 'none' ? 'no auth' : 'auth'}...`); - // Cleanup any leftover directories before starting - const projectName = `test-cloud-${config.databaseHost}-${config.databaseEngine}-${config.orm}-${config.frontend}-${config.authProvider === 'none' ? 'noauth' : 'auth'}-${config.useTailwind ? 'tw' : 'notw'}`.replace(/[^a-z0-9-]/g, '-'); - try { - const { $ } = await import('bun'); - await $`rm -rf ${projectName}`.quiet().nothrow(); - await new Promise(resolve => setTimeout(resolve, 100)); - } catch { - // Ignore cleanup errors - } - const result = await scaffoldAndTestCloudProvider(config);
399-401: Use Bun-native module detection.
require.main === moduleis a CommonJS pattern that may not work reliably in Bun's ESM context.Apply this diff to use Bun's native detection:
// CLI usage -if (require.main === module) { +if (import.meta.main) { runCloudProviderTests().catch(console.error); }scripts/functional-tests/html-test-runner.ts (2)
262-267: Consider usingcleanupProjectDirectoryfor consistency.The code uses
cleanupProjectDirectoryat line 47 (pre-scaffold cleanup) but direct shellrm -rfcommands at lines 264 and 280 (post-test cleanup). UsingcleanupProjectDirectoryconsistently would improve maintainability and provides better error handling (existence checks, structured warnings).Apply this diff:
// Cleanup try { - await $`rm -rf ${projectPath}`.quiet(); + cleanupProjectDirectory(projectPath); } catch { // Ignore cleanup errors }// Cleanup on error try { - await $`rm -rf ${projectPath}`.quiet(); + cleanupProjectDirectory(projectPath); } catch { // Ignore cleanup errors }Also applies to: 279-283
294-298: Unused parameter:maxConcurrentis defined but not used.The
maxConcurrentparameter is defined at line 296 and parsed from CLI arguments at line 361, but is never used—the loop at line 319 runs sequentially. The comment indicates parallelization is planned, but until then the parameter serves no purpose and may confuse readers.Consider either:
- Removing the parameter until parallelization is implemented, or
- Adding a TODO comment explaining it's reserved for future parallel execution
async function runHTMLTests( matrixFile: string = 'test-matrix.json', - maxConcurrent: number = 2, testSubset?: number ): Promise<void> {if (require.main === module) { const matrixFile = process.argv[2] || 'test-matrix.json'; - const maxConcurrent = parseInt(process.argv[3] || '2', 10); - const testSubset = process.argv[4] ? parseInt(process.argv[4], 10) : undefined; + const testSubset = process.argv[3] ? parseInt(process.argv[3], 10) : undefined; - runHTMLTests(matrixFile, maxConcurrent, testSubset).catch((e) => { + runHTMLTests(matrixFile, testSubset).catch((e) => {Also applies to: 318-319
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
scripts/functional-tests/cloud-provider-test-runner.ts(1 hunks)scripts/functional-tests/html-test-runner.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
scripts/functional-tests/html-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/html-validator.ts (1)
validateHTMLFramework(24-187)
scripts/functional-tests/cloud-provider-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(7-19)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(53-59)getOrInstallDependencies(64-126)scripts/functional-tests/cloud-provider-validator.ts (1)
validateCloudProvider(26-231)
🔇 Additional comments (3)
scripts/functional-tests/cloud-provider-test-runner.ts (1)
105-183: LGTM - Scaffold execution properly fixed.The spawn implementation correctly addresses the previous issue by passing the executable and arguments separately (
spawn(cmd[0], cmd.slice(1))). Timeout handling and error propagation are properly implemented.scripts/functional-tests/html-test-runner.ts (2)
36-50: LGTM:$utility is correctly imported at function scope.The import at line 49 ensures
$is available for cleanup operations in both the try block (line 264) and catch block (line 280), addressing the scope concern raised in previous reviews.
104-150: LGTM: Scaffold execution properly usesspawn()with timeout.The use of
spawn(cmd[0], cmd.slice(1), ...)correctly passes the command and arguments separately, avoiding the array interpolation issue mentioned in previous reviews. Timeout and error handling are well-structured.
|
Note Docstrings generation - SUCCESS |
Docstrings generation was requested by @eugenegraves. * #4 (comment) The following files were modified: * `scripts/check-project-structure.ts` * `scripts/functional-tests/api-endpoint-tester.ts` * `scripts/functional-tests/auth-test-runner.ts` * `scripts/functional-tests/auth-validator.ts` * `scripts/functional-tests/build-validator.ts` * `scripts/functional-tests/cloud-provider-test-runner.ts` * `scripts/functional-tests/cloud-provider-validator.ts` * `scripts/functional-tests/database-connection-tester.ts` * `scripts/functional-tests/dependency-cache.ts` * `scripts/functional-tests/dependency-installer-tester.ts` * `scripts/functional-tests/frontend-renderer-tester.ts` * `scripts/functional-tests/functional-test-runner.ts` * `scripts/functional-tests/html-test-runner.ts` * `scripts/functional-tests/html-validator.ts` * `scripts/functional-tests/htmx-test-runner.ts` * `scripts/functional-tests/htmx-validator.ts` * `scripts/functional-tests/mongodb-test-runner.ts` * `scripts/functional-tests/mongodb-validator.ts` * `scripts/functional-tests/mysql-test-runner.ts` * `scripts/functional-tests/mysql-validator.ts` * `scripts/functional-tests/postgresql-test-runner.ts` * `scripts/functional-tests/postgresql-validator.ts` * `scripts/functional-tests/react-test-runner.ts` * `scripts/functional-tests/react-validator.ts` * `scripts/functional-tests/server-startup-validator.ts` * `scripts/functional-tests/sqlite-test-runner.ts` * `scripts/functional-tests/sqlite-validator.ts` * `scripts/functional-tests/svelte-test-runner.ts` * `scripts/functional-tests/svelte-validator.ts` * `scripts/functional-tests/test-utils.ts` * `scripts/functional-tests/vue-test-runner.ts` * `scripts/functional-tests/vue-validator.ts` * `scripts/generate-test-matrix.ts` * `scripts/verify-test-matrix.ts`
📝 Add docstrings to `test-suite`
There was a problem hiding this comment.
Actionable comments posted: 11
♻️ Duplicate comments (4)
scripts/functional-tests/postgresql-test-runner.ts (1)
116-125: Restore structured Bun command invocationPassing the
cmdarray straight into the tagged template coerces it tobun,run,src/index.ts,…, recreating the scaffold failure I flagged earlier. Use the object form so Bun receives discrete arguments.- const scaffoldPromise = $`${cmd}`.quiet().nothrow(); + const scaffoldPromise = $({ cmd }).quiet().nothrow();scripts/functional-tests/sqlite-validator.ts (1)
104-133: Stop short-circuitingconnectionWorkswhen the query returns nothing.Because
testQuery.includes('users')/'count_history'is always true, any zero-exitsqlite3call marks the connection (and subsequently the entire validator) as passing even when the table is absent. That recreates the false-positive highlighted earlier. Capture actual output instead.- if (result.exitCode === 0) { - const output = result.stdout?.toString() || ''; - if (output.trim() || testQuery.includes('users') || testQuery.includes('count_history')) { - sqliteSpecific.connectionWorks = true; + if (result.exitCode === 0) { + sqliteSpecific.connectionWorks = true; + const output = (result.stdout?.toString() ?? '').trim(); + if (output.length > 0) { // Try a more comprehensive query to verify tables existscripts/functional-tests/react-test-runner.ts (1)
99-145: Scaffold command never executes because${cmd}stringifies to commas.Interpolating the array directly (
$${cmd}``) rendersbun,run,src/index.ts,…, so Bun looks for a binary literally named `bun,run,src/index.ts` and the scaffold fails outright. Join/escape the arguments or switch to `$.spawn({ cmd })` so each token is passed separately.Minimal fix:
- const scaffoldPromise = $`${cmd}`.quiet().nothrow(); + const scaffoldCommand = cmd.join(' '); + const scaffoldPromise = $`${scaffoldCommand}`.quiet().nothrow();(Or adopt
$.spawnfor stronger quoting.)scripts/functional-tests/react-validator.ts (1)
67-88: Support both single- and multi-frontend React directories.Still hard-coding
src/frontend/*causes every multi-frontend scaffold (which places React undersrc/frontend/react) to fail this validator even when files exist. Check both candidate roots and only evaluate required files when a valid root is found.- const reactComponentsPath = join(projectPath, 'src', 'frontend', 'components'); - const reactPagesPath = join(projectPath, 'src', 'frontend', 'pages'); - const reactStylesPath = join(projectPath, 'src', 'frontend', 'styles'); - const reactAssetsPath = join(projectPath, 'src', 'backend', 'assets', 'svg', 'react.svg'); - - const requiredFiles = [ - join(reactComponentsPath, 'App.tsx'), - join(reactComponentsPath, 'Head.tsx'), - join(reactComponentsPath, 'Dropdown.tsx'), - join(reactPagesPath, 'ReactExample.tsx'), - join(reactStylesPath, 'react-example.css'), - reactAssetsPath - ]; - - const missingFiles = requiredFiles.filter((file) => !existsSync(file)); - - if (missingFiles.length > 0) { - errors.push(`Missing React files: ${missingFiles.join(', ')}`); - } else { - reactSpecific.filesExist = true; - } + const reactAssetsPath = join(projectPath, 'src', 'backend', 'assets', 'svg', 'react.svg'); + const candidateReactDirs = [ + join(projectPath, 'src', 'frontend', 'react'), + join(projectPath, 'src', 'frontend') + ]; + const reactRoot = candidateReactDirs.find((dir) => + ['components', 'pages', 'styles'].every((sub) => existsSync(join(dir, sub))) + ); + + if (!reactRoot) { + errors.push('React frontend directory not found (checked src/frontend/react and src/frontend)'); + } else { + const requiredFiles = [ + join(reactRoot, 'components', 'App.tsx'), + join(reactRoot, 'components', 'Head.tsx'), + join(reactRoot, 'components', 'Dropdown.tsx'), + join(reactRoot, 'pages', 'ReactExample.tsx'), + join(reactRoot, 'styles', 'react-example.css'), + reactAssetsPath + ]; + const missingFiles = requiredFiles.filter((file) => !existsSync(file)); + if (missingFiles.length > 0) { + errors.push(`Missing React files: ${missingFiles.join(', ')}`); + } else { + reactSpecific.filesExist = true; + } + }
🧹 Nitpick comments (7)
scripts/functional-tests/build-validator.ts (2)
16-22: Fix JSDoc comment formatting.The JSDoc comment for
validateBuildincorrectly starts on the same line as theCOMPILE_TIMEOUTconstant declaration. Move the JSDoc to a separate line above the function for clarity and to avoid confusing documentation parsers.Apply this diff:
-const COMPILE_TIMEOUT = 60000; /** +const COMPILE_TIMEOUT = 60000; + +/** * Validates that a scaffolded project compiles by checking for tsconfig.json, ensuring package.json has a `typecheck` script, and running that script. * * @param projectPath - Path to the project directory to validate * @param packageManager - Package manager to run the `typecheck` script with (`'bun' | 'npm' | 'pnpm' | 'yarn'`); defaults to `'bun'` * @returns A BuildResult where `passed` is `true` when compilation succeeds, `errors` contains failure messages when present, and `compileTime` (milliseconds) is included when a compilation attempt was performed */ - export async function validateBuild(
119-120: Validate package manager argument instead of casting toany.The
as anycast bypasses type safety. Consider validating thatprocess.argv[3]is one of the allowed package managers or falls back to'bun'.Apply this diff:
const projectPath = process.argv[2]; - const packageManager = (process.argv[3] as any) || 'bun'; + const allowedManagers = ['bun', 'npm', 'pnpm', 'yarn'] as const; + const packageManager = allowedManagers.includes(process.argv[3] as any) + ? (process.argv[3] as 'bun' | 'npm' | 'pnpm' | 'yarn') + : 'bun';scripts/functional-tests/database-connection-tester.ts (1)
11-11: Remove unused import.
readFileSyncis imported but never used in this file.Apply this diff to remove the unused import:
-import { existsSync, readFileSync } from 'fs'; +import { existsSync } from 'fs';scripts/functional-tests/mysql-validator.ts (4)
7-7: Remove unused import.
readFileSyncis imported but never used in this file.-import { existsSync, readFileSync } from 'fs'; +import { existsSync } from 'fs';
67-77: Add explicit validation for databaseHost values.The code only checks for
'none'/falsy and'planetscale', but doesn't validate against unexpected values. If an invalid host like'neon'or'turso'is passed, both conditions fail silently, potentially causing confusing validation failures later.Consider adding explicit validation at the start of the function:
// After line 59 const validHosts = ['none', 'planetscale', undefined]; if (config.databaseHost && !validHosts.includes(config.databaseHost)) { errors.push(`Invalid databaseHost for MySQL: ${config.databaseHost}. Expected 'none', 'planetscale', or undefined`); return { passed: false, errors, warnings, mysqlSpecific }; }
87-91: Clarify schema validation for non-ORM case.Setting
schemaFileExists = truewithout checking any file is misleading. For non-ORM MySQL, tables are created via Docker exec during scaffolding, so no persistent schema file exists. Consider either:
- Checking for evidence of successful table creation instead
- Renaming the field to
schemaReadyto better reflect what's being validated
115-115: Consider making timeout configurable.The fixed 2-second wait may be insufficient in slower environments (e.g., resource-constrained CI runners, cold container starts). While the subsequent polling loop (lines 120-127) provides additional resilience, the initial delay could be made configurable or adaptive.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (34)
scripts/check-project-structure.ts(1 hunks)scripts/functional-tests/api-endpoint-tester.ts(1 hunks)scripts/functional-tests/auth-test-runner.ts(1 hunks)scripts/functional-tests/auth-validator.ts(1 hunks)scripts/functional-tests/build-validator.ts(1 hunks)scripts/functional-tests/cloud-provider-test-runner.ts(1 hunks)scripts/functional-tests/cloud-provider-validator.ts(1 hunks)scripts/functional-tests/database-connection-tester.ts(1 hunks)scripts/functional-tests/dependency-cache.ts(1 hunks)scripts/functional-tests/dependency-installer-tester.ts(1 hunks)scripts/functional-tests/frontend-renderer-tester.ts(1 hunks)scripts/functional-tests/functional-test-runner.ts(1 hunks)scripts/functional-tests/html-test-runner.ts(1 hunks)scripts/functional-tests/html-validator.ts(1 hunks)scripts/functional-tests/htmx-test-runner.ts(1 hunks)scripts/functional-tests/htmx-validator.ts(1 hunks)scripts/functional-tests/mongodb-test-runner.ts(1 hunks)scripts/functional-tests/mongodb-validator.ts(1 hunks)scripts/functional-tests/mysql-test-runner.ts(1 hunks)scripts/functional-tests/mysql-validator.ts(1 hunks)scripts/functional-tests/postgresql-test-runner.ts(1 hunks)scripts/functional-tests/postgresql-validator.ts(1 hunks)scripts/functional-tests/react-test-runner.ts(1 hunks)scripts/functional-tests/react-validator.ts(1 hunks)scripts/functional-tests/server-startup-validator.ts(1 hunks)scripts/functional-tests/sqlite-test-runner.ts(1 hunks)scripts/functional-tests/sqlite-validator.ts(1 hunks)scripts/functional-tests/svelte-test-runner.ts(1 hunks)scripts/functional-tests/svelte-validator.ts(1 hunks)scripts/functional-tests/test-utils.ts(1 hunks)scripts/functional-tests/vue-test-runner.ts(1 hunks)scripts/functional-tests/vue-validator.ts(1 hunks)scripts/generate-test-matrix.ts(1 hunks)scripts/verify-test-matrix.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
- scripts/functional-tests/functional-test-runner.ts
- scripts/functional-tests/frontend-renderer-tester.ts
- scripts/functional-tests/api-endpoint-tester.ts
- scripts/generate-test-matrix.ts
- scripts/functional-tests/sqlite-test-runner.ts
- scripts/functional-tests/auth-test-runner.ts
- scripts/functional-tests/vue-test-runner.ts
- scripts/functional-tests/mongodb-test-runner.ts
- scripts/functional-tests/test-utils.ts
- scripts/verify-test-matrix.ts
🧰 Additional context used
🧬 Code graph analysis (24)
scripts/check-project-structure.ts (2)
src/generators/configurations/initializeRoot.ts (1)
projectName(4-44)src/generators/configurations/generatePackageJson.ts (1)
CreatePackageJsonProps(31-226)
scripts/functional-tests/sqlite-validator.ts (3)
src/utils/checkSqliteInstalled.ts (7)
hasSqlite(137-159)commandExists(80-110)hasSqlite(112-117)ensureSudo(37-49)commandExists(119-135)$(27-32)$(34-35)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)
scripts/functional-tests/dependency-installer-tester.ts (2)
src/utils/commandMaps.ts (1)
installCommands(17-22)src/commands/installDependencies.ts (1)
packageManager(8-24)
scripts/functional-tests/mysql-validator.ts (4)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)src/generators/configurations/generatePackageJson.ts (1)
CreatePackageJsonProps(31-226)
scripts/functional-tests/htmx-validator.ts (2)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(41-137)src/generators/htmx/scaffoldHTMX.ts (1)
ScaffoldFrontendProps(8-46)
scripts/functional-tests/htmx-test-runner.ts (5)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(11-23)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(61-67)getOrInstallDependencies(79-141)scripts/functional-tests/htmx-validator.ts (1)
validateHTMXFramework(33-190)src/generators/htmx/scaffoldHTMX.ts (1)
ScaffoldFrontendProps(8-46)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)
scripts/functional-tests/dependency-cache.ts (1)
src/commands/installDependencies.ts (1)
packageManager(8-24)
scripts/functional-tests/react-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(11-23)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(61-67)getOrInstallDependencies(79-141)scripts/functional-tests/react-validator.ts (1)
validateReactFramework(41-157)
scripts/functional-tests/mysql-test-runner.ts (7)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(11-23)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(61-67)getOrInstallDependencies(79-141)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(41-137)scripts/functional-tests/mysql-validator.ts (1)
validateMySQLDatabase(41-216)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)
scripts/functional-tests/cloud-provider-validator.ts (4)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(41-137)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)
scripts/functional-tests/html-validator.ts (5)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(41-137)src/generators/html/scaffoldHTML.ts (1)
ScaffoldHTMLProps(11-41)src/generators/htmx/scaffoldHTMX.ts (1)
ScaffoldFrontendProps(8-46)src/generators/html/generateHTMLPage.ts (1)
frontends(4-75)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)
scripts/functional-tests/build-validator.ts (2)
src/generators/configurations/scaffoldConfigurationFiles.ts (1)
AddConfigurationProps(22-77)src/generators/configurations/generatePackageJson.ts (1)
CreatePackageJsonProps(31-226)
scripts/functional-tests/postgresql-test-runner.ts (4)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(11-23)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(61-67)getOrInstallDependencies(79-141)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(41-137)scripts/functional-tests/postgresql-validator.ts (1)
validatePostgreSQLDatabase(33-208)
scripts/functional-tests/svelte-validator.ts (3)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(41-137)src/generators/svelte/scaffoldSvelte.ts (1)
ScaffoldFrontendProps(6-33)src/generators/svelte/generateSveltePage.ts (1)
frontends(4-218)
scripts/functional-tests/database-connection-tester.ts (5)
src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)src/generators/configurations/generateEnv.ts (1)
GenerateEnvProps(23-44)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)
scripts/functional-tests/html-test-runner.ts (5)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(11-23)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(61-67)getOrInstallDependencies(79-141)scripts/functional-tests/html-validator.ts (1)
validateHTMLFramework(43-206)src/generators/html/scaffoldHTML.ts (1)
ScaffoldHTMLProps(11-41)src/generators/html/generateHTMLPage.ts (1)
frontends(4-75)
scripts/functional-tests/cloud-provider-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(11-23)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(61-67)getOrInstallDependencies(79-141)scripts/functional-tests/cloud-provider-validator.ts (1)
validateCloudProvider(46-251)
scripts/functional-tests/postgresql-validator.ts (6)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)src/generators/project/generateDBBlock.ts (1)
GenerateDBBlockProps(54-103)src/generators/configurations/generatePackageJson.ts (1)
CreatePackageJsonProps(31-226)
scripts/functional-tests/svelte-test-runner.ts (3)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(11-23)scripts/functional-tests/dependency-cache.ts (2)
hasCachedDependencies(61-67)getOrInstallDependencies(79-141)scripts/functional-tests/svelte-validator.ts (1)
validateSvelteFramework(35-173)
scripts/functional-tests/react-validator.ts (3)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(41-137)src/generators/react/scaffoldReact.ts (1)
ScaffoldFrontendProps(7-35)src/templates/react/pages/ReactExample.tsx (1)
ReactExampleProps(7-18)
scripts/functional-tests/mongodb-validator.ts (3)
src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)
scripts/functional-tests/server-startup-validator.ts (3)
src/generators/project/generateServer.ts (1)
CreateServerFileProps(27-94)src/generators/configurations/scaffoldConfigurationFiles.ts (1)
AddConfigurationProps(22-77)src/generators/configurations/generatePackageJson.ts (1)
CreatePackageJsonProps(31-226)
scripts/functional-tests/vue-validator.ts (2)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(41-137)src/generators/vue/scaffoldVue.ts (1)
ScaffoldVueProps(8-27)
scripts/functional-tests/auth-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(11-22)runFunctionalTests(41-137)
🔇 Additional comments (12)
scripts/functional-tests/build-validator.ts (2)
24-56: LGTM on validation checks.The initial validation logic correctly checks for
tsconfig.json,package.json, and thetypecheckscript with appropriate error handling and early returns.
58-114: Compilation and timeout logic works correctly.The timeout is correctly handled via the catch block when
timeoutPromiserejects. The error extraction logic appropriately filters TypeScript errors and limits output. The type assertion on line 69 is slightly misleading (impliesresultcould be from timeout path) but functionally correct since timeout rejection jumps to the catch block.scripts/functional-tests/database-connection-tester.ts (2)
14-18: LGTM!The
DatabaseConnectionResulttype is well-structured and follows the pattern used by other validators in the test suite.
37-79: LGTM!The function implementation correctly performs basic filesystem checks, handles early returns appropriately, and accumulates warnings as documented. The placeholder nature is clearly communicated through inline comments and warnings.
scripts/functional-tests/mysql-validator.ts (7)
23-48: LGTM!The function signature and documentation are clear and comprehensive.
49-65: LGTM!Proper initialization and early validation with clear error handling.
136-170: LGTM!The query construction correctly handles auth vs. non-auth cases, and the table verification logic is thorough.
187-192: LGTM!The PlanetScale handling is appropriate—optimistically passing with clear warnings when live testing isn't feasible.
194-202: LGTM!Handler file validation correctly matches the scaffolding logic from
scaffoldDatabase.ts.
204-216: LGTM!The result computation correctly evaluates all checks and handles both local Docker and PlanetScale remote cases.
218-258: LGTM!The CLI interface is well-structured with clear usage messages, proper error handling, and readable output formatting.
scripts/functional-tests/dependency-installer-tester.ts (1)
16-28: Close the doc comment so TypeScript can parse the module.The
/**afterINSTALL_TIMEOUTnever terminates, so everything that follows is commented out and the file won’t compile. Please close the block before the JSDoc.-const INSTALL_TIMEOUT = 120000; /** +const INSTALL_TIMEOUT = 120000; + +/**Likely an incorrect or invalid review comment.
Summary
Testing
Structural Changes
Functional Fixes
All suites above were re-run after these changes, completing at 100%. |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/generators/db/scaffoldDocker.ts (1)
48-62: MongoDB initialization is completely skipped—critical issue.The condition on line 48 (
if (databaseEngine !== 'mongodb')) excludes MongoDB entirely from the initialization block. While PostgreSQL, MySQL, and MariaDB execute initialization commands (lines 53–61) that populateusersandcount_historycollections viauserTablesandcountHistoryTables, MongoDB gets no equivalent initialization.MongoDB is fundamentally designed for "create on first use", so if you do not insert data, then no database is created. Without the initialization commands that other engines receive, MongoDB will have empty or missing collections. This directly aligns with the PR objective noting "MongoDB: sandbox failures due to undefined users/count_history collections."
MongoDB initialization must be added. The
initTemplates[mongodb],userTables[mongodb], andcountHistoryTables[mongodb]are imported but never used. Either:
- Add MongoDB initialization logic in an
elseblock (lines 62+), or- Verify MongoDB initialization happens elsewhere and update logic accordingly.
♻️ Duplicate comments (6)
src/generators/configurations/generatePackageJson.ts (1)
229-230: Fix mongosh readiness loop authentication.The
db:mongoshreadiness check callsmongosh --evalwithout credentials, but the MongoDB container requires authentication (-u user -p password --authenticationDatabase admin database). The ping will fail with exit code 18, causing theuntilloop to hang indefinitely. Both the readiness probe and the interactive shell need credentials.Apply this diff to fix the authentication:
- scripts['db:mongosh'] = - "docker compose -p mongodb -f db/docker-compose.db.yml exec db bash -lc 'until mongosh --eval \"db.runCommand({ ping: 1 })\" --quiet; do sleep 1; done; exec mongosh'"; + scripts['db:mongosh'] = + "docker compose -p mongodb -f db/docker-compose.db.yml exec db bash -lc 'until mongosh -u user -p password --authenticationDatabase admin database --eval \"db.runCommand({ ping: 1 })\" --quiet; do sleep 1; done; exec mongosh -u user -p password --authenticationDatabase admin database'";scripts/functional-tests/server-startup-validator.ts (1)
92-155: Still runningtypecheckeven when the script isn't defined.We continue to spawn
${packageManager} run typecheckwithout first verifying the script exists. Several generated packages (for example the minimal HTML/HTMX scaffolds) only exposedevandbuild, so this exits with “Missing script: typecheck” and the validator reports a failure despite the server scaffold being fine. Please reuse the package.json probing logic so we skip or fall back when the script is absent instead of treating it as an error.scripts/functional-tests/htmx-test-runner.ts (1)
103-132: Timeout branch still fires after a successful scaffoldWe’re still racing the scaffold promise against an uncancellable
bun.sleep. When the scaffold finishes under the deadline, the race resolves immediately, butsleepkeeps running and eventually invokesonTimeout(), killing the already-finished process and throwing an unhandled rejection minutes later—the same dangling-timer problem from the earlier review. Please switch back to an explicitsetTimeoutthat you clear in afinallyblock so the timeout path can’t execute once the scaffold promise settles.-const raceWithTimeout = async <T>( - promise: Promise<T>, - timeoutMs: number, - onTimeout: () => void -) => { - const bunModule = await loadBunModule(); - const timeoutPromise = bunModule.sleep(timeoutMs).then(() => { - onTimeout(); - throw new Error('TIMEOUT'); - }); - - return Promise.race([promise, timeoutPromise]) as Promise<T>; -}; +const raceWithTimeout = async <T>( + promise: Promise<T>, + timeoutMs: number, + onTimeout: () => void +) => { + let timeoutId: ReturnType<typeof setTimeout> | undefined; + try { + return await Promise.race([ + promise, + new Promise<never>((_, reject) => { + timeoutId = setTimeout(() => { + try { + onTimeout(); + } finally { + reject(new Error('TIMEOUT')); + } + }, timeoutMs); + }) + ]); + } finally { + if (timeoutId !== undefined) { + clearTimeout(timeoutId); + } + } +};scripts/functional-tests/mysql-validator.ts (1)
105-160: Docker skips still report successWhen
bun db:upfails because Docker needs sudo/is absent,handleDockerUnavailablemarksconnectionWorks/queriesWorktrue andgetDockerStartErrorsreturns an empty list. The call at Line 208 therefore leaveserrorsempty, so the validator ends up reportingpassed: trueeven though no MySQL checks ran and the container never started. That’s the same false-positive scenario I called out earlier. Please fail (or require an explicit skip flag) rather than assuming success so CI can catch real MySQL regressions. Suggested fix:const handleDockerUnavailable = ( stderr: string, warnings: string[], mysqlSpecific: MySQLValidationResult['mysqlSpecific'] ) => { warnings.push( `Docker not available or requires sudo - skipping local MySQL connection test: ${stderr.slice(0, DOCKER_WARNING_SNIPPET_LENGTH)}` ); - mysqlSpecific.connectionWorks = true; - mysqlSpecific.queriesWork = true; + mysqlSpecific.connectionWorks = false; + mysqlSpecific.queriesWork = false; }; const getDockerStartErrors = ( stderr: string, warnings: string[], mysqlSpecific: MySQLValidationResult['mysqlSpecific'] ) => { const lowerStderr = stderr.toLowerCase(); const requiresDockerAccess = stderr.includes('sudo') || lowerStderr.includes('docker'); if (requiresDockerAccess) { - handleDockerUnavailable(stderr, warnings, mysqlSpecific); - - return []; + handleDockerUnavailable(stderr, warnings, mysqlSpecific); + + return [ + 'Docker not available or requires sudo - cannot execute local MySQL validation' + ]; }scripts/functional-tests/mongodb-validator.ts (1)
97-151: Remote Docker skip still yields a passIf
bun db:upfails because Docker needs sudo/is absent,handleDockerUnavailableflipsconnectionWorks/queriesWorkto true andgetDockerStartErrorsreturns an empty array. The early return at Line 209 then hands back no errors, so the top-level validator happily marks the run as passed even though no MongoDB checks ran. This keeps masking real regressions—the exact issue from the previous review. Please treat this as a failure (or gate it behind an explicit skip flag). For example:const handleDockerUnavailable = ( stderr: string, warnings: string[], mongodbSpecific: MongoDBValidationResult['mongodbSpecific'] ) => { warnings.push( `Docker not available or requires sudo - skipping local MongoDB connection test: ${stderr.slice(0, DOCKER_WARNING_SNIPPET_LENGTH)}` ); - mongodbSpecific.connectionWorks = true; - mongodbSpecific.queriesWork = true; + mongodbSpecific.connectionWorks = false; + mongodbSpecific.queriesWork = false; }; ... if (requiresDockerAccess) { - handleDockerUnavailable(stderr, warnings, mongodbSpecific); - - return []; + handleDockerUnavailable(stderr, warnings, mongodbSpecific); + + return [ + 'Docker not available or requires sudo - cannot execute local MongoDB validation' + ]; }scripts/functional-tests/react-validator.ts (1)
48-72: Handle multi-frontend React directoriesWhen
scaffoldFrontendsprovisions multiple frontends, React assets live undersrc/frontend/react/...instead ofsrc/frontend. Hard-coding the single-front paths makes every multi-front scaffold look broken even though the files exist, so the validator produces false failures. Please detect the React root first (e.g. probe bothsrc/frontend/reactandsrc/frontend) and only assert the file list inside the directory that actually exists; fall back to an error if neither is present. Reusing_config.isMultiFrontendor a helper similar to the HTMX validator would solve it.Apply this diff as a starting point:
-const REQUIRED_COMPONENT_FILES = [ - ['src', 'frontend', 'components', 'App.tsx'], - ['src', 'frontend', 'components', 'Head.tsx'], - ['src', 'frontend', 'components', 'Dropdown.tsx'], - ['src', 'frontend', 'pages', 'ReactExample.tsx'], - ['src', 'frontend', 'styles', 'react-example.css'], - ['src', 'backend', 'assets', 'svg', 'react.svg'] -]; +const REACT_DIRECTORY_CANDIDATES = ['src/frontend/react', 'src/frontend'] as const; +const REACT_REQUIRED_SUBPATHS = { + components: ['components', 'App.tsx', 'Head.tsx', 'Dropdown.tsx'], + pages: ['pages', 'ReactExample.tsx'], + styles: ['styles', 'react-example.css'] +}; + +const resolveReactDirectory = (projectPath: string) => + REACT_DIRECTORY_CANDIDATES.map((relative) => join(projectPath, relative)).find((candidate) => + existsSync(join(candidate, 'components')) + );Then join the resolved directory with the required subpaths before validating and keep the backend asset check separate.
🧹 Nitpick comments (6)
src/generators/db/scaffoldDocker.ts (2)
38-42: Add explanatory comment for test-specific behavior.The shared container logic is not immediately obvious without context. Consider adding a brief comment explaining that this optimization allows test runners to reuse containers across test permutations.
+ // In test mode, PostgreSQL/MySQL/MariaDB can share a single container + // across multiple test permutations to reduce overhead const useSharedContainer = process.env.ABSOLUTE_TEST === 'true' && (databaseEngine === 'postgresql' || databaseEngine === 'mysql' || databaseEngine === 'mariadb');
45-46: Consider error handling for file write operation.The
writeFileSynccall could fail ifprojectDatabaseDirectorydoesn't exist or has permission issues. While the directory may be created earlier in the call chain, adding error handling here would provide clearer feedback.- const composePath = join(projectDatabaseDirectory, 'docker-compose.db.yml'); - writeFileSync(composePath, dbContainer, 'utf-8'); + const composePath = join(projectDatabaseDirectory, 'docker-compose.db.yml'); + try { + writeFileSync(composePath, dbContainer, 'utf-8'); + } catch (error) { + throw new Error( + `Failed to write docker-compose file to ${composePath}: ${error instanceof Error ? error.message : String(error)}` + ); + }src/generators/project/generateDBBlock.ts (1)
96-101: Clarify the fallback logic in expression selection.The expression selection logic has fallbacks that may be confusing:
const isRemoteHost = hostKey !== 'none' && hostKey in remoteDrizzleInit; const expr = isRemoteHost ? (remoteDrizzleInit[hostKey] ?? engineGroup[hostKey]?.expr) : (engineGroup[hostKey]?.expr ?? remoteDrizzleInit[hostKey]);For remote hosts: Falls back from
remoteDrizzleInit[hostKey]→engineGroup[hostKey]?.expr
For local hosts: Falls back fromengineGroup[hostKey]?.expr→remoteDrizzleInit[hostKey]The local-host fallback to
remoteDrizzleInitseems unexpected. IfengineGroup[hostKey]?.expris undefined for a local host, falling back to a remote initialization expression could cause runtime issues.Consider simplifying without the fallback, or adding a guard:
const isRemoteHost = hostKey !== 'none' && hostKey in remoteDrizzleInit; -const expr = isRemoteHost - ? (remoteDrizzleInit[hostKey] ?? engineGroup[hostKey]?.expr) - : (engineGroup[hostKey]?.expr ?? remoteDrizzleInit[hostKey]); +const expr = isRemoteHost + ? remoteDrizzleInit[hostKey] + : engineGroup[hostKey]?.expr; if (!expr) return '';This relies on the existing
if (!expr)guard at Line 101 to catch missing configurations.src/generators/db/ensurePostgresSqlAdapter.ts (1)
40-66: Consider documenting the object serialization behavior.The
normaliseValuefunction JSON-stringifies all objects (Line 59), with a fallback toString(value)on error. This is a reasonable default, but developers might expect different behavior depending on the column type (e.g., JSONB vs TEXT vs custom types).Add a comment documenting this behavior:
if (typeof value === 'object') { + // Objects are JSON-stringified by default. Use explicit JSON.stringify() + // or custom type handlers for precise control over serialization. try { return JSON.stringify(value) } catch { return String(value) } }scripts/functional-tests/cloud-provider-test-runner.ts (2)
408-454: Consider renamingsortedResultsto avoid confusion.The variable
sortedResultscreates a deep copy of the results but performs no sorting, making the name misleading.If sorting isn't needed, consider either:
- Renaming to
processedResultsor simply usingresultsdirectly, or- Adding actual sorting if needed (e.g., by databaseHost or pass/fail status)
- const sortedResults = results.map((result) => ({ + const processedResults = results.map((result) => ({ config: {and update references accordingly. If the deep copy serves a specific purpose, a brief comment would clarify the intent.
491-540: LGTM with a minor inconsistency note.The main orchestration correctly loads, filters, executes, and summarizes tests with proper exit codes.
Consider using a consistent error display limit or documenting the distinction:
- Line 521: Inline errors limited to 2
- Line 450: Summary errors limited to
MAX_ERRORS_TO_DISPLAY(3)If the difference is intentional (inline brevity vs. summary detail), a brief comment would clarify. Otherwise, consider:
- console.log(` Errors: ${outcome.errors.slice(0, 2).join('; ')}`); + console.log(` Errors: ${outcome.errors.slice(0, MAX_ERRORS_TO_DISPLAY).join('; ')}`);or introduce a separate constant like
MAX_INLINE_ERRORS = 2.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (41)
package.json(1 hunks)scripts/functional-tests/api-endpoint-tester.ts(1 hunks)scripts/functional-tests/auth-test-runner.ts(1 hunks)scripts/functional-tests/auth-validator.ts(1 hunks)scripts/functional-tests/build-validator.ts(1 hunks)scripts/functional-tests/cloud-provider-test-runner.ts(1 hunks)scripts/functional-tests/cloud-provider-validator.ts(1 hunks)scripts/functional-tests/database-connection-tester.ts(1 hunks)scripts/functional-tests/dependency-cache.ts(1 hunks)scripts/functional-tests/dependency-installer-tester.ts(1 hunks)scripts/functional-tests/frontend-renderer-tester.ts(1 hunks)scripts/functional-tests/functional-test-runner.ts(1 hunks)scripts/functional-tests/html-test-runner.ts(1 hunks)scripts/functional-tests/htmx-test-runner.ts(1 hunks)scripts/functional-tests/htmx-validator.ts(1 hunks)scripts/functional-tests/matrix.ts(1 hunks)scripts/functional-tests/mongodb-test-runner.ts(1 hunks)scripts/functional-tests/mongodb-validator.ts(1 hunks)scripts/functional-tests/mysql-test-runner.ts(1 hunks)scripts/functional-tests/mysql-validator.ts(1 hunks)scripts/functional-tests/postgresql-test-runner.ts(1 hunks)scripts/functional-tests/postgresql-validator.ts(1 hunks)scripts/functional-tests/react-test-runner.ts(1 hunks)scripts/functional-tests/react-validator.ts(1 hunks)scripts/functional-tests/server-startup-validator.ts(1 hunks)scripts/functional-tests/sqlite-test-runner.ts(1 hunks)scripts/functional-tests/sqlite-validator.ts(1 hunks)scripts/functional-tests/svelte-test-runner.ts(1 hunks)scripts/functional-tests/svelte-validator.ts(1 hunks)scripts/functional-tests/test-cli.ts(1 hunks)scripts/functional-tests/test-utils.ts(1 hunks)scripts/functional-tests/vue-validator.ts(1 hunks)src/generators/configurations/generatePackageJson.ts(3 hunks)src/generators/db/ensurePostgresSqlAdapter.ts(1 hunks)src/generators/db/generateDrizzleSchema.ts(1 hunks)src/generators/db/handlerTemplates.ts(6 hunks)src/generators/db/scaffoldDocker.ts(2 hunks)src/generators/project/generateDBBlock.ts(3 hunks)src/generators/project/generateImportsBlock.ts(2 hunks)src/generators/project/generateServer.ts(3 hunks)tsconfig.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- scripts/functional-tests/database-connection-tester.ts
- src/generators/db/handlerTemplates.ts
- scripts/functional-tests/sqlite-test-runner.ts
- scripts/functional-tests/svelte-test-runner.ts
- scripts/functional-tests/mysql-test-runner.ts
- package.json
🧰 Additional context used
🧬 Code graph analysis (29)
tsconfig.json (1)
src/generators/configurations/scaffoldConfigurationFiles.ts (1)
AddConfigurationProps(22-77)
src/generators/project/generateServer.ts (1)
src/generators/db/ensurePostgresSqlAdapter.ts (1)
ensurePostgresSqlAdapter(98-104)
src/generators/db/generateDrizzleSchema.ts (2)
src/questions/databaseHost.ts (1)
databaseEngine(6-35)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
src/generators/db/scaffoldDocker.ts (1)
src/generators/db/generateDockerContainer.ts (1)
generateDockerContainer(84-114)
scripts/functional-tests/svelte-validator.ts (4)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)src/generators/svelte/scaffoldSvelte.ts (1)
ScaffoldFrontendProps(6-33)src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)src/generators/svelte/generateSveltePage.ts (1)
frontends(4-218)
scripts/functional-tests/test-cli.ts (2)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (1)
cleanupCache(282-313)
scripts/functional-tests/auth-validator.ts (2)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
scripts/functional-tests/react-test-runner.ts (4)
scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)scripts/functional-tests/react-validator.ts (1)
validateReactFramework(210-249)scripts/functional-tests/matrix.ts (1)
createMatrix(82-93)
scripts/functional-tests/build-validator.ts (1)
src/generators/configurations/scaffoldConfigurationFiles.ts (1)
AddConfigurationProps(22-77)
src/generators/db/ensurePostgresSqlAdapter.ts (1)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
src/generators/project/generateDBBlock.ts (3)
src/questions/databaseHost.ts (1)
databaseEngine(6-35)src/generators/configurations/generateEnv.ts (1)
GenerateEnvProps(23-44)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
scripts/functional-tests/dependency-installer-tester.ts (1)
src/commands/installDependencies.ts (1)
packageManager(8-24)
scripts/functional-tests/server-startup-validator.ts (1)
src/generators/configurations/scaffoldConfigurationFiles.ts (1)
AddConfigurationProps(22-77)
scripts/functional-tests/dependency-cache.ts (1)
src/commands/installDependencies.ts (1)
installDependencies(8-24)
scripts/functional-tests/vue-validator.ts (2)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)src/generators/vue/scaffoldVue.ts (1)
ScaffoldVueProps(8-27)
scripts/functional-tests/mysql-validator.ts (4)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)src/utils/parseCommandLineOptions.ts (1)
parseArgs(32-332)
scripts/functional-tests/cloud-provider-test-runner.ts (4)
scripts/functional-tests/matrix.ts (2)
MatrixConfig(33-42)createMatrix(82-93)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)scripts/functional-tests/cloud-provider-validator.ts (1)
validateCloudProvider(247-320)
scripts/functional-tests/htmx-test-runner.ts (4)
scripts/functional-tests/matrix.ts (2)
MatrixConfig(33-42)createMatrix(82-93)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)scripts/functional-tests/htmx-validator.ts (1)
validateHTMXFramework(230-269)
scripts/functional-tests/sqlite-validator.ts (2)
src/utils/checkSqliteInstalled.ts (8)
hasSqlite(137-159)commandExists(80-110)ensureSudo(37-49)commandExists(119-135)hasSqlite(112-117)cmd(21-25)$(34-35)$(27-32)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
scripts/functional-tests/postgresql-validator.ts (2)
src/generators/db/dockerInitTemplates.ts (3)
initTemplates(111-140)userTables(91-99)countHistoryTables(101-109)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
scripts/functional-tests/mongodb-validator.ts (2)
src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/generateDockerContainer.ts (1)
databaseEngine(84-114)
scripts/functional-tests/functional-test-runner.ts (3)
scripts/functional-tests/dependency-installer-tester.ts (1)
testDependencyInstallation(117-163)scripts/functional-tests/build-validator.ts (1)
validateBuild(107-158)scripts/functional-tests/server-startup-validator.ts (1)
validateServerStartup(157-198)
scripts/functional-tests/html-test-runner.ts (3)
scripts/functional-tests/matrix.ts (2)
MatrixConfig(33-42)createMatrix(82-93)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)
scripts/functional-tests/cloud-provider-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)
scripts/functional-tests/mongodb-test-runner.ts (5)
scripts/functional-tests/matrix.ts (2)
MatrixConfig(33-42)createMatrix(82-93)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(116-170)scripts/functional-tests/mongodb-validator.ts (1)
validateMongoDBDatabase(262-334)
scripts/functional-tests/auth-test-runner.ts (4)
scripts/functional-tests/matrix.ts (2)
MatrixConfig(33-42)createMatrix(82-93)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)scripts/functional-tests/auth-validator.ts (1)
validateAuthConfiguration(222-290)
scripts/functional-tests/react-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)
scripts/functional-tests/htmx-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)
scripts/functional-tests/postgresql-test-runner.ts (5)
scripts/functional-tests/matrix.ts (2)
MatrixConfig(33-42)createMatrix(82-93)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(116-170)scripts/functional-tests/postgresql-validator.ts (3)
validatePostgreSQLDatabase(398-482)isPostgresDockerManaged(288-288)stopManagedPostgresDocker(284-286)
🔇 Additional comments (26)
src/generators/configurations/generatePackageJson.ts (2)
169-170: LGTM!The PostgreSQL native driver and types are correctly added only for local Docker setups, aligning with the pattern where cloud providers (Neon) use their own packages.
189-191: MongoDB dependency pattern is consistent with MySQL.The
mongodbpackage is added unconditionally, matching themysql2pattern (line 186). This works for the current implementation since no cloud MongoDB provider is configured in thedatabaseHostswitch. When cloud MongoDB support is added, verify whether it uses the nativemongodbpackage or requires a provider-specific package like Neon/PlanetScale.src/generators/db/scaffoldDocker.ts (1)
2-2: LGTM: Modern import syntax.Using the
node:prefix for built-in modules is a best practice.src/generators/project/generateImportsBlock.ts (3)
82-91: LGTM! Dynamic Neon import selection is well-designed.The
getNeonImport()helper correctly handles the different import requirements:
- Drizzle ORM needs
Poolfrom@neondatabase/serverlessfor connection pooling- Non-Drizzle scenarios use the
neonserverless functionThis centralizes the logic and makes the connector imports maintainable.
169-174: LGTM! MongoDB import path is now explicit and correct.The refactored MongoDB path clearly imports
MongoClientandgetEnv, removing the previous conditional complexity. This aligns with the MongoDB connection handling added ingenerateDBBlock.ts.
153-167: Verification confirmed: adapter creation is guaranteed before import generation.The conditions in
generateServer.ts:47(whereensurePostgresSqlAdapteris called) andgenerateImportsBlock.ts:153-167(where the import is generated) are perfectly aligned. Both requiredatabaseEngine === 'postgresql', no ORM, and local host (not remote). SincegenerateImportsBlockis only called fromgenerateServerFileimmediately after the adapter is created, all codepaths that generate this import also ensure the adapter file exists.src/generators/project/generateServer.ts (2)
42-48: LGTM! Adapter scaffolding is properly gated.The conditions correctly identify when the PostgreSQL adapter is needed:
- PostgreSQL database engine
- No ORM (undefined or 'none')
- Local host (undefined or 'none')
This ensures
createPgSql.tsis available beforegenerateImportsBlocktries to import it at Line 162.
85-86: LGTM! PassingdatabaseEngineto route generation.This change enables route generation logic to adapt based on the database engine, which is necessary for the expanded test coverage across different database configurations mentioned in the PR objectives.
src/generators/project/generateDBBlock.ts (3)
17-17: Good fix! Removed syntax error in MongoDB connection string.The extra closing brace
}has been correctly removed from the MongoDBnoneexpression.
28-28: LGTM! Neon expression updated for non-Drizzle usage.Changed from
new Pool({ connectionString: getEnv("DATABASE_URL") })toneon(getEnv("DATABASE_URL")). This is correct for non-Drizzle + Neon scenarios where you use the serverlessneon()function instead of a connection pool.
73-91: LGTM! Special handling for MongoDB and PostgreSQL is correct.The non-Drizzle paths now have engine-specific initialization:
- MongoDB (lines 74-80): Creates client, connects, and gets database handle - necessary for MongoDB's connection model
- PostgreSQL + local (lines 82-87): Creates pool and wraps it with
createPgSqladapter - aligns with the scaffolded adapter- Fallback (lines 89-91): Generic
const db = ${expr}for other enginesThis handles the connection lifecycle differences across database engines correctly.
src/generators/db/ensurePostgresSqlAdapter.ts (3)
21-38: LGTM! Standard PostgreSQL parameterization.The
buildQueryfunction correctly constructs parameterized queries by:
- Interleaving template string parts
- Replacing parameters with
$1,$2, etc. placeholders- Accumulating parameter values
This follows PostgreSQL's parameterized query conventions.
73-95: LGTM! Clean template literal API with raw query support.The
createPgSqlfunction provides:
- Template literal interface:
sql<T>\SELECT * FROM users WHERE id = ${id}``- Raw query method:
sql.query<T>(text, params)- Cleanup:
sql.end()terminates the poolThe type safety with
QueryResultRowgenerics is well-designed.
98-104: LGTM! Adapter scaffolding is straightforward.The
ensurePostgresSqlAdapterfunction creates the necessary directory structure and writes the adapter file tobackend/database/createPgSql.ts. This integrates cleanly with the import added ingenerateImportsBlock.tsat Line 162.scripts/functional-tests/cloud-provider-test-runner.ts (12)
1-46: LGTM! Clean imports and well-structured types.The type definitions properly model the test execution flow, and the dependency configuration structure correctly matches the cache fingerprinting requirements.
47-56: LGTM! Constants properly scope the test matrix.The supported sets correctly limit testing to stable combinations (Neon/Turso with SQLite/PostgreSQL), aligning with the PR's approach to exclude failing MySQL/MongoDB and PlanetScale configurations.
57-65: LGTM! Efficient module caching pattern.Lazy-loading the Bun module with caching avoids repeated dynamic imports across multiple test executions.
67-117: LGTM! Deterministic command construction.The helper functions correctly build scaffold commands with appropriate flags for each configuration. Project naming ensures valid, predictable identifiers.
119-162: LGTM! Robust command execution with timeout handling.The command spawning correctly uses the cmd array format, and the timeout mechanism properly kills hung processes. Previous command interpolation issues have been addressed.
164-212: LGTM! Clean scaffolding orchestration.Pre-run cleanup, timeout handling, and exit code validation are properly implemented with clear user feedback.
214-267: LGTM! Proper dependency cache integration.The dependency installation correctly leverages the cache mechanism, with proper error handling and timing feedback.
269-303: LGTM! Correct validation integration.The validation correctly skips dependency installation (already performed) while running build and server checks, properly propagating errors and warnings.
305-379: LGTM! Comprehensive test orchestration.The pipeline properly sequences scaffolding, dependency installation, and validation with appropriate early exits and guaranteed cleanup in all paths.
381-392: LGTM! Matrix filtering aligns with supported configurations.The filter correctly limits testing to stable cloud provider combinations and default directory configurations.
394-406: LGTM! Standard sequential execution pattern.The reduce-based sequential runner correctly chains test executions and accumulates results.
456-489: LGTM! Backward-compatible argument parsing.The parser gracefully handles legacy two-argument format while supporting the new single-argument subset parameter, with appropriate warnings.
| const LOCK_FILES = ['bun.lockb', 'package-lock.json']; | ||
| const MINUTES_PER_INSTALL_TIMEOUT = 5; | ||
| const SECONDS_PER_MINUTE = 60; | ||
| const MILLISECONDS_PER_SECOND = 1_000; | ||
| const INSTALL_TIMEOUT_MS = MINUTES_PER_INSTALL_TIMEOUT * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND; | ||
| const DEFAULT_CACHE_MAX_AGE_DAYS = 7; | ||
| const HOURS_PER_DAY = 24; | ||
| const MINUTES_PER_HOUR = 60; | ||
| const FORCE_KILL_DELAY_MS = 100; | ||
|
|
||
| const createFingerprintKey = (config: DependencyFingerprint, manifestHash: string) => | ||
| JSON.stringify({ | ||
| authProvider: config.authProvider, | ||
| codeQualityTool: config.codeQualityTool ?? 'none', | ||
| databaseEngine: config.databaseEngine, | ||
| databaseHost: config.databaseHost, | ||
| frontend: config.frontend, | ||
| manifestHash, | ||
| orm: config.orm, | ||
| useTailwind: config.useTailwind | ||
| }); | ||
|
|
||
| const FINGERPRINT_LENGTH = 16; | ||
|
|
||
| const getDependencyFingerprint = (config: DependencyFingerprint, manifestHash: string) => | ||
| createHash('sha256') | ||
| .update(createFingerprintKey(config, manifestHash)) | ||
| .digest('hex') | ||
| .slice(0, FINGERPRINT_LENGTH); | ||
|
|
||
| const getCachePath = (fingerprint: string) => join(CACHE_DIR, fingerprint); | ||
|
|
||
| const safeRead = (path: string) => { | ||
| try { | ||
| return readFileSync(path); | ||
| } catch { | ||
| return null; | ||
| } | ||
| }; | ||
|
|
||
| const ensureCacheDir = () => { | ||
| if (!existsSync(CACHE_DIR)) { | ||
| mkdirSync(CACHE_DIR, { recursive: true }); | ||
| } | ||
| }; | ||
|
|
||
| export const computeManifestHash = (packageJsonPath: string) => { | ||
| if (!existsSync(packageJsonPath)) { | ||
| return 'missing'; | ||
| } | ||
|
|
||
| const hash = createHash('sha256'); | ||
| const packageJsonContents = safeRead(packageJsonPath); | ||
|
|
||
| if (!packageJsonContents) { | ||
| return 'error:package-json-unreadable'; | ||
| } | ||
|
|
||
| hash.update(packageJsonContents); | ||
|
|
||
| const packageDir = dirname(packageJsonPath); | ||
|
|
||
| LOCK_FILES.forEach((lockFile) => { | ||
| const lockPath = join(packageDir, lockFile); | ||
| const contents = safeRead(lockPath); | ||
|
|
||
| if (contents) { | ||
| hash.update(contents); | ||
| } | ||
| }); | ||
|
|
||
| return hash.digest('hex'); |
There was a problem hiding this comment.
Include pnpm/yarn lockfiles in the cache key
The manifest hash (and therefore the cache fingerprint) ignores pnpm-lock.yaml and yarn.lock. Any matrix run using pnpm or yarn can update its lockfile without ever invalidating the cached node_modules, leading to stale dependency trees and spurious build/runtime failures. Please add both lockfiles to LOCK_FILES (and copy them alongside package.json) so cache hits stay valid.
-const LOCK_FILES = ['bun.lockb', 'package-lock.json'];
+const LOCK_FILES = ['bun.lockb', 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock'];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const LOCK_FILES = ['bun.lockb', 'package-lock.json']; | |
| const MINUTES_PER_INSTALL_TIMEOUT = 5; | |
| const SECONDS_PER_MINUTE = 60; | |
| const MILLISECONDS_PER_SECOND = 1_000; | |
| const INSTALL_TIMEOUT_MS = MINUTES_PER_INSTALL_TIMEOUT * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND; | |
| const DEFAULT_CACHE_MAX_AGE_DAYS = 7; | |
| const HOURS_PER_DAY = 24; | |
| const MINUTES_PER_HOUR = 60; | |
| const FORCE_KILL_DELAY_MS = 100; | |
| const createFingerprintKey = (config: DependencyFingerprint, manifestHash: string) => | |
| JSON.stringify({ | |
| authProvider: config.authProvider, | |
| codeQualityTool: config.codeQualityTool ?? 'none', | |
| databaseEngine: config.databaseEngine, | |
| databaseHost: config.databaseHost, | |
| frontend: config.frontend, | |
| manifestHash, | |
| orm: config.orm, | |
| useTailwind: config.useTailwind | |
| }); | |
| const FINGERPRINT_LENGTH = 16; | |
| const getDependencyFingerprint = (config: DependencyFingerprint, manifestHash: string) => | |
| createHash('sha256') | |
| .update(createFingerprintKey(config, manifestHash)) | |
| .digest('hex') | |
| .slice(0, FINGERPRINT_LENGTH); | |
| const getCachePath = (fingerprint: string) => join(CACHE_DIR, fingerprint); | |
| const safeRead = (path: string) => { | |
| try { | |
| return readFileSync(path); | |
| } catch { | |
| return null; | |
| } | |
| }; | |
| const ensureCacheDir = () => { | |
| if (!existsSync(CACHE_DIR)) { | |
| mkdirSync(CACHE_DIR, { recursive: true }); | |
| } | |
| }; | |
| export const computeManifestHash = (packageJsonPath: string) => { | |
| if (!existsSync(packageJsonPath)) { | |
| return 'missing'; | |
| } | |
| const hash = createHash('sha256'); | |
| const packageJsonContents = safeRead(packageJsonPath); | |
| if (!packageJsonContents) { | |
| return 'error:package-json-unreadable'; | |
| } | |
| hash.update(packageJsonContents); | |
| const packageDir = dirname(packageJsonPath); | |
| LOCK_FILES.forEach((lockFile) => { | |
| const lockPath = join(packageDir, lockFile); | |
| const contents = safeRead(lockPath); | |
| if (contents) { | |
| hash.update(contents); | |
| } | |
| }); | |
| return hash.digest('hex'); | |
| const LOCK_FILES = ['bun.lockb', 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock']; | |
| const MINUTES_PER_INSTALL_TIMEOUT = 5; | |
| const SECONDS_PER_MINUTE = 60; | |
| const MILLISECONDS_PER_SECOND = 1_000; | |
| const INSTALL_TIMEOUT_MS = MINUTES_PER_INSTALL_TIMEOUT * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND; | |
| const DEFAULT_CACHE_MAX_AGE_DAYS = 7; | |
| const HOURS_PER_DAY = 24; | |
| const MINUTES_PER_HOUR = 60; | |
| const FORCE_KILL_DELAY_MS = 100; | |
| const createFingerprintKey = (config: DependencyFingerprint, manifestHash: string) => | |
| JSON.stringify({ | |
| authProvider: config.authProvider, | |
| codeQualityTool: config.codeQualityTool ?? 'none', | |
| databaseEngine: config.databaseEngine, | |
| databaseHost: config.databaseHost, | |
| frontend: config.frontend, | |
| manifestHash, | |
| orm: config.orm, | |
| useTailwind: config.useTailwind | |
| }); | |
| const FINGERPRINT_LENGTH = 16; | |
| const getDependencyFingerprint = (config: DependencyFingerprint, manifestHash: string) => | |
| createHash('sha256') | |
| .update(createFingerprintKey(config, manifestHash)) | |
| .digest('hex') | |
| .slice(0, FINGERPRINT_LENGTH); | |
| const getCachePath = (fingerprint: string) => join(CACHE_DIR, fingerprint); | |
| const safeRead = (path: string) => { | |
| try { | |
| return readFileSync(path); | |
| } catch { | |
| return null; | |
| } | |
| }; | |
| const ensureCacheDir = () => { | |
| if (!existsSync(CACHE_DIR)) { | |
| mkdirSync(CACHE_DIR, { recursive: true }); | |
| } | |
| }; | |
| export const computeManifestHash = (packageJsonPath: string) => { | |
| if (!existsSync(packageJsonPath)) { | |
| return 'missing'; | |
| } | |
| const hash = createHash('sha256'); | |
| const packageJsonContents = safeRead(packageJsonPath); | |
| if (!packageJsonContents) { | |
| return 'error:package-json-unreadable'; | |
| } | |
| hash.update(packageJsonContents); | |
| const packageDir = dirname(packageJsonPath); | |
| LOCK_FILES.forEach((lockFile) => { | |
| const lockPath = join(packageDir, lockFile); | |
| const contents = safeRead(lockPath); | |
| if (contents) { | |
| hash.update(contents); | |
| } | |
| }); | |
| return hash.digest('hex'); |
🤖 Prompt for AI Agents
In scripts/functional-tests/dependency-cache.ts around lines 34 to 105, the
manifest hash currently ignores pnpm and yarn lockfiles; add 'pnpm-lock.yaml'
and 'yarn.lock' to the LOCK_FILES array so computeManifestHash incorporates
them, and update any cache copy logic that copies package.json to also copy
these lockfiles from the package directory when present to ensure cache
invalidation on lockfile changes.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (8)
scripts/functional-tests/htmx-test-runner.ts (2)
211-227: Consider removing the redundant cache check.The
hasCachedDependenciescall on lines 211-215 duplicates the cache-hit logic already performed insidegetOrInstallDependencies(which callsrestoreCacheinternally). The returnedcachedflag is sufficient for the console message.Apply this diff to simplify the logic:
process.stdout.write(' → Installing dependencies... '); const manifestHash = computeManifestHash(packageJsonPath); const dependencyConfig: DependencyConfig = { authProvider: config.authProvider, codeQualityTool: config.codeQualityTool, databaseEngine: config.databaseEngine, databaseHost: config.databaseHost, frontend: config.frontend, orm: config.orm, useTailwind: config.useTailwind }; - const cachedDependency = hasCachedDependencies( - dependencyConfig, - packageJsonPath, - manifestHash - ); - try { const { cached, installTime } = await getOrInstallDependencies( projectPath, dependencyConfig, packageJsonPath, manifestHash ); console.log( - cached || cachedDependency ? `✓ (cached, ${installTime}ms)` : `✓ (${installTime}ms)` + cached ? `✓ (cached, ${installTime}ms)` : `✓ (${installTime}ms)` );
49-468: Significant code duplication with vue-test-runner.ts.This file shares ~400 lines of identical or near-identical code with
vue-test-runner.ts, includingloadBunModule,raceWithTimeout,runCommand,recordFailure,scaffoldProject,installDependencies,runSequentially,printSummary, andparseSubsetFromArgs. Consider extracting these shared utilities into a common test-runner-utils module to improve maintainability and reduce duplication.scripts/functional-tests/dependency-cache.ts (1)
158-166: Consider confirming SIGTERM completion before SIGKILL.The current code sends SIGKILL after a fixed 100ms delay without checking whether SIGTERM succeeded. While this works for stuck processes, consider either increasing the delay or checking process state before escalating to SIGKILL for a more graceful shutdown sequence.
scripts/functional-tests/vue-test-runner.ts (2)
233-249: Consider removing the redundant cache check.The
hasCachedDependenciescall on lines 233-237 duplicates the cache-hit logic already performed insidegetOrInstallDependencies. The returnedcachedflag is sufficient for the console message. This is the same pattern as inhtmx-test-runner.tslines 211-227.Apply this diff:
const manifestHash = computeManifestHash(packageJsonPath); const dependencyConfig: DependencyConfig = { authProvider: config.authProvider, codeQualityTool: config.codeQualityTool, databaseEngine: config.databaseEngine, databaseHost: config.databaseHost, frontend: config.frontend, orm: config.orm, useTailwind: config.useTailwind }; - const cachedDependency = hasCachedDependencies( - dependencyConfig, - packageJsonPath, - manifestHash - ); - try { const { cached, installTime } = await getOrInstallDependencies( projectPath, dependencyConfig, packageJsonPath, manifestHash ); console.log( - cached || cachedDependency ? `✓ (cached, ${installTime}ms)` : `✓ (${installTime}ms)` + cached ? `✓ (cached, ${installTime}ms)` : `✓ (${installTime}ms)` );
55-478: Significant code duplication with htmx-test-runner.ts.This file duplicates ~400 lines from
htmx-test-runner.ts, includingloadBunModule,raceWithTimeout,runCommand,recordFailure,scaffoldProject,installDependencies,runSequentially,printSummary, andparseSubsetFromArgs. Both files would benefit from extracting these shared utilities into a common module. (Same issue flagged in htmx-test-runner.ts review.)scripts/functional-tests/functional-test-runner.ts (1)
257-263: Remove unreachable return statement.Line 262's
return undefinedis unreachable becauseprocess.exit()on line 260 terminates the process. Remove the dead code for clarity.Apply this diff:
runFunctionalTests(projectPath, packageManager, options) .then((result) => { printCliSummary(result); process.exit(result.passed ? 0 : 1); - - return undefined; }) .catch((error) => { console.error('✗ Functional test runner error:', extractErrorMessage(error)); process.exit(1); });src/generators/db/scaffoldDocker.ts (1)
45-46: Add error handling or ensure directory exists.The
writeFileSynccall lacks error handling and will throw ifprojectDatabaseDirectorydoesn't exist. Consider wrapping this in a try-catch or ensuring the directory is created beforehand.Apply this pattern to add basic error handling:
const composePath = join(projectDatabaseDirectory, 'docker-compose.db.yml'); -writeFileSync(composePath, dbContainer, 'utf-8'); +try { + writeFileSync(composePath, dbContainer, 'utf-8'); +} catch (error) { + throw new Error(`Failed to write docker-compose file to ${composePath}: ${error}`); +}scripts/functional-tests/postgresql-validator.ts (1)
286-290: Consider removing unused parameter for clarity.The
_projectPathparameter is prefixed with an underscore to indicate it's intentionally unused. If it's not needed for API consistency with other validators, consider removing it to simplify the signature.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
scripts/functional-tests/build-validator.ts(1 hunks)scripts/functional-tests/dependency-cache.ts(1 hunks)scripts/functional-tests/functional-test-runner.ts(1 hunks)scripts/functional-tests/htmx-test-runner.ts(1 hunks)scripts/functional-tests/postgresql-validator.ts(1 hunks)scripts/functional-tests/sqlite-validator.ts(1 hunks)scripts/functional-tests/vue-test-runner.ts(1 hunks)src/generators/db/dockerInitTemplates.ts(4 hunks)src/generators/db/scaffoldDocker.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- scripts/functional-tests/sqlite-validator.ts
- scripts/functional-tests/build-validator.ts
🧰 Additional context used
🧬 Code graph analysis (6)
scripts/functional-tests/postgresql-validator.ts (3)
src/generators/db/dockerInitTemplates.ts (3)
initTemplates(119-152)userTables(97-106)countHistoryTables(108-117)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)
scripts/functional-tests/functional-test-runner.ts (3)
scripts/functional-tests/dependency-installer-tester.ts (1)
testDependencyInstallation(117-163)scripts/functional-tests/build-validator.ts (1)
validateBuild(260-295)scripts/functional-tests/server-startup-validator.ts (1)
validateServerStartup(157-198)
scripts/functional-tests/vue-test-runner.ts (4)
scripts/functional-tests/matrix.ts (2)
MatrixConfig(33-42)createMatrix(82-93)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)scripts/functional-tests/vue-validator.ts (1)
validateVueFramework(231-270)
scripts/functional-tests/dependency-cache.ts (2)
src/commands/installDependencies.ts (1)
installDependencies(8-24)src/generators/configurations/generatePackageJson.ts (1)
dep(79-84)
src/generators/db/scaffoldDocker.ts (2)
src/generators/db/generateDockerContainer.ts (1)
generateDockerContainer(84-114)src/generators/db/dockerInitTemplates.ts (3)
initTemplates(119-152)userTables(97-106)countHistoryTables(108-117)
scripts/functional-tests/htmx-test-runner.ts (4)
scripts/functional-tests/matrix.ts (2)
MatrixConfig(33-42)createMatrix(82-93)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (3)
computeManifestHash(80-106)hasCachedDependencies(224-248)getOrInstallDependencies(250-280)scripts/functional-tests/htmx-validator.ts (1)
validateHTMXFramework(230-269)
🔇 Additional comments (21)
scripts/functional-tests/dependency-cache.ts (1)
250-280: LGTM - Manifest hash recomputation after install is correct.The code correctly recomputes the manifest hash after installation (line 273) and stores the cache with the updated fingerprint. This handles the case where installation modifies package.json or generates lockfiles, ensuring the cache key reflects the actual installed state rather than the requested state.
scripts/functional-tests/functional-test-runner.ts (1)
215-229: LGTM - Package manager normalization correctly handles flags.The
normalizePackageManagerfunction properly addresses the previous review concern by detecting when the argument is a flag (starts with '-') or an invalid package manager, defaulting to 'bun' and preserving the argument in the remaining array.src/generators/db/dockerInitTemplates.ts (1)
103-103: MongoDB initialization template structure looks correct.The additions to
userTables,countHistoryTables, andinitTemplatesare structurally sound and follow the established patterns for other database engines. The mongosh CLI commands and ping-based readiness check are appropriate for MongoDB.Note: Plain-text credentials in the connection string are consistent with other database templates in this file (lines 129, 141, 149), suggesting this is acceptable for local Docker development scenarios.
Also applies to: 114-114, 136-139
src/generators/db/scaffoldDocker.ts (4)
2-2: LGTM!The import is necessary for accessing
process.env.ABSOLUTE_TESTin the shared container logic.
52-61: LGTM!The database initialization logic is preserved correctly for non-shared-container scenarios. The code properly:
- Selects the appropriate SQL/NoSQL commands based on
authProvider- Executes container startup, initialization, and shutdown
- Uses the
initTemplatesto handle engine-specific CLI syntax
38-42: Shared containers are properly initialized in the validator before scaffolding runs.Verification confirms that
validatePostgreSQLDatabase(called before scaffolding) creates and seeds shared containers usinguserTablesorcountHistoryTablesbased on the auth configuration. Thedocker-compose.db.ymlfile is copied to a persistent cache directory viaensureSharedComposeFile, allowing containers to be reused across test runs. When scaffolding executes withABSOLUTE_TEST=true, the early return at line 49 correctly skips redundant initialization since the validator has already completed seeding.
48-50: Shared container workflow verified—but confirm state isolation between test matrix runs.The shared container is correctly pre-initialized: when
useSharedContainerreturns early (lines 48-50), the database has already been started and seeded byvalidatePostgreSQLDatabase→startDockerContainer(postgresql-validator.ts:208-245). The schema and seed data are established before test execution.However, the container persists across all test matrix entries without data cleanup between projects:
- Schema init uses
CREATE TABLE IF NOT EXISTS(existing tables are skipped)- Data inserted by Project N remains when Project N+1 runs
- Container only stops after the entire test matrix completes (postgresql-test-runner.ts:615)
Verify that test isolation doesn't depend on stale data cleanup, or add
TRUNCATEcalls after each project's test execution.scripts/functional-tests/postgresql-validator.ts (14)
1-30: LGTM! Well-organized imports and constants.The constants are appropriately scoped and the timeout values are reasonable for database operations.
31-39: LGTM! Clean dynamic import caching.The pattern correctly caches the Bun module to avoid repeated dynamic imports.
49-100: LGTM! Robust command execution with proper timeout handling.The escalation from SIGTERM to SIGKILL and comprehensive error handling are well-implemented.
102-111: LGTM! Path helpers correctly implement expected logic.The conditional path selection based on ORM and auth configuration is appropriate.
123-140: LGTM! Docker unavailability is now handled correctly.The implementation no longer short-circuits or marks skipped Docker checks as passed. When Docker is unavailable, a warning is pushed but validation continues with remaining structural checks, allowing the final pass/fail decision to be based on all available signals.
142-160: LGTM! Solid retry pattern for database readiness.The recursive approach with bounded attempts and appropriate delays is well-implemented.
162-176: LGTM! Clean type definitions and state management.The module-level state enables efficient container reuse across validations.
178-190: LGTM! Shared compose file management is well-implemented.Centralizing the compose file enables efficient container reuse across multiple validations.
192-206: LGTM! Container status check is correctly implemented.The command and output parsing appropriately verify the 'db' service is running.
254-274: LGTM! Clean container lifecycle management.The teardown functions properly reset state and handle errors gracefully, which is appropriate for cleanup operations.
276-284: LGTM! SQL is now passed safely without shell quoting issues.The query is passed as a separate command argument to
psql -c, avoiding bash string interpolation issues that would occur with embedded single or double quotes. The PGPASSWORD environment variable is the standard secure method for non-interactive authentication.
291-370: LGTM! Local validation logic is comprehensive and correct.The validation properly handles all failure scenarios, and the flags correctly reflect the actual state rather than assuming success when checks are skipped.
449-453: Neon configurations always pass connection checks without testing.Since Neon is a remote service requiring credentials, the validator skips actual connection tests and marks
connectionWorksandqueriesWorkastrue. This means Neon configurations cannot detect connection issues during validation, which could mask problems. However, this is a reasonable trade-off given the credentials constraint.Document this limitation so that Neon validation failures in production are understood to not be caught by the validator.
384-468: LGTM! Main validation function handles local and remote configurations appropriately.The logic correctly differentiates between Docker-based local setups and Neon remote configurations, with appropriate checks for each.
| const mongodbUsers = | ||
| "const admin = db.getSiblingDB('admin'); admin.auth('user', 'password'); const database = db.getSiblingDB('database'); database.users.updateOne({ auth_sub: 'seed-user' }, { \\$setOnInsert: { auth_sub: 'seed-user', created_at: new Date(), metadata: {} } }, { upsert: true });"; |
There was a problem hiding this comment.
🧩 Analysis chain
Verify the MongoDB operator escaping.
The double backslash in \\$setOnInsert will produce a literal backslash character when evaluated by mongosh, breaking the MongoDB operator syntax (should be $setOnInsert). Please verify whether these strings undergo additional processing that requires this escaping, or if this is a bug.
Run the following script to check how these templates are consumed:
🏁 Script executed:
#!/bin/bash
# Description: Find usages of mongodbUsers to verify string processing context
# Search for references to userTables or mongodbUsers
rg -n -A5 -B5 'userTables\[|mongodbUsers' --type=tsLength of output: 2797
🏁 Script executed:
#!/bin/bash
# Search for other MongoDB shell/mongosh commands in the codebase to see if the escaping pattern is consistent
rg -n 'mongosh|mongo\s' --type=ts --type=js -B2 -A2Length of output: 2273
🏁 Script executed:
#!/bin/bash
# Search for the pattern of $set, $update, etc. to see if escaping is used elsewhere
rg -n '\$setOnInsert|\$set|\$update' --type=ts --type=js -B1 -A1Length of output: 844
🏁 Script executed:
#!/bin/bash
# Check if there are any test files or documentation about database initialization
fd -e test.ts -e spec.ts -e '.md' | xargs rg -l 'mongodb|mongosh|updateOne' 2>/dev/null | head -10Length of output: 9
🌐 Web query:
MongoDB mongosh updateOne $setOnInsert operator syntax correct format
💡 Result:
Use $setOnInsert inside the update document and pass { upsert: true } to updateOne. Example (mongosh):
db.collection.updateOne(
{ _id: 1 }, // filter
{
$set: { item: "apple" }, // applied on match or insert
$setOnInsert: { defaultQty: 100, createdAt: new Date() } // only when inserted
},
{ upsert: true } // must be true for $setOnInsert to run
)
Notes:
- $setOnInsert does nothing when a matching document is found; it only applies when the operation inserts a new document via upsert. [1][2]
Sources:
[1] MongoDB docs — $setOnInsert operator.
[2] MongoDB docs — db.collection.updateOne() syntax.
Fix MongoDB operator escaping syntax.
The double backslash in \\$setOnInsert produces a literal backslash when passed to mongosh, breaking the MongoDB operator syntax. MongoDB mongosh requires $setOnInsert directly without escape characters.
- Line 26: Change
\\$setOnInsertto$setOnInsertin mongodbUsers - Line 29: Change
\\$setOnInsertto$setOnInsertin mongodbCountHistory
🤖 Prompt for AI Agents
In src/generators/db/dockerInitTemplates.ts around lines 25-29 the MongoDB
operator is incorrectly escaped: the string uses "\\$setOnInsert" which yields a
literal backslash and breaks mongosh; replace the escaped token with the plain
"$setOnInsert" in both mongodbUsers (line ~26) and mongodbCountHistory (line
~29) so the generated script contains the correct MongoDB operator syntax.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
scripts/functional-tests/postgresql-validator.ts(1 hunks)src/generators/db/dockerInitTemplates.ts(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
scripts/functional-tests/postgresql-validator.ts (2)
src/generators/db/dockerInitTemplates.ts (3)
initTemplates(119-152)userTables(97-106)countHistoryTables(108-117)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)
🔇 Additional comments (1)
src/generators/db/dockerInitTemplates.ts (1)
136-139: LGTM: MongoDB initialization configuration is correct.The mongosh CLI commands and wait logic are properly configured. Authentication credentials ('user'/'password') match those used in the MongoDB template scripts (lines 26, 29), ensuring consistency across the initialization flow.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
scripts/functional-tests/postgresql-validator.ts (2)
206-234: Consider simplifying the promise pattern for clarity.The sequential promise chaining using
forEachand promise reassignment works correctly but is harder to follow than a standardfor-ofloop withawait. This pattern is functionally correct but less idiomatic.Consider this refactor for improved readability:
const runPostgresSeedScripts = async ( seeds: readonly string[], executeSeed: (seed: string) => Promise<CommandResult>, errors: string[] ) => { - let resultPromise = Promise.resolve(true); - - seeds.forEach((seed) => { - resultPromise = resultPromise.then(async (previousSucceeded) => { - if (!previousSucceeded) { - return false; - } - - const seedResult = await executeSeed(seed); - - if (seedResult.exitCode !== 0) { - errors.push( - `Failed to initialise PostgreSQL schema: ${seedResult.stderr.slice(0, DOCKER_ERROR_SNIPPET_LENGTH) || 'Unknown error'}` - ); - - return false; - } - - return true; - }); - }); - - return resultPromise; + for (const seed of seeds) { + const seedResult = await executeSeed(seed); + + if (seedResult.exitCode !== 0) { + errors.push( + `Failed to initialise PostgreSQL schema: ${seedResult.stderr.slice(0, DOCKER_ERROR_SNIPPET_LENGTH) || 'Unknown error'}` + ); + return false; + } + } + + return true; };
236-242: Consider removing the unused parameter.The
_authProviderparameter is prefixed with an underscore to indicate it's intentionally unused, which is correct since both tables are now seeded unconditionally (line 255). However, removing the parameter entirely would further simplify the function signature.Apply this diff:
const startDockerContainer = async ( composePath: string, - _authProvider: string | undefined, warnings: string[], postgresqlSpecific: PostgreSQLValidationResult['postgresqlSpecific'], errors: string[] ) => {And update the call site at line 339:
if ( !usingExistingContainer && - !(await startDockerContainer(sharedComposePath, authProvider, warnings, postgresqlSpecific, errors)) + !(await startDockerContainer(sharedComposePath, warnings, postgresqlSpecific, errors)) ) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
scripts/functional-tests/postgresql-validator.ts(1 hunks)src/generators/db/dockerInitTemplates.ts(4 hunks)src/generators/db/scaffoldDocker.ts(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/generators/db/scaffoldDocker.ts (3)
src/generators/db/generateDockerContainer.ts (1)
generateDockerContainer(84-114)src/generators/db/dockerInitTemplates.ts (3)
initTemplates(119-152)userTables(97-106)countHistoryTables(108-117)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
scripts/functional-tests/postgresql-validator.ts (1)
src/generators/db/dockerInitTemplates.ts (3)
initTemplates(119-152)userTables(97-106)countHistoryTables(108-117)
🔇 Additional comments (7)
src/generators/db/dockerInitTemplates.ts (3)
25-29: MongoDB templates look correct; verify handler alignment with singleton pattern.The templates correctly use
$setOnInsert(escaping issue from past review resolved) and include theuidfield incount_history(schema mismatch resolved). The escaping will work correctly: line 57 of scaffoldDocker.ts escapes$to\$, which bash interprets as literal$for mongosh.However, the
mongodbCountHistorytemplate creates a singleton document withuid: 1using an if-check + insertOne pattern, while SQL variants use AUTO_INCREMENT to create multiple records. Past review comments indicated this was addressed in commit 4348df6, but please verify that the current handler logic matches this singleton pattern (e.g., usingupdateOne({uid: 1})rather thaninsertOne()for new history entries).
103-103: LGTM!MongoDB entries correctly added to
userTablesandcountHistoryTablesexports, consistent with other database engines.Also applies to: 114-114
136-139: LGTM!MongoDB
initTemplatesentry correctly configured with mongosh CLI and readiness wait command usingdb.runCommand({ ping: 1 }).src/generators/db/scaffoldDocker.ts (3)
2-2: Verify MongoDB exclusion from shared container logic.The
useSharedContainerlogic enables test efficiency for PostgreSQL, MySQL, and MariaDB by skipping initialization whenABSOLUTE_TEST=true. However, MongoDB is excluded from this optimization.Is this intentional? The PR objectives mention "MongoDB: sandbox failures due to missing users/count_history collections," which may explain why shared containers aren't enabled for MongoDB yet. If this is temporary while MongoDB issues are resolved, consider adding a TODO comment. If intentional for other reasons, the current implementation is fine.
Also applies to: 38-50
57-57: LGTM!The escaping logic correctly handles MongoDB operators like
$setOnInsert. When passed through bash double quotes in the command template (lines 60-61),\$is interpreted as literal$, allowing mongosh to receive the correct operator syntax.
52-62: LGTM!The Docker initialization flow correctly:
- Selects the appropriate table template based on auth configuration
- Escapes special characters for shell execution
- Ensures database readiness with the wait command before executing initialization
- Properly uses Bun template literal interpolation
scripts/functional-tests/postgresql-validator.ts (1)
1-492: Excellent implementation with robust error handling and proper resource cleanup.The validator successfully addresses all previously flagged issues:
- ✅ No early returns that skip structural validation when Docker is unavailable
- ✅ Proper SQL command escaping via separate
-carguments- ✅ Docker unavailability warnings don't falsely mark tests as passed
- ✅ Both
usersandcount_historytables are seeded to support container reuse across different auth configurations (line 255)- ✅ Docker Compose cache is refreshed on every run to catch template regressions (lines 182-183)
The implementation demonstrates solid engineering practices:
- Robust timeout handling with graceful SIGTERM followed by SIGKILL
- Proper process lifecycle management with cleanup on failures
- Structured error collection with bounded log snippets to prevent spam
- Clear separation between local Docker validation and Neon remote flows
- Comprehensive validation of schema files, handler files, and Docker artifacts
The Neon handling (lines 473-477) correctly bypasses connection tests with warnings, which aligns with the PR objectives stating that credentials aren't available in CI.
There was a problem hiding this comment.
Actionable comments posted: 18
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/generators/project/generateDBBlock.ts (1)
41-45: Fix Neon remote Drizzle initializer to useneon()Drizzle remote hosts route through
remoteDrizzleInit, so fordatabaseHost: "neon"we still emitconst pool = new Pool(...). After the connection-map change, the import generator now pulls inneoninstead ofPool, leaving the scaffolded project referencing an undefinedPooland blowing up the first time it runs. Please update the Neon entry here to use the sameneon(getEnv("DATABASE_URL"))initializer so the emitted code matches the imports.Apply this diff:
- neon: 'new Pool({ connectionString: getEnv("DATABASE_URL") })', + neon: 'neon(getEnv("DATABASE_URL"))',
♻️ Duplicate comments (1)
src/generators/db/handlerTemplates.ts (1)
43-54: Same TypeScript typing issue asgetUser.The subject derivation logic here has the same incomplete type cast. See the fix proposed for
getUserabove.
🧹 Nitpick comments (10)
test-cli-project/src/frontend/styles/colors.ts (1)
1-11: LGTM! Color constants are well-defined and consistent.The color palette is valid and the primary colors correctly match those used in the generated CSS (seen in generateMarkupCSS.ts). The naming convention is clear and consistent.
For improved type safety, consider adding
as constassertions to enable literal type inference:-export const primaryColor = '#5FBEEB'; -export const secondaryColor = '#35d5a2'; -export const tertiaryColor = '#ff4b91'; +export const primaryColor = '#5FBEEB' as const; +export const secondaryColor = '#35d5a2' as const; +export const tertiaryColor = '#ff4b91' as const; -export const lightPrimaryColor = '#ffffff'; -export const lightSecondaryColor = '#f5f5f5'; -export const lightTertiaryColor = '#e0e0e0'; +export const lightPrimaryColor = '#ffffff' as const; +export const lightSecondaryColor = '#f5f5f5' as const; +export const lightTertiaryColor = '#e0e0e0' as const; -export const darkPrimaryColor = '#1a1a1a'; -export const darkSecondaryColor = '#2c2c2c'; -export const darkTertiaryColor = '#3c3c3c'; +export const darkPrimaryColor = '#1a1a1a' as const; +export const darkSecondaryColor = '#2c2c2c' as const; +export const darkTertiaryColor = '#3c3c3c' as const;Alternatively, for better organization, you could structure these as a theme object:
export const theme = { colors: { primary: '#5FBEEB', secondary: '#35d5a2', tertiary: '#ff4b91', }, light: { primary: '#ffffff', secondary: '#f5f5f5', tertiary: '#e0e0e0', }, dark: { primary: '#1a1a1a', secondary: '#2c2c2c', tertiary: '#3c3c3c', }, } as const;src/generators/db/generateDockerContainer.ts (1)
30-30: Consider non-standard host ports for other database engines.For consistency and to avoid conflicts with local installations, consider mapping other database engines to non-standard host ports as well. Currently, MariaDB, MySQL, and SingleStore all use the standard port
3306:3306, which could conflict with local installations or with each other if multiple services are run simultaneously.Example approach:
- MariaDB:
3307:3306- MySQL:
3308:3306- SingleStore:
3309:3306Also applies to: 61-61, 79-79
docs/test-cli-migration-phase0.md (1)
46-46: Track acknowledged cleanup debt.Line 46 notes that "Several suites still list behavioural tests even though the corresponding
tests/behavioural/*.test.tsfiles were deleted earlier" and calls for "cleanup in later phases." This is a known inconsistency worth tracking as a follow-up issue.Would you like me to open a follow-up issue to track this cleanup task, or is it already captured in your tracking system?
tests/behavioural/cloud-matrix.test.ts (1)
43-71: Consider validating that environment variables are non-empty strings.The current check at line 47 (
!process.env[source]) correctly filters out undefined values, but an environment variable set to an empty string would pass this check and potentially cause connection failures later in the test flow. While the current behavior may be acceptable, explicitly checking for non-empty strings would provide clearer, earlier error messages.If you'd like to add this validation, apply this diff:
const resolveScenario = ( definition: CloudScenarioDefinition ): BehaviouralScenario | null => { const missing = definition.requiredEnv.filter( - ({ source }) => !process.env[source] + ({ source }) => !process.env[source] || process.env[source]?.trim() === '' );tests/behavioural/auth-matrix.test.ts (1)
8-28: Consider expanding AUTH_SCENARIOS for comprehensive coverage.The current matrix only covers React + SQLite (with and without Drizzle). Based on the PR objectives mentioning Vue/Svelte/HTML/HTMX frameworks and PostgreSQL/MySQL/MongoDB databases, consider whether additional scenarios should be included here or if this is intentionally a focused subset for smoke testing.
test-cli-project/src/backend/server.ts (2)
27-36: Remove duplicate route definition.The
'/'and'/react'routes have identical implementations. Consider removing one or extracting the handler to a shared function if both routes are intentionally needed.+const renderReactExample = () => handleReactPageRequest( + ReactExample, + asset(manifest, 'ReactExampleIndex'), + { initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS') } +); + .use(networking) .use(staticPlugin({"assets":"./build","prefix":""})) - .get('/', () => handleReactPageRequest( - ReactExample, - asset(manifest, 'ReactExampleIndex'), - { initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS') } - )) - .get('/react', () => handleReactPageRequest( - ReactExample, - asset(manifest, 'ReactExampleIndex'), - { initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS') } - )) + .get('/', renderReactExample) + .get('/react', renderReactExample)
15-22: Add connection error handling for PostgreSQL pool.The Pool is created without error handling. If the connection string is invalid or the database is unavailable, the error will only surface when queries are attempted, making debugging harder.
const connectionString = getEnv("DATABASE_URL") if (process.env.ABSOLUTE_TEST_VERBOSE === '1') { console.log('Server runtime env: DATABASE_URL=' + connectionString) console.log('Server runtime env: PGHOST=' + (process.env.PGHOST ?? 'undefined')) console.log('Server runtime env: PGPORT=' + (process.env.PGPORT ?? 'undefined')) } -const pool = new Pool({ connectionString }) + +const pool = new Pool({ connectionString }) + +pool.on('error', (err) => { + console.error('Unexpected PostgreSQL pool error:', err) +}) + const db = createPgSql(pool)scripts/functional-tests/cloud-provider-validator.ts (1)
108-124: Validate CLI arguments to prevent runtime errors.The
parseCliArgumentsfunction destructures 8 positional arguments without validation and castspackageManagerwithout checking. Invalid inputs could cause runtime failures.const parseCliArguments = (argv: string[]) => { const [, , projectPath, packageManager, databaseEngine, databaseHost, orm, authProvider] = argv; + + const validPackageManagers = ['bun', 'npm', 'pnpm', 'yarn']; + const pm = packageManager ?? DEFAULT_PACKAGE_MANAGER; + + if (!validPackageManagers.includes(pm)) { + throw new Error(`Invalid package manager: ${pm}. Expected: ${validPackageManagers.join(', ')}`); + } return { authProvider: authProvider ?? 'none', databaseEngine: databaseEngine ?? 'none', databaseHost: databaseHost ?? 'none', options: { skipBuild: argv.includes('--skip-build'), skipDependencies: argv.includes('--skip-deps'), skipServer: argv.includes('--skip-server') }, orm: orm ?? 'none', - packageManager: (packageManager as 'bun' | 'npm' | 'pnpm' | 'yarn') ?? DEFAULT_PACKAGE_MANAGER, + packageManager: pm as 'bun' | 'npm' | 'pnpm' | 'yarn', projectPath }; };tests/functional/frameworks/svelte.test.ts (1)
10-15: Make project slug host/tool aware to avoid collisions.Multiple matrix entries differ only by
databaseHostorcodeQualityTool, so the current slug reuses the same directory, which risks cross-scenario residue if cleanup ever skips or tests run in parallel. Folding those fields into the slug keeps each scenario isolated.-const createProjectName = (config: SvelteMatrixEntry) => - `test-svelte-${config.databaseEngine}-${config.orm}-${config.authProvider === 'none' ? 'noauth' : 'auth'}-${ - config.useTailwind ? 'tw' : 'notw' - }` - .replace(/[^a-z0-9-]/g, '-') - .toLowerCase(); +const createProjectName = (config: SvelteMatrixEntry) => + [ + 'test-svelte', + config.databaseEngine, + config.databaseHost, + config.orm, + config.authProvider === 'none' ? 'noauth' : 'auth', + config.useTailwind ? 'tw' : 'notw', + config.codeQualityTool ?? null + ] + .filter(Boolean) + .join('-') + .replace(/[^a-z0-9-]/g, '-') + .toLowerCase();tests/functional/frameworks/html.test.ts (1)
10-15: Mirror the slug fix for HTML scenarios.HTML matrix entries also differ by host/code-quality, so keeping those in the slug prevents different runs from sharing the same project directory.
-const createProjectName = (config: HtmlMatrixEntry) => - `test-html-${config.databaseEngine}-${config.orm}-${config.authProvider === 'none' ? 'noauth' : 'auth'}-${ - config.useTailwind ? 'tw' : 'notw' - }` - .replace(/[^a-z0-9-]/g, '-') - .toLowerCase(); +const createProjectName = (config: HtmlMatrixEntry) => + [ + 'test-html', + config.databaseEngine, + config.databaseHost, + config.orm, + config.authProvider === 'none' ? 'noauth' : 'auth', + config.useTailwind ? 'tw' : 'notw', + config.codeQualityTool ?? null + ] + .filter(Boolean) + .join('-') + .replace(/[^a-z0-9-]/g, '-') + .toLowerCase();
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
bun.lockis excluded by!**/*.locktest-cli-project/src/backend/assets/ico/favicon.icois excluded by!**/*.icotest-cli-project/src/backend/assets/png/absolutejs-temp.pngis excluded by!**/*.pngtest-cli-project/src/backend/assets/svg/react.svgis excluded by!**/*.svg
📒 Files selected for processing (82)
README.md(0 hunks)docs/test-cli-migration-phase0.md(1 hunks)docs/test-cli-migration-phase1.md(1 hunks)docs/test-cli-ux.md(1 hunks)eslint.config.mjs(1 hunks)package.json(1 hunks)scripts/functional-tests/auth-validator.ts(1 hunks)scripts/functional-tests/build-validator.ts(1 hunks)scripts/functional-tests/cloud-provider-validator.ts(1 hunks)scripts/functional-tests/dependency-cache.ts(1 hunks)scripts/functional-tests/dependency-installer-tester.ts(1 hunks)scripts/functional-tests/htmx-validator.ts(1 hunks)scripts/functional-tests/mongodb-validator.ts(1 hunks)scripts/functional-tests/mysql-validator.ts(1 hunks)scripts/functional-tests/postgresql-validator.ts(1 hunks)scripts/functional-tests/react-validator.ts(1 hunks)scripts/functional-tests/server-startup-validator.ts(1 hunks)scripts/functional-tests/sqlite-validator.ts(1 hunks)scripts/functional-tests/svelte-validator.ts(1 hunks)scripts/functional-tests/test-cli-registry.ts(1 hunks)scripts/functional-tests/test-cli.ts(1 hunks)scripts/functional-tests/vue-validator.ts(1 hunks)src/generators/configurations/generateEnv.ts(1 hunks)src/generators/db/dockerInitTemplates.ts(4 hunks)src/generators/db/generateDockerContainer.ts(2 hunks)src/generators/db/handlerTemplates.ts(7 hunks)src/generators/project/generateDBBlock.ts(3 hunks)test-cli-project/.prettierignore(1 hunks)test-cli-project/.prettierrc.json(1 hunks)test-cli-project/README.md(1 hunks)test-cli-project/db/docker-compose.db.yml(1 hunks)test-cli-project/eslint.config.mjs(1 hunks)test-cli-project/package.json(1 hunks)test-cli-project/src/backend/database/createPgSql.ts(1 hunks)test-cli-project/src/backend/handlers/countHistoryHandlers.ts(1 hunks)test-cli-project/src/backend/server.ts(1 hunks)test-cli-project/src/constants.ts(1 hunks)test-cli-project/src/frontend/components/App.tsx(1 hunks)test-cli-project/src/frontend/components/Dropdown.tsx(1 hunks)test-cli-project/src/frontend/components/Head.tsx(1 hunks)test-cli-project/src/frontend/pages/ReactExample.tsx(1 hunks)test-cli-project/src/frontend/styles/colors.ts(1 hunks)test-cli-project/src/frontend/styles/react-example.css(1 hunks)test-cli-project/src/frontend/styles/reset.css(1 hunks)test-cli-project/tsconfig.json(1 hunks)tests/behavioural/auth-matrix.test.ts(1 hunks)tests/behavioural/cloud-matrix.test.ts(1 hunks)tests/behavioural/database-hooks.ts(1 hunks)tests/behavioural/database-matrix-definitions.ts(1 hunks)tests/behavioural/database-matrix.test.ts(1 hunks)tests/behavioural/database-matrix.ts(1 hunks)tests/behavioural/utils.ts(1 hunks)tests/functional/auth.test.ts(1 hunks)tests/functional/cloud.test.ts(1 hunks)tests/functional/databases/mongodb.test.ts(1 hunks)tests/functional/databases/mysql.test.ts(1 hunks)tests/functional/databases/postgresql.test.ts(1 hunks)tests/functional/databases/sqlite.test.ts(1 hunks)tests/functional/frameworks/html.test.ts(1 hunks)tests/functional/frameworks/htmx.test.ts(1 hunks)tests/functional/frameworks/react.test.ts(1 hunks)tests/functional/frameworks/svelte.test.ts(1 hunks)tests/functional/frameworks/test-utils.ts(1 hunks)tests/functional/frameworks/vue.test.ts(1 hunks)tests/functional/support/assertions.ts(1 hunks)tests/functional/support/docker.ts(1 hunks)tests/functional/support/filesystem.ts(1 hunks)tests/functional/support/http.ts(1 hunks)tests/functional/support/index.ts(1 hunks)tests/functional/support/install.ts(1 hunks)tests/functional/support/scaffold.ts(1 hunks)tests/functional/support/timing.ts(1 hunks)tests/functional/support/types.ts(1 hunks)tests/harness/cli.ts(1 hunks)tests/harness/harness.test.ts(1 hunks)tests/harness/http.ts(1 hunks)tests/harness/index.ts(1 hunks)tests/harness/process.ts(1 hunks)tests/harness/project.ts(1 hunks)tests/harness/server.ts(1 hunks)tests/harness/types.ts(1 hunks)tsconfig.json(1 hunks)
💤 Files with no reviewable changes (1)
- README.md
✅ Files skipped from review due to trivial changes (5)
- docs/test-cli-migration-phase1.md
- test-cli-project/src/frontend/styles/reset.css
- test-cli-project/README.md
- test-cli-project/.prettierrc.json
- test-cli-project/.prettierignore
🚧 Files skipped from review as they are similar to previous changes (5)
- tsconfig.json
- scripts/functional-tests/sqlite-validator.ts
- package.json
- scripts/functional-tests/react-validator.ts
- src/generators/db/dockerInitTemplates.ts
🧰 Additional context used
🧬 Code graph analysis (56)
test-cli-project/src/frontend/pages/ReactExample.tsx (3)
test-cli-project/src/frontend/components/Head.tsx (1)
Head(9-34)test-cli-project/src/frontend/components/Dropdown.tsx (1)
Dropdown(3-18)test-cli-project/src/frontend/components/App.tsx (1)
App(5-52)
test-cli-project/src/frontend/components/Head.tsx (2)
src/templates/react/components/Head.tsx (1)
HeadProps(9-34)src/templates/react/pages/ReactExample.tsx (1)
ReactExampleProps(7-18)
test-cli-project/src/frontend/styles/react-example.css (4)
src/generators/project/generateMarkupCSS.ts (1)
frontend(3-157)src/templates/react/pages/ReactExample.tsx (1)
ReactExampleProps(7-18)src/templates/react/components/Head.tsx (1)
HeadProps(9-34)src/generators/react/generateReactPage.ts (1)
frontends(4-26)
test-cli-project/db/docker-compose.db.yml (1)
src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)
tests/functional/frameworks/vue.test.ts (3)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)tests/functional/frameworks/test-utils.ts (1)
runFrameworkMatrix(77-165)scripts/functional-tests/vue-validator.ts (1)
validateVueFramework(61-87)
tests/functional/support/scaffold.ts (4)
tests/functional/support/timing.ts (2)
minutesToMilliseconds(22-22)MILLISECONDS_PER_SECOND(1-1)tests/functional/support/types.ts (3)
StepResult(1-6)createFailure(8-13)createSuccess(15-23)tests/harness/project.ts (2)
scaffoldProject(26-58)cleanupProject(139-143)tests/functional/support/filesystem.ts (1)
removeDirectoryIfExists(3-14)
scripts/functional-tests/cloud-provider-validator.ts (2)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(58-155)
test-cli-project/package.json (3)
src/generators/configurations/generatePackageJson.ts (2)
CreatePackageJsonProps(31-226)dep(79-84)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
scripts/functional-tests/postgresql-validator.ts (2)
tests/harness/process.ts (1)
runCommand(14-66)src/generators/db/dockerInitTemplates.ts (3)
initTemplates(119-152)userTables(97-106)countHistoryTables(108-117)
tests/functional/frameworks/htmx.test.ts (2)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)tests/functional/frameworks/test-utils.ts (1)
runFrameworkMatrix(77-165)
test-cli-project/src/frontend/components/Dropdown.tsx (3)
src/generators/react/generateReactPage.ts (1)
frontends(4-26)src/templates/react/pages/ReactExample.tsx (1)
ReactExampleProps(7-18)src/generators/react/scaffoldReact.ts (1)
ScaffoldFrontendProps(7-35)
tests/functional/databases/sqlite.test.ts (4)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(116-170)tests/functional/frameworks/test-utils.ts (1)
runMatrixSuite(167-167)scripts/functional-tests/sqlite-validator.ts (1)
validateSQLiteDatabase(148-183)
tests/harness/server.ts (2)
tests/harness/types.ts (2)
StartServerOptions(54-61)RunningServer(63-66)tests/harness/http.ts (1)
waitForHttpOk(6-32)
tests/functional/frameworks/react.test.ts (3)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)tests/functional/frameworks/test-utils.ts (1)
runFrameworkMatrix(77-165)scripts/functional-tests/react-validator.ts (1)
validateReactFramework(62-88)
tests/functional/frameworks/html.test.ts (2)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)tests/functional/frameworks/test-utils.ts (1)
runFrameworkMatrix(77-165)
tests/behavioural/database-matrix.ts (2)
tests/harness/types.ts (3)
Frontend(1-7)Orm(15-15)DatabaseEngine(9-9)tests/behavioural/utils.ts (3)
BehaviouralScenario(13-16)ScenarioHooks(18-27)runCountHistoryScenario(257-484)
test-cli-project/src/frontend/styles/colors.ts (1)
src/generators/project/generateMarkupCSS.ts (1)
frontend(3-157)
tests/functional/cloud.test.ts (3)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)tests/functional/frameworks/test-utils.ts (1)
runMatrixSuite(167-167)scripts/functional-tests/cloud-provider-validator.ts (1)
validateCloudProvider(62-99)
test-cli-project/src/frontend/components/App.tsx (3)
src/templates/react/components/App.tsx (2)
AppProps(5-52)setCount(27-27)src/templates/react/pages/ReactExample.tsx (1)
ReactExampleProps(7-18)src/templates/react/components/Head.tsx (1)
HeadProps(9-34)
tests/behavioural/auth-matrix.test.ts (1)
tests/behavioural/utils.ts (2)
BehaviouralScenario(13-16)runAuthScenario(496-593)
test-cli-project/src/backend/server.ts (3)
test-cli-project/src/backend/database/createPgSql.ts (1)
createPgSql(70-92)test-cli-project/src/frontend/pages/ReactExample.tsx (1)
ReactExample(7-18)test-cli-project/src/backend/handlers/countHistoryHandlers.ts (2)
getCountHistory(4-11)createCountHistory(13-20)
tests/harness/project.ts (4)
tests/harness/types.ts (2)
ScaffoldOptions(21-33)ScaffoldResult(35-38)tests/harness/cli.ts (1)
buildScaffoldArguments(11-59)tests/harness/process.ts (1)
runCommand(14-66)scripts/functional-tests/dependency-cache.ts (4)
DependencyFingerprint(23-31)computeManifestHash(80-106)hasCachedDependencies(225-249)getOrInstallDependencies(251-282)
scripts/functional-tests/auth-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)
tests/behavioural/cloud-matrix.test.ts (1)
tests/behavioural/utils.ts (2)
BehaviouralScenario(13-16)runCountHistoryScenario(257-484)
tests/harness/cli.ts (2)
tests/harness/types.ts (1)
ScaffoldOptions(21-33)src/utils/parseCommandLineOptions.ts (1)
parseArgs(32-332)
tests/functional/auth.test.ts (3)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)tests/functional/frameworks/test-utils.ts (1)
runMatrixSuite(167-167)scripts/functional-tests/auth-validator.ts (1)
validateAuthConfiguration(61-95)
tests/functional/frameworks/test-utils.ts (6)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)tests/functional/support/scaffold.ts (3)
ScaffoldOptions(18-33)scaffoldProject(99-211)cleanupProject(213-215)scripts/functional-tests/dependency-cache.ts (1)
DependencyFingerprint(23-31)tests/functional/support/timing.ts (1)
minutesToMilliseconds(22-22)tests/functional/support/assertions.ts (1)
assertStepSuccess(3-15)tests/functional/support/install.ts (1)
installDependencies(25-62)
src/generators/db/handlerTemplates.ts (1)
src/generators/db/generateSqliteSchema.ts (1)
authProvider(3-14)
tests/functional/support/assertions.ts (1)
tests/functional/support/types.ts (1)
StepResult(1-6)
tests/functional/support/docker.ts (3)
tests/functional/support/timing.ts (2)
minutesToMilliseconds(22-22)MILLISECONDS_PER_SECOND(1-1)tests/functional/support/types.ts (2)
createFailure(8-13)createSuccess(15-23)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)
scripts/functional-tests/dependency-cache.ts (2)
tests/functional/support/install.ts (1)
installDependencies(25-62)tests/harness/project.ts (1)
installDependencies(62-137)
src/generators/configurations/generateEnv.ts (1)
src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)
tests/functional/databases/mongodb.test.ts (5)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(116-170)tests/functional/frameworks/test-utils.ts (1)
runMatrixSuite(167-167)tests/functional/support/docker.ts (1)
ensureDockerAvailable(79-100)scripts/functional-tests/mongodb-validator.ts (1)
validateMongoDBDatabase(255-307)
eslint.config.mjs (1)
src/generators/configurations/scaffoldConfigurationFiles.ts (1)
AddConfigurationProps(22-77)
scripts/functional-tests/mongodb-validator.ts (4)
tests/functional/support/timing.ts (2)
MILLISECONDS_PER_SECOND(1-1)SECONDS_PER_MINUTE(2-2)tests/harness/process.ts (1)
runCommand(14-66)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)
tests/harness/process.ts (2)
tests/functional/support/timing.ts (2)
MILLISECONDS_PER_SECOND(1-1)SECONDS_PER_MINUTE(2-2)tests/harness/types.ts (2)
RunCommandOptions(40-45)RunCommandResult(47-52)
scripts/functional-tests/mysql-validator.ts (5)
tests/functional/support/timing.ts (2)
MILLISECONDS_PER_SECOND(1-1)SECONDS_PER_MINUTE(2-2)tests/harness/process.ts (1)
runCommand(14-66)tests/functional/support/assertions.ts (1)
logWarnings(17-19)src/generators/db/scaffoldDatabase.ts (1)
ScaffoldDatabaseProps(27-107)src/generators/db/scaffoldDocker.ts (1)
ScaffoldDockerProps(20-56)
tests/functional/databases/postgresql.test.ts (5)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(116-170)tests/functional/frameworks/test-utils.ts (1)
runMatrixSuite(167-167)tests/functional/support/docker.ts (1)
ensureDockerAvailable(79-100)scripts/functional-tests/postgresql-validator.ts (1)
validatePostgreSQLDatabase(388-433)
tests/harness/harness.test.ts (4)
tests/harness/project.ts (3)
scaffoldProject(26-58)installDependencies(62-137)cleanupProject(139-143)tests/harness/server.ts (1)
startServer(14-156)tests/harness/process.ts (1)
runCommand(14-66)tests/harness/cli.ts (1)
buildScaffoldArguments(11-59)
test-cli-project/eslint.config.mjs (2)
src/generators/configurations/scaffoldConfigurationFiles.ts (1)
AddConfigurationProps(22-77)src/generators/configurations/generatePackageJson.ts (1)
CreatePackageJsonProps(31-226)
tests/functional/support/install.ts (3)
scripts/functional-tests/dependency-cache.ts (4)
DependencyFingerprint(23-31)getOrInstallDependencies(251-282)hasCachedDependencies(225-249)computeManifestHash(80-106)tests/functional/support/types.ts (3)
StepResult(1-6)createSuccess(15-23)createFailure(8-13)tests/harness/project.ts (1)
installDependencies(62-137)
tests/behavioural/utils.ts (4)
tests/harness/project.ts (3)
scaffoldProject(26-58)installDependencies(62-137)cleanupProject(139-143)tests/harness/process.ts (1)
runCommand(14-66)tests/harness/types.ts (1)
RunningServer(63-66)tests/harness/server.ts (1)
startServer(14-156)
test-cli-project/src/backend/handlers/countHistoryHandlers.ts (2)
test-cli-project/src/backend/database/createPgSql.ts (1)
PgSql(68-68)src/generators/db/generateSqliteSchema.ts (1)
authProvider(3-14)
tests/behavioural/database-matrix.test.ts (2)
tests/behavioural/database-matrix-definitions.ts (1)
DATABASE_MATRIX_DEFINITIONS(17-79)tests/behavioural/database-matrix.ts (1)
describeDatabaseMatrix(75-98)
tests/functional/databases/mysql.test.ts (5)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)scripts/functional-tests/functional-test-runner.ts (1)
runFunctionalTests(116-170)tests/functional/frameworks/test-utils.ts (1)
runMatrixSuite(167-167)tests/functional/support/docker.ts (1)
ensureDockerAvailable(79-100)scripts/functional-tests/mysql-validator.ts (1)
validateMySQLDatabase(270-325)
scripts/functional-tests/dependency-installer-tester.ts (2)
src/commands/installDependencies.ts (1)
packageManager(8-24)src/generators/configurations/generatePackageJson.ts (1)
CreatePackageJsonProps(31-226)
tests/harness/types.ts (1)
tests/functional/support/scaffold.ts (2)
ScaffoldOptions(18-33)ScaffoldResult(35-40)
tests/behavioural/database-matrix-definitions.ts (3)
tests/behavioural/database-matrix.ts (1)
DatabaseMatrixDefinition(18-26)tests/behavioural/database-hooks.ts (3)
createPostgresHooks(4-45)createMysqlHooks(47-90)createMongoHooks(92-239)src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)
test-cli-project/tsconfig.json (2)
src/generators/configurations/generatePackageJson.ts (1)
CreatePackageJsonProps(31-226)src/generators/configurations/scaffoldConfigurationFiles.ts (1)
AddConfigurationProps(22-77)
tests/behavioural/database-hooks.ts (2)
tests/behavioural/utils.ts (1)
ScenarioHooks(18-27)tests/harness/process.ts (1)
runCommand(14-66)
tests/functional/frameworks/svelte.test.ts (3)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-42)tests/functional/frameworks/test-utils.ts (1)
runFrameworkMatrix(77-165)scripts/functional-tests/svelte-validator.ts (1)
validateSvelteFramework(61-87)
scripts/functional-tests/vue-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)
scripts/functional-tests/test-cli.ts (3)
scripts/functional-tests/test-cli-registry.ts (6)
SuiteDefinition(13-25)SUITE_REGISTRY(29-235)KNOWN_PROVIDERS(248-248)SUITE_MAP(237-239)KNOWN_FRAMEWORKS(246-246)KNOWN_DATABASES(247-247)scripts/functional-tests/test-utils.ts (1)
cleanupProjectDirectory(9-20)scripts/functional-tests/dependency-cache.ts (1)
cleanupCache(284-315)
scripts/functional-tests/svelte-validator.ts (1)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)
src/generators/project/generateDBBlock.ts (1)
src/generators/configurations/generateDrizzleConfig.ts (1)
CreateDrizzleConfigProps(11-34)
scripts/functional-tests/htmx-validator.ts (2)
scripts/functional-tests/functional-test-runner.ts (2)
FunctionalTestResult(24-34)runFunctionalTests(116-170)tests/functional/support/assertions.ts (1)
logWarnings(17-19)
🪛 Biome (2.1.2)
test-cli-project/src/frontend/components/App.tsx
[error] 11-11: Avoid using target="_blank" without rel="noopener" or rel="noreferrer".
Opening external links in new tabs without rel="noopener" is a security risk. See the explanation for more details.
Safe fix: Add the rel="noopener" attribute.
(lint/security/noBlankTarget)
🪛 LanguageTool
docs/test-cli-ux.md
[grammar] ~6-~6: Use a hyphen to join words.
Context: ...he legacy runner: intuitive flags, human friendly progress, concise summary, pred...
(QB_NEW_EN_HYPHEN)
🪛 markdownlint-cli2 (0.18.1)
docs/test-cli-ux.md
45-45: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (33)
test-cli-project/tsconfig.json (1)
27-29: Verify that the include pattern covers all required TypeScript files.The current
includepattern covers onlysrc/**/*, but the AI summary and PR objectives indicate that TypeScript files fromscripts/functional-tests/and test-cli-project are expected to be compiled under this configuration (e.g., scripts/functional-tests/test-cli.ts). If this is the project-wide TypeScript configuration, the include pattern may be incomplete.Please confirm:
- Is this tsconfig intended to cover only source files under
src/, or should it also include test and functional-test files?- If test files need compilation, add them to the
includearray:"include": [ - "src/**/*" + "src/**/*", + "scripts/functional-tests/**/*.ts", + "test-cli-project/**/*.ts" ]Alternatively, if separate TypeScript configurations are preferred for tests (e.g.,
tsconfig.test.json), confirm that arrangement and ensure the test runner uses the appropriate config.test-cli-project/src/constants.ts (1)
1-2: These constants are unused dead code and should be removed or their purpose clarified.Verification confirms that
HOURS_IN_DAYandTWO_THIRDSare never imported or used anywhere in the codebase—they are only defined. While unused code in test projects may sometimes be intentional for validation purposes, exported constants that serve no function should be removed to keep the test project clean and focused.src/generators/configurations/generateEnv.ts (3)
15-15: Verify the intentional password inconsistency.MariaDB and MySQL now use
userpasswordwhile other databases retainpassword. This inconsistency may confuse maintainers or lead to test setup errors if not clearly documented.If this aligns with your Docker Compose or test fixture credentials, consider adding a comment explaining the variance. Otherwise, standardize the passwords across all engines.
Also applies to: 18-18
16-16: Good addition of authSource parameter.Including
authSource=adminin the MongoDB connection string is a standard practice when authentication is enabled and aligns with common MongoDB Docker image configurations.
16-16: Verify MongoDB port configuration and normalize host values to 127.0.0.1 for consistency.The review observations are accurate. Verification confirms:
Non-standard ports confirmed: PostgreSQL port 5433 is configured in
test-cli-project/db/docker-compose.db.yml(line 10:5433:5432). MongoDB port 27018 is referenced in the code but no corresponding docker-compose port mapping was found.Host inconsistency verified: MongoDB (line 16) and PostgreSQL (line 19) use
127.0.0.1, while other database entries (lines 13–15, 17–18, 20) uselocalhost. This mixed approach creates maintenance inconsistency.Missing MongoDB setup: Unlike PostgreSQL, no Docker Compose or test configuration explicitly configures port 27018. Ensure this is set up in your test environment.
Action: Verify that MongoDB docker-compose maps
27018:27017and consider normalizing all database URLs to use127.0.0.1for consistency.docs/test-cli-migration-phase0.md (2)
3-3: Clarify the Phase 3 reference and tense.Line 3 states "Phase 3 replaced the legacy…" but this is Phase 0 documentation. This creates ambiguity about whether Phase 3 is already complete or a future milestone. Please clarify the intended meaning and correct the tense if necessary.
If Phase 3 is a future phase, rephrase to "Phase 3 will replace…" or document the actual state of the transition.
40-40: Documentation is accurate; no changes needed.The verification confirms that line 40's description is correct:
test-cli-registry.tsexists and exportsKNOWN_FRAMEWORKS,KNOWN_DATABASES, andKNOWN_PROVIDERS- These constants are used directly for CLI flag validation in
test-cli.ts(lines 251, 307, 323 check.has()against user input and throw errors for unknown values)- The parity requirement is valid: these sets must remain synchronized when testing frameworks change
docs/test-cli-ux.md (2)
68-96: Both documented behaviors are correctly implemented; no issues found.The verification confirms:
Skip exit codes (line 73): Skip paths (lines 510–522, 524–539) correctly return
exitCode: 0andskipped: true. The summary displays skipped suites with⚠symbol and reason text (lines 482–485, 511). ✓ABSOLUTE_BEHAVIOURAL_MODE (line 89): The environment variable is explicitly set to
'1'when chaining functional runners (line 561) and defaults to'0'for downstream processes that may not have it set (line 565). ✓The documentation accurately reflects the implementation.
12-41: All runner files exist and environment variable checks are properly implemented.Verification complete:
- ✓ All 10 runner files listed in the Suite Taxonomy table exist
- ✓ Environment variable checks for cloud credentials (
ABSOLUTE_BEHAVIOURAL_NEON_DATABASE_URL,ABSOLUTE_BEHAVIOURAL_TURSO_DATABASE_URL) are implemented intests/behavioural/cloud-matrix.test.ts- ✓ Skip logic works correctly: missing credentials cause
resolveScenario()to returnnull, which triggers an early return in the test (lines 68–71), effectively skipping the test with a warning messageThe documentation accurately reflects the implementation. No corrections needed.
tests/functional/databases/sqlite.test.ts (2)
85-93: Fingerprint excludesdirectoryConfig— verify this is intentional.The
createFingerprintfunction omitsdirectoryConfig, whilebuildScaffoldOptionsincludes it (line 81). Since the filter constrains all entries todirectoryConfig === 'default', this field is constant and doesn't affect cache validity. However, if future changes relax the filter to allow other directory configurations, the fingerprint could produce incorrect cache hits across differentdirectoryConfigvalues.Consider explicitly documenting this design choice or including
directoryConfigin the fingerprint for future-proofing:createFingerprint: (config) => ({ authProvider: config.authProvider, codeQualityTool: config.codeQualityTool, databaseEngine: config.databaseEngine, databaseHost: config.databaseHost, + directoryConfig: config.directoryConfig, frontend: config.frontend, orm: config.orm, useTailwind: config.useTailwind }),
1-107: Well-structured test suite with comprehensive coverage.The implementation follows the repository's matrix-driven validation pattern effectively:
- Proper type constraints via
SqliteMatrixEntryensure type safety throughout the pipeline- Error handling in
runFunctionalSuite(lines 51-55, 59-67) is defensive and provides clear diagnostics- The three-phase validation (functional tests → database-specific checks) aligns with the comprehensive testing approach described in the PR objectives
- Configuration mapping correctly handles edge cases (e.g.,
framework: undefinedwhenfrontend === 'none')The test structure is consistent with other database validators referenced in the PR and should reliably validate SQLite configurations across the supported matrix.
src/generators/db/handlerTemplates.ts (3)
171-188: Good use of upsert for idempotency.The
updateOnewith{ upsert: true }ensures that repeated calls with the sameauth_subare idempotent, and the projection correctly excludes MongoDB's internal_id.
343-362: Verify MySQL RETURNING support before production.The manual
insertIdextraction (lines 348-355) with array/object fallbacks suggests the result shape is inconsistent across MySQL2 or Drizzle versions. This workaround is brittle.Please confirm whether Drizzle ORM's
.returning()is unsupported for MySQL in this configuration. If it is supported, refactor to match the simpler pattern used for PostgreSQL/SQLite:const [newHistory] = await db .insert(schema.countHistory) .values({ count }) .returning() return newHistoryOtherwise, document why the fallback is necessary (e.g., "MySQL <8.0.1 / MariaDB does not support RETURNING").
420-440: LGTM! PostgreSQL configuration updates are consistent.The import path changes for
NodePgDatabaseand the newPgSqltype abstraction align well with the stated PR objective to introducebackend/database/createPgSql.ts. The query operations remain unchanged and correct.tests/behavioural/cloud-matrix.test.ts (3)
1-6: LGTM!Imports are clean and appropriate for the test infrastructure.
8-12: LGTM!Type definition clearly expresses the structure for cloud scenario configurations with environment variable mapping.
14-41: Well-structured scenario definitions.The consistent structure and use of
as constensures type safety and immutability for the test matrix.eslint.config.mjs (1)
223-231: LGTM! Test-specific ESLint configuration is appropriate.The configuration correctly:
- Provides Node.js globals for test files
- Disables
import/no-unused-modulessince test files are entry pointsThis aligns with the existing pattern of file-specific rule overrides in the configuration.
test-cli-project/db/docker-compose.db.yml (1)
1-15: Configuration is appropriate for test infrastructure.The Docker Compose setup uses standard PostgreSQL 15 with hardcoded credentials (
database/password/user), which is acceptable for test scenarios. Port mapping to 5433 avoids conflicts with default PostgreSQL instances running on 5432.tests/functional/support/filesystem.ts (1)
3-14: LGTM! Robust cleanup implementation.The function appropriately:
- Guards against non-existent paths
- Catches and logs errors without throwing, allowing cleanup to continue
- Uses
force: trueandrecursive: truefor thorough removalThis is well-suited for test cleanup scenarios where failures shouldn't halt execution.
tests/functional/support/http.ts (1)
1-19: LGTM! Clean HTTP test utilities.Both functions are well-implemented with:
- Clear, descriptive error messages
- Type safety through generics
- Appropriate error handling for test scenarios
These provide useful building blocks for HTTP assertions in functional tests.
tests/functional/support/types.ts (1)
1-23: LGTM! Well-structured result types.The
StepResulttype and factory functions provide:
- Immutability through readonly fields
- Consistent structure via factory functions
- Sensible defaults (empty arrays for optional warnings)
This pattern ensures test results are correctly structured across the functional test suite.
scripts/functional-tests/cloud-provider-validator.ts (1)
62-99: Validation logic is sound and well-structured.The function appropriately:
- Validates provider against VALID_PROVIDERS with early return
- Wraps functional tests in try/catch
- Aggregates errors and warnings from test results
- Computes
passedbased on both zero errors AND successful functional testsThis defensive approach ensures robust validation reporting.
tests/functional/databases/mysql.test.ts (1)
40-71: Preflight functional run reads well.Running the full functional suite up front and echoing elapsed timing plus warnings keeps the MySQL matrix failures actionable without duplicating logic. Nicely structured.
tests/functional/support/scaffold.ts (1)
99-205: Timeout-aware scaffolding helper looks great.I like how this helper removes any stale directory, streams output for postmortems, and reports timeouts with captured logs—makes diagnosing scaffold failures much easier.
tests/functional/auth.test.ts (1)
62-84: Auth matrix filtering is on point.Restricting to the supported engines and enforcing an auth provider keeps the validator focused on the combinations we can genuinely verify right now. Looks good.
tests/harness/index.ts (1)
1-7: LGTM: Clean barrel export pattern.The barrel file consolidates test harness utilities into a single entry point, following standard TypeScript conventions.
tests/harness/harness.test.ts (1)
12-24: LGTM: Appropriate smoke tests for harness validation.The test suite correctly validates that the harness exports the expected helpers as functions and that
buildScaffoldArgumentsreturns an array.tests/functional/support/index.ts (1)
1-9: LGTM: Functional support utilities consolidated.Standard barrel export pattern for functional test support modules.
test-cli-project/src/frontend/components/App.tsx (1)
5-52: Component logic is sound.The React component correctly manages state and renders the UI as expected.
tests/harness/cli.ts (1)
11-59: LGTM: Scaffold argument builder is well-structured.The function correctly translates
ScaffoldOptionsinto CLI arguments, handling default values and 'none' options appropriately. The conditional logic aligns with the CLI parser expectations.test-cli-project/src/frontend/components/Head.tsx (1)
1-34: LGTM: Well-structured Head component.The component provides a clean abstraction for HTML head elements with sensible defaults and optional CSS path injection.
tests/harness/http.ts (1)
6-32: LGTM: Robust HTTP polling implementation.The recursive polling approach with async/await is safe from stack overflow, and the error handling correctly allows the server time to boot before succeeding.
| ## Goals | ||
|
|
||
| - Provide a single entry point (`bun run test:cli`) for every validation path (functional harness + behavioural specs). | ||
| - Preserve the stakeholder‑approved experience from the legacy runner: intuitive flags, human friendly progress, concise summary, predictable exit codes. |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Apply hyphen to compound adjective.
Line 6: "human friendly progress" should be "human-friendly progress" to maintain proper grammar for compound modifiers preceding a noun.
Apply this diff:
- Preserve the stakeholder‑approved experience from the legacy runner: intuitive flags, human friendly progress, concise summary, predictable exit codes.
+ Preserve the stakeholder‑approved experience from the legacy runner: intuitive flags, human-friendly progress, concise summary, predictable exit codes.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - Preserve the stakeholder‑approved experience from the legacy runner: intuitive flags, human friendly progress, concise summary, predictable exit codes. | |
| - Preserve the stakeholder‑approved experience from the legacy runner: intuitive flags, human-friendly progress, concise summary, predictable exit codes. |
🧰 Tools
🪛 LanguageTool
[grammar] ~6-~6: Use a hyphen to join words.
Context: ...he legacy runner: intuitive flags, human friendly progress, concise summary, pred...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
In docs/test-cli-ux.md around line 6, the phrase "human friendly progress"
should be corrected to the compound adjective "human-friendly progress"; update
that line to insert the hyphen so the sentence reads "...intuitive flags,
human-friendly progress, concise summary, predictable exit codes."
| ``` | ||
| bun run test:cli [options] | ||
| ``` |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Specify language for fenced code block.
The code block lacks a language identifier, which violates Markdown best practices and prevents proper syntax highlighting.
Apply this diff:
-\`\`\`
+\`\`\`bash
bun run test:cli [options]
-\`\`\`
+\`\`\`🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
45-45: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In docs/test-cli-ux.md around lines 45 to 47, the fenced code block lacks a
language identifier; update the block opener to include a shell language (e.g.,
```bash or ```sh) so the snippet reads as a fenced code block with a language
specifier to enable proper syntax highlighting and adhere to Markdown best
practices.
| const [, , projectPath, packageManagerArg, ...flags] = process.argv; | ||
| const packageManager = (packageManagerArg as 'bun' | 'npm' | 'pnpm' | 'yarn' | undefined) ?? 'bun'; | ||
|
|
||
| const skipDependencies = flags.includes('--skip-deps'); | ||
| const skipBuild = flags.includes('--skip-build'); | ||
| const skipServer = flags.includes('--skip-server'); | ||
|
|
||
| return { | ||
| packageManager, | ||
| projectPath, | ||
| skipBuild, | ||
| skipDependencies, | ||
| skipServer | ||
| } as const; | ||
| }; |
There was a problem hiding this comment.
Guard the optional package-manager argument from CLI flags
Line 90 currently assumes the third CLI argument is always a package manager, so a call such as bun run scripts/functional-tests/htmx-validator.ts ./tmp --skip-deps ends up setting packageManager to "--skip-deps". We then try to spawn that string as the package manager and the validator crashes, even though the usage banner says the package manager is optional. Please treat the third argument as a package manager only when it matches the supported binaries and otherwise push it back into the flags list. Based on PR objectives
Apply this diff to fix the parsing:
-const parseCliArguments = () => {
- const [, , projectPath, packageManagerArg, ...flags] = process.argv;
- const packageManager = (packageManagerArg as 'bun' | 'npm' | 'pnpm' | 'yarn' | undefined) ?? 'bun';
-
- const skipDependencies = flags.includes('--skip-deps');
- const skipBuild = flags.includes('--skip-build');
- const skipServer = flags.includes('--skip-server');
-
- return {
- packageManager,
- projectPath,
- skipBuild,
- skipDependencies,
- skipServer
- } as const;
-};
+const parseCliArguments = () => {
+ const [, , projectPath, packageManagerCandidate, ...flagArgs] = process.argv;
+
+ const isKnownPackageManager = (
+ value: string | undefined
+ ): value is 'bun' | 'npm' | 'pnpm' | 'yarn' =>
+ value === 'bun' || value === 'npm' || value === 'pnpm' || value === 'yarn';
+
+ const flags = [...flagArgs];
+ const packageManager = isKnownPackageManager(packageManagerCandidate) ? packageManagerCandidate : 'bun';
+
+ if (!isKnownPackageManager(packageManagerCandidate) && packageManagerCandidate) {
+ flags.unshift(packageManagerCandidate);
+ }
+
+ const skipDependencies = flags.includes('--skip-deps');
+ const skipBuild = flags.includes('--skip-build');
+ const skipServer = flags.includes('--skip-server');
+
+ return {
+ packageManager,
+ projectPath,
+ skipBuild,
+ skipDependencies,
+ skipServer
+ } as const;
+};🤖 Prompt for AI Agents
In scripts/functional-tests/htmx-validator.ts around lines 90 to 104, the CLI
parsing assumes the third argv entry is always a package manager which allows
flags (e.g. --skip-deps) to be misinterpreted as the package manager; change the
logic to first inspect the third arg and only treat it as packageManager if it
exactly matches one of the supported binaries ('bun','npm','pnpm','yarn'),
otherwise leave packageManager undefined/default to 'bun' and push the original
third arg back into the flags array (so flags includes any provided options),
then compute skipDependencies/skipBuild/skipServer from the corrected flags and
return the typed result as before.
| }, | ||
| image: 'mongo:7.0', | ||
| port: '27017:27017', | ||
| port: '27018:27017', |
There was a problem hiding this comment.
🧩 Analysis chain
Verify connection strings use the updated host ports.
The port mappings correctly avoid conflicts with local database installations by using non-standard host ports (27018 for MongoDB, 5433 for PostgreSQL). The PR objectives mention that generateEnv.ts was updated to reflect these changes.
Verify that all connection strings, environment variables, and test configurations consistently reference the new host ports:
Also applies to: 71-71
🏁 Script executed:
#!/bin/bash
# Description: Verify all MongoDB and PostgreSQL connection references use the new ports.
# Search for hardcoded port references to old ports
echo "=== Checking for hardcoded old port references ==="
rg -n '\b27017\b' --type ts --type js -g '!*.lock*' -C2
rg -n '\b5432\b' --type ts --type js -g '!*.lock*' -C2
# Search for new port references to confirm they're being used
echo "=== Confirming new port references exist ==="
rg -n '\b27018\b' --type ts --type js -g '!*.lock*' -C2
rg -n '\b5433\b' --type ts --type js -g '!*.lock*' -C2
# Check environment generation for port consistency
echo "=== Checking generateEnv.ts for port mappings ==="
fd -e ts -e js 'generateEnv' --exec cat {}Length of output: 5919
Critical port configuration mismatches detected—update these hardcoded connection strings to use the new host ports.
The port mapping changes in generateDockerContainer.ts are correct, and most connection strings have been updated in generateEnv.ts and test configurations. However, three files still contain hardcoded references to the old ports, which will cause connection failures:
src/generators/db/dockerInitTemplates.ts(lines 133-134): MongoDB CLI and wait commands reference old port27017—update both to27018tests/behavioural/database-hooks.ts(line 146): MongoDB connection string uses old port27017—update to27018src/generators/configurations/generateEnv.ts(line 14): PostgreSQL "gel" database URL uses old port5432—update to5433
🤖 Prompt for AI Agents
In src/generators/db/dockerInitTemplates.ts around lines 133-134,
tests/behavioural/database-hooks.ts line 146, and
src/generators/configurations/generateEnv.ts line 14, update the hardcoded DB
ports to match the new Docker mappings: change both MongoDB CLI/wait command
port references from 27017 to 27018 in dockerInitTemplates.ts, change the
MongoDB connection string port from 27017 to 27018 in
tests/behavioural/database-hooks.ts, and change the PostgreSQL "gel" database
URL port from 5432 to 5433 in generateEnv.ts; ensure only the port numbers are
adjusted and connection string syntax remains valid.
| export const getUser = async ({ authProvider, db, userIdentity }: UserHandlerProps) => { | ||
| if (!isValidProviderOption(authProvider)) throw new Error(\`Invalid auth provider: \${authProvider}\`) | ||
| const subject = providers[authProvider].extractSubjectFromIdentity(userIdentity) | ||
| const provider = providers[authProvider as keyof typeof providers] | ||
| const identity = userIdentity as Record<string, unknown> | ||
| const subject = | ||
| (provider as any).extractSubjectFromIdentity?.(identity) ?? | ||
| (identity.sub as string | undefined) ?? | ||
| (identity.id as string | undefined) ?? | ||
| String(identity.sub || identity.id || 'unknown') | ||
| const authSub = \`\${authProvider.toUpperCase()}|\${subject}\` | ||
| ${queries.selectUser} | ||
| } |
There was a problem hiding this comment.
TypeScript typing fix is still incomplete.
The cast to Record<string, unknown> on line 33 does not resolve the TypeScript compilation error flagged in the past review. Record<string, unknown> has an index signature but no explicit sub or id properties, so accessing identity.sub or identity.id with dot notation will still fail tsc.
Use either bracket notation or an intersection type:
Option 1 (bracket notation):
const identity = userIdentity as Record<string, unknown>
const subject =
(provider as any).extractSubjectFromIdentity?.(identity) ??
- (identity.sub as string | undefined) ??
- (identity.id as string | undefined) ??
- String(identity.sub || identity.id || 'unknown')
+ (identity['sub'] as string | undefined) ??
+ (identity['id'] as string | undefined) ??
+ String(identity['sub'] ?? identity['id'] ?? 'unknown')Option 2 (intersection type):
- const identity = userIdentity as Record<string, unknown>
+ const identity = userIdentity as Record<string, unknown> & { sub?: unknown; id?: unknown }
const subject =
(provider as any).extractSubjectFromIdentity?.(identity) ??
(identity.sub as string | undefined) ??
(identity.id as string | undefined) ??
- String(identity.sub || identity.id || 'unknown')
+ String(identity.sub ?? identity.id ?? 'unknown')Also applies to createUser on lines 43-54.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const getUser = async ({ authProvider, db, userIdentity }: UserHandlerProps) => { | |
| if (!isValidProviderOption(authProvider)) throw new Error(\`Invalid auth provider: \${authProvider}\`) | |
| const subject = providers[authProvider].extractSubjectFromIdentity(userIdentity) | |
| const provider = providers[authProvider as keyof typeof providers] | |
| const identity = userIdentity as Record<string, unknown> | |
| const subject = | |
| (provider as any).extractSubjectFromIdentity?.(identity) ?? | |
| (identity.sub as string | undefined) ?? | |
| (identity.id as string | undefined) ?? | |
| String(identity.sub || identity.id || 'unknown') | |
| const authSub = \`\${authProvider.toUpperCase()}|\${subject}\` | |
| ${queries.selectUser} | |
| } | |
| export const getUser = async ({ authProvider, db, userIdentity }: UserHandlerProps) => { | |
| if (!isValidProviderOption(authProvider)) throw new Error(`Invalid auth provider: ${authProvider}`) | |
| const provider = providers[authProvider as keyof typeof providers] | |
| const identity = userIdentity as Record<string, unknown> & { sub?: unknown; id?: unknown } | |
| const subject = | |
| (provider as any).extractSubjectFromIdentity?.(identity) ?? | |
| (identity.sub as string | undefined) ?? | |
| (identity.id as string | undefined) ?? | |
| String(identity.sub ?? identity.id ?? 'unknown') | |
| const authSub = `${authProvider.toUpperCase()}|${subject}` | |
| ${queries.selectUser} | |
| } |
🤖 Prompt for AI Agents
In src/generators/db/handlerTemplates.ts around lines 30 to 41 (and also apply
the same fix to createUser on lines 43 to 54), the current cast to
Record<string, unknown> still triggers TypeScript errors when accessing
identity.sub or identity.id with dot notation; change the typing or access to
satisfy the compiler: either cast identity to an intersection type that includes
optional sub and id properties (e.g., Record<string, unknown> & { sub?: string;
id?: string }) so dot access is valid, or keep Record<string, unknown> but use
safe bracket notation (identity['sub'] / identity['id']) and coerce to string
where needed; apply the same approach in createUser so both handlers compile
cleanly.
| filterMatrix: (config): config is CloudMatrixEntry => | ||
| config.databaseHost !== 'none' && | ||
| SUPPORTED_DATABASE_ENGINES.has(config.databaseEngine) && | ||
| SUPPORTED_ORMS.has(config.orm) && | ||
| SUPPORTED_FRONTENDS.has(config.frontend) && | ||
| config.directoryConfig === 'default', |
There was a problem hiding this comment.
Exclude local hosts from the cloud provider matrix.
Right now filterMatrix only checks that databaseHost !== 'none'. Matrix entries with databaseHost === 'docker' (or other non-cloud hosts) therefore slip through, yet validateCloudProvider only accepts neon, planetscale, or turso. Every such entry fails with Invalid cloud provider: docker, and the type guard claims these configs are CloudMatrixEntry even though the runtime value disagrees. Please tighten the host filter so only the supported cloud hosts make it into this suite.
const SUPPORTED_DATABASE_ENGINES = new Set(['sqlite', 'postgresql']);
const SUPPORTED_ORMS = new Set(['none', 'drizzle']);
const SUPPORTED_FRONTENDS = new Set(['html', 'react', 'vue', 'svelte']);
+const SUPPORTED_DATABASE_HOSTS = new Set(['neon', 'turso']);
...
- filterMatrix: (config): config is CloudMatrixEntry =>
- config.databaseHost !== 'none' &&
+ filterMatrix: (config): config is CloudMatrixEntry =>
+ SUPPORTED_DATABASE_HOSTS.has(config.databaseHost) &&
SUPPORTED_DATABASE_ENGINES.has(config.databaseEngine) &&Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In tests/functional/cloud.test.ts around lines 62–67, the filterMatrix type
guard currently only excludes 'none' hosts, allowing non-cloud hosts like
'docker' to pass and later fail validateCloudProvider; update the predicate so
it only accepts known cloud hosts (e.g. neon, planetscale, turso) by either
checking a SUPPORTED_CLOUD_PROVIDERS set/array or invoking the existing
validateCloudProvider logic in the filter, replacing the databaseHost !== 'none'
check with a membership check
(SUPPORTED_CLOUD_PROVIDERS.has(config.databaseHost) or equivalent) so the guard
accurately reflects CloudMatrixEntry at runtime.
| createProjectName, describeBlock: 'MongoDB database matrix', describeConfig, beforeValidate: async ({ config, projectPath }) => { | ||
| await runFunctionalSuite(projectPath); | ||
|
|
||
| if (config.databaseHost === 'none') { | ||
| const dockerStatus = ensureDockerAvailable(); | ||
|
|
||
| if (!dockerStatus.available) { | ||
| throw new Error(`Docker unavailable: ${dockerStatus.message}`); | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove redundant Docker availability check.
The beforeValidate hook checks Docker availability and throws if unavailable, but validateMongoDBDatabase already handles Docker unavailability gracefully by detecting the condition and returning warnings instead of errors (see mongodb-validator.ts lines 195-200 and handleDockerUnavailable). This redundant check prevents the validator from applying its own detection logic and causes unnecessary test failures in environments where Docker is unavailable.
Remove the Docker check from beforeValidate:
beforeValidate: async ({ config, projectPath }) => {
await runFunctionalSuite(projectPath);
-
- if (config.databaseHost === 'none') {
- const dockerStatus = ensureDockerAvailable();
-
- if (!dockerStatus.available) {
- throw new Error(`Docker unavailable: ${dockerStatus.message}`);
- }
- }
},🤖 Prompt for AI Agents
In tests/functional/databases/mongodb.test.ts around lines 72 to 81, remove the
redundant Docker availability check inside the beforeValidate hook: delete the
conditional block that calls ensureDockerAvailable() and throws when
dockerStatus.available is false (the if (config.databaseHost === 'none') { ... }
block), leaving only the await runFunctionalSuite(projectPath); so that
validateMongoDBDatabase can handle Docker-unavailable cases and emit warnings
instead of forcing test failures.
| }), filterMatrix: (config): config is HtmxMatrixEntry => | ||
| config.frontend === 'htmx' && | ||
| config.directoryConfig === 'default' && | ||
| SUPPORTED_DATABASE_ENGINES.has(config.databaseEngine) && | ||
| SUPPORTED_ORMS.has(config.orm), validate: async ({ config, projectPath }) => { |
There was a problem hiding this comment.
Exclude unsupported Drizzle/MongoDB combinations.
The current filter lets databaseEngine === 'mongodb' pair with orm === 'drizzle'. Our scaffolder immediately throws (isDrizzleDialect rejects MongoDB), so every such matrix entry fails before validation begins. Tighten the predicate so Drizzle only runs with the supported SQL engine (sqlite in this filtered set).
Apply this diff to fix the issue:
- SUPPORTED_DATABASE_ENGINES.has(config.databaseEngine) &&
- SUPPORTED_ORMS.has(config.orm), validate: async ({ config, projectPath }) => {
+ SUPPORTED_DATABASE_ENGINES.has(config.databaseEngine) &&
+ SUPPORTED_ORMS.has(config.orm) &&
+ (config.orm !== 'drizzle' || config.databaseEngine === 'sqlite'), validate: async ({ config, projectPath }) => {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| }), filterMatrix: (config): config is HtmxMatrixEntry => | |
| config.frontend === 'htmx' && | |
| config.directoryConfig === 'default' && | |
| SUPPORTED_DATABASE_ENGINES.has(config.databaseEngine) && | |
| SUPPORTED_ORMS.has(config.orm), validate: async ({ config, projectPath }) => { | |
| }), filterMatrix: (config): config is HtmxMatrixEntry => | |
| config.frontend === 'htmx' && | |
| config.directoryConfig === 'default' && | |
| SUPPORTED_DATABASE_ENGINES.has(config.databaseEngine) && | |
| SUPPORTED_ORMS.has(config.orm) && | |
| (config.orm !== 'drizzle' || config.databaseEngine === 'sqlite'), validate: async ({ config, projectPath }) => { |
🤖 Prompt for AI Agents
In tests/functional/frameworks/htmx.test.ts around lines 58 to 62, the
filterMatrix predicate currently allows orm === 'drizzle' to pair with
databaseEngine === 'mongodb', which the scaffolder rejects; tighten the
predicate so Drizzle only runs with the supported SQL engine by adding a clause
that excludes Drizzle+MongoDB combos (e.g. require config.orm !== 'drizzle' ||
config.databaseEngine === 'sqlite' or explicitly disallow config.orm ===
'drizzle' && config.databaseEngine === 'mongodb'), ensuring the filter only
yields valid matrix entries.
| const [exitCode] = (await once(child, 'close')) as [number | null]; | ||
| clearTimeout(timeoutHandle); |
There was a problem hiding this comment.
Handle child-process spawn errors to avoid hangs.
When spawn fails before the process starts (missing executable, permission issues, etc.), Node emits an 'error' event without ever firing 'close'. Because we only await 'close', runCommand never resolves and the harness deadlocks. Please race the 'close' event with 'error' and clear the timeout in both paths.
- const [exitCode] = (await once(child, 'close')) as [number | null];
- clearTimeout(timeoutHandle);
+ const closePromise = once(child, 'close') as Promise<[number | null, NodeJS.Signals | null]>;
+ const errorPromise = once(child, 'error').then((error) => {
+ throw error;
+ });
+
+ let exitCode: number | null = null;
+ try {
+ [exitCode] = await Promise.race([closePromise, errorPromise]);
+ } finally {
+ clearTimeout(timeoutHandle);
+ }🤖 Prompt for AI Agents
In tests/harness/process.ts around lines 45-46, the current await only listens
for the child's 'close' event so if spawn emits an 'error' (e.g., missing
executable) the promise never resolves and the test harness hangs; update the
logic to race/listen for both 'close' and 'error' (e.g., Promise.race or once
for both events), handle the 'error' path by rejecting or returning an
appropriate non-null exit/error result, and ensure clearTimeout(timeoutHandle)
is called in both the 'close' and 'error' handlers so the timeout is always
cleared.
| const child = spawn(command[0], command.slice(1), { | ||
| cwd: projectPath, | ||
| env: childEnv, | ||
| stdio: [ | ||
| 'ignore', | ||
| options.forwardStdout ? 'inherit' : 'pipe', | ||
| options.forwardStderr ? 'inherit' : 'pipe' | ||
| ] | ||
| }); | ||
|
|
||
| let exited = false; | ||
| let exitCode: number | null = null; | ||
|
|
||
| const exitWatcher = once(child, 'exit').then(([code, signal]) => { | ||
| exited = true; | ||
| exitCode = code ?? 0; | ||
|
|
||
| if (!options.forwardStdout && child.stdout) { | ||
| child.stdout.removeAllListeners('data'); | ||
| } | ||
| if (!options.forwardStderr && child.stderr) { | ||
| child.stderr.removeAllListeners('data'); | ||
| } | ||
|
|
||
| const terminatedBySignal = | ||
| typeof signal === 'string' && signal.length > 0; | ||
|
|
||
| if (!terminatedBySignal && exitCode !== 0) { | ||
| console.warn(`Server process exited prematurely with code ${code}`); | ||
| } | ||
|
|
||
| return exitCode ?? 0; | ||
| }); | ||
|
|
||
| if (!options.forwardStdout && child.stdout) { | ||
| child.stdout.on('data', (chunk: Buffer) => { | ||
| const text = chunk.toString(); | ||
| stdoutBuffer.push(text); | ||
| if (captureOutput) { | ||
| process.stdout.write(text); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| if (!options.forwardStderr && child.stderr) { | ||
| child.stderr.on('data', (chunk: Buffer) => { | ||
| const text = chunk.toString(); | ||
| stderrBuffer.push(text); | ||
| if (captureOutput) { | ||
| process.stderr.write(text); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| const buildDiagnosticMessage = (base: string, cause?: unknown) => { | ||
| const tail = (lines: string[], maxLines: number) => | ||
| lines.join('').split('\n').filter(Boolean).slice(-maxLines).join('\n'); | ||
|
|
||
| const stdoutTail = tail(stdoutBuffer, OUTPUT_TAIL_LINES); | ||
| const stderrTail = tail(stderrBuffer, OUTPUT_TAIL_LINES); | ||
|
|
||
| const details: string[] = [base]; | ||
|
|
||
| if (stdoutTail.length > 0) { | ||
| details.push(`stdout:\n${stdoutTail}`); | ||
| } | ||
|
|
||
| if (stderrTail.length > 0) { | ||
| details.push(`stderr:\n${stderrTail}`); | ||
| } | ||
|
|
||
| if (cause) { | ||
| const message = cause instanceof Error ? cause.message : String(cause); | ||
| details.push(`cause: ${message}`); | ||
| } | ||
|
|
||
| return details.join('\n\n'); | ||
| }; | ||
|
|
||
| try { | ||
| await waitForHttpOk(readyUrl, readyTimeoutMs); | ||
| } catch (error) { | ||
| child.kill('SIGTERM'); | ||
| await exitWatcher; | ||
| if (exitCode && exitCode !== 0) { | ||
| throw new Error( | ||
| buildDiagnosticMessage( | ||
| `Server process exited with code ${exitCode} while waiting for readiness (${readyUrl}).`, | ||
| error | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| throw new Error( | ||
| buildDiagnosticMessage( | ||
| `Server did not become ready within ${readyTimeoutMs}ms (${readyUrl}).`, | ||
| error | ||
| ) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Handle spawn failures so the harness doesn’t crash.
Line 39 spawns the dev server without attaching an 'error' listener. When the executable is missing (e.g., bun not installed) or cannot start, Node emits an 'error' event; without a listener the process throws and the entire test harness crashes before we can surface diagnostics. We need to race readiness with that 'error' event and convert it into a controlled failure, while avoiding SIGTERM/exitWatcher waits when the child never spawned.
@@
- const exitWatcher = once(child, 'exit').then(([code, signal]) => {
+ const exitWatcher = once(child, 'exit').then(([code, signal]) => {
exited = true;
exitCode = code ?? 0;
@@
- try {
- await waitForHttpOk(readyUrl, readyTimeoutMs);
+ const spawnErrorWatcher = once(child, 'error');
+
+ try {
+ await Promise.race([
+ waitForHttpOk(readyUrl, readyTimeoutMs),
+ spawnErrorWatcher
+ ]);
} catch (error) {
- child.kill('SIGTERM');
- await exitWatcher;
- if (exitCode && exitCode !== 0) {
- throw new Error(
- buildDiagnosticMessage(
- `Server process exited with code ${exitCode} while waiting for readiness (${readyUrl}).`,
- error
- )
- );
- }
-
- throw new Error(
- buildDiagnosticMessage(
- `Server did not become ready within ${readyTimeoutMs}ms (${readyUrl}).`,
- error
- )
- );
+ const processStarted = typeof child.pid === 'number' && child.pid > 0;
+
+ if (processStarted && !exited) {
+ child.kill('SIGTERM');
+ await Promise.race([exitWatcher, delay(STOP_TIMEOUT_MS)]);
+
+ if (!exited) {
+ child.kill('SIGKILL');
+ await exitWatcher.catch(() => undefined);
+ }
+ }
+
+ if (exitCode !== null && exitCode !== 0) {
+ throw new Error(
+ buildDiagnosticMessage(
+ `Server process exited with code ${exitCode} while waiting for readiness (${readyUrl}).`,
+ error
+ )
+ );
+ }
+
+ throw new Error(
+ buildDiagnosticMessage(
+ processStarted
+ ? `Server did not become ready within ${readyTimeoutMs}ms (${readyUrl}).`
+ : `Failed to start server process (${command.join(' ')})`,
+ error
+ )
+ );
}Committable suggestion skipped: line range outside the PR's diff.
…skips in functional framework runner
- Simplify cloud env var names (NEON_DATABASE_URL, TURSO_DB_URL) - Broaden auth filter to include postgresql for proper matrix skip handling - Expand auth behavioural coverage to Vue and Svelte frontends - Document functional vs behavioural env var behavior in guide
Fixed all remaining ESLint violations to achieve zero-error lint status: ESLint Fixes: - Remove unused 'config' parameter from isValidMatrixConfig in matrix.ts - Remove explicit return type annotations to rely on TypeScript inference - extractProvidersArray, getRedirectWarning, buildAuthConfig in generateUseBlock.ts - annotateMatrixEntry in matrix.ts - Flatten deeply nested blocks to comply with max-depth-extended rule - Extract writeTsconfigFile helper in scaffoldConfigurationFiles.ts - Simplify PostgreSQL imports logic in generateImportsBlock.ts - Extract processFrontend helper in frontendDirectoryConfigurations.ts - Flatten --skip section conditionals in parseCommandLineOptions.ts - Simplify environment variable check in test-utils.ts Test Cleanup: - Remove test-cli-project directory and all generated artifacts - Clean up behavioural test temporary directories - Remove test-auth-* project directories from functional testing All changes maintain existing functionality while improving code quality. Verified with: bun lint (zero errors), bun test ./tests/harness/harness.test.ts (passing)
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (3)
docs/test-cli-ux.md (2)
6-6: Fix compound adjective with hyphen.This was already flagged in a prior review: the phrase "human friendly progress" should be "human-friendly progress" to properly form the compound adjective.
Apply this diff:
-Preserve the stakeholder‑approved experience from the legacy runner: intuitive flags, human friendly progress, concise summary, predictable exit codes. +Preserve the stakeholder‑approved experience from the legacy runner: intuitive flags, human-friendly progress, concise summary, predictable exit codes.
64-66: Add language identifier to fenced code block.This was already flagged in a prior review: the fenced code block lacks a language specifier for syntax highlighting.
Apply this diff:
-\`\`\` +\`\`\`bash bun run test:cli [options] -\`\`\` +\`\`\`src/generators/project/generateUseBlock.ts (1)
49-51: FixgetUserargument shape and reconsider broad callback castingTwo concerns in the callback construction:
Inconsistent
userIdentityproperty name
Previously, bothcreateUserandgetUserwere called with{ userIdentity }. The new code keepscreateUser({ …, userIdentity })but changesgetUsertogetUser({ authProvider, db, user_identity: userIdentity }). UnlessgetUser’s signature was explicitly changed to expectuser_identity, this is likely a breaking change and will passundefinedinto the handler.Suggested fix to keep the handlers consistent:
createUser: (userIdentity: Record<string, unknown>) => createUser({ authProvider, db, userIdentity }), getUser: (userIdentity: Record<string, unknown>) => getUser({ authProvider, db, user_identity: userIdentity }) } as Record<string, unknown>)`
createUser: (userIdentity: Record<string, unknown>) => createUser({ authProvider, db, userIdentity }), getUser: (userIdentity: Record<string, unknown>) => getUser({ authProvider, db, userIdentity }) } as Record<string, unknown>)`
Outer
as Record<string, unknown>cast on the callback
mergedConfigwraps the whole function inas Record<string, unknown>:onCallbackSuccess: (${callback}) as Record<string, unknown>This largely sidesteps the function’s actual type, similar to the earlier concern about heavy
anyusage in this callback. IfabsoluteAuthexposes a concrete callback type, prefer casting to that or letting inference work instead of forcing a generic record type.A lighter option (if types permit) would be to drop the outer cast:
- mergedConfig +=
${routesString} onCallbackSuccess: (${callback}) as Record<string, unknown> ${redirectWarning} };
- mergedConfig +=
${routesString} onCallbackSuccess: (${callback})${redirectWarning} };To double‑check the handler contract, you can search how `getUser` is declared: ```shell #!/bin/bash # Inspect getUser/createUser handler signatures to confirm expected payload keys. rg -n "function getUser|const getUser|export const getUser" -C3 rg -n "function createUser|const createUser|export const createUser" -C3Also applies to: 63-63
🧹 Nitpick comments (10)
docs/test-cli-ux.md (1)
26-35: Replace hard tabs with spaces for list indentation.The nested list items (lines 29, 31, 33) use hard tabs for indentation; Markdown linting requires 2 spaces per nesting level.
Apply this diff:
Usage: -- Dry run (list directories found): - - `bash scripts/clean-tests.sh` +- Dry run (list directories found): + - `bash scripts/clean-tests.sh` - Delete test projects (standard): - - `bash scripts/clean-tests.sh --confirm` + - `bash scripts/clean-tests.sh --confirm` - Full cleanup (also removes `.test-dependency-cache`): - - `bash scripts/clean-tests.sh --full --confirm` + - `bash scripts/clean-tests.sh --full --confirm`scripts/clean-tests.sh (1)
35-35: Note potential portability limitation withfind -printfon BSD/macOS.The
find -printf '%f\n'option is a GNU find extension and may not be available on macOS (BSD find). While the|| truefallback prevents script failure,TEST_DIRSwould be empty unexpectedly on systems without GNU find, silently skipping the cleanup. If macOS support is required, consider using a more portable approach.For portability, consider:
# Option 1: Use -print with basename extraction (more portable) mapfile -t TEST_DIRS < <(find "$ROOT_DIR" -maxdepth 1 -type d -name 'test-*' ! -name 'test-cli-project' -print | xargs -I {} basename {} || true) # Option 2: Use find with -type d and -exec basename mapfile -t TEST_DIRS < <(find "$ROOT_DIR" -maxdepth 1 -type d -name 'test-*' ! -name 'test-cli-project' -exec basename {} \;)src/generators/configurations/scaffoldConfigurationFiles.ts (1)
47-67: Refactor to eliminate code duplication in directory creation and file writing.Lines 58-59 and 65-66 duplicate the
mkdirSyncandwriteFileSynccalls. The early return at line 61 forces this repetition, but the operations are identical in both branches.Apply this diff to consolidate the duplicated logic:
const writeTsconfigFile = () => { const tsconfigContent = readFileSync(tsconfigTemplatePath, 'utf-8'); const tsconfig = JSON.parse(tsconfigContent); if (!tsconfig.compilerOptions) { tsconfig.compilerOptions = {}; } const jsxOption = getJsxOption(); - if (!jsxOption) { + if (jsxOption) { + tsconfig.compilerOptions.jsx = jsxOption; + } else { delete tsconfig.compilerOptions.jsx; - mkdirSync(projectName, { recursive: true }); - writeFileSync(tsconfigTargetPath, `${JSON.stringify(tsconfig, null, 2)}\n`); - - return; } - tsconfig.compilerOptions.jsx = jsxOption; mkdirSync(projectName, { recursive: true }); writeFileSync(tsconfigTargetPath, `${JSON.stringify(tsconfig, null, 2)}\n`); };eslint.config.mjs (1)
223-231: Configuration for test files looks good.The test-specific block correctly:
- Overrides browser globals with Node globals for the test environment
- Disables
import/no-unused-modulesfor test utilities- Relies on earlier TypeScript parser configuration (which will merge correctly in flat config)
Consider also relaxing
no-magic-numbersfor test files, as tests commonly use literal values for test data and assertions:{ files: ['tests/**/*.{ts,tsx}'], languageOptions: { globals: globals.node }, rules: { - 'import/no-unused-modules': 'off' + 'import/no-unused-modules': 'off', + 'no-magic-numbers': 'off' } },This mirrors the existing override for configuration files (lines 184-194).
tests/behavioural/database-matrix.ts (1)
39-74: Env merge and options construction are correct; consider tightening baseOptions typingThe env merge and override order (
baseOptions→ per‑scenariooptions→ fixeddatabase/frontend→ optionalorm) look correct and predictable, and only attachingoptions.envwhen there’s at least one key avoids spurious empty env blocks.One optional refinement:
baseOptionscurrently allowsfrontend(but it’s always overridden byconfig.frontend). To avoid any confusion for callers, you could excludefrontendthere as well:- baseOptions?: Partial<Omit<BehaviouralScenario['options'], 'database'>>; + baseOptions?: Partial< + Omit<BehaviouralScenario['options'], 'database' | 'frontend'> + >;Not mandatory, but it would better express the actual behavior of
buildScenario.src/generators/project/generateImportsBlock.ts (2)
163-168: Consider adding explicit validation for remote PostgreSQL host.The code safely handles invalid
databaseHostvalues with the conditional check at line 166, but silently skipping imports could mask configuration errors. Since PostgreSQL remote hosting is effectively limited to Neon in the currentconnectorImportsmap, consider adding an explicit type constraint or runtime assertion to ensuredatabaseHostis 'neon' in this path.Example:
if (shouldAddPostgresqlImports && isRemoteHost) { - const connectorKey = databaseHost; + if (databaseHost !== 'neon') { + throw new Error(`Unsupported PostgreSQL remote host: ${databaseHost}`); + } + const connectorKey = databaseHost as 'neon'; const connectorImportsList = connectorImports[connectorKey]; if (connectorImportsList) rawImports.push(...connectorImportsList); rawImports.push(`import { getEnv } from '@absolutejs/absolute'`); }
216-231: EnhanceparseImportClauseto handle mixed default and named imports.The current implementation assumes import clauses are either default-only or named-only, but doesn't handle the mixed pattern (e.g.,
React, { useState }). While the existing code doesn't generate mixed imports, this is a latent bug that could surface if the import generation logic changes.Apply this diff to handle mixed imports:
const parseImportClause = ( importClause: string, entry: { defaultImport: string | null; namedImports: Set<string> } ) => { - if (importClause.startsWith('{')) { + const parts = importClause.split(',').map((s) => s.trim()); + + for (const part of parts) { + if (part.startsWith('{')) { + // Named imports - importClause - .slice(1, -1) + part + .slice(1, part.endsWith('}') ? -1 : part.length) .split(',') .map((segment) => segment.trim()) .filter(Boolean) .forEach((name) => entry.namedImports.add(name)); - } else { + } else if (!part.endsWith('}')) { + // Default import - entry.defaultImport = importClause.trim(); + entry.defaultImport = part; + } } };docs/cloud-auth-test-verification.md (1)
26-45: Add language specifications to code blocks for better readability.The code blocks at lines 26-29, 32-34, 37-39, and 42-45 lack language specifications. Adding
bashorshellidentifiers will enable syntax highlighting.Apply this pattern to the affected blocks:
-``` +```bash bun run typecheck npm run lint</blockquote></details> <details> <summary>src/commands/initializeGit.ts (1)</summary><blockquote> `21-27`: **Stop the spinner before calling checkGitInstalled().** The spinner "Checking git availability..." continues running while `checkGitInstalled()` may display interactive prompts and start its own spinners for package installation. This creates overlapping UI elements and confusing UX. Apply this diff to stop the spinner before the interactive check: ```diff - spin.start('Checking git availability...'); + spin.start('Checking git availability...'); const isGitInstalled = await checkGitInstalled(); + spin.stop(); if (!isGitInstalled) { - spin.stop(red('Git is not installed. Please install git before proceeding.'), 1); + console.log(red('✖ Git is not installed. Please install git before proceeding.')); abort(); }Alternatively, remove the spinner entirely since
checkGitInstalled()manages its own progress indicators:- spin.start('Checking git availability...'); const isGitInstalled = await checkGitInstalled(); if (!isGitInstalled) { - spin.stop(red('Git is not installed. Please install git before proceeding.'), 1); + console.log(red('✖ Git is not installed. Please install git before proceeding.')); abort(); }src/questions/frontendDirectoryConfigurations.ts (1)
55-91: Logic is correct with minor harmless redundancy.The
processFrontendhelper properly implements the custom directory flow: prefilled values are used directly, custom configurations trigger prompts, and defaults are applied otherwise.Note: Line 88 passes
passedFrontendDirectories?.[name], but this will always beundefinedfor items infrontendsToPrompt(since prefilled values are filtered out earlier). This redundancy is harmless asgetDirectoryForFrontendalready handles undefinedprovidedValue.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
docs/cloud-auth-test-verification.md(1 hunks)docs/test-cli-ux.md(1 hunks)eslint.config.mjs(2 hunks)package.json(1 hunks)scripts/clean-tests.sh(1 hunks)scripts/functional-tests/matrix.ts(1 hunks)src/commands/formatProject.ts(2 hunks)src/commands/initializeGit.ts(1 hunks)src/data.ts(2 hunks)src/generators/configurations/generatePackageJson.ts(4 hunks)src/generators/configurations/scaffoldConfigurationFiles.ts(3 hunks)src/generators/db/generateHandlers.ts(2 hunks)src/generators/project/generateImportsBlock.ts(4 hunks)src/generators/project/generateServer.ts(3 hunks)src/generators/project/generateUseBlock.ts(2 hunks)src/questions/directoryConfiguration.ts(1 hunks)src/questions/frontendDirectoryConfigurations.ts(3 hunks)src/utils/checkGitInstalled.ts(1 hunks)src/utils/parseCommandLineOptions.ts(2 hunks)tests/behavioural/auth-matrix.test.ts(1 hunks)tests/behavioural/cloud-matrix.test.ts(1 hunks)tests/behavioural/database-matrix-definitions.ts(1 hunks)tests/behavioural/database-matrix.test.ts(1 hunks)tests/behavioural/database-matrix.ts(1 hunks)tests/behavioural/utils.ts(1 hunks)tests/functional/auth.test.ts(1 hunks)tests/functional/frameworks/test-utils.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
- package.json
- tests/behavioural/auth-matrix.test.ts
- src/commands/formatProject.ts
- tests/functional/frameworks/test-utils.ts
- src/utils/parseCommandLineOptions.ts
- tests/behavioural/cloud-matrix.test.ts
- tests/behavioural/database-matrix-definitions.ts
- src/generators/project/generateServer.ts
- tests/behavioural/utils.ts
- src/generators/db/generateHandlers.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-23T22:49:50.485Z
Learnt from: absolutejs
Repo: absolutejs/create-absolutejs PR: 15
File: src/data.ts:138-156
Timestamp: 2025-11-23T22:49:50.485Z
Learning: In the create-absolutejs repository, React-specific ESLint plugins (eslint-plugin-jsx-a11y, eslint-plugin-react, eslint-plugin-react-compiler, eslint-plugin-react-hooks) should only be installed conditionally when the project uses React (flags.requiresReact is true), not for all projects using eslint+prettier.
Applied to files:
eslint.config.mjs
🧬 Code graph analysis (9)
src/utils/checkGitInstalled.ts (2)
src/utils/checkDockerInstalled.ts (6)
$(114-134)commandExists(80-112)commandExists(136-190)spin(71-78)cmd(21-25)env(9-10)src/utils/checkSqliteInstalled.ts (2)
hasSqlite(137-159)hasSqlite(112-117)
src/questions/directoryConfiguration.ts (2)
src/prompt.ts (1)
argumentConfiguration(18-123)src/questions/configurationType.ts (1)
directoryConfig(5-16)
src/generators/project/generateUseBlock.ts (1)
src/types.ts (1)
ORM(52-52)
src/generators/configurations/generatePackageJson.ts (1)
src/data.ts (2)
prismaRuntimeDependencies(140-149)prismaDevDependencies(151-156)
src/data.ts (2)
src/types.ts (1)
AvailableDependency(31-36)src/generators/project/collectDependencies.ts (2)
dependency(39-39)CollectDependenciesProps(17-48)
src/generators/configurations/scaffoldConfigurationFiles.ts (3)
src/generators/project/scaffoldFrontends.ts (1)
ScaffoldFrontendsProps(19-106)src/generators/project/generateRoutesBlock.ts (1)
frontend(20-70)src/generators/vue/generateVuePage.ts (1)
frontends(4-269)
tests/functional/auth.test.ts (3)
scripts/functional-tests/matrix.ts (1)
MatrixConfig(33-46)tests/functional/frameworks/test-utils.ts (1)
runMatrixSuite(183-183)scripts/functional-tests/auth-validator.ts (1)
validateAuthConfiguration(61-95)
tests/behavioural/database-matrix.test.ts (3)
tests/behavioural/database-matrix-definitions.ts (1)
DATABASE_MATRIX_DEFINITIONS(17-62)tests/behavioural/database-matrix.ts (1)
describeDatabaseMatrix(76-99)src/generators/db/generateDrizzleSchema.ts (1)
GenerateSchemaProps(66-163)
src/commands/initializeGit.ts (3)
src/utils/checkGitInstalled.ts (1)
checkGitInstalled(261-301)src/utils/abort.ts (1)
abort(5-8)src/questions/initializeGitNow.ts (1)
initializeGitNow(4-11)
🪛 LanguageTool
docs/test-cli-ux.md
[grammar] ~6-~6: Use a hyphen to join words.
Context: ...he legacy runner: intuitive flags, human friendly progress, concise summary, pred...
(QB_NEW_EN_HYPHEN)
🪛 markdownlint-cli2 (0.18.1)
docs/cloud-auth-test-verification.md
26-26: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
32-32: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
37-37: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
42-42: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/test-cli-ux.md
29-29: Unordered list indentation
Expected: 2; Actual: 1
(MD007, ul-indent)
29-29: Hard tabs
Column: 1
(MD010, no-hard-tabs)
31-31: Unordered list indentation
Expected: 2; Actual: 1
(MD007, ul-indent)
31-31: Hard tabs
Column: 1
(MD010, no-hard-tabs)
33-33: Unordered list indentation
Expected: 2; Actual: 1
(MD007, ul-indent)
33-33: Hard tabs
Column: 1
(MD010, no-hard-tabs)
64-64: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 Shellcheck (0.11.0)
scripts/clean-tests.sh
[warning] 52-52: Use "${var:?}" to ensure this never expands to / .
(SC2115)
🔇 Additional comments (33)
docs/test-cli-ux.md (1)
1-117: Excellent documentation structure and content clarity.The specification comprehensively covers the Test CLI UX with well-organized sections, clear tables, and actionable command examples. The suite taxonomy, execution semantics, and behavioral integration details are all clearly explained. Once the formatting issues above are resolved, this will serve as strong reference documentation for developers and CI workflows.
scripts/clean-tests.sh (1)
4-68: Solid cleanup utility with clear dry-run safety and modular flags.The overall design is well-structured: argument parsing is explicit, the dry-run default prevents accidental deletion, and separation of test-directory cleanup from cache cleanup allows flexible workflows. The conditional logic correctly enforces
--confirmfor destructive operations and handles edge cases (e.g., no test dirs but cache removal still allowed in full mode).src/generators/configurations/scaffoldConfigurationFiles.ts (1)
119-130: LGTM! Vue type declarations properly implemented.The directory is created with
{ recursive: true }before writing the Vue shim file, eliminating the ENOENT risk flagged in the previous review. The module declaration correctly types.vuefile imports for TypeScript.eslint.config.mjs (1)
19-19: LGTM!Adding
test-cli-project/**to the ignore list is appropriate for excluding scaffolded test projects from linting, consistent with the existingabsolutejs-project/**pattern.tests/behavioural/database-matrix.test.ts (1)
1-4: Simple, correct wiring for database behavioural matrixThe test file cleanly delegates all behavior to
describeDatabaseMatrixfor each entry inDATABASE_MATRIX_DEFINITIONS; registration is synchronous and top-level, which is whatbun:testexpects. No issues here.tests/behavioural/database-matrix.ts (2)
5-25: Type-driven matrix definition looks solid and future‑proofDeriving
Frontend,Orm, andDatabaseEnginefromBehaviouralScenario['options']keeps the matrix types in sync with the underlying scenario options, andScenarioConfig/DatabaseMatrixDefinitiongive a clear, constrained shape for callers. This is a good balance between flexibility (partial options) and type safety.
76-99: Remove review comment; auth and cloud matrices don't follow the database-matrix filtering pattern.The review assumes other behavioural matrices (auth/cloud) use similar
ABSOLUTE_BEHAVIOURAL_*_FILTERenv var patterns. Verification shows this is not the case:auth-matrix.test.tsuses hardcoded scenarios with direct describe/it calls, whilecloud-matrix.test.tsuses arequiredEnvmapping pattern for environment variables. Onlydatabase-matrix.tsimplements the filtering approach. No consistency issue exists because the implementation patterns are fundamentally different across these test files. Additionally, no documentation references theABSOLUTE_BEHAVIOURAL_DATABASE_FILTERenv var.Likely an incorrect or invalid review comment.
src/generators/project/generateImportsBlock.ts (3)
82-92: LGTM! Dynamic Neon import resolution is correct.The function correctly returns Pool imports for Drizzle ORM and neon imports for no-ORM scenarios. The logic properly ensures that the appropriate import is selected based on the ORM value, and since the mutually exclusive execution paths (Drizzle at line 110 vs. no-ORM at line 163) consume this value appropriately, the behavior is sound.
170-175: LGTM! MongoDB no-ORM imports are correct.The explicit import of
MongoClientandgetEnvfor no-ORM MongoDB paths is appropriate and aligns with the broader pattern of ORM-aware import resolution in this PR.
238-251: LGTM! Import consolidation logic is clean and correct.The refactoring to use
parseImportClauseconsolidates duplicate imports effectively (leveraging Set for deduplication), and the overall flow is more maintainable than inline parsing.scripts/functional-tests/matrix.ts (3)
70-96: LGTM!The host constraint annotation logic correctly handles environment variable requirements for cloud providers and appropriately skips PlanetScale flows per the documented test strategy.
124-146: LGTM!The matrix creation using reduce/flatMap correctly generates the cartesian product of all configuration dimensions, and the file I/O operations are implemented appropriately.
27-31: No changes needed—the code is accurate.PlanetScale supports both PostgreSQL and MySQL. PlanetScale offers a managed PostgreSQL product called "PlanetScale for Postgres" (GA announced July 1, 2025), making the HOST_CONSTRAINTS declaration on line 29 correct.
Likely an incorrect or invalid review comment.
tests/functional/auth.test.ts (3)
5-10: LGTM!The type definition appropriately extends
MatrixConfigto ensureauthProvideris required anddirectoryConfigis locked to 'default'. The limited database engine support aligns with the documented test scope.
12-37: LGTM!The helper functions correctly transform matrix configurations into project names and test descriptions. The sanitization in
createProjectName(lines 17-19) properly handles special characters.
39-85: LGTM!The matrix suite configuration correctly maps configurations to scaffold options, applies appropriate filters for auth-enabled scenarios, and integrates with the auth validator. The hardcoded 'bun' package manager (line 69) is acceptable for this test suite scope.
src/data.ts (1)
90-99: LGTM!The GitHub credentials configuration structure is appropriate for scaffolding templates, with clear placeholder values for test purposes.
src/generators/configurations/generatePackageJson.ts (2)
10-12: LGTM!The new Prisma dependency imports are correctly added and align with the exports from
src/data.ts.
153-154: LGTM!The clarifying comment accurately describes the purpose of the cloud provider dependencies.
src/utils/checkGitInstalled.ts (6)
1-31: LGTM: Environment detection is comprehensive.The platform detection logic correctly handles Windows, macOS, WSL, and Linux environments. The isWSL check covers both WSL_DISTRO_NAME and kernel release patterns.
33-55: LGTM: Helper functions follow established patterns.The implementation matches the patterns used in similar utilities like
checkDockerInstalled.tsandcheckSqliteInstalled.ts.
63-148: LGTM: Package manager installers are well-structured.All installers follow a consistent pattern with appropriate non-interactive flags. The use of
DEBIAN_FRONTEND=noninteractivefor apt is correct.
156-186: LGTM: Platform-specific installers handle their constraints appropriately.The macOS installer correctly omits
sudofor Homebrew. The Windows installer reasonably directs users to manual installation rather than attempting automated installation with winget/choco.
194-244: LGTM: Platform wrappers prioritize package managers appropriately.The fallback sequence makes sense: apt (most common), yum, dnf, pacman. Manual installation guidance is clear.
251-252: LGTM: Git detection is straightforward and correct.src/commands/initializeGit.ts (3)
4-5: LGTM: New imports support the Git availability check.
7-16: LGTM: Good refactor extracting initialization logic.The helper function improves code organization and makes the main flow easier to follow.
29-34: LGTM: Error handling for repository initialization is appropriate.src/generators/project/generateUseBlock.ts (3)
3-31: Auth config helpers are defensive and read clearly
extractProvidersArrayandgetRedirectWarningsafely handle missing/ill‑shapedprovidersConfiguration, defaulting to[]and omitting the warning rather than throwing. That’s appropriate for generator code that must not crash on partially specified configs.
65-68: Authusechain and providers/session routes look consistentThe
.use(absoluteAuth…)chain with the/auth/providersand/auth/sessionroutes is built in one place now, and the providers route correctly reuses the derivedprovidersArray(or[]when unspecified). This centralization should make future auth route tweaks easier.
87-89: Delegating auth plugin handling tobuildAuthConfigsimplifiesgenerateUseBlockConditionally routing
absoluteAuththroughbuildAuthConfig(pluginImport, databaseEngine, orm)keeps the maingenerateUseBlockflow straightforward while leaving other plugins’ behavior unchanged. This refactor improves readability without altering external behavior.src/questions/frontendDirectoryConfigurations.ts (2)
1-2: LGTM!The
processimport is correctly added to support non-interactive environment detection.
12-44: Well-designed non-interactive handling!The function correctly prioritizes provided values, detects non-interactive environments to prevent hangs, and only prompts when running interactively. The TTY checks are comprehensive.
| for d in "${TEST_DIRS[@]}"; do | ||
| echo "Removing: $d" | ||
| rm -rf "$ROOT_DIR/$d" | ||
| done | ||
| fi |
There was a problem hiding this comment.
Use parameter expansion to guard against unsafe rm -rf expansion.
Line 52 uses variables in a destructive rm -rf operation without the Bash best practice of parameter expansion checks. While $ROOT_DIR is set to $(pwd) and $d comes from find output, using "${var:?message}" syntax explicitly prevents accidental expansion to unsafe paths.
Apply this diff to add safety guards:
for d in "${TEST_DIRS[@]}"; do
echo "Removing: $d"
- rm -rf "$ROOT_DIR/$d"
+ rm -rf "${ROOT_DIR:?ROOT_DIR not set}/${d:?d is empty}"
doneAlternatively, validate ROOT_DIR once at initialization:
-ROOT_DIR="$(pwd)"
+ROOT_DIR="${ROOT_DIR:-.}"
+ROOT_DIR="${ROOT_DIR:?ROOT_DIR not set}"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for d in "${TEST_DIRS[@]}"; do | |
| echo "Removing: $d" | |
| rm -rf "$ROOT_DIR/$d" | |
| done | |
| fi | |
| for d in "${TEST_DIRS[@]}"; do | |
| echo "Removing: $d" | |
| rm -rf "${ROOT_DIR:?ROOT_DIR not set}/${d:?d is empty}" | |
| done | |
| fi |
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 52-52: Use "${var:?}" to ensure this never expands to / .
(SC2115)
🤖 Prompt for AI Agents
In scripts/clean-tests.sh around lines 50 to 54, the rm -rf call uses unguarded
variables which can expand to unsafe paths; change the destructive command to
use Bash parameter-expansion guards and validate variables by replacing rm -rf
"$ROOT_DIR/$d" with rm -rf "${ROOT_DIR:?}/$d" (or more strictly rm -rf
"${ROOT_DIR:?}/${d:?}") and/or validate ROOT_DIR once at script initialization
(e.g., ensure ROOT_DIR is set and non-empty using : "${ROOT_DIR:?ROOT_DIR is not
set}" ) so the script will fail fast instead of accidentally running rm -rf /.
| export const isValidMatrixConfig = () => | ||
| // Keep validation permissive here; skip/invalid combinations are annotated | ||
| // and handled by the test harness so they appear in generated matrix with | ||
| // an explicit skip reason. This helps produce transparent reports. | ||
| true | ||
| ;type MatrixField = { |
There was a problem hiding this comment.
Fix syntax error: misplaced semicolon.
The semicolon is incorrectly placed at the start of line 53 instead of at the end of line 52. This will cause a compilation error.
Apply this diff:
export const isValidMatrixConfig = () =>
// Keep validation permissive here; skip/invalid combinations are annotated
// and handled by the test harness so they appear in generated matrix with
// an explicit skip reason. This helps produce transparent reports.
- true
-;type MatrixField = {
+ true;
+
+type MatrixField = {
key: keyof MatrixConfig;
values: ReadonlyArray<MatrixConfig[keyof MatrixConfig]>;
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const isValidMatrixConfig = () => | |
| // Keep validation permissive here; skip/invalid combinations are annotated | |
| // and handled by the test harness so they appear in generated matrix with | |
| // an explicit skip reason. This helps produce transparent reports. | |
| true | |
| ;type MatrixField = { | |
| export const isValidMatrixConfig = () => | |
| // Keep validation permissive here; skip/invalid combinations are annotated | |
| // and handled by the test harness so they appear in generated matrix with | |
| // an explicit skip reason. This helps produce transparent reports. | |
| true; | |
| type MatrixField = { | |
| key: keyof MatrixConfig; | |
| values: ReadonlyArray<MatrixConfig[keyof MatrixConfig]>; | |
| }; |
🤖 Prompt for AI Agents
In scripts/functional-tests/matrix.ts around lines 48 to 53, there's a misplaced
semicolon beginning line 53 which causes a syntax error before the type
declaration; move the semicolon so it terminates the previous statement (place
it at the end of the line that returns true for isValidMatrixConfig) or remove
the extraneous newline so the export const line ends with a semicolon and the
type declaration starts cleanly.
| export const prismaRuntimeDependencies: AvailableDependency[] = [ | ||
| { | ||
| latestVersion: '6.2.1', | ||
| value: '@prisma/client' | ||
| }, | ||
| { | ||
| latestVersion: '5.23.0', | ||
| value: '@prisma/extension-accelerate' | ||
| } | ||
| ]; | ||
|
|
||
| export const prismaDevDependencies: AvailableDependency[] = [ | ||
| { | ||
| latestVersion: '6.2.1', | ||
| value: 'prisma' | ||
| } | ||
| ]; |
There was a problem hiding this comment.
🧩 Analysis chain
Verify Prisma package versions are current and secure.
Ensure the specified versions are valid and check for any security advisories or updates since my knowledge cutoff.
🌐 Web query:
What are the latest versions of @prisma/client, @prisma/extension-accelerate, and prisma npm packages?
💡 Result:
- @prisma/client — 6.19.0. [1]
- prisma — 6.19.0. [1]
- @prisma/extension-accelerate — 2.0.2. [2]
Sources:
[1] Prisma releases (GitHub) — 6.19.0 release.
[2] @prisma/extension-accelerate package on npm (v2.0.2).
Update Prisma dependency versions to latest stable releases.
The latest versions are @prisma/client 6.19.0, prisma 6.19.0, and @prisma/extension-accelerate 2.0.2. The code specifies outdated versions:
- @prisma/client: 6.2.1 → 6.19.0
- prisma: 6.2.1 → 6.19.0
- @prisma/extension-accelerate: 5.23.0 → 2.0.2
Update lines 141, 147, and 151 in src/data.ts with the latest stable versions to ensure security patches and bug fixes are included.
🤖 Prompt for AI Agents
In src/data.ts around lines 140 to 156, the pinned Prisma package versions are
outdated; update the version strings for the three entries: change
@prisma/client at line ~141 from "6.2.1" to "6.19.0", change
@prisma/extension-accelerate at line ~147 from "5.23.0" to "2.0.2", and change
prisma in prismaDevDependencies at line ~151 from "6.2.1" to "6.19.0"; keep the
object structure unchanged and ensure versions are exact strings.
| if (orm === 'prisma') { | ||
| prismaRuntimeDependencies.forEach((dep) => { | ||
| dependencies[dep.value] = resolveVersion(dep.value, dep.latestVersion); | ||
| }); | ||
|
|
||
| prismaDevDependencies.forEach((dep) => { | ||
| if (dep.value === '@prisma/extension-accelerate' && !usesAccelerate) return; | ||
| devDependencies[dep.value] = resolveVersion( | ||
| dep.value, | ||
| dep.latestVersion | ||
| ); | ||
| }); | ||
| } |
There was a problem hiding this comment.
Fix misplaced conditional check for @prisma/extension-accelerate.
The condition on line 145 checks if dep.value === '@prisma/extension-accelerate' within the prismaDevDependencies.forEach loop, but @prisma/extension-accelerate is defined in prismaRuntimeDependencies (see lines 145-148 in src/data.ts), not in prismaDevDependencies. This means the condition will never match, and the Accelerate extension will always be added to dependencies even when usesAccelerate is false.
Apply this diff to move the check to the correct loop:
if (orm === 'prisma') {
prismaRuntimeDependencies.forEach((dep) => {
+ if (dep.value === '@prisma/extension-accelerate' && !usesAccelerate) return;
dependencies[dep.value] = resolveVersion(dep.value, dep.latestVersion);
});
prismaDevDependencies.forEach((dep) => {
- if (dep.value === '@prisma/extension-accelerate' && !usesAccelerate) return;
devDependencies[dep.value] = resolveVersion(
dep.value,
dep.latestVersion
);
});
}🤖 Prompt for AI Agents
In src/generators/configurations/generatePackageJson.ts around lines 139 to 151,
the check for '@prisma/extension-accelerate' is placed inside the
prismaDevDependencies.forEach loop but that package lives in
prismaRuntimeDependencies, so the condition never matches and the accelerate
runtime package is always added; move the conditional into the
prismaRuntimeDependencies.forEach loop so that when iterating runtime deps you
skip adding dep.value === '@prisma/extension-accelerate' if !usesAccelerate,
leaving the devDependencies loop unchanged and continue to resolve and assign
versions for all other deps as before.
| if (orm === 'prisma') { | ||
| scripts['postinstall'] = 'prisma generate'; | ||
| scripts['db:generate'] = 'prisma generate'; | ||
| scripts['db:push'] = 'prisma db push'; | ||
| scripts['db:studio'] = 'prisma studio'; | ||
| scripts['db:migrate'] = 'prisma migrate dev'; | ||
| scripts['db:migrate:deploy'] = 'prisma migrate deploy'; | ||
| scripts['db:migrate:reset'] = 'prisma migrate reset'; | ||
|
|
||
| } |
There was a problem hiding this comment.
Fix indentation in Prisma scripts block.
The script definitions (lines 235-241) have inconsistent indentation with excessive leading whitespace.
Apply this diff to normalize the indentation:
if (orm === 'prisma') {
- scripts['postinstall'] = 'prisma generate';
- scripts['db:generate'] = 'prisma generate';
- scripts['db:push'] = 'prisma db push';
- scripts['db:studio'] = 'prisma studio';
- scripts['db:migrate'] = 'prisma migrate dev';
- scripts['db:migrate:deploy'] = 'prisma migrate deploy';
- scripts['db:migrate:reset'] = 'prisma migrate reset';
-
+ scripts['postinstall'] = 'prisma generate';
+ scripts['db:generate'] = 'prisma generate';
+ scripts['db:push'] = 'prisma db push';
+ scripts['db:studio'] = 'prisma studio';
+ scripts['db:migrate'] = 'prisma migrate dev';
+ scripts['db:migrate:deploy'] = 'prisma migrate deploy';
+ scripts['db:migrate:reset'] = 'prisma migrate reset';
}🤖 Prompt for AI Agents
In src/generators/configurations/generatePackageJson.ts around lines 234 to 243,
the block adding Prisma scripts has inconsistent/excessive leading indentation;
normalize the indentation so each scripts[...] assignment aligns with the
surrounding code (remove extra leading spaces before scripts['postinstall']
through scripts['db:migrate:reset']), keeping the same statements and spacing
style as other script entries in the file.
| const baseConfigString = | ||
| pluginImport.config !== null | ||
| ? JSON.stringify(pluginImport.config).slice(1, -1) | ||
| : ''; | ||
|
|
There was a problem hiding this comment.
Guard against undefined configs to avoid runtime crash in baseConfigString
When pluginImport.config is undefined, the condition pluginImport.config !== null is true, so JSON.stringify(pluginImport.config) returns undefined and .slice(1, -1) will throw at generation time. This is a hard failure if absoluteAuth is registered without an explicit config.
You can fix this by treating both null and undefined as “no base config” and normalizing config before passing to helpers:
- const baseConfigString =
- pluginImport.config !== null
- ? JSON.stringify(pluginImport.config).slice(1, -1)
- : '';
+ const baseConfigString =
+ pluginImport.config != null
+ ? JSON.stringify(pluginImport.config).slice(1, -1)
+ : '';
- const config = pluginImport.config as Record<string, unknown> | null;
+ const config = (pluginImport.config ?? null) as Record<string, unknown> | null;This preserves existing behavior for null while avoiding the JSON.stringify(undefined) edge case and aligning the runtime value with the declared helper parameter type.
Also applies to: 55-57
🤖 Prompt for AI Agents
In src/generators/project/generateUseBlock.ts around lines 39-43 (and similarly
at 55-57), the code treats only null as “no config” but not undefined, causing
JSON.stringify(undefined) and .slice to throw; normalize pluginImport.config to
treat both null and undefined as absent (e.g., coalesce undefined to null or to
an empty object/string) before calling JSON.stringify and slicing, or check for
both null and undefined in the conditional so you only call JSON.stringify when
config is a real value; update both places to use the same normalized guard to
preserve existing null behavior while avoiding the undefined crash.
| // Build directory - use default if not provided (non-interactive mode) | ||
| const buildDirectory = | ||
| argumentConfiguration.buildDirectory ?? | ||
| (await text({ | ||
| message: 'Build directory:', | ||
| placeholder: 'build' | ||
| })); | ||
| if (isCancel(buildDirectory)) abort(); | ||
| argumentConfiguration.buildDirectory ?? 'build'; | ||
|
|
||
| // Assets directory | ||
| // Assets directory - use default if not provided (non-interactive mode) | ||
| const assetsDirectory = | ||
| argumentConfiguration.assetsDirectory ?? | ||
| (await text({ | ||
| message: 'Assets directory:', | ||
| placeholder: 'src/backend/assets' | ||
| })); | ||
| if (isCancel(assetsDirectory)) abort(); | ||
| argumentConfiguration.assetsDirectory ?? 'src/backend/assets'; | ||
|
|
||
| // Tailwind directory | ||
| // Tailwind directory - use defaults if not provided (non-interactive mode) | ||
| let tailwind; | ||
| if (useTailwind) { | ||
| const input = | ||
| argumentConfiguration.tailwind?.input ?? | ||
| (await text({ | ||
| message: 'Tailwind input CSS file:', | ||
| placeholder: './src/frontend/styles/tailwind.css' | ||
| })); | ||
| if (isCancel(input)) abort(); | ||
| './src/frontend/styles/tailwind.css'; | ||
|
|
||
| const output = | ||
| argumentConfiguration.tailwind?.output ?? | ||
| (await text({ | ||
| message: 'Tailwind output CSS file:', | ||
| placeholder: '/assets/css/tailwind.generated.css' | ||
| })); | ||
| if (isCancel(output)) abort(); | ||
| '/assets/css/tailwind.generated.css'; | ||
|
|
||
| tailwind = { input, output }; | ||
| } else { | ||
| tailwind = undefined; | ||
| } | ||
|
|
||
| // Database | ||
| // Database - use default if not provided (non-interactive mode) | ||
| let databaseDirectory; | ||
| if (databaseEngine !== undefined && databaseEngine !== 'none') { | ||
| databaseDirectory = | ||
| argumentConfiguration.databaseDirectory ?? | ||
| (await text({ | ||
| message: 'Database directory:', | ||
| placeholder: 'db' | ||
| })); | ||
| if (isCancel(databaseDirectory)) abort(); | ||
| argumentConfiguration.databaseDirectory ?? 'db'; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
Clarify intended behavior for custom directory configuration.
The non-default (custom) branch always uses defaults from argumentConfiguration or hardcoded fallbacks, with no interactive prompting—even when a user explicitly chooses "custom" configuration. This differs from frontendDirectoryConfigurations.ts, which detects non-interactive mode and prompts appropriately in interactive contexts.
Current behavior:
- User selects "custom" configuration interactively
- Expects to be prompted for custom directories (build, assets, tailwind, database)
- Actually receives default values identical to "default" configuration
- Custom values only work if passed via CLI arguments
Questions:
- Is this intentional? Should build/assets/tailwind/database directories support custom prompts in interactive mode?
- If not, should the "custom" option in
getConfigurationType()clarify it only affects frontend directories? - Should this function check
isNonInteractive(like line 31 infrontendDirectoryConfigurations.ts) and prompt only when interactive?
If custom prompts are intended here, apply a pattern similar to frontendDirectoryConfigurations.ts:
+import process from 'node:process';
+import { isCancel, text } from '@clack/prompts';
+import { abort } from '../utils/abort';
+
export const getDirectoryConfiguration = async ({
directoryConfig,
useTailwind,
databaseEngine,
argumentConfiguration
}: GetDirectoryConfigurationProps) => {
if (directoryConfig === 'default') {
return {
assetsDirectory:
argumentConfiguration.assetsDirectory ?? 'src/backend/assets',
buildDirectory: argumentConfiguration.buildDirectory ?? 'build',
databaseDirectory:
databaseEngine !== undefined && databaseEngine !== 'none'
? (argumentConfiguration.databaseDirectory ?? 'db')
: undefined,
tailwind: useTailwind
? {
input:
argumentConfiguration.tailwind?.input ??
'./src/frontend/styles/tailwind.css',
output:
argumentConfiguration.tailwind?.output ??
'/assets/css/tailwind.generated.css'
}
: undefined
};
}
- // Build directory - use default if not provided (non-interactive mode)
- const buildDirectory =
- argumentConfiguration.buildDirectory ?? 'build';
+ // Detect non-interactive environment
+ const isNonInteractive = !process.stdin.isTTY || !process.stdout.isTTY || !process.stdin.readable;
+
+ // Build directory
+ let buildDirectory = argumentConfiguration.buildDirectory;
+ if (buildDirectory === undefined) {
+ if (isNonInteractive) {
+ buildDirectory = 'build';
+ } else {
+ const response = await text({
+ message: 'Build directory:',
+ placeholder: 'build'
+ });
+ if (isCancel(response)) abort();
+ buildDirectory = response;
+ }
+ }
- // Assets directory - use default if not provided (non-interactive mode)
- const assetsDirectory =
- argumentConfiguration.assetsDirectory ?? 'src/backend/assets';
+ // Assets directory
+ let assetsDirectory = argumentConfiguration.assetsDirectory;
+ if (assetsDirectory === undefined) {
+ if (isNonInteractive) {
+ assetsDirectory = 'src/backend/assets';
+ } else {
+ const response = await text({
+ message: 'Assets directory:',
+ placeholder: 'src/backend/assets'
+ });
+ if (isCancel(response)) abort();
+ assetsDirectory = response;
+ }
+ }
- // Tailwind directory - use defaults if not provided (non-interactive mode)
let tailwind;
if (useTailwind) {
- const input =
- argumentConfiguration.tailwind?.input ??
- './src/frontend/styles/tailwind.css';
+ let input = argumentConfiguration.tailwind?.input;
+ if (input === undefined) {
+ if (isNonInteractive) {
+ input = './src/frontend/styles/tailwind.css';
+ } else {
+ const response = await text({
+ message: 'Tailwind input file:',
+ placeholder: './src/frontend/styles/tailwind.css'
+ });
+ if (isCancel(response)) abort();
+ input = response;
+ }
+ }
- const output =
- argumentConfiguration.tailwind?.output ??
- '/assets/css/tailwind.generated.css';
+ let output = argumentConfiguration.tailwind?.output;
+ if (output === undefined) {
+ if (isNonInteractive) {
+ output = '/assets/css/tailwind.generated.css';
+ } else {
+ const response = await text({
+ message: 'Tailwind output file:',
+ placeholder: '/assets/css/tailwind.generated.css'
+ });
+ if (isCancel(response)) abort();
+ output = response;
+ }
+ }
tailwind = { input, output };
} else {
tailwind = undefined;
}
- // Database - use default if not provided (non-interactive mode)
let databaseDirectory;
if (databaseEngine !== undefined && databaseEngine !== 'none') {
- databaseDirectory =
- argumentConfiguration.databaseDirectory ?? 'db';
+ databaseDirectory = argumentConfiguration.databaseDirectory;
+ if (databaseDirectory === undefined) {
+ if (isNonInteractive) {
+ databaseDirectory = 'db';
+ } else {
+ const response = await text({
+ message: 'Database directory:',
+ placeholder: 'db'
+ });
+ if (isCancel(response)) abort();
+ databaseDirectory = response;
+ }
+ }
}
return {
assetsDirectory,
buildDirectory,
databaseDirectory,
tailwind
};
};🏁 Script executed:
#!/bin/bash
# Find and examine frontendDirectoryConfigurations.ts to verify the pattern
fd -t f 'frontendDirectoryConfigurations' -x cat {}Length of output: 2688
🏁 Script executed:
#!/bin/bash
# Find getConfigurationType to understand available configuration types
rg -n 'getConfigurationType' --type=ts -A 20Length of output: 3332
🏁 Script executed:
#!/bin/bash
# Examine full directoryConfiguration.ts file to understand both branches
fd -t f 'directoryConfiguration.ts' -x cat {}Length of output: 2078
🏁 Script executed:
#!/bin/bash
# Search for isNonInteractive pattern and usage
rg -n 'isNonInteractive' --type=ts -B 2 -A 2Length of output: 610
🏁 Script executed:
#!/bin/bash
# Look for tests related to directory configuration
fd -t f -e 'test.ts' -e 'test.js' -e 'spec.ts' | xargs grep -l 'directoryConfiguration\|getDirectoryConfiguration' 2>/dev/null || echo "No test files found with this pattern"Length of output: 37
🏁 Script executed:
#!/bin/bash
# Check recent git history/PR info if available
if [ -f '.git/config' ]; then
git log --oneline -20 -- 'src/questions/directoryConfiguration.ts' 2>/dev/null || echo "No git history available"
fiLength of output: 958
Add interactive mode prompting to custom directory configuration to match frontend behavior.
The custom branch (lines 38-67) never prompts for custom values, always using argumentConfiguration or hardcoded defaults—even when selected interactively. This differs from frontendDirectoryConfigurations.ts, which detects non-interactive environments (line 31) and prompts only when interactive.
Issue:
- User selects "custom" configuration interactively → expects prompts for build, assets, tailwind, and database directories
- Function ignores this and applies defaults regardless
- Custom values only take effect via CLI arguments, making the UI selection non-functional
Fix:
Add isNonInteractive detection (process.stdin/stdout checks) and prompt only when interactive, mirroring the pattern already established in frontendDirectoryConfigurations.ts. Use defaults in non-interactive mode (CI/--skip).
+import process from 'node:process';
+import { isCancel, text } from '@clack/prompts';
+import { abort } from '../utils/abort';
+
export const getDirectoryConfiguration = async ({
directoryConfig,
useTailwind,
databaseEngine,
argumentConfiguration
}: GetDirectoryConfigurationProps) => {
if (directoryConfig === 'default') {
return {
assetsDirectory:
argumentConfiguration.assetsDirectory ?? 'src/backend/assets',
buildDirectory: argumentConfiguration.buildDirectory ?? 'build',
databaseDirectory:
databaseEngine !== undefined && databaseEngine !== 'none'
? (argumentConfiguration.databaseDirectory ?? 'db')
: undefined,
tailwind: useTailwind
? {
input:
argumentConfiguration.tailwind?.input ??
'./src/frontend/styles/tailwind.css',
output:
argumentConfiguration.tailwind?.output ??
'/assets/css/tailwind.generated.css'
}
: undefined
};
}
+ const isNonInteractive = !process.stdin.isTTY || !process.stdout.isTTY || !process.stdin.readable;
+
- // Build directory - use default if not provided (non-interactive mode)
- const buildDirectory =
- argumentConfiguration.buildDirectory ?? 'build';
+ let buildDirectory = argumentConfiguration.buildDirectory;
+ if (buildDirectory === undefined) {
+ if (isNonInteractive) {
+ buildDirectory = 'build';
+ } else {
+ const response = await text({
+ message: 'Build directory:',
+ placeholder: 'build'
+ });
+ if (isCancel(response)) abort();
+ buildDirectory = response;
+ }
+ }
- // Assets directory - use default if not provided (non-interactive mode)
- const assetsDirectory =
- argumentConfiguration.assetsDirectory ?? 'src/backend/assets';
+ let assetsDirectory = argumentConfiguration.assetsDirectory;
+ if (assetsDirectory === undefined) {
+ if (isNonInteractive) {
+ assetsDirectory = 'src/backend/assets';
+ } else {
+ const response = await text({
+ message: 'Assets directory:',
+ placeholder: 'src/backend/assets'
+ });
+ if (isCancel(response)) abort();
+ assetsDirectory = response;
+ }
+ }
- // Tailwind directory - use defaults if not provided (non-interactive mode)
let tailwind;
if (useTailwind) {
- const input =
- argumentConfiguration.tailwind?.input ??
- './src/frontend/styles/tailwind.css';
+ let input = argumentConfiguration.tailwind?.input;
+ if (input === undefined) {
+ if (isNonInteractive) {
+ input = './src/frontend/styles/tailwind.css';
+ } else {
+ const response = await text({
+ message: 'Tailwind input file:',
+ placeholder: './src/frontend/styles/tailwind.css'
+ });
+ if (isCancel(response)) abort();
+ input = response;
+ }
+ }
- const output =
- argumentConfiguration.tailwind?.output ??
- '/assets/css/tailwind.generated.css';
+ let output = argumentConfiguration.tailwind?.output;
+ if (output === undefined) {
+ if (isNonInteractive) {
+ output = '/assets/css/tailwind.generated.css';
+ } else {
+ const response = await text({
+ message: 'Tailwind output file:',
+ placeholder: '/assets/css/tailwind.generated.css'
+ });
+ if (isCancel(response)) abort();
+ output = response;
+ }
+ }
tailwind = { input, output };
} else {
tailwind = undefined;
}
- // Database - use default if not provided (non-interactive mode)
let databaseDirectory;
if (databaseEngine !== undefined && databaseEngine !== 'none') {
- databaseDirectory =
- argumentConfiguration.databaseDirectory ?? 'db';
+ databaseDirectory = argumentConfiguration.databaseDirectory;
+ if (databaseDirectory === undefined) {
+ if (isNonInteractive) {
+ databaseDirectory = 'db';
+ } else {
+ const response = await text({
+ message: 'Database directory:',
+ placeholder: 'db'
+ });
+ if (isCancel(response)) abort();
+ databaseDirectory = response;
+ }
+ }
}
return {
assetsDirectory,
buildDirectory,
databaseDirectory,
tailwind
};
};Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/questions/directoryConfiguration.ts around lines 38-67, the "custom"
branch always pulls values from argumentConfiguration or hardcoded defaults and
never prompts the user; update it to detect interactive mode (mirror
frontendDirectoryConfigurations.ts — e.g., check process.stdin.isTTY &&
process.stdout.isTTY or reuse the existing isNonInteractive helper) and only
apply non-interactive defaults when non-interactive; when interactive, prompt
for buildDirectory, assetsDirectory, tailwind (input and output) and
databaseDirectory (using argumentConfiguration values as the prompt defaults),
and keep using the hardcoded defaults when neither arguments nor interactive
input are provided so the behavior matches the frontend implementation.
| export const checkGitInstalled = async () => { | ||
| // Git is already installed | ||
| if (await hasGit()) return true; | ||
|
|
||
| // Prompt user to install Git | ||
| const proceed = await confirm({ | ||
| initialValue: true, | ||
| message: 'Git is required for project initialization. Install it now?' | ||
| }); | ||
|
|
||
| if (!proceed) return false; | ||
|
|
||
| // Attempt platform-specific installation | ||
| switch (hostEnv) { | ||
| case 'windows': | ||
| await installWindows(); | ||
| break; | ||
| case 'darwin': | ||
| if (await commandExists('brew')) { | ||
| if (await brewInstall()) return hasGit(); | ||
| } | ||
| console.log( | ||
| `${dim('│')}\n${yellow('▲')} Please install Git from: ${GIT_URL}` | ||
| ); | ||
| break; | ||
| case 'wsl': | ||
| if (await installWSL()) return hasGit(); | ||
| break; | ||
| case 'linux': | ||
| if (await installLinux()) return hasGit(); | ||
| break; | ||
| } | ||
|
|
||
| // Installation failed or not automated - direct user to manual installation | ||
| console.log( | ||
| `${dim('│')}\n${yellow('▲')} Couldn't install Git automatically. Please download it from: ${GIT_URL}` | ||
| ); | ||
| console.log(`${dim('│')} After installation, restart your terminal and try again.`); | ||
|
|
||
| return hasGit(); | ||
| }; |
There was a problem hiding this comment.
Duplicate error messages due to inconsistent control flow.
The function prints redundant failure messages because platform-specific installers print their own messages before falling through to the generic fallback at lines 295-298. This results in duplicate messages in several scenarios:
- Windows: Always prints both the Windows-specific message (lines 180-183 via
installWindows) and the generic message (lines 295-298) - macOS: Prints duplicate messages when brew is unavailable or installation fails
- WSL/Linux: When installation fails, platform wrappers print their own messages (lines 205-207, 239-241), then fall through to the generic message
Apply this diff to add early returns and eliminate duplicates:
// Attempt platform-specific installation
switch (hostEnv) {
case 'windows':
await installWindows();
+ return hasGit();
case 'darwin':
if (await commandExists('brew')) {
if (await brewInstall()) return hasGit();
+ } else {
+ console.log(
+ `${dim('│')}\n${yellow('▲')} Please install Git from: ${GIT_URL}`
+ );
}
- console.log(
- `${dim('│')}\n${yellow('▲')} Please install Git from: ${GIT_URL}`
- );
- break;
+ return hasGit();
case 'wsl':
if (await installWSL()) return hasGit();
- break;
+ return hasGit();
case 'linux':
if (await installLinux()) return hasGit();
- break;
+ return hasGit();
}
-
- // Installation failed or not automated - direct user to manual installation
- console.log(
- `${dim('│')}\n${yellow('▲')} Couldn't install Git automatically. Please download it from: ${GIT_URL}`
- );
- console.log(`${dim('│')} After installation, restart your terminal and try again.`);
-
- return hasGit();
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const checkGitInstalled = async () => { | |
| // Git is already installed | |
| if (await hasGit()) return true; | |
| // Prompt user to install Git | |
| const proceed = await confirm({ | |
| initialValue: true, | |
| message: 'Git is required for project initialization. Install it now?' | |
| }); | |
| if (!proceed) return false; | |
| // Attempt platform-specific installation | |
| switch (hostEnv) { | |
| case 'windows': | |
| await installWindows(); | |
| break; | |
| case 'darwin': | |
| if (await commandExists('brew')) { | |
| if (await brewInstall()) return hasGit(); | |
| } | |
| console.log( | |
| `${dim('│')}\n${yellow('▲')} Please install Git from: ${GIT_URL}` | |
| ); | |
| break; | |
| case 'wsl': | |
| if (await installWSL()) return hasGit(); | |
| break; | |
| case 'linux': | |
| if (await installLinux()) return hasGit(); | |
| break; | |
| } | |
| // Installation failed or not automated - direct user to manual installation | |
| console.log( | |
| `${dim('│')}\n${yellow('▲')} Couldn't install Git automatically. Please download it from: ${GIT_URL}` | |
| ); | |
| console.log(`${dim('│')} After installation, restart your terminal and try again.`); | |
| return hasGit(); | |
| }; | |
| export const checkGitInstalled = async () => { | |
| // Git is already installed | |
| if (await hasGit()) return true; | |
| // Prompt user to install Git | |
| const proceed = await confirm({ | |
| initialValue: true, | |
| message: 'Git is required for project initialization. Install it now?' | |
| }); | |
| if (!proceed) return false; | |
| // Attempt platform-specific installation | |
| switch (hostEnv) { | |
| case 'windows': | |
| await installWindows(); | |
| return hasGit(); | |
| case 'darwin': | |
| if (await commandExists('brew')) { | |
| if (await brewInstall()) return hasGit(); | |
| } else { | |
| console.log( | |
| `${dim('│')}\n${yellow('▲')} Please install Git from: ${GIT_URL}` | |
| ); | |
| } | |
| return hasGit(); | |
| case 'wsl': | |
| if (await installWSL()) return hasGit(); | |
| return hasGit(); | |
| case 'linux': | |
| if (await installLinux()) return hasGit(); | |
| return hasGit(); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In src/utils/checkGitInstalled.ts around lines 261 to 301, the generic fallback
messages are printed even when platform-specific installers already printed
failure/success messages, causing duplicates; update the switch to return
immediately after any platform-specific install that either succeeds (return
hasGit()) or already displayed a failure message (return false) so the generic
"Couldn't install Git automatically" block is only reached when no platform
branch handled the outcome; specifically add early returns after
installWindows(), after the brew branch when brewInstall() is false or brew is
missing (return false), after installWSL() and installLinux() when they report
failure (return false), and keep the final generic fallback only for unhandled
paths, then return hasGit() only where appropriate.
Summary
src/typesdirectory exists before writing.CLI Fixes Driven by Testing
src/templates/configurations/tsconfig.example.json,src/templates/configurations/eslint.config.mjs, andsrc/templates/configurations/.prettierignoreto resolve TypeScript compile errors and lint failures during scaffolded project validation.cleanupProjectDirectoryand wired it into every runner to remove stale scaffold directories before each test, preventing “directory already exists” aborts.node_modulessnapshots, stabilizing install steps and cutting runtime.getFrontendDirectoryConfigurationsprompts for custom layouts instead of silently applying defaults, while non-custom flows retain automatic values for CI/--skip.src/types/automatically for Vue projects before emittingvue-shim.d.ts, eliminating intermittent ENOENT failures in validators.Test Coverage & Results (Most Recent Full Runs)
test:functional,test:server,test:build,test:deps)uid) still pending fix.users/count_historycollections; captured for follow-up.absoluteAuthacross frameworks/DBs)Totals reflect supported combinations after matrix filtering; Docker-dependent failures and template gaps remain documented but no longer bring down the suite.
Testing Commands
bun run test:functionalbun run test:serverbun run test:buildbun run test:depsbun run test:reactbun run test:react:allbun run test:vuebun run test:vue:allbun run test:sveltebun run test:svelte:allbun run test:htmlbun run test:html:allbun run test:htmxbun run test:htmx:allbun run test:sqlitebun run test:sqlite:allbun run test:postgresqlbun run test:postgresql:allbun run test:mysqlbun run test:mysql:allbun run test:mongodbbun run test:mongodb:allbun run test:cloudbun run test:cloud:allbun run test:authbun run test:auth:allSummary by CodeRabbit
Release Notes
New Features
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.