Skip to content

Conversation

HouseinIsProgramming
Copy link
Collaborator

@HouseinIsProgramming HouseinIsProgramming commented Jun 20, 2025

Description

  • Refactor cli to use declarative array approach
  • Add a "operations" layer to unify code path and allow of straightforward integration with other tools
  • Adapts the already existing feature (interactive cli) to use the new structure
  • Reformats the error logging to show only relevant info and shows clear error messages when arguments are missing in non-interactive mode.

TO-DO:

  • time-out messages on interactive mode (to send clear errors if called by any kind of automation)
  • Documentation
  • Testing
  • fix SonarQube duplicated code issue

Checklist

📌 Always:

  • I have set a clear title
  • My PR is small and contains a single feature
  • I have checked my own PR

👍 Most of the time:

  • I have added or updated test cases
  • I have updated the README if needed

Summary by CodeRabbit

  • New Features

    • Added non-interactive mode to CLI commands, enabling direct execution with flags for automation and CI/CD use cases.
    • Enhanced CLI commands (add, migrate, and sub-commands) with new options for specifying plugins, entities, services, job queues, API extensions, UI extensions, and custom config files.
    • Introduced timeout protection for interactive prompts, with guidance for using non-interactive flags if prompts time out.
    • Improved error handling and validation for CLI operations.
    • Centralized plugin resolution logic to support interactive and non-interactive modes.
    • Added comprehensive migration operations for generating, running, and reverting database migrations via CLI.
    • Added a new CLI command declarations system and batch command registration for streamlined CLI setup.
  • Documentation

    • Updated CLI documentation to cover interactive and non-interactive usage, detailed flag descriptions, and usage examples.
    • Added a new README for the CLI package, outlining command structures, usage, and file organization.
  • Bug Fixes

    • Improved error messages and validation for missing or incorrect command options in both interactive and non-interactive modes.
  • Tests

    • Added new and extended test suites to cover migration operations and CLI entity addition logic.
    • Added end-to-end tests for migration command lifecycle and error recovery.
    • Added end-to-end tests for add command operations covering various sub-commands.
  • Chores

    • Refactored CLI command registration and option handling for better maintainability and extensibility.
    • Enhanced project analysis and configuration loading with explicit config file support.
    • Updated Vendure config file resolution logic for clearer error handling and file selection.
    • Made tsconfig file selection automatic, removing interactive prompts.
    • Added utility for wrapping interactive prompts with timeout handling.

Copy link

vercel bot commented Jun 20, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
docs ✅ Ready (Inspect) Visit Preview Jun 25, 2025 4:07am

Copy link
Contributor

coderabbitai bot commented Jun 20, 2025

Walkthrough

This change introduces a comprehensive overhaul of the Vendure CLI's command structure to support both interactive and non-interactive modes. It adds new modules for command registration, plugin resolution, and project validation, and refactors existing commands to accept options for non-interactive execution. Extensive documentation and usage examples are provided, along with improved error handling, prompt timeouts, and test coverage for migration operations.

Changes

File(s) / Path(s) Change Summary
packages/cli/src/README.md, docs/docs/guides/developer-guide/cli/index.md Added/updated documentation for CLI command structure, interactive vs non-interactive usage, flags, and help.
packages/cli/src/cli.ts Refactored CLI entrypoint to batch-register commands via a registry instead of individual definitions.
packages/cli/src/commands/command-declarations.ts, packages/cli/src/shared/cli-command-definition.ts, packages/cli/src/shared/command-registry.ts Introduced new command declaration/config interfaces and a command registry for dynamic CLI command registration.
packages/cli/src/commands/add/add-operations.ts, packages/cli/src/commands/add/add.ts Added operation dispatcher for "add" sub-commands and refactored to support both interactive and non-interactive flows.
packages/cli/src/commands/add/plugin/create-new-plugin.ts, packages/cli/src/commands/add/plugin/types.ts Refactored plugin creation to accept options for non-interactive mode and updated type signatures.
packages/cli/src/commands/add/entity/add-entity.ts, packages/cli/src/commands/add/service/add-service.ts, packages/cli/src/commands/add/job-queue/add-job-queue.ts, packages/cli/src/commands/add/codegen/add-codegen.ts, packages/cli/src/commands/add/api-extension/add-api-extension.ts, packages/cli/src/commands/add/ui-extensions/add-ui-extensions.ts Refactored all "add" sub-commands to support non-interactive options, plugin resolution by name, and improved error handling.
packages/cli/src/commands/migrate/migrate.ts, packages/cli/src/commands/migrate/migration-operations.ts Refactored "migrate" command to support non-interactive execution and added a new module for migration operations.
packages/cli/src/commands/migrate/migration-operations.spec.ts Added tests for migration operations, focusing on error handling and result structure.
packages/cli/src/commands/add/entity/codemods/add-entity-to-plugin/add-entity-to-plugin.spec.ts Added tests for entity-to-plugin codemod, including error cases and import checks.
packages/cli/src/commands/add/ui-extensions/codemods/update-admin-ui-plugin-init/update-admin-ui-plugin-init.spec.ts Minor update to constructor usage in tests.
packages/cli/src/shared/shared-prompts.ts, packages/cli/src/utilities/ast-utils.ts, packages/cli/src/commands/migrate/generate-migration/generate-migration.ts Wrapped interactive prompts with a timeout utility to prevent hanging in automated environments.
packages/cli/src/shared/plugin-resolution.ts New module for resolving plugins by name or reference, supporting both interactive and non-interactive flows.
packages/cli/src/shared/project-validation.ts New module for validating Vendure project directories.
packages/cli/src/shared/vendure-config-ref.ts Refactored config file resolution logic, now supporting explicit config file paths and improved error messages.
packages/cli/src/utilities/utils.ts Added a utility function to wrap prompts with a timeout and provide user guidance in non-interactive environments.
packages/cli/e2e/fixtures/test-entity.ts, packages/cli/e2e/fixtures/test-project/**, packages/cli/e2e/fixtures/vendure-config.ts Added end-to-end test fixtures including a test entity, Vendure config, and project files.
packages/cli/e2e/migrate-command.e2e-spec.ts Added comprehensive end-to-end tests for migration commands covering generate, run, and revert operations.
packages/cli/e2e/vitest.e2e.config.mts Added Vitest configuration for end-to-end tests.
packages/cli/package.json Added "e2e" script for running end-to-end tests with Vitest.
packages/cli/tsconfig.json Excluded dist directory from TypeScript compilation.
packages/cli/.gitignore Added .gitignore to exclude dist/, dist-e2e/, and node_modules/ directories.
.eslintrc.js Added a blank line after the last override in ESLint config.

Sequence Diagram(s)

High-level Control Flow: CLI Command Execution (Interactive vs Non-Interactive)

sequenceDiagram
    participant User
    participant CLI
    participant CommandRegistry
    participant CommandHandler

    User->>CLI: Run CLI command (e.g., add, migrate)
    CLI->>CommandRegistry: Register commands
    CLI->>CommandHandler: Invoke command with options

    alt Non-interactive mode (flags provided)
        CommandHandler->>CommandHandler: Validate and execute with options
        CommandHandler->>CLI: Output result, exit
    else Interactive mode (no flags)
        CommandHandler->>User: Prompt for input (with timeout)
        User->>CommandHandler: Provide input
        CommandHandler->>CommandHandler: Execute with user input
        CommandHandler->>CLI: Output result, exit
    end
Loading

Plugin Resolution Logic

sequenceDiagram
    participant CommandHandler
    participant PluginResolution
    participant User

    CommandHandler->>PluginResolution: resolvePluginFromOptions(options)
    alt Plugin provided
        PluginResolution-->>CommandHandler: Return plugin
    else Plugin name provided
        PluginResolution->>PluginResolution: Search plugins by name
        alt Found
            PluginResolution-->>CommandHandler: Return plugin
        else Not found
            PluginResolution-->>CommandHandler: Throw error (list available plugins)
        end
    else Non-interactive mode
        PluginResolution-->>CommandHandler: Throw error (plugin required)
    else Interactive mode
        PluginResolution-->>CommandHandler: Indicate prompt needed
        CommandHandler->>User: Prompt for plugin selection
        User->>CommandHandler: Select plugin
        CommandHandler->>PluginResolution: Return selected plugin
    end
Loading

Migration Operation (Non-Interactive)

sequenceDiagram
    participant User
    participant CLI
    participant MigrationOperation

    User->>CLI: Run migrate command with flags (--generate, --run, --revert)
    CLI->>MigrationOperation: Call corresponding operation with options
    MigrationOperation->>MigrationOperation: Validate project, analyze config
    MigrationOperation->>CLI: Return result (success/error)
    CLI->>User: Output result, exit
Loading

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-24T19_56_30_920Z-debug-0.log


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84d79b1 and 1e4de15.

📒 Files selected for processing (1)
  • packages/cli/src/commands/add/add-operations.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/commands/add/add-operations.ts
⏰ Context from checks skipped due to timeout of 90000ms (15)
  • GitHub Check: e2e tests (22.x, mysql)
  • GitHub Check: e2e tests (22.x, mariadb)
  • GitHub Check: e2e tests (22.x, sqljs)
  • GitHub Check: e2e tests (22.x, postgres)
  • GitHub Check: e2e tests (20.x, postgres)
  • GitHub Check: e2e tests (20.x, mysql)
  • GitHub Check: e2e tests (20.x, mariadb)
  • GitHub Check: e2e tests (20.x, sqljs)
  • GitHub Check: publish_install (macos-latest, 20.x)
  • GitHub Check: publish_install (windows-latest, 20.x)
  • GitHub Check: publish_install (ubuntu-latest, 20.x)
  • GitHub Check: publish_install (windows-latest, 22.x)
  • GitHub Check: publish_install (ubuntu-latest, 22.x)
  • GitHub Check: publish_install (macos-latest, 22.x)
  • GitHub Check: Analyze (javascript-typescript)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (7)
packages/cli/src/shared/cli-command-definition.ts (1)

1-19: Strong foundation for the new CLI architecture.

The interfaces provide a clean, declarative approach to command definition. The nested sub-options feature (line 7) is particularly well-designed for complex CLI scenarios.

Consider improving type safety:

-    defaultValue?: any;
+    defaultValue?: string | number | boolean;

The Record<string, any> type for the action function parameter (line 14) may be acceptable for CLI flexibility, but consider if a more specific type would be beneficial as the codebase evolves.

packages/cli/src/commands/command-declarations.ts (1)

80-84: Consider adding error handling around dynamic imports.

While the current implementation is clean, consider wrapping the dynamic import and command execution in a try-catch block to provide better error messages if the command modules fail to load or execute.

 action: async options => {
-    const { addCommand } = await import('./add/add');
-    await addCommand(options);
-    process.exit(0);
+    try {
+        const { addCommand } = await import('./add/add');
+        await addCommand(options);
+        process.exit(0);
+    } catch (error) {
+        console.error(`Failed to execute add command: ${error.message}`);
+        process.exit(1);
+    }
 },
packages/cli/src/shared/command-registry.ts (1)

35-50: Consider adding validation for option format.

While the current implementation works well, consider adding validation to ensure option strings follow expected patterns (e.g., long options start with --).

 function addOption(command: Command, option: CliCommandOption): void {
     const parts: string[] = [];
     if (option.short) {
+        if (!option.short.startsWith('-') || option.short.startsWith('--')) {
+            throw new Error(`Invalid short option format: ${option.short}. Should start with single dash.`);
+        }
         parts.push(option.short);
     }
+    if (!option.long.startsWith('--')) {
+        throw new Error(`Invalid long option format: ${option.long}. Should start with double dash.`);
+    }
     parts.push(option.long);
packages/cli/src/commands/add/service/add-service.ts (1)

42-48: Improve error message for non-interactive mode.

The error message mentions using selectPlugin in interactive mode, which is not applicable here.

-throw new Error('Plugin must be specified when running in non-interactive mode. Use selectPlugin in interactive mode.');
+throw new Error('Plugin must be specified when running in non-interactive mode.');
packages/cli/src/shared/vendure-config-ref.ts (1)

73-82: Simplify the helper method logic.

The default value for checkFileName is true but it's always called with false. Also, the nested ternary reduces readability.

private isVendureConfigFile(
    sourceFile: SourceFile,
-    options: { checkFileName?: boolean } = {},
+    options: { checkFileName: boolean } = { checkFileName: true },
): boolean {
-    const checkFileName = options.checkFileName ?? true;
-    return (
-        (checkFileName ? sourceFile.getFilePath().endsWith('vendure-config.ts') : true) &&
-        !!sourceFile.getVariableDeclarations().find(v => this.isVendureConfigVariableDeclaration(v))
-    );
+    const hasVendureConfig = sourceFile
+        .getVariableDeclarations()
+        .some(v => this.isVendureConfigVariableDeclaration(v));
+    
+    if (!hasVendureConfig) {
+        return false;
+    }
+    
+    if (!options.checkFileName) {
+        return true;
+    }
+    
+    return sourceFile.getFilePath().endsWith('vendure-config.ts');
}
packages/cli/src/commands/add/job-queue/add-job-queue.ts (1)

82-87: Remove redundant non-interactive mode check.

The check on lines 85-87 is redundant because plugin is already assigned on line 82 using the nullish coalescing operator. In non-interactive mode, this check will never be true.

     plugin = plugin ?? (await selectPlugin(project, cancelledMessage));
 
-    // In non-interactive mode, we cannot prompt for service selection
-    if (isNonInteractive && !plugin) {
-        throw new Error('Cannot select service in non-interactive mode - plugin must be specified');
-    }
packages/cli/src/commands/migrate/migration-operations.ts (1)

162-164: Improve Vendure dependency detection to avoid false positives.

The current check might incorrectly identify third-party packages that contain '@vendure/' in their name as official Vendure packages.

             const hasVendureDeps = Object.keys(dependencies).some(
-                dep => dep.includes('@vendure/') || dep === 'vendure',
+                dep => dep.startsWith('@vendure/') || dep === '@vendure/core',
             );

This ensures only official Vendure packages are detected.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcc3335 and 77c962c.

📒 Files selected for processing (20)
  • packages/cli/src/README.md (1 hunks)
  • packages/cli/src/cli.ts (2 hunks)
  • packages/cli/src/commands/add/add-operations.ts (1 hunks)
  • packages/cli/src/commands/add/add.ts (2 hunks)
  • packages/cli/src/commands/add/api-extension/add-api-extension.ts (3 hunks)
  • packages/cli/src/commands/add/codegen/add-codegen.ts (4 hunks)
  • packages/cli/src/commands/add/entity/add-entity.ts (4 hunks)
  • packages/cli/src/commands/add/job-queue/add-job-queue.ts (5 hunks)
  • packages/cli/src/commands/add/plugin/create-new-plugin.ts (3 hunks)
  • packages/cli/src/commands/add/plugin/types.ts (1 hunks)
  • packages/cli/src/commands/add/service/add-service.ts (3 hunks)
  • packages/cli/src/commands/add/ui-extensions/add-ui-extensions.ts (3 hunks)
  • packages/cli/src/commands/add/ui-extensions/codemods/update-admin-ui-plugin-init/update-admin-ui-plugin-init.spec.ts (2 hunks)
  • packages/cli/src/commands/command-declarations.ts (1 hunks)
  • packages/cli/src/commands/migrate/migrate.ts (2 hunks)
  • packages/cli/src/commands/migrate/migration-operations.ts (1 hunks)
  • packages/cli/src/shared/cli-command-definition.ts (1 hunks)
  • packages/cli/src/shared/command-registry.ts (1 hunks)
  • packages/cli/src/shared/shared-prompts.ts (2 hunks)
  • packages/cli/src/shared/vendure-config-ref.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (20)
  • GitHub Check: publish_install (windows-latest, 20.x)
  • GitHub Check: publish_install (macos-latest, 22.x)
  • GitHub Check: publish_install (ubuntu-latest, 22.x)
  • GitHub Check: publish_install (macos-latest, 20.x)
  • GitHub Check: publish_install (windows-latest, 22.x)
  • GitHub Check: publish_install (ubuntu-latest, 20.x)
  • GitHub Check: e2e tests (20.x, mysql)
  • GitHub Check: e2e tests (22.x, postgres)
  • GitHub Check: e2e tests (22.x, mysql)
  • GitHub Check: e2e tests (22.x, sqljs)
  • GitHub Check: e2e tests (20.x, postgres)
  • GitHub Check: codegen / codegen
  • GitHub Check: e2e tests (20.x, mariadb)
  • GitHub Check: e2e tests (22.x, mariadb)
  • GitHub Check: e2e tests (20.x, sqljs)
  • GitHub Check: build (20.x)
  • GitHub Check: build (22.x)
  • GitHub Check: unit tests (20.x)
  • GitHub Check: unit tests (22.x)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (31)
packages/cli/src/commands/add/plugin/types.ts (1)

4-4: LGTM: Clean interface extension.

The addition of the optional config property appropriately supports the new non-interactive mode functionality while maintaining backward compatibility.

packages/cli/src/commands/add/ui-extensions/codemods/update-admin-ui-plugin-init/update-admin-ui-plugin-init.spec.ts (1)

17-17: Verify VendureConfigRef constructor change doesn't break functionality.

The removal of the { checkFileName: false } option suggests a breaking change to the VendureConfigRef constructor API. Ensure that the new constructor signature properly handles the file name checking functionality that was previously controlled by this option.

#!/bin/bash
# Description: Verify VendureConfigRef constructor and its usage across the codebase
# Expected: Find new constructor signature and ensure all usages are updated

# Search for VendureConfigRef constructor definition
ast-grep --pattern 'class VendureConfigRef {
  $$$
  constructor($$$) {
    $$$
  }
  $$$
}'

# Search for VendureConfigRef instantiations to verify consistency
rg -A 3 "new VendureConfigRef"

Also applies to: 35-35

packages/cli/src/cli.ts (2)

6-7: Clean architectural improvement.

The new imports support the centralized command registration approach, moving away from individual command definition to a more maintainable declarative structure.


30-31: I couldn’t confirm support for options, sub-commands, or handlers without seeing the full implementation. Let’s pull the contents of both files:

#!/bin/bash
# Show the registerCommands implementation
cat packages/cli/src/shared/command-registry.ts

# Show the cliCommands definitions
cat packages/cli/src/commands/command-declarations.ts
packages/cli/src/shared/shared-prompts.ts (3)

16-16: Good addition to support non-interactive mode.

The optional config parameter enables explicit configuration file specification, supporting the CLI's new non-interactive capabilities.


27-36: Excellent improvement for CLI project analysis.

The addition of rootDir: './src' compiler option ensures the CLI analyzes source files rather than compiled JavaScript files, which is exactly what's needed for CLI tooling. The structured approach to passing compiler options is clean and maintainable.


41-41: Proper config parameter propagation.

Including the config option in the return value ensures it's available to downstream consumers, maintaining consistency with the non-interactive mode architecture.

packages/cli/src/commands/command-declarations.ts (1)

3-85: Well-structured command declaration with good separation of concerns.

The declarative approach for CLI commands is excellent - it centralizes command definitions and makes the CLI more maintainable. The option structure is comprehensive and properly typed.

packages/cli/src/README.md (2)

22-29: Documentation inconsistency with actual implementation.

The CliCommandOption interface documented here uses a flag property, but the actual implementation in command-declarations.ts uses separate short and long properties.

 interface CliCommandOption {
-    flag: string;                    // Option flag (e.g., '-f, --file <path>')
+    short?: string;                  // Short flag (e.g., '-f')
+    long: string;                    // Long flag (e.g., '--file <path>')
     description: string;             // Option description
     required?: boolean;              // Whether the option is required
     defaultValue?: any;              // Default value for the option
+    subOptions?: CliCommandOption[]; // Optional nested sub-options
 }

Likely an incorrect or invalid review comment.


78-89: Update example to match actual implementation.

The example uses the flag property which doesn't match the actual interface. Update to use short and long properties.

 options: [
     {
-        flag: '-f, --file <path>',
+        short: '-f',
+        long: '--file <path>',
         description: 'Path to the file',
         required: true,
     },
     {
-        flag: '-v, --verbose',
+        long: '--verbose',
         description: 'Enable verbose output',
         required: false,
         defaultValue: false,
     },
 ],

Likely an incorrect or invalid review comment.

packages/cli/src/commands/add/ui-extensions/add-ui-extensions.ts (3)

15-20: Good interface extension for non-interactive mode support.

The addition of pluginName, config, and isNonInteractive options properly extends the interface to support both interactive and non-interactive usage patterns.


39-58: Excellent plugin resolution and validation logic.

The plugin lookup by name with proper error handling and the enforcement of plugin specification in non-interactive mode are well-implemented. The error message listing available plugins is particularly helpful for users.


111-111: Consistent config parameter usage.

The VendureConfigRef instantiation properly uses the optional config parameter, maintaining consistency with the enhanced interface.

packages/cli/src/commands/add/entity/add-entity.ts (3)

27-29: Consistent interface extension.

The addition of config and isNonInteractive options maintains consistency with other command interfaces in the refactor.


44-47: Clear error handling for non-interactive mode.

The validation that ensures a plugin is specified in non-interactive mode is essential and provides a clear error message.


89-95: Sensible defaults for non-interactive mode.

Providing default feature flags (customFields: true, translatable: false) when running in non-interactive mode without explicit features is a good UX decision.

packages/cli/src/shared/command-registry.ts (2)

5-33: Excellent centralized command registration system.

The registerCommands function elegantly handles the complex command structure with nested sub-options. The visual indentation for sub-options in help text is a nice UX touch.


44-47: Smart handling of optional value syntax.

The regex replacement converting <value> to [value] for optional options is a clever solution that maintains Commander.js compatibility while supporting the declarative option structure.

packages/cli/src/commands/add/codegen/add-codegen.ts (4)

16-19: LGTM! Clear interface extension for non-interactive mode.

The added properties properly support non-interactive CLI usage with explicit plugin and config specification.


33-33: LGTM! Config parameter properly propagated.


63-65: LGTM! Clean conditional logic for plugin selection.


111-114: LGTM! Consistent plugin processing.

The refactored loop simplifies the code by always iterating through the plugins array.

packages/cli/src/commands/add/service/add-service.ts (4)

27-29: LGTM! Interface properly extended.


52-65: LGTM! Proper handling of interactive vs non-interactive modes.

The code correctly defaults to 'basic' type and skips cancel checks in non-interactive mode.


67-70: LGTM! Proper option setup with sensible defaults.


94-115: LGTM! Smart service name handling.

The code efficiently skips the prompt when a custom service name is provided.

packages/cli/src/commands/add/add.ts (3)

8-20: LGTM! Clean imports and interface definition.


21-31: LGTM! Clear separation of interactive and non-interactive modes.

The logic correctly detects non-interactive mode based on the presence of any options.


63-113: LGTM! Clean refactoring of interactive mode logic.

The code was successfully extracted into a separate function without changing its behavior.

packages/cli/src/commands/add/add-operations.ts (1)

10-35: LGTM! Well-structured interface for CLI operations.

The interface provides a comprehensive set of options for all add operations with clear documentation.

packages/cli/src/shared/vendure-config-ref.ts (1)

27-40: LGTM! Excellent error messages for config file issues.

The error messages clearly guide users on how to resolve multiple config files or missing config scenarios.

coderabbitai bot added a commit that referenced this pull request Jun 20, 2025
Docstrings generation was requested by @HouseinIsProgramming.

* #3606 (comment)

The following files were modified:

* `packages/cli/src/commands/add/add-operations.ts`
* `packages/cli/src/commands/add/add.ts`
* `packages/cli/src/commands/add/api-extension/add-api-extension.ts`
* `packages/cli/src/commands/add/codegen/add-codegen.ts`
* `packages/cli/src/commands/add/entity/add-entity.ts`
* `packages/cli/src/commands/add/job-queue/add-job-queue.ts`
* `packages/cli/src/commands/add/plugin/create-new-plugin.ts`
* `packages/cli/src/commands/add/service/add-service.ts`
* `packages/cli/src/commands/add/ui-extensions/add-ui-extensions.ts`
* `packages/cli/src/commands/migrate/migrate.ts`
* `packages/cli/src/commands/migrate/migration-operations.ts`
* `packages/cli/src/shared/command-registry.ts`
* `packages/cli/src/shared/shared-prompts.ts`
Copy link
Contributor

coderabbitai bot commented Jun 20, 2025

Note

Generated docstrings for this pull request at #3607

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
packages/cli/src/commands/add/add-operations.ts (1)

240-254: Improve error handling consistency.

The current approach of checking for specific error messages is fragile and creates tight coupling, as noted in previous reviews.

Consider using error types or codes instead:

} catch (error: any) {
-    // Re-throw validation errors so they can be properly handled with stack trace
-    if (
-        error.message.includes('is required') ||
-        error.message.includes('cannot be empty') ||
-        error.message.includes('must be specified')
-    ) {
-        throw error;
-    }
+    // Re-throw validation errors
+    if (error.name === 'ValidationError' || error.code === 'VALIDATION_ERROR') {
+        throw error;
+    }
    return {
        success: false,
        message: error.message ?? 'Add operation failed',
    };
}

Then update the validation errors to use a custom error class:

class ValidationError extends Error {
    name = 'ValidationError';
    code = 'VALIDATION_ERROR';
}
docs/docs/guides/developer-guide/cli/index.md (1)

44-44: Address previous reviewer feedback on terminology.

A previous reviewer requested using "scripting" instead of "automation" in this context.

Consider updating:

- Non-interactive mode: Allows direct command execution with arguments and options, perfect for automation, CI/CD, and AI agents
+ Non-interactive mode: Allows direct command execution with arguments and options, perfect for scripting, CI/CD, and AI agents
🧹 Nitpick comments (5)
packages/cli/e2e/migrate-command.e2e-spec.ts (5)

83-97: Expand test coverage for invalid migration names.

The test only covers basic invalid names. Consider adding more edge cases for comprehensive validation.

             const invalidNames = [
                 '123-invalid', // starts with number
                 'test migration', // contains space
                 'test@migration', // special character
+                '', // empty string
+                'a', // too short (less than 2 chars)
+                'test/migration', // path separator
+                'test\\migration', // backslash
+                'test.migration', // dot
+                'migration!', // exclamation
+                'test>migration', // greater than
+                'test<migration', // less than
+                'a'.repeat(256), // extremely long name
             ];

117-122: Remove implementation details from test comments.

The comment mentions "synchronize is false" which is an implementation detail that doesn't belong in tests. This makes the test fragile to implementation changes.

-                // Since synchronize is false, generateMigration will create the initial migration
-                // The first time it runs, it will generate all tables
-                // Subsequent runs may report no changes
-                // Both are valid outcomes
+                // The operation should complete successfully
+                // It may generate migrations or report no changes depending on the database state

332-353: Enhance concurrent operations test to verify proper concurrency handling.

The test runs operations concurrently but doesn't verify if they properly handle potential race conditions or file conflicts.

         it('should handle concurrent operations gracefully', async () => {
             process.chdir(TEST_PROJECT_DIR);

             // Try to run multiple operations concurrently
             const operations = [
                 generateMigrationOperation({ name: 'Concurrent1', outputDir: MIGRATIONS_DIR }),
                 generateMigrationOperation({ name: 'Concurrent2', outputDir: MIGRATIONS_DIR }),
                 generateMigrationOperation({ name: 'Concurrent3', outputDir: MIGRATIONS_DIR }),
             ];

             const results = await Promise.all(operations);

             // All should complete without throwing
             results.forEach(result => {
                 expect(result).toHaveProperty('success');
                 expect(result).toHaveProperty('message');
             });

             // At least some should succeed
             const successCount = results.filter(r => r.success).length;
             expect(successCount).toBeGreaterThan(0);
+
+            // Verify that generated files don't conflict
+            const files = await fs.readdir(MIGRATIONS_DIR);
+            const timestamps = files
+                .filter(f => f.endsWith('.ts'))
+                .map(f => f.split('-')[0]);
+            
+            // Check for unique timestamps (no race condition in timestamp generation)
+            const uniqueTimestamps = new Set(timestamps);
+            expect(uniqueTimestamps.size).toBe(timestamps.length);
         });

356-373: Improve interrupted migration simulation.

The hardcoded partial migration content might not accurately represent a real interrupted migration scenario.

         it('should recover from interrupted migration generation', async () => {
             process.chdir(TEST_PROJECT_DIR);

             // Create a partial migration file to simulate interruption
             const partialFile = path.join(MIGRATIONS_DIR, '1234567890-Partial.ts');
-            await fs.writeFile(partialFile, 'export class Partial1234567890 {}');
+            // Create a more realistic partial migration file
+            await fs.writeFile(partialFile, `
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class Partial1234567890 implements MigrationInterface {
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        // Incomplete migration
+`);

             // Should still be able to generate new migrations
             const result = await generateMigrationOperation({
                 name: 'RecoveryTest',
                 outputDir: MIGRATIONS_DIR,
             });

             // The operation should complete successfully
             expect(result.success).toBe(true);
             expect(result.message).toBeDefined();
         });

399-400: Add newline at end of file.

The file is missing a newline character at the end, which is a common convention.

     });
 });
+
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a9c4731 and c0731a2.

📒 Files selected for processing (16)
  • .eslintrc.js (1 hunks)
  • docs/docs/guides/developer-guide/cli/index.md (3 hunks)
  • packages/cli/.gitignore (1 hunks)
  • packages/cli/e2e/config/tsconfig.e2e.json (1 hunks)
  • packages/cli/e2e/fixtures/test-entity.ts (1 hunks)
  • packages/cli/e2e/fixtures/test-project/package.json (1 hunks)
  • packages/cli/e2e/fixtures/test-project/src/vendure-config.ts (1 hunks)
  • packages/cli/e2e/fixtures/test-project/tsconfig.json (1 hunks)
  • packages/cli/e2e/fixtures/vendure-config.ts (1 hunks)
  • packages/cli/e2e/migrate-command.e2e-spec.ts (1 hunks)
  • packages/cli/e2e/vitest.e2e.config.mts (1 hunks)
  • packages/cli/package.json (1 hunks)
  • packages/cli/src/README.md (1 hunks)
  • packages/cli/src/commands/add/add-operations.ts (1 hunks)
  • packages/cli/src/commands/command-declarations.ts (1 hunks)
  • packages/cli/tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (9)
  • .eslintrc.js
  • packages/cli/e2e/fixtures/test-project/tsconfig.json
  • packages/cli/tsconfig.json
  • packages/cli/e2e/fixtures/test-project/package.json
  • packages/cli/.gitignore
  • packages/cli/src/README.md
  • packages/cli/e2e/config/tsconfig.e2e.json
  • packages/cli/e2e/fixtures/vendure-config.ts
  • packages/cli/e2e/fixtures/test-project/src/vendure-config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/commands/command-declarations.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: codegen / codegen
  • GitHub Check: build (22.x)
  • GitHub Check: publish_install (ubuntu-latest, 22.x)
  • GitHub Check: publish_install (macos-latest, 20.x)
  • GitHub Check: publish_install (macos-latest, 22.x)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
packages/cli/src/commands/add/add-operations.ts (1)

60-234: Comprehensive validation implementation looks excellent.

The validation logic for all operations is thorough and consistent. Each operation properly validates required parameters with clear error messages and appropriate usage examples. This addresses the previous concern about missing validation for other operations.

docs/docs/guides/developer-guide/cli/index.md (1)

155-267: Excellent comprehensive documentation.

The documentation clearly distinguishes between interactive and non-interactive modes with comprehensive examples, detailed flag descriptions, and proper validation notes. This significantly improves the developer experience for both manual and automated CLI usage.

packages/cli/package.json (1)

25-26: Clean e2e script addition.

The new e2e script properly integrates with the Vitest e2e configuration and follows the existing script pattern.

packages/cli/e2e/vitest.e2e.config.mts (1)

1-31: Well-configured e2e test setup.

The Vitest configuration is properly set up for CLI e2e testing:

  • SWC plugin enables decorator support for TypeORM entities
  • Single fork prevents test conflicts
  • Appropriate timeout and test pattern matching
  • Node environment suitable for CLI testing
packages/cli/e2e/fixtures/test-entity.ts (1)

1-15: Clean test entity implementation.

The test entity follows proper TypeORM and Vendure conventions with appropriate field types and decorators. Well-suited for testing CLI migration and entity generation functionality.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/cli/src/commands/add/service/add-service.ts (1)

53-53: Improve non-interactive mode detection logic.

The current detection providedOptions?.serviceName !== undefined may incorrectly classify empty strings as interactive mode triggers. Consider using a more explicit check.

-    const isNonInteractive = providedOptions?.serviceName !== undefined || providedOptions?.isNonInteractive;
+    const isNonInteractive = (providedOptions?.serviceName !== undefined && providedOptions?.serviceName !== '') || providedOptions?.isNonInteractive;

Alternatively, consider requiring an explicit isNonInteractive flag for clarity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0731a2 and 50fa7c0.

📒 Files selected for processing (4)
  • packages/cli/src/commands/add/add-operations.ts (1 hunks)
  • packages/cli/src/commands/add/entity/add-entity.ts (5 hunks)
  • packages/cli/src/commands/add/service/add-service.ts (4 hunks)
  • packages/cli/src/commands/command-declarations.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/cli/src/commands/command-declarations.ts
  • packages/cli/src/commands/add/add-operations.ts
  • packages/cli/src/commands/add/entity/add-entity.ts
⏰ Context from checks skipped due to timeout of 90000ms (20)
  • GitHub Check: unit tests (20.x)
  • GitHub Check: e2e tests (20.x, mariadb)
  • GitHub Check: e2e tests (22.x, mariadb)
  • GitHub Check: codegen / codegen
  • GitHub Check: e2e tests (22.x, mysql)
  • GitHub Check: e2e tests (20.x, sqljs)
  • GitHub Check: e2e tests (22.x, postgres)
  • GitHub Check: e2e tests (22.x, sqljs)
  • GitHub Check: e2e tests (20.x, mysql)
  • GitHub Check: e2e tests (20.x, postgres)
  • GitHub Check: unit tests (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: build (20.x)
  • GitHub Check: publish_install (macos-latest, 22.x)
  • GitHub Check: publish_install (ubuntu-latest, 20.x)
  • GitHub Check: publish_install (macos-latest, 20.x)
  • GitHub Check: publish_install (windows-latest, 20.x)
  • GitHub Check: publish_install (ubuntu-latest, 22.x)
  • GitHub Check: publish_install (windows-latest, 22.x)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (13)
packages/cli/src/commands/add/service/add-service.ts (13)

16-16: LGTM: Import addition is appropriate.

The getPluginClasses import aligns with the new plugin resolution functionality added below.


18-18: LGTM: Timeout utility import supports interactive enhancements.

The withInteractiveTimeout import is correctly used to wrap interactive prompts throughout the file.


28-32: LGTM: Interface extension supports non-interactive mode.

The new optional properties appropriately extend the interface to support both interactive and non-interactive modes.


46-50: LGTM: Config option passed to analyzeProject.

The config parameter is correctly passed through to support project analysis with custom configuration.


54-58: LGTM: Appropriate validation for non-interactive mode.

The error message clearly indicates what's required and provides helpful guidance for the user.


63-75: LGTM: Plugin resolution by name is well-implemented.

The logic correctly finds plugins by name and provides helpful error messages with available alternatives when the specified plugin is not found.


81-93: LGTM: Service type selection handles both modes appropriately.

The logic correctly defaults to 'basic' in non-interactive mode and wraps the interactive prompt with timeout functionality.


94-97: LGTM: Cancellation handling respects non-interactive mode.

The condition correctly skips cancellation handling when in non-interactive mode.


99-102: LGTM: Options assignment includes new config parameter.

The config option is properly passed through to support the enhanced functionality.


107-118: LGTM: Entity selection by name is well-implemented.

The logic correctly finds entities by name within the plugin and provides helpful error messages with available alternatives.


119-132: LGTM: Fallback to interactive entity selection is appropriate.

The existing interactive logic is preserved when not in non-interactive mode or when no entity name is provided.


142-156: LGTM: Service name handling supports both modes.

The logic correctly skips the prompt when a non-default service name is provided and maintains the validation logic for interactive mode.


158-163: LGTM: Cancellation handling consistent with non-interactive mode.

The condition correctly skips cancellation handling when in non-interactive mode, maintaining consistency with the pattern established earlier in the file.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/cli/e2e/vitest.e2e.config.mts (1)

14-14: Consider improving type safety for the SWC plugin configuration.

The as any type assertion suggests a potential type compatibility issue with the SWC plugin and Vitest.

Consider using a more specific type assertion if possible:

-        }) as any,
+        }) as Parameters<typeof defineConfig>[0]['plugins'][0],

Or alternatively, check if there's a more recent version of unplugin-swc that provides better TypeScript compatibility with Vitest.

packages/cli/e2e/add-command.e2e-spec.ts (1)

25-33: Consider improving type safety in the stubRun utility.

The as any casting in the stubRun function, while functional, could be improved for better type safety.

Consider using a more specific type constraint:

-function stubRun(cmd: { run: (...args: any[]) => any }): Spy {
+function stubRun<T extends { run: (...args: any[]) => Promise<any> }>(cmd: T): Spy {
     // Cast to 'any' to avoid over-constraining the generic type parameters that
     // vitest uses on spyOn, which causes type inference issues in strict mode.
     // The runtime behaviour (spying on an object method) is what matters for
     // these tests – the precise compile-time types are not important.
     return vi
-        .spyOn(cmd as any, 'run')
+        .spyOn(cmd, 'run')
         .mockResolvedValue({ project: undefined, modifiedSourceFiles: [] } as any);
 }

This maintains the flexibility while providing better type constraints.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a49dee3 and 386a0f6.

📒 Files selected for processing (3)
  • packages/cli/e2e/add-command.e2e-spec.ts (1 hunks)
  • packages/cli/e2e/migrate-command.e2e-spec.ts (1 hunks)
  • packages/cli/e2e/vitest.e2e.config.mts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/e2e/migrate-command.e2e-spec.ts
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: build (22.x)
  • GitHub Check: publish_install (macos-latest, 22.x)
  • GitHub Check: publish_install (windows-latest, 20.x)
🔇 Additional comments (5)
packages/cli/e2e/vitest.e2e.config.mts (1)

1-31: Well-configured e2e test setup for CLI testing.

The Vitest configuration is appropriately structured for end-to-end CLI testing with proper environment settings, timeout configuration, and SWC plugin integration for decorator support.

packages/cli/e2e/add-command.e2e-spec.ts (4)

1-201: Excellent comprehensive test coverage for the add command.

This test suite provides thorough coverage of all add command operations including success scenarios, error handling, and non-interactive mode validation. The test structure is well-organized with proper setup and cleanup.


69-74: Good validation test for plugin name requirements.

The test properly validates that empty plugin names are rejected, which is essential for non-interactive mode reliability.


96-101: Excellent test coverage for non-interactive mode constraints.

This test properly validates that the add command correctly enforces plugin name requirements when running in non-interactive mode, which is crucial for the new CLI structure.


191-199: Good fallback behavior test for invalid operations.

The test ensures that the command gracefully handles cases where no valid operation is specified, providing appropriate error messaging.

Copy link
Collaborator

@dlhck dlhck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🚀 Please check why the E2E tests are failing now. All checks should be green before we can merge the PR.

Copy link
Contributor

github-actions bot commented Jun 24, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@HouseinIsProgramming
Copy link
Collaborator Author

I have read the CLA Document and I hereby sign the CLA

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
6.1% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@dlhck dlhck merged commit 7d9f03b into minor Jun 25, 2025
39 of 40 checks passed
@dlhck dlhck deleted the feat-cli-noninteractive branch June 25, 2025 09:33
@github-actions github-actions bot locked and limited conversation to collaborators Jun 25, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants