diff --git a/.cursor/commands/code-review.md b/.cursor/commands/code-review.md index 669fec771..c336c0aa1 100644 --- a/.cursor/commands/code-review.md +++ b/.cursor/commands/code-review.md @@ -1,6 +1,6 @@ --- name: code-review -description: Automated PR review using comprehensive checklist tailored for modularized Contentstack CLI +description: Automated PR review using comprehensive checklist tailored for Contentstack CLI plugins --- # Code Review Command @@ -10,9 +10,9 @@ description: Automated PR review using comprehensive checklist tailored for modu ### Scope-Based Reviews - `/code-review` - Review all current changes with full checklist - `/code-review --scope typescript` - Focus on TypeScript configuration and patterns -- `/code-review --scope testing` - Focus on Mocha/Chai test patterns +- `/code-review --scope testing` - Focus on Mocha/Chai/Sinon test patterns +- `/code-review --scope contentstack` - Focus on API integration and CLI patterns - `/code-review --scope oclif` - Focus on command structure and OCLIF patterns -- `/code-review --scope packages` - Focus on package structure and organization ### Severity Filtering - `/code-review --severity critical` - Show only critical issues (security, breaking changes) @@ -20,137 +20,103 @@ description: Automated PR review using comprehensive checklist tailored for modu - `/code-review --severity all` - Show all issues including suggestions ### Package-Aware Reviews -- `/code-review --package contentstack-import` - Review changes in import package -- `/code-review --package contentstack-export` - Review changes in export package -- `/code-review --package-type plugin` - Review all plugin packages (all 12 packages are plugins) -- `/code-review --package-scope cm` - Review CM (content management) related packages +- `/code-review --package contentstack-import` - Review changes in specific package +- `/code-review --package-type plugin` - Review plugin packages only +- `/code-review --package-type library` - Review library packages (e.g., variants) ### File Type Focus - `/code-review --files commands` - Review command files only - `/code-review --files tests` - Review test files only -- `/code-review --files utils` - Review utility files +- `/code-review --files modules` - Review import/export modules ## Comprehensive Review Checklist ### Monorepo Structure Compliance -- **Package organization**: 12 plugin packages under `packages/contentstack-*` -- **pnpm workspace**: Correct `pnpm-workspace.yaml` configuration +- **Package organization**: Proper placement in `packages/` structure +- **pnpm workspace**: Correct `package.json` workspace configuration - **Build artifacts**: No `lib/` directories committed to version control - **Dependencies**: Proper use of shared utilities (`@contentstack/cli-command`, `@contentstack/cli-utilities`) -- **Scripts**: Consistent build, test, and lint scripts across packages -### Package-Specific Structure -- **All packages are plugins**: Each has `oclif.commands` configuration pointing to `./lib/commands` -- **Plugin topics**: All commands under `cm:` topic (content management) -- **Base commands**: Each plugin defines its own `BaseCommand` extending `@contentstack/cli-command` Command -- **Inter-plugin dependencies**: Some plugins depend on others (e.g., import depends on audit) -- **Dependency versions**: Using consistent versions across plugins - -### TypeScript Standards -- **Configuration compliance**: Follows package TypeScript config (`strict: false`, `target: es2017`) +### TypeScript Standards (Repository-Specific) +- **Configuration compliance**: Follows package-specific TypeScript config - **Naming conventions**: kebab-case files, PascalCase classes, camelCase functions +- **Type safety**: Appropriate use of strict mode vs relaxed settings per package - **Import patterns**: ES modules with proper default/named exports -- **Type safety**: No unnecessary `any` types in production code - -### OCLIF Command Patterns -- **Base class usage**: Extends plugin-specific `BaseCommand` or `@contentstack/cli-command` Command -- **Command structure**: Proper `static id`, `static description`, `static examples`, `static flags` -- **Topic organization**: Uses `cm:stacks:*` structure (`cm:stacks:import`, `cm:stacks:export`, `cm:stacks:audit`) -- **Error handling**: Uses `handleAndLogError` from utilities with context -- **Flag validation**: Early validation and user-friendly error messages -- **Service delegation**: Commands are thin, services handle business logic - -### Testing Excellence (Mocha/Chai Stack) -- **Framework compliance**: Uses Mocha + Chai (not Jest) -- **File patterns**: Follows `*.test.ts` naming convention -- **Directory structure**: Proper placement in `test/unit/` -- **Test organization**: Arrange-Act-Assert pattern consistently used -- **Isolation**: Proper setup/teardown with beforeEach/afterEach +- **Migration strategy**: Proper use of `@ts-ignore` during gradual migration + +### OCLIF Command Patterns (Actual Implementation) +- **Base class usage**: Extends `@contentstack/cli-command` (not `@oclif/core`) +- **Command structure**: Proper `static description`, `examples`, `flags` +- **Topic organization**: Uses `cm` topic structure (`cm:stacks:import`) +- **Error handling**: Uses `handleAndLogError` from utilities +- **Validation**: Early flag validation and user-friendly error messages +- **Service delegation**: Commands orchestrate, services implement business logic + +### Testing Excellence (Mocha/Chai/Sinon Stack) +- **Framework compliance**: Uses Mocha + Chai + Sinon (not Jest) +- **File patterns**: Follows `*.test.ts` naming (or `*.test.js` for bootstrap) +- **Directory structure**: Proper placement in `test/unit/`, `test/lib/`, etc. +- **Mock patterns**: Proper Sinon stubbing of SDK methods +- **Coverage configuration**: Correct nyc setup (watch for `inlcude` typo) +- **Test isolation**: Proper `beforeEach`/`afterEach` with `sinon.restore()` - **No real API calls**: All external dependencies properly mocked -### Error Handling Standards -- **Consistent patterns**: Use `handleAndLogError` from utilities -- **User-friendly messages**: Clear error descriptions for end users -- **Logging**: Proper use of `log.debug` for diagnostic information -- **Status messages**: Use `cliux` for user feedback (success, error, info) - -### Build and Compilation -- **TypeScript compilation**: Clean compilation with no errors -- **OCLIF manifest**: Generated for command discovery -- **README generation**: Commands documented in package README -- **Source maps**: Properly configured for debugging -- **No build artifacts in commit**: `.gitignore` excludes `lib/` directories - -### Testing Coverage -- **Test structure**: Tests in `test/unit/` with descriptive names -- **Command testing**: Uses @oclif/test for command validation -- **Error scenarios**: Tests for both success and failure paths -- **Mocking**: All dependencies properly mocked - -### Package.json Compliance -- **Correct metadata**: name, description, version, author -- **Script definitions**: build, compile, test, lint scripts present -- **Dependencies**: Correct versions of shared packages -- **Main/types**: Properly configured for library packages -- **OCLIF config**: Present for plugin packages +### Contentstack API Integration (Real Patterns) +- **SDK usage**: Proper `managementSDKClient` and fluent API chaining +- **Authentication**: Correct `configHandler` and token alias handling +- **Rate limiting compliance**: + - Batch spacing (minimum 1 second between batches) + - 429 retry handling with exponential backoff + - Pagination throttling for variants +- **Error handling**: Proper `handleAndLogError` usage and user-friendly messages +- **Configuration**: Proper regional endpoint and management token handling + +### Import/Export Module Architecture +- **BaseClass extension**: Proper inheritance from import/export BaseClass +- **Batch processing**: Correct use of `makeConcurrentCall` and `logMsgAndWaitIfRequired` +- **Module organization**: Proper entity-specific module structure +- **Configuration handling**: Proper `ModuleClassParams` usage +- **Progress feedback**: Appropriate user feedback during long operations ### Security and Best Practices -- **No secrets**: No API keys or tokens in code or tests +- **Token security**: No API keys or tokens logged or committed - **Input validation**: Proper validation of user inputs and flags -- **Process management**: Appropriate use of error codes -- **File operations**: Safe handling of file system operations - -### Code Quality -- **Naming consistency**: Follow established conventions -- **Comments**: Only for non-obvious logic (no "narration" comments) -- **Error messages**: Clear, actionable messages for users -- **Module organization**: Proper separation of concerns +- **Error exposure**: No sensitive information in error messages +- **File permissions**: Proper handling of file system operations +- **Process management**: Appropriate use of `process.exit(1)` for critical failures + +### Performance Considerations +- **Concurrent processing**: Proper use of `Promise.allSettled` for batch operations +- **Memory management**: Appropriate handling of large datasets +- **Rate limiting**: Compliance with Contentstack API limits (10 req/sec) +- **Batch sizing**: Appropriate batch sizes for different operations +- **Progress tracking**: Efficient progress reporting without performance impact + +### Package-Specific Patterns +- **Plugin vs Library**: Correct `oclif.commands` configuration for plugin packages +- **Command compilation**: Proper build pipeline (`tsc` → `lib/commands` → `oclif manifest`) +- **Dependency management**: Correct use of shared vs package-specific dependencies +- **Test variations**: Handles different test patterns per package (JS vs TS, different structures) ## Review Execution ### Automated Checks -1. **Lint compliance**: ESLint checks for code style -2. **TypeScript compiler**: Successful compilation to `lib/` directories -3. **Test execution**: All tests pass successfully -4. **Build verification**: Build scripts complete without errors +1. **Lint compliance**: ESLint and TypeScript compiler checks +2. **Test coverage**: nyc coverage thresholds (where enforced) +3. **Build verification**: Successful compilation to `lib/` directories +4. **Dependency audit**: No security vulnerabilities in dependencies ### Manual Review Focus Areas -1. **Command usability**: Clear help text and realistic examples -2. **Error handling**: Appropriate error messages and recovery options -3. **Test quality**: Comprehensive test coverage for critical paths -4. **Monorepo consistency**: Consistent patterns across all packages -5. **Flag design**: Intuitive flag names and combinations +1. **API integration patterns**: Verify proper SDK usage and error handling +2. **Rate limiting implementation**: Check for proper throttling mechanisms +3. **Test quality**: Verify comprehensive mocking and error scenario coverage +4. **Command usability**: Ensure clear help text and examples +5. **Monorepo consistency**: Check for consistent patterns across packages ### Common Issues to Flag -- **Inconsistent TypeScript settings**: Mixed strict mode without reason -- **Real API calls in tests**: Unmocked external dependencies -- **Missing error handling**: Commands that fail silently -- **Poor test organization**: Tests without clear Arrange-Act-Assert -- **Build artifacts committed**: `lib/` directories in version control -- **Unclear error messages**: Non-actionable error descriptions -- **Inconsistent flag naming**: Similar flags with different names -- **Missing command examples**: Examples not showing actual usage - -## Repository-Specific Checklist - -### For Modularized CLI -- [ ] Command properly extends `@contentstack/cli-command` Command -- [ ] Flags defined with proper types from `@contentstack/cli-utilities` -- [ ] Error handling uses `handleAndLogError` utility -- [ ] User feedback uses `cliux` utilities -- [ ] Tests use Mocha + Chai pattern with mocked dependencies -- [ ] Package.json has correct scripts (build, compile, test, lint) -- [ ] TypeScript compiles with no errors -- [ ] Tests pass: `pnpm test` -- [ ] No `.only` or `.skip` in test files -- [ ] Build succeeds: `pnpm run build` -- [ ] OCLIF manifest generated successfully - -### Before Merge -- [ ] All review items addressed -- [ ] No build artifacts in commit -- [ ] Tests added for new functionality -- [ ] Documentation updated if needed -- [ ] No console.log() statements (use log.debug instead) -- [ ] Error messages are user-friendly -- [ ] No secrets or credentials in code +- **Coverage config typos**: `"inlcude"` instead of `"include"` in `.nycrc.json` +- **Inconsistent TypeScript**: Mixed strict mode usage without migration plan +- **Real API calls in tests**: Any unmocked external dependencies +- **Missing rate limiting**: API calls without proper throttling +- **Build artifacts committed**: Any `lib/` directories in version control +- **Inconsistent error handling**: Not using utilities error handling patterns diff --git a/.cursor/commands/execute-tests.md b/.cursor/commands/execute-tests.md index a27de0cdc..7cde58bbd 100644 --- a/.cursor/commands/execute-tests.md +++ b/.cursor/commands/execute-tests.md @@ -9,24 +9,25 @@ description: Run tests by scope, file, or module with intelligent filtering for ### Monorepo-Wide Testing - `/execute-tests` - Run all tests across all packages -- `/execute-tests --coverage` - Run all tests with coverage reporting +- `/execute-tests --coverage` - Run all tests with nyc coverage report - `/execute-tests --parallel` - Run package tests in parallel using pnpm ### Package-Specific Testing -- `/execute-tests contentstack-import` - Run tests for import package -- `/execute-tests contentstack-export` - Run tests for export package -- `/execute-tests contentstack-audit` - Run tests for audit package -- `/execute-tests contentstack-clone` - Run tests for clone package -- `/execute-tests packages/contentstack-import/` - Run tests using path +- `/execute-tests packages/contentstack-audit/` - Run tests for specific package +- `/execute-tests packages/contentstack-import/` - Run import package tests +- `/execute-tests packages/contentstack-export/` - Run export package tests +- `/execute-tests contentstack-migration` - Run tests by package name (shorthand) ### Scope-Based Testing - `/execute-tests unit` - Run unit tests only (`test/unit/**/*.test.ts`) -- `/execute-tests commands` - Run command tests (`test/unit/commands/**/*.test.ts`) +- `/execute-tests commands` - Run command tests (`test/commands/**/*.test.ts`) - `/execute-tests services` - Run service layer tests +- `/execute-tests modules` - Run import/export module tests ### File Pattern Testing - `/execute-tests *.test.ts` - Run all TypeScript tests -- `/execute-tests test/unit/commands/` - Run tests for specific directory +- `/execute-tests *.test.js` - Run JavaScript tests (bootstrap package) +- `/execute-tests test/unit/services/` - Run tests for specific directory ### Watch and Development - `/execute-tests --watch` - Run tests in watch mode with file monitoring @@ -36,26 +37,11 @@ description: Run tests by scope, file, or module with intelligent filtering for ## Intelligent Filtering ### Repository-Aware Detection -- **Test patterns**: All use `*.test.ts` naming convention -- **Directory structures**: Standard `test/unit/` layout -- **Test locations**: `packages/*/test/unit/**/*.test.ts` +- **Test patterns**: Primarily `*.test.ts`, some `*.test.js` (bootstrap), rare `*.spec.ts` +- **Directory structures**: `test/unit/`, `test/lib/`, `test/seed/`, `test/commands/` +- **Package variations**: Different test layouts per package - **Build exclusion**: Ignores `lib/` directories (compiled artifacts) -### Package Structure -The monorepo contains 12 CLI plugin packages: -- `contentstack-audit` - Stack audit and fix operations -- `contentstack-bootstrap` - Seed/bootstrap stacks -- `contentstack-branches` - Git-based branch management -- `contentstack-bulk-publish` - Bulk publish operations -- `contentstack-clone` - Clone/duplicate stacks -- `contentstack-export` - Export stack content -- `contentstack-export-to-csv` - Export to CSV format -- `contentstack-import` - Import content to stacks -- `contentstack-import-setup` - Import setup and validation -- `contentstack-migration` - Content migration workflows -- `contentstack-seed` - Seed stacks with data -- `contentstack-variants` - Manage content variants - ### Monorepo Integration - **pnpm workspace support**: Uses `pnpm -r --filter` for package targeting - **Dependency awareness**: Understands package interdependencies @@ -64,9 +50,9 @@ The monorepo contains 12 CLI plugin packages: ### Framework Detection - **Mocha configuration**: Respects `.mocharc.json` files per package -- **TypeScript compilation**: Handles test TypeScript setup -- **Test setup**: Detects test helper initialization files -- **Test timeout**: 30 seconds standard (configurable per package) +- **TypeScript compilation**: Handles `pretest: tsc -p test` scripts +- **Coverage integration**: Works with nyc configuration (`.nycrc.json`) +- **Test helpers**: Detects and includes test initialization files ## Execution Examples @@ -76,16 +62,16 @@ The monorepo contains 12 CLI plugin packages: /execute-tests --coverage # Test specific package during development -/execute-tests contentstack-import --watch +/execute-tests packages/contentstack-import/ --watch -# Run only command tests across all packages -/execute-tests commands +# Run only unit tests across all packages +/execute-tests unit -# Run unit tests with detailed output -/execute-tests --debug +# Test import/export modules specifically +/execute-tests modules --coverage -# Test until first failure (quick feedback) -/execute-tests --bail +# Debug failing tests in audit package +/execute-tests packages/contentstack-audit/ --debug --bail ``` ### Package-Specific Commands Generated @@ -93,160 +79,29 @@ The monorepo contains 12 CLI plugin packages: # For contentstack-import package cd packages/contentstack-import && pnpm test -# For all packages with parallel execution -pnpm -r run test +# For all packages with coverage +pnpm -r --filter './packages/*' run test:coverage # For specific test file -cd packages/contentstack-import && npx mocha "test/unit/commands/import.test.ts" - -# With coverage -pnpm -r run test:coverage +cd packages/contentstack-export && npx mocha test/unit/export/modules/stack.test.ts ``` ## Configuration Awareness ### Mocha Integration - Respects individual package `.mocharc.json` configurations -- Handles TypeScript compilation via ts-node/register +- Handles TypeScript compilation via `ts-node/register` - Supports test helpers and initialization files -- Manages timeout settings per package (default 30 seconds) - -### Test Configuration -```json -// .mocharc.json -{ - "require": [ - "test/helpers/init.js", - "ts-node/register", - "source-map-support/register" - ], - "recursive": true, - "timeout": 30000, - "spec": "test/**/*.test.ts" -} -``` +- Manages timeout settings per package + +### Coverage Integration +- Uses nyc for coverage reporting +- Respects `.nycrc.json` configurations (with typo detection) +- Generates HTML, text, and lcov reports +- Handles TypeScript source mapping ### pnpm Workspace Features - Leverages workspace dependency resolution - Supports filtered execution by package patterns - Enables parallel test execution across packages - Respects package-specific scripts and configurations - -## Test Structure - -### Standard Test Organization -``` -packages/*/ -├── test/ -│ └── unit/ -│ ├── commands/ # Command-specific tests -│ ├── services/ # Service/business logic tests -│ └── utils/ # Utility function tests -└── src/ - ├── commands/ # CLI commands - ├── services/ # Business logic - └── utils/ # Utilities -``` - -### Test File Naming -- **Pattern**: `*.test.ts` across all packages -- **Location**: `test/unit/` directories -- **Organization**: Mirrors `src/` structure for easy navigation - -## Performance Optimization - -### Parallel Testing -```bash -# Run tests in parallel for faster feedback -pnpm -r --filter './packages/*' run test - -# Watch mode during development -/execute-tests --watch -``` - -### Selective Testing -- Run only affected packages' tests during development -- Use `--bail` to stop on first failure for quick iteration -- Target specific test files for focused debugging - -## Troubleshooting - -### Common Issues - -**Tests not found** -- Check that files follow `*.test.ts` pattern -- Verify files are in `test/unit/` directory -- Ensure `.mocharc.json` has correct spec pattern - -**TypeScript compilation errors** -- Verify `tsconfig.json` in package root -- Check that `ts-node/register` is in `.mocharc.json` requires -- Run `pnpm compile` to check TypeScript errors - -**Watch mode not detecting changes** -- Verify `--watch` flag is supported in your Mocha version -- Check that file paths are correct -- Ensure no excessive `.gitignore` patterns - -**Port conflicts** -- Tests should not use hard-coded ports -- Use dynamic port allocation or test isolation -- Check for process cleanup in `afterEach` hooks - -## Best Practices - -### Test Execution -- Run tests before committing: `pnpm test` -- Use `--bail` during development for quick feedback -- Run full suite before opening PR -- Check coverage for critical paths - -### Test Organization -- Keep tests close to source code structure -- Use descriptive test names -- Group related tests with `describe` blocks -- Clean up resources in `afterEach` - -### Debugging -- Use `--debug` flag for detailed output -- Add `log.debug()` statements in tests -- Run individual test files for isolation -- Use `--bail` to stop at first failure - -## Integration with CI/CD - -### GitHub Actions -- Runs `pnpm test` on pull requests -- Enforces test passage before merge -- May include coverage reporting -- Runs linting and build verification - -### Local Development -```bash -# Before committing -pnpm test -pnpm run lint -pnpm run build - -# Or use watch mode for faster iteration -pnpm test --watch -``` - -## Coverage Reporting - -### Coverage Commands -```bash -# Run tests with coverage -/execute-tests --coverage - -# Coverage output location -coverage/ -├── index.html # HTML report -├── coverage-summary.json # JSON summary -└── lcov.info # LCOV format -``` - -### Coverage Goals -- **Team aspiration**: 80% minimum coverage -- **Focus on**: Critical business logic and error paths -- **Not critical**: Utility functions and edge cases diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md index 6c4c0e333..f5c1f8701 100644 --- a/.cursor/rules/README.md +++ b/.cursor/rules/README.md @@ -1,102 +1,5 @@ -# Cursor Rules +# Cursor (optional) -Context-aware rules that load automatically based on the files you're editing, optimized for this CLI plugins monorepo. +**Cursor** users: start at **[AGENTS.md](../../AGENTS.md)**. All conventions live in **`skills/*/SKILL.md`**. -## Rule Files - -| File | Scope | Always Applied | Purpose | -|------|-------|----------------|---------| -| `dev-workflow.md` | `**/*.ts`, `**/*.js`, `**/*.json` | Yes | Monorepo TDD workflow, pnpm workspace patterns (12 plugin packages) | -| `typescript.mdc` | `**/*.ts`, `**/*.tsx` | No | TypeScript configurations and naming conventions | -| `testing.mdc` | `**/test/**/*.ts`, `**/test/**/*.js`, `**/__tests__/**/*.ts`, `**/*.spec.ts`, `**/*.test.ts` | Yes | Mocha, Chai test patterns and test structure | -| `oclif-commands.mdc` | `**/commands/**/*.ts`, `**/base-command.ts` | No | OCLIF command patterns and CLI validation | -| `contentstack-plugin.mdc` | `packages/contentstack-*/src/**/*.ts`, `packages/contentstack-*/src/**/*.js` | No | CLI plugin package patterns, commands, services, and inter-plugin dependencies | - -## Commands - -| File | Trigger | Purpose | -|------|---------|---------| -| `execute-tests.md` | `/execute-tests` | Run tests by scope, package, or module with monorepo awareness | -| `code-review.md` | `/code-review` | Automated PR review with CLI-specific checklist | - -## Loading Behaviour - -### File Type Mapping -- **TypeScript files** → `typescript.mdc` + `dev-workflow.md` -- **Command files** (`packages/*/src/commands/**/*.ts`) → `oclif-commands.mdc` + `typescript.mdc` + `dev-workflow.md` -- **Base command files** (`packages/*/src/base-command.ts`, `packages/*/*base-command.ts`) → `oclif-commands.mdc` + `typescript.mdc` + `dev-workflow.md` -- **Plugin package files** (`packages/contentstack-*/src/**/*.ts`) → `contentstack-plugin.mdc` + `typescript.mdc` + `dev-workflow.md` -- **Test files** (`packages/*/test/**/*.{ts,js}`) → `testing.mdc` + `dev-workflow.md` -- **Utility files** (`packages/*/src/utils/**/*.ts`) → `typescript.mdc` + `dev-workflow.md` - -### Package-Specific Loading -- **Plugin packages** (with `oclif.commands`) → Full command and utility rules -- **Library packages** → TypeScript and utility rules only - -## Repository-Specific Features - -### Monorepo Structure - -This is a **CLI plugins** monorepo with plugin packages under `packages/`, including: -- `contentstack-audit` - Stack audit and fix operations -- `contentstack-bootstrap` - Seed/bootstrap stacks with content -- `contentstack-branches` - Git-based branch management for stacks -- `contentstack-bulk-publish` - Bulk publish operations for entries/assets -- `contentstack-clone` - Clone/duplicate stacks -- `contentstack-export` - Export stack content to filesystem -- `contentstack-export-to-csv` - Export stack data to CSV format -- `contentstack-import` - Import content into stacks -- `contentstack-import-setup` - Setup and validation for imports -- `contentstack-migration` - Content migration workflows -- `contentstack-seed` - Seed stacks with generated data -- `contentstack-variants` - Manage content variants -- `contentstack-apps-cli` - Developer Hub apps (`app:*` commands; npm `@contentstack/apps-cli`) -- `contentstack-content-type` - Content Type introspection (`content-type:*` commands; npm `contentstack-cli-content-type`; Jest tests) -- `contentstack-cli-tsgen` - TypeScript typings (`csdx tsgen`; npm `contentstack-cli-tsgen`; Jest integration tests) - -All plugins depend on: -- `@contentstack/cli-command` - Base Command class -- `@contentstack/cli-utilities` - Shared utilities and helpers -- Optionally on each other (e.g., `contentstack-import` depends on `@contentstack/cli-audit`) - -### Build Configuration -- **pnpm workspaces** configuration (all 12 plugins under `packages/`) -- **Shared dependencies**: Each plugin depends on `@contentstack/cli-command` and `@contentstack/cli-utilities` -- **Inter-plugin dependencies**: Some plugins depend on others (e.g., import → audit) -- **Build process**: TypeScript compilation → `lib/` directories -- **OCLIF manifest** generation per plugin for command discovery - -### Actual Patterns Detected -- **Testing**: Mocha + Chai (consistent across all plugins) -- **TypeScript**: Strict mode for type safety -- **Commands**: Extend `@contentstack/cli-command` Command class with plugin-specific base-commands -- **Topics**: All commands under `cm:` topic (content management) -- **Services/Modules**: Domain-specific business logic organized by concern -- **Build artifacts**: `lib/` directories (excluded from rules) - -## Performance Benefits - -- **Lightweight loading** - Only relevant rules activate based on file patterns -- **Precise glob patterns** - Avoid loading rules for build artifacts -- **Context-aware** - Rules load based on actual file structure - -## Design Principles - -### Validated Against Codebase -- Rules reflect **actual patterns** found in repository -- Glob patterns match **real file structure** -- Examples use **actual dependencies** and APIs - -### Lightweight and Focused -- Each rule has **single responsibility** -- Package-specific variations acknowledged -- `alwaysApply: true` only for truly universal patterns - -## Quick Reference - -For detailed patterns: -- **Testing**: See `testing.mdc` for Mocha/Chai test structure -- **Commands**: See `oclif-commands.mdc` for command development -- **Plugins**: See `contentstack-plugin.mdc` for plugin architecture and patterns -- **Development**: See `dev-workflow.md` for TDD and monorepo workflow -- **TypeScript**: See `typescript.mdc` for type safety patterns +This folder only points contributors to **`AGENTS.md`** so editor-specific config does not duplicate the canonical docs. diff --git a/.cursor/rules/contentstack-cli.mdc b/.cursor/rules/contentstack-cli.mdc new file mode 100644 index 000000000..b7ec1b81b --- /dev/null +++ b/.cursor/rules/contentstack-cli.mdc @@ -0,0 +1,165 @@ +--- +description: 'Contentstack CLI specific patterns and API integration' +globs: ['**/import/**/*.ts', '**/export/**/*.ts', '**/modules/**/*.ts', '**/services/**/*.ts', '**/utils/**/*.ts'] +alwaysApply: false +--- + +# Contentstack CLI Standards + +## API Integration + +- Use `@contentstack/cli-utilities` for SDK factory: `managementSDKClient(config)` +- Stack-scoped API access: `stackAPIClient.asset()`, `stackAPIClient.extension()` +- Fluent SDK chaining: `stack.contentType().entry().query().find()` +- Custom HTTP for variants: `apiClient.put/get` with path strings + +## Authentication + +- Use `@contentstack/cli-utilities` for token management +- Management token alias: `configHandler.get('tokens.')` +- OAuth context: `configHandler.get('userUid'|'email'|'oauthOrgUid')` +- Authentication check: `isAuthenticated()` before operations +- Never log API keys or tokens in console or files + +## Rate Limiting - Multiple Mechanisms + +### Batch Spacing (Import/Export) +```typescript +// ✅ GOOD - Ensure minimum 1 second between batches +async logMsgAndWaitIfRequired(processName: string, start: number): Promise { + const end = Date.now(); + const exeTime = end - start; + if (exeTime < 1000) await this.delay(1000 - exeTime); +} +``` + +### 429 Retry (Branches) +```typescript +// ✅ GOOD - Handle 429 with retry +export async function handleErrorMsg(err, retryCallback?: () => Promise) { + if (err?.status === 429 || err?.response?.status === 429) { + await new Promise((resolve) => setTimeout(resolve, 1000)); // 1 sec delay + if (retryCallback) { + return retryCallback(); // Retry the request + } + } +} +``` + +### Variant Pagination Throttle +```typescript +// ✅ GOOD - Throttle variant API requests +if (requestTime < 1000) { + await delay(1000 - requestTime); +} +``` + +## Error Handling + +### Standard Pattern +```typescript +// ✅ GOOD - Use handleAndLogError from utilities +try { + const result = await this.stack.contentType().entry().fetch(); +} catch (error) { + handleAndLogError(error); + this.logAndPrintErrorDetails(error, config); +} +``` + +### User-Friendly Errors +```typescript +// ✅ GOOD - User-facing error display +cliux.print(errorMessage, { color: 'red' }); +// For critical failures +process.exit(1); +``` + +## Module Architecture (Import/Export) + +### BaseClass Pattern +```typescript +// ✅ GOOD - Extend BaseClass for entity modules +export class ContentTypes extends BaseClass { + constructor(params: ModuleClassParams) { + super(params); + // Entity-specific initialization + } + + async import(): Promise { + // Use this.makeConcurrentCall for batching + // Use this.logMsgAndWaitIfRequired for rate limiting + } +} +``` + +### Batch Processing +```typescript +// ✅ GOOD - Concurrent batch processing +const batches = chunk(apiContent, batchSize); +for (const batch of batches) { + const start = Date.now(); + await this.makeConcurrentCall(batch, this.processItem.bind(this)); + await this.logMsgAndWaitIfRequired('Processing', start, batches.length, batchIndex); +} +``` + +## Configuration Patterns + +### Import/Export Config +```typescript +// ✅ GOOD - Use configHandler for management tokens +const config = { + host: configHandler.get('region.cma'), + managementTokenAlias: flags.alias, + stackApiKey: flags['stack-api-key'], + rateLimit: 5, // Default rate limit +}; +``` + +### Regional Configuration +```typescript +// ✅ GOOD - Handle regional endpoints +const defaultConfig = { + host: 'https://api.contentstack.io', + cdn: 'https://cdn.contentstack.io', + // Regional developer hub URLs +}; +``` + +## Testing Patterns + +### SDK Mocking +```typescript +// ✅ GOOD - Mock stack client methods +const mockStackClient = { + fetch: sinon.stub().resolves({ name: 'Test Stack', uid: 'stack-uid' }), + locale: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ items: [], count: 0 }), + }), + }), +}; +``` + +### Error Simulation +```typescript +// ✅ GOOD - Test error handling +it('should handle 429 rate limit', async () => { + const error = { status: 429 }; + mockClient.fetch.rejects(error); + // Test retry logic +}); +``` + +## Package-Specific Patterns + +### Plugin vs Library +- **Plugin packages**: Have `oclif.commands` in package.json +- **Library packages** (e.g., variants): No OCLIF commands, consumed by other packages + +### Monorepo Structure +- Commands: `packages/*/src/commands/cm/**/*.ts` +- Modules: `packages/*/src/{import,export,modules}/**/*.ts` +- Utilities: `packages/*/src/utils/**/*.ts` +- Built artifacts: `packages/*/lib/**` (not source) diff --git a/.cursor/rules/contentstack-plugin.mdc b/.cursor/rules/contentstack-plugin.mdc deleted file mode 100644 index e653d2c57..000000000 --- a/.cursor/rules/contentstack-plugin.mdc +++ /dev/null @@ -1,475 +0,0 @@ ---- -description: "Contentstack CLI plugin package patterns — commands, services, base-commands, and inter-plugin dependencies" -globs: ["packages/contentstack-*/src/**/*.ts", "packages/contentstack-*/src/**/*.js"] -alwaysApply: false ---- - -# Contentstack CLI Plugin Standards - -## Overview - -The **cli-plugins** monorepo contains 12 OCLIF plugin packages under `packages/`: -- `contentstack-audit`, `contentstack-bootstrap`, `contentstack-branches`, `contentstack-bulk-publish`, `contentstack-clone`, `contentstack-export`, `contentstack-export-to-csv`, `contentstack-import`, `contentstack-import-setup`, `contentstack-migration`, `contentstack-seed`, `contentstack-variants` - -Each plugin is a self-contained OCLIF package that: -- **Defines commands** — via `oclif.commands` in `package.json` pointing to `./lib/commands` -- **Depends on shared libraries** — `@contentstack/cli-command` (Base Command class), `@contentstack/cli-utilities` (shared utils and services) -- **May depend on other plugins** — e.g., `contentstack-import` depends on `@contentstack/cli-audit` for audit operations -- **Implements business logic** — in services, modules, and utility classes -- **Has a local base-command** — extending `@contentstack/cli-command` Command class with plugin-specific initialization and flags - -## Architecture - -### Package Structure - -``` -packages/contentstack-import/ -├── src/ -│ ├── commands/ -│ │ └── cm/ -│ │ └── stacks/ -│ │ └── import.ts -│ ├── services/ -│ │ ├── import-service.ts -│ │ └── validation-service.ts -│ ├── modules/ -│ │ ├── entries.ts -│ │ ├── assets.ts -│ │ └── ... -│ ├── base-command.ts (or import-base-command.ts) -│ ├── types/ -│ ├── interfaces/ -│ ├── messages/ -│ └── utils/ -├── test/ -│ └── unit/ -│ ├── commands/ -│ ├── services/ -│ └── ... -├── package.json -├── tsconfig.json -└── .mocharc.json -``` - -### Package Configuration - -Each plugin's `package.json` declares its commands and declares itself as an OCLIF plugin: - -```json -{ - "name": "@contentstack/cli-cm-import", - "oclif": { - "commands": "./lib/commands", - "topics": { - "stacks": { - "description": "Manage stacks" - } - } - }, - "dependencies": { - "@contentstack/cli-command": "~1.8.0", - "@contentstack/cli-utilities": "~1.18.0", - "@contentstack/cli-audit": "~1.19.0" - } -} -``` - -## Base Command Pattern - -### Plugin-Specific Base Command - -Each plugin defines its own `BaseCommand` (or specialized variant like `AuditBaseCommand`): - -```typescript -// ✅ GOOD - packages/contentstack-audit/src/base-command.ts -import { Command } from '@contentstack/cli-command'; -import { Flags, FlagInput } from '@contentstack/cli-utilities'; - -export abstract class BaseCommand extends Command { - protected sharedConfig = { - basePath: process.cwd(), - }; - - static baseFlags: FlagInput = { - config: Flags.string({ - char: 'c', - description: 'Path to config file', - }), - 'data-dir': Flags.string({ - char: 'd', - description: 'Data directory path', - }), - }; - - public async init(): Promise { - await super.init(); - const { args, flags } = await this.parse({ - flags: this.ctor.flags, - args: this.ctor.args, - strict: this.ctor.strict !== false, - }); - this.args = args; - this.flags = flags; - } -} -``` - -### Specialized Base Commands - -Some plugins define specialized versions for specific concerns: - -```typescript -// ✅ GOOD - packages/contentstack-audit/src/audit-base-command.ts -// Extends BaseCommand with audit-specific logic -import { BaseCommand } from './base-command'; - -export abstract class AuditBaseCommand extends BaseCommand { - // Audit-specific initialization and helpers - protected async runAudit(): Promise { - // Common audit logic - } -} - -// Usage in commands -export default class AuditFixCommand extends AuditBaseCommand { - async run(): Promise { - await this.runAudit(); - } -} -``` - -## Command Structure - -### CM Topic Commands - -Commands are organized under the `cm` topic with subtopics for domains: - -```typescript -// ✅ GOOD - packages/contentstack-import/src/commands/cm/stacks/import.ts -import { Flags, FlagInput, cliux } from '@contentstack/cli-utilities'; -import { BaseCommand } from '../../../base-command'; - -export default class ImportCommand extends BaseCommand { - static id = 'cm:stacks:import'; - static description = 'Import content into a stack'; - static examples = [ - '$ csdx cm:stacks:import -k -d ', - '$ csdx cm:stacks:import -k -d --content-types entry,asset', - ]; - - static flags: FlagInput = { - 'stack-api-key': Flags.string({ - char: 'k', - description: 'Stack API key', - required: true, - }), - 'data-dir': Flags.string({ - char: 'd', - description: 'Directory with import data', - required: true, - }), - 'content-types': Flags.string({ - description: 'Content types to import (comma-separated)', - default: 'all', - }), - }; - - async run(): Promise { - try { - const { flags } = this; - cliux.loaderV2('Starting import...'); - - // Delegate to service - const importService = new ImportService(flags); - await importService.import(); - - cliux.success('Import completed'); - } catch (error) { - handleAndLogError(error, { - module: 'import', - command: this.id, - }); - } - } -} -``` - -## Service and Module Patterns - -### Service Layer - -Services encapsulate business logic and are used by commands: - -```typescript -// ✅ GOOD - packages/contentstack-import/src/services/import-service.ts -import { cliux, log } from '@contentstack/cli-utilities'; - -export class ImportService { - constructor(private flags: any) {} - - async import(): Promise { - // Orchestrate import workflow - await this.validateInput(); - await this.loadData(); - await this.importContent(); - } - - private async validateInput(): Promise { - log.debug('Validating input', { module: 'import-service' }); - // Validation logic - } - - private async loadData(): Promise { - // Load data from directory - } - - private async importContent(): Promise { - // Import content logic - } -} -``` - -### Module Pattern - -Some plugins use modules for domain-specific operations: - -```typescript -// ✅ GOOD - packages/contentstack-import/src/modules/entries.ts -import isEmpty from 'lodash/isEmpty'; -import { log } from '@contentstack/cli-utilities'; - -export class Entries { - constructor(private client: any, private basePath: string) {} - - async import(entries: any[]): Promise { - if (isEmpty(entries)) { - log.debug('No entries to import'); - return; - } - - for (const entry of entries) { - await this.importEntry(entry); - } - } - - private async importEntry(entry: any): Promise { - // Import individual entry - } -} -``` - -## Shared Dependencies - -All plugins depend on core libraries: - -```json -{ - "dependencies": { - "@contentstack/cli-command": "~1.8.0", - "@contentstack/cli-utilities": "~1.18.0" - } -} -``` - -### Common Utilities Used - -```typescript -// ✅ GOOD - Import and use shared utilities -import { - cliux, // CLI UI helpers (loaders, tables, success/error) - ux, // OCLIF ux utilities - log, // Structured logging - handleAndLogError, // Error handling with context - configHandler, // CLI configuration management - sanitizePath, // Path sanitization - managementSDKClient, // Contentstack API client factory -} from '@contentstack/cli-utilities'; - -import { Command, Interfaces } from '@contentstack/cli-command'; -``` - -## Inter-Plugin Dependencies - -Plugins can depend on other plugins to share functionality: - -```json -{ - "dependencies": { - "@contentstack/cli-audit": "~1.19.0" - } -} -``` - -### Using Shared Plugin Code - -```typescript -// ✅ GOOD - Import from other plugin packages -import { AuditService } from '@contentstack/cli-audit'; - -export class ImportService { - async import(): Promise { - // Do import - await new AuditService().runAudit(); - } -} -``` - -## Error Handling - -Error handling follows a consistent pattern across plugins: - -```typescript -// ✅ GOOD - Comprehensive error handling -import { handleAndLogError, CLIError } from '@contentstack/cli-utilities'; - -async run(): Promise { - try { - // Business logic - const result = await this.importService.import(); - return result; - } catch (error) { - // Log error with module/command context - handleAndLogError(error, { - module: 'import', - command: this.id, - dataDir: this.flags['data-dir'], - }); - this.exit(1); - } -} -``` - -## Build Process - -Each plugin builds independently but follows the same pattern: - -```bash -# In package.json scripts -"build": "pnpm compile && oclif manifest" -``` - -### Build Steps - -1. **compile** — TypeScript → JavaScript in `lib/` -2. **oclif manifest** — Generate `oclif.manifest.json` for command discovery - -### Build Artifacts - -- `lib/` — Compiled commands, services, modules -- `oclif.manifest.json` — Command registry for this plugin -- `README.md` — Generated command documentation (optional) - -## Configuration and Messaging - -### Messages - -Plugins store user-facing strings in centralized message files: - -```typescript -// ✅ GOOD - packages/contentstack-import/src/messages/index.ts -export const importMsg = { - IMPORT_START: 'Starting import...', - IMPORT_SUCCESS: 'Import completed successfully', - VALIDATION_ERROR: 'Validation failed: {{reason}}', -}; -``` - -### Configuration - -Plugin-specific defaults are stored in config files: - -```typescript -// ✅ GOOD - packages/contentstack-import/src/config/index.ts -export default { - batchSize: 50, - retryAttempts: 3, - timeout: 30000, - logLevel: 'info', -}; -``` - -## Testing Patterns - -### Command Testing - -Test commands using `@oclif/test`: - -```typescript -// ✅ GOOD - packages/contentstack-import/test/unit/commands/import.test.ts -import { test } from '@oclif/test'; -import { expect } from 'chai'; - -describe('ImportCommand', () => { - test - .stdout() - .command(['cm:stacks:import', '--help']) - .it('shows help message', (ctx) => { - expect(ctx.stdout).to.contain('Import content'); - }); - - test - .command(['cm:stacks:import', '-k', 'test-key', '-d', '/tmp/data']) - .it('runs import command'); -}); -``` - -### Service Testing - -Test services with unit tests: - -```typescript -// ✅ GOOD - packages/contentstack-import/test/unit/services/import-service.test.ts -import { expect } from 'chai'; -import { ImportService } from '../../../src/services/import-service'; - -describe('ImportService', () => { - let service: ImportService; - - beforeEach(() => { - service = new ImportService({ - 'stack-api-key': 'test-key', - 'data-dir': '/tmp/data', - }); - }); - - it('should validate input before import', async () => { - // Test validation logic - }); - - it('should handle import errors', async () => { - // Test error handling - }); -}); -``` - -## Best Practices - -### Command Design -- Keep commands thin — delegate to services -- Validate flags early and fail fast -- Provide clear error messages with actionable guidance -- Include command examples in static `examples` - -### Service Design -- Keep services focused on a single domain -- Make services testable by accepting dependencies via constructor -- Use modules for complex domain operations -- Document service public API clearly - -### Error Handling -- Always provide context in error logs (module, command, relevant state) -- Use structured error types (CLIError) for user-facing errors -- Include remediation guidance in error messages -- Log all errors, even those caught and handled - -### Testing -- Test commands with @oclif/test -- Test services with unit tests and mocks -- Cover both happy path and error cases -- Use fixtures for test data, not live APIs - -### Dependencies -- Always use `@contentstack/cli-utilities` for CLI concerns -- Use `@contentstack/cli-command` as base for commands -- Depend on other plugins only if truly needed (watch for circular deps) -- Pin dependency versions to minor (`~` semver) for stability diff --git a/.cursor/rules/dev-workflow.md b/.cursor/rules/dev-workflow.md index 4bfe91360..757e305fd 100644 --- a/.cursor/rules/dev-workflow.md +++ b/.cursor/rules/dev-workflow.md @@ -9,29 +9,11 @@ alwaysApply: true ## Monorepo Structure ### Package Organization -This **CLI plugins** monorepo has 12 packages under `packages/`: - -1. **contentstack-audit** - Stack audit and fix operations -2. **contentstack-bootstrap** - Seed/bootstrap stacks -3. **contentstack-branches** - Git-based branch management -4. **contentstack-bulk-publish** - Bulk publish operations -5. **contentstack-clone** - Clone/duplicate stacks -6. **contentstack-export** - Export stack content -7. **contentstack-export-to-csv** - Export to CSV format -8. **contentstack-import** - Import content to stacks -9. **contentstack-import-setup** - Import setup and validation -10. **contentstack-migration** - Content migration workflows -11. **contentstack-seed** - Seed stacks with data -12. **contentstack-variants** - Manage content variants - -All plugins depend on `@contentstack/cli-command` and `@contentstack/cli-utilities`. Some plugins also depend on each other. - -### pnpm Workspace Configuration -```json -{ - "workspaces": ["packages/*"] -} -``` +- **12+ plugin packages** under `packages/` +- `contentstack-cli-cm-regex-validate` - Regex validation for Content Type/Global Field fields (`cm:stacks:validate-regex`; npm `@contentstack/cli-cm-regex-validate`; Jest tests) +- **pnpm workspaces** with `workspaces: ["packages/*"]` +- **Shared dependencies**: `@contentstack/cli-command`, `@contentstack/cli-utilities` +- **Build artifacts**: `lib/` directory (compiled from `src/`) ### Development Commands ```bash @@ -39,10 +21,7 @@ All plugins depend on `@contentstack/cli-command` and `@contentstack/cli-utiliti pnpm install # Run command across all packages -pnpm -r run - -# Run command in specific package -pnpm -r --filter '@contentstack/cli-cm-import' test +pnpm -r --filter './packages/*' # Work on specific package cd packages/contentstack-import @@ -58,16 +37,19 @@ pnpm test ### Test-First Examples ```typescript // ✅ GOOD - Write test first -describe('ConfigService', () => { - it('should load configuration', async () => { +describe('ImportService', () => { + it('should import content types', async () => { // Arrange - Set up mocks - const mockConfig = { region: 'us', alias: 'default' }; - + mockStackClient.contentType.returns({ + create: sinon.stub().resolves({ uid: 'ct-uid' }) + }); + // Act - Call the method - const result = await configService.load(); - + const result = await importService.importContentTypes(); + // Assert - Verify behavior - expect(result).to.deep.equal(mockConfig); + expect(result.success).to.be.true; + expect(mockStackClient.contentType).to.have.been.called; }); }); ``` @@ -76,67 +58,43 @@ describe('ConfigService', () => { ### Testing Standards - **NO implementation before tests** - Test-driven development only +- **Coverage aspiration**: 80% minimum (not uniformly enforced) - **Mock all external dependencies** - No real API calls in tests -- **Use Mocha + Chai** - Standard testing stack -- **Coverage aspiration**: 80% minimum +- **Use Mocha + Chai + Sinon** - Standard testing stack ### Code Quality -- **TypeScript configuration**: Varies by package +- **TypeScript configuration**: Varies by package (strict mode aspirational) - **NO test.skip or .only in commits** - Clean test suites only -- **Proper error handling** - Clear error messages +- **Proper error handling** - Use `handleAndLogError` from utilities ### Build Process ```bash -# Standard build process for each package -pnpm run build # tsc compilation + oclif manifest +# Standard build process +pnpm run build # tsc compilation pnpm run test # Run test suite -pnpm run lint # ESLint checks +oclif manifest # Generate OCLIF manifest ``` ## Package-Specific Patterns -### Plugin Packages (auth, config) +### Plugin Packages - Have `oclif.commands` in `package.json` - Commands in `src/commands/cm/**/*.ts` - Built commands in `lib/commands/` -- Extend `@oclif/core` Command class -- Script: `build`: compiles TypeScript, generates OCLIF manifest and README +- Extend `@contentstack/cli-command` -### Library Packages (command, utilities, dev-dependencies) +### Library Packages (e.g., variants) - No OCLIF commands configuration -- Pure TypeScript/JavaScript libraries +- Pure TypeScript libraries - Consumed by other packages - `main` points to `lib/index.js` -### Main CLI Package (contentstack) -- Entry point through `bin/run.js` -- Aggregates plugin commands -- Package dependencies reference plugin packages - -## Script Conventions - -### Build Scripts -```json -{ - "build": "pnpm compile && oclif manifest && oclif readme", - "compile": "tsc -b tsconfig.json", - "prepack": "pnpm compile && oclif manifest && oclif readme", - "test": "mocha \"test/unit/**/*.test.ts\"", - "lint": "eslint src/**/*.ts" -} -``` - -### Key Build Steps -1. **compile** - TypeScript compilation to `lib/` -2. **oclif manifest** - Generate command manifest for discovery -3. **oclif readme** - Generate command documentation - ## Quick Reference -For detailed patterns, see: -- `@testing` - Mocha, Chai test patterns -- `@oclif-commands` - Command structure and validation -- `@dev-workflow` (this document) - Monorepo workflow and TDD +For detailed patterns, see skills: +- `@skills/testing` - Mocha, Chai, Sinon patterns and TDD workflow +- `@skills/contentstack-cli` - API integration, rate limiting, authentication +- `@skills/oclif-commands` - Command structure, base classes, validation ## Development Checklist @@ -149,7 +107,8 @@ For detailed patterns, see: ### During Development - [ ] Write failing test first - [ ] Implement minimal code to pass -- [ ] Mock external dependencies +- [ ] Mock external dependencies (SDK, file system, etc.) +- [ ] Use proper error handling patterns - [ ] Follow naming conventions (kebab-case files, PascalCase classes) ### Before Committing @@ -161,46 +120,30 @@ For detailed patterns, see: ## Common Patterns -### Service/Class Architecture +### Service Layer Architecture ```typescript // ✅ GOOD - Separate concerns -export default class ConfigCommand extends Command { - static description = 'Manage CLI configuration'; - +export default class ImportCommand extends Command { async run(): Promise { + const config = this.buildConfig(); + const service = new ImportService(config); + try { - const service = new ConfigService(); await service.execute(); - this.log('Configuration updated successfully'); + this.log('Import completed successfully'); } catch (error) { - this.error('Configuration update failed'); + handleAndLogError(error); } } } ``` -### Error Handling +### Rate Limiting Compliance ```typescript -// ✅ GOOD - Clear error messages -try { - await this.performAction(); -} catch (error) { - if (error instanceof ValidationError) { - this.error(`Invalid input: ${error.message}`); - } else { - this.error('Operation failed'); - } +// ✅ GOOD - Respect API limits +async processBatch(batch: Item[]): Promise { + const start = Date.now(); + await this.makeConcurrentCall(batch, this.processItem); + await this.logMsgAndWaitIfRequired('Processing', start); } ``` - -## CI/CD Integration - -### GitHub Actions -- Uses workflow files in `.github/workflows/` -- Runs linting, tests, and builds on pull requests -- Enforces code quality standards - -### Pre-commit Hooks -- Husky integration for pre-commit checks -- Prevents commits with linting errors -- Located in `.husky/` diff --git a/.cursor/rules/oclif-commands.mdc b/.cursor/rules/oclif-commands.mdc index 7ca9bc25a..ac186ff52 100644 --- a/.cursor/rules/oclif-commands.mdc +++ b/.cursor/rules/oclif-commands.mdc @@ -1,6 +1,6 @@ --- description: 'OCLIF command development patterns and CLI best practices' -globs: ['**/commands/**/*.ts', '**/base-command.ts'] +globs: ['**/commands/**/*.ts'] alwaysApply: false --- @@ -12,63 +12,84 @@ alwaysApply: false ```typescript // ✅ GOOD - Standard command structure import { Command } from '@contentstack/cli-command'; -import { cliux, flags, FlagInput, handleAndLogError } from '@contentstack/cli-utilities'; -export default class ConfigSetCommand extends Command { - static description = 'Set CLI configuration values'; +export default class ImportCommand extends Command { + static description = 'Import content from a stack'; - static flags: FlagInput = { - region: flags.string({ - char: 'r', - description: 'Set region (us/eu)', - }), - alias: flags.string({ - char: 'a', - description: 'Configuration alias', - }), - }; - - static examples = [ - 'csdx config:set --region eu', - 'csdx config:set --region us --alias default', + static examples: string[] = [ + 'csdx cm:stacks:import --stack-api-key --data-dir ', + 'csdx cm:stacks:import --alias --config ', ]; + static flags = { + // Define flags using utilities + }; + async run(): Promise { - try { - const { flags: configFlags } = await this.parse(ConfigSetCommand); - // Command logic here - } catch (error) { - handleAndLogError(error, { module: 'config-set' }); - } + // Main command logic } } ``` -## Base Classes +## Base Classes Available -### Command Base Class +### BaseCommand (Audit Package) ```typescript -// ✅ GOOD - Extend Command from @contentstack/cli-command -import { Command } from '@contentstack/cli-command'; +// ✅ GOOD - Extend BaseCommand for shared functionality +export abstract class BaseCommand extends Command { + static baseFlags: FlagInput = { + config: Flags.string({ char: 'c', description: 'Config path' }), + 'data-dir': Flags.string({ char: 'd', description: 'Data directory' }), + 'show-console-output': Flags.boolean({ description: 'Show console output' }), + }; -export default class MyCommand extends Command { - async run(): Promise { - // Command implementation + public async init(): Promise { + await super.init(); + const { args, flags } = await this.parse({ + flags: this.ctor.flags, + baseFlags: (super.ctor as typeof BaseCommand).baseFlags, + // ... + }); } } ``` -### Custom Base Classes +### BaseCommand (Export-to-CSV Package) ```typescript -// ✅ GOOD - Create custom base classes for shared functionality -export abstract class BaseCommand extends Command { - protected contextDetails = { - command: this.id || 'unknown', - }; +// ✅ GOOD - Lightweight base with command context +export abstract class BaseCommand extends Command { + public commandContext!: CommandContext; - async init(): Promise { + public async init(): Promise { await super.init(); - log.debug('Command initialized', this.contextDetails); + this.commandContext = this.createCommandContext(); + log.debug('Command initialized', this.commandContext); + } + + protected async catch(err: Error & { exitCode?: number }): Promise { + log.debug('Command error caught', { ...this.commandContext, error: err.message }); + return super.catch(err); + } +} +``` + +## Command Patterns + +### Import Commands +- Use `@contentstack/cli-command` Command base +- Parse with `ImportCommand` type for config validation +- Handle authentication via `configHandler` and `isAuthenticated` +- Delegate to service layer modules + +### Direct Extension Pattern +```typescript +// ✅ GOOD - Most packages extend Command directly +export default class BranchMerge extends Command { + static description = 'Merge branches'; + + async run(): Promise { + const { flags } = await this.parse(BranchMerge); + // Command-specific logic } } ``` @@ -87,54 +108,9 @@ export abstract class BaseCommand extends Command { ``` ### Command Topics -- All commands use `cm` topic: `cm:config:set`, `cm:auth:login` +- All commands use `cm` topic: `cm:stacks:import`, `cm:branches:merge` - Built commands live in `lib/commands` (compiled from `src/commands`) -- Commands use nested directories: `src/commands/config/set.ts` → `cm:config:set` - -### Command Naming -- **Topic hierarchy**: `config/remove/proxy.ts` → `cm:config:remove:proxy` -- **Descriptive names**: Use verb-noun pattern (`set`, `remove`, `show`) -- **Grouping**: Related commands share parent topics - -## Flag Management - -### Flag Definition Patterns -```typescript -// ✅ GOOD - Define flags clearly -static flags: FlagInput = { - 'stack-api-key': flags.string({ - char: 'k', - description: 'Stack API key', - required: false, - }), - region: flags.string({ - char: 'r', - description: 'Set region', - options: ['us', 'eu'], - }), - verbose: flags.boolean({ - char: 'v', - description: 'Show verbose output', - default: false, - }), -}; -``` - -### Flag Parsing -```typescript -// ✅ GOOD - Parse and validate flags -async run(): Promise { - const { flags: parsedFlags } = await this.parse(MyCommand); - - // Validate flag combinations - if (!parsedFlags['stack-api-key'] && !parsedFlags.alias) { - this.error('Either --stack-api-key or --alias is required'); - } - - // Use parsed flags - const region = parsedFlags.region || 'us'; -} -``` +- Optional `csdxConfig.shortCommandName` for abbreviated names ## Error Handling @@ -144,23 +120,19 @@ async run(): Promise { try { await this.executeCommand(); } catch (error) { - handleAndLogError(error, { module: 'my-command' }); + handleAndLogError(error); + this.logAndPrintErrorDetails(error, config); } ``` ### User-Friendly Messages ```typescript // ✅ GOOD - Clear user feedback -import { cliux } from '@contentstack/cli-utilities'; +cliux.print('Operation completed successfully', { color: 'green' }); +cliux.print('Error occurred', { color: 'red' }); -// Success message -cliux.success('Configuration updated successfully', { color: 'green' }); - -// Error message -cliux.error('Invalid region specified', { color: 'red' }); - -// Info message -cliux.print('Setting region to eu', { color: 'blue' }); +// For critical failures +process.exit(1); ``` ## Validation Patterns @@ -171,47 +143,44 @@ cliux.print('Setting region to eu', { color: 'blue' }); async run(): Promise { const { flags } = await this.parse(MyCommand); - // Validate required flags - if (!flags.region) { - this.error('--region is required'); - } - - // Validate flag values - if (!['us', 'eu'].includes(flags.region)) { - this.error('Region must be "us" or "eu"'); + // Validate required combinations + if (!flags.alias && !flags['stack-api-key']) { + this.error('Either --alias or --stack-api-key is required'); } // Proceed with validated input } ``` +### Authentication Check +```typescript +// ✅ GOOD - Check authentication before operations +if (!isAuthenticated()) { + this.error('Please login first using: csdx auth:login'); +} +``` + ## Progress and Logging -### User Feedback +### Progress Feedback ```typescript // ✅ GOOD - Provide user feedback -import { log, cliux } from '@contentstack/cli-utilities'; - -// Regular logging -this.log('Starting configuration update...'); +this.log('Starting import process...'); +cliux.print('Processing entries...', { color: 'blue' }); -// Debug logging -log.debug('Detailed operation information', { context: 'data' }); - -// Status messages -cliux.print('Processing...', { color: 'blue' }); +// Use progress bars for long operations +const progressBar = cliux.progress.start(total); +progressBar.increment(); +progressBar.stop(); ``` -### Progress Indication +### Debug Logging ```typescript -// ✅ GOOD - Show progress for long operations -cliux.print('Processing items...', { color: 'blue' }); -let count = 0; -for (const item of items) { - await this.processItem(item); - count++; - cliux.print(`Processed ${count}/${items.length} items`, { color: 'blue' }); -} +// ✅ GOOD - Use structured logging +log.debug('Command initialized', { + command: this.id, + flags: this.flags +}); ``` ## Command Delegation @@ -220,13 +189,12 @@ for (const item of items) { ```typescript // ✅ GOOD - Commands orchestrate, services implement async run(): Promise { + const config = this.buildConfig(); + const service = new ImportService(config); + try { - const { flags } = await this.parse(MyCommand); - const config = this.buildConfig(flags); - const service = new ConfigService(config); - await service.execute(); - cliux.success('Operation completed successfully'); + this.log('Import completed successfully'); } catch (error) { this.handleError(error); } @@ -240,113 +208,12 @@ async run(): Promise { // ✅ GOOD - Use @oclif/test for command testing import { test } from '@oclif/test'; -describe('cm:config:set', () => { +describe('cm:stacks:import', () => { test .stdout() - .command(['cm:config:set', '--help']) + .command(['cm:stacks:import', '--help']) .it('shows help', ctx => { - expect(ctx.stdout).to.contain('Set CLI configuration'); - }); - - test - .stdout() - .command(['cm:config:set', '--region', 'eu']) - .it('sets region to eu', ctx => { - expect(ctx.stdout).to.contain('success'); + expect(ctx.stdout).to.contain('Import content from a stack'); }); }); ``` - -## Log Integration - -### Debug Logging -```typescript -// ✅ GOOD - Use structured debug logging -import { log } from '@contentstack/cli-utilities'; - -log.debug('Command started', { - command: this.id, - flags: this.flags, - timestamp: new Date().toISOString(), -}); - -log.debug('Processing complete', { - itemsProcessed: count, - module: 'my-command', -}); -``` - -### Error Context -```typescript -// ✅ GOOD - Include context in error handling -try { - await operation(); -} catch (error) { - handleAndLogError(error, { - module: 'config-set', - command: 'cm:config:set', - flags: { region: 'eu' }, - }); -} -``` - -## Multi-Topic Commands - -### Nested Command Structure -```typescript -// File: src/commands/config/show.ts -export default class ShowConfigCommand extends Command { - static description = 'Show current configuration'; - static examples = ['csdx config:show']; - async run(): Promise { } -} - -// File: src/commands/config/set.ts -export default class SetConfigCommand extends Command { - static description = 'Set configuration values'; - static examples = ['csdx config:set --region eu']; - async run(): Promise { } -} - -// Generated commands: -// - cm:config:show -// - cm:config:set -``` - -## Best Practices - -### Command Organization -```typescript -// ✅ GOOD - Well-organized command -export default class MyCommand extends Command { - static description = 'Clear, concise description'; - - static flags: FlagInput = { - // Define all flags - }; - - static examples = [ - 'csdx my:command', - 'csdx my:command --flag value', - ]; - - async run(): Promise { - try { - const { flags } = await this.parse(MyCommand); - await this.execute(flags); - } catch (error) { - handleAndLogError(error, { module: 'my-command' }); - } - } - - private async execute(flags: Flags): Promise { - // Implementation - } -} -``` - -### Clear Help Text -- Write description as action-oriented statement -- Provide multiple examples for common use cases -- Document each flag with clear description -- Show output format or examples of results diff --git a/.cursor/rules/testing.mdc b/.cursor/rules/testing.mdc index daf6de108..7fc3a7c93 100644 --- a/.cursor/rules/testing.mdc +++ b/.cursor/rules/testing.mdc @@ -11,31 +11,28 @@ alwaysApply: true ### Primary Testing Tools - **Mocha** - Test runner (used across all packages) - **Chai** - Assertion library -- **@oclif/test** - Command testing support (for plugin packages) +- **Sinon** - Mocking and stubbing +- **@oclif/test** - Command testing support +- **nyc** - Code coverage -### Test Setup -- TypeScript compilation via ts-node/register -- Source map support for stack traces -- Global test timeout: 30 seconds (configurable per package) +### Package-Specific Tools +- **nock** - HTTP mocking (migration package) +- **rewire** - Module patching (import package) ## Test File Patterns ### Naming Conventions -- **Primary**: `*.test.ts` (standard pattern across all packages) -- **Location**: `test/unit/**/*.test.ts` (most packages) +- **Primary**: `*.test.ts` (dominant pattern) +- **Alternative**: `*.spec.ts` (less common) +- **Bootstrap exception**: `*.test.js` (JavaScript tests) ### Directory Structure ``` packages/*/ -├── test/ -│ └── unit/ -│ ├── commands/ # Command-specific tests -│ ├── services/ # Service/business logic tests -│ └── utils/ # Utility function tests -└── src/ # Source code - ├── commands/ # CLI commands - ├── services/ # Business logic - └── utils/ # Utilities +├── test/unit/**/*.test.ts # Most packages +├── test/lib/**/*.test.ts # clone package +├── test/seed/**/*.test.ts # seed package +└── test/commands/**/*.test.ts # command-specific tests ``` ## Mocha Configuration @@ -58,87 +55,125 @@ packages/*/ ```json // package.json scripts { - "test": "mocha \"test/unit/**/*.test.ts\"", - "test:coverage": "nyc mocha \"test/unit/**/*.test.ts\"" + "pretest": "tsc -p test", + "test": "nyc --extension .ts mocha" } ``` -## Test Structure +## Mocking Patterns -### Standard Test Pattern +### Sinon SDK Mocking ```typescript -// ✅ GOOD - Comprehensive test structure -describe('ConfigService', () => { - let service: ConfigService; - - beforeEach(() => { - service = new ConfigService(); - }); +// ✅ GOOD - Mock Contentstack SDK methods +const mockStackClient = { + fetch: sinon.stub().resolves({ + name: 'Test Stack', + uid: 'stack-uid', + org_uid: 'org-uid' + }), + locale: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: [{ + uid: 'locale-1', + name: 'English (United States)', + code: 'en-us' + }], + count: 1, + }), + }), + }), +}; +``` - describe('loadConfig()', () => { - it('should load configuration successfully', async () => { - // Arrange - const expectedConfig = { region: 'us' }; - - // Act - const result = await service.loadConfig(); - - // Assert - expect(result).to.deep.equal(expectedConfig); - }); +### Module Stubbing +```typescript +// ✅ GOOD - Stub sibling modules +beforeEach(() => { + sinon.stub(mapModule, 'processEntries').resolves([]); + sinon.stub(configModule, 'getConfig').returns(mockConfig); +}); - it('should handle missing configuration', async () => { - // Arrange & Act & Assert - await expect(service.loadConfig()).to.be.rejectedWith('Config not found'); - }); - }); +afterEach(() => { + sinon.restore(); }); ``` -### Async/Await Pattern +### HTTP Mocking (Migration) ```typescript -// ✅ GOOD - Use async/await in tests -it('should process data asynchronously', async () => { - const result = await service.processAsync(); - expect(result).to.exist; -}); +// ✅ GOOD - Use nock for HTTP mocking +import nock from 'nock'; -// ✅ GOOD - Explicit Promise handling -it('should return a promise', () => { - return service.asyncMethod().then(result => { - expect(result).to.be.true; - }); +beforeEach(() => { + nock('https://api.contentstack.io') + .get('/v3/stacks') + .reply(200, { stacks: [] }); }); ``` -## Mocking Patterns +## Coverage Configuration -### Class Mocking -```typescript -// ✅ GOOD - Mock class dependencies -class MockConfigService { - async loadConfig() { - return { region: 'us' }; - } +### NYC Setup (.nycrc.json) +```json +{ + "extension": [".ts"], + "include": ["src/**/*.ts"], + "exclude": ["**/*.test.ts", "**/*.spec.ts"], + "reporter": ["text", "html", "lcov"], + "all": true } - -it('should use mocked service', async () => { - const mockService = new MockConfigService(); - const result = await mockService.loadConfig(); - expect(result.region).to.equal('us'); -}); ``` -### Function Stubs +### Coverage Targets +- **Team aspiration**: 80% minimum coverage +- **Current enforcement**: Inconsistent across packages +- **Note**: Some packages have `check-coverage: false` +- **Typo alert**: Several `.nycrc.json` files have `"inlcude"` instead of `"include"` + +## Test Structure + +### Standard Test Pattern ```typescript -// ✅ GOOD - Stub module functions if needed -beforeEach(() => { - // Stub file system operations - // Stub network calls -}); +// ✅ GOOD - Comprehensive test structure +describe('ContentTypes Module', () => { + let mockStackClient: any; + let contentTypes: ContentTypes; -afterEach(() => { - // Restore original implementations + beforeEach(() => { + mockStackClient = createMockStackClient(); + contentTypes = new ContentTypes({ + stackAPIClient: mockStackClient, + importConfig: mockConfig, + }); + }); + + afterEach(() => { + sinon.restore(); + }); + + describe('import()', () => { + it('should import content types successfully', async () => { + // Arrange + mockStackClient.contentType.returns({ + create: sinon.stub().resolves({ uid: 'ct-uid' }) + }); + + // Act + await contentTypes.import(); + + // Assert + expect(mockStackClient.contentType).to.have.been.called; + }); + + it('should handle API errors gracefully', async () => { + // Arrange + const error = new Error('API Error'); + mockStackClient.contentType.throws(error); + + // Act & Assert + await expect(contentTypes.import()).to.be.rejectedWith('API Error'); + }); + }); }); ``` @@ -149,65 +184,47 @@ afterEach(() => { // ✅ GOOD - Test commands with @oclif/test import { test } from '@oclif/test'; -describe('cm:config:region', () => { +describe('cm:stacks:import', () => { test .stdout() - .command(['cm:config:region', '--help']) + .command(['cm:stacks:import', '--help']) .it('shows help message', ctx => { - expect(ctx.stdout).to.contain('Display region'); + expect(ctx.stdout).to.contain('Import content from a stack'); }); test - .stdout() - .command(['cm:config:region']) - .it('shows current region', ctx => { - expect(ctx.stdout).to.contain('us'); - }); -}); -``` - -### Command Flag Testing -```typescript -// ✅ GOOD - Test command flags and arguments -describe('cm:config:set', () => { - test - .command(['cm:config:set', '--help']) - .it('shows usage information'); - - test - .command(['cm:config:set', '--region', 'eu']) - .it('sets region to eu'); + .stderr() + .command(['cm:stacks:import']) + .exit(2) + .it('fails without required flags'); }); ``` ## Error Testing -### Error Handling +### Rate Limit Testing ```typescript -// ✅ GOOD - Test error scenarios -it('should throw ValidationError on invalid input', async () => { - const invalidInput = ''; - await expect(service.validate(invalidInput)) - .to.be.rejectedWith('Invalid input'); -}); +// ✅ GOOD - Test rate limiting behavior +it('should handle 429 rate limit errors', async () => { + const rateLimitError = { status: 429 }; + mockClient.fetch.onFirstCall().rejects(rateLimitError); + mockClient.fetch.onSecondCall().resolves(mockResponse); -it('should handle network errors gracefully', async () => { - // Mock network failure const result = await service.fetchWithRetry(); - expect(result).to.be.null; + + expect(mockClient.fetch).to.have.been.calledTwice; + expect(result).to.equal(mockResponse); }); ``` -### Error Types +### Authentication Testing ```typescript -// ✅ GOOD - Test specific error types -it('should throw appropriate error', async () => { - try { - await service.failingOperation(); - } catch (error) { - expect(error).to.be.instanceof(ValidationError); - expect(error.code).to.equal('INVALID_CONFIG'); - } +// ✅ GOOD - Test authentication scenarios +it('should handle token expiration', async () => { + const authError = { status: 401, message: 'Unauthorized' }; + mockClient.fetch.rejects(authError); + + await expect(service.makeRequest()).to.be.rejectedWith('Unauthorized'); }); ``` @@ -217,16 +234,12 @@ it('should throw appropriate error', async () => { ```typescript // ✅ GOOD - Organize test data const mockData = { - validConfig: { - region: 'us', - timeout: 30000, - }, - invalidConfig: { - region: '', - }, - users: [ - { email: 'user1@example.com', name: 'User 1' }, - { email: 'user2@example.com', name: 'User 2' }, + contentTypes: [ + { uid: 'ct1', title: 'Content Type 1' }, + { uid: 'ct2', title: 'Content Type 2' }, + ], + entries: [ + { uid: 'entry1', title: 'Entry 1', content_type: 'ct1' }, ], }; ``` @@ -234,90 +247,20 @@ const mockData = { ### Test Helpers ```typescript // ✅ GOOD - Create reusable test utilities -export function createMockConfig(overrides?: Partial): Config { +export function createMockStackClient() { return { - region: 'us', - timeout: 30000, - ...overrides, + fetch: sinon.stub(), + contentType: sinon.stub(), + entry: sinon.stub(), + // ... other methods }; } - -export function createMockService( - config: Config = createMockConfig() -): ConfigService { - return new ConfigService(config); -} -``` - -## Coverage - -### Coverage Goals -- **Team aspiration**: 80% minimum coverage -- **Current enforcement**: Applied consistently across packages -- **Focus areas**: Critical business logic and error paths - -### Coverage Reporting -```bash -# Run tests with coverage -pnpm test:coverage - -# Coverage reports generated in: -# - coverage/index.html (HTML report) -# - coverage/coverage-summary.json (JSON report) ``` ## Critical Testing Rules -- **No real external calls** - Mock all dependencies -- **Test both success and failure paths** - Cover error scenarios completely -- **One assertion per test** - Focus each test on single behavior -- **Use descriptive test names** - Test name should explain what's tested -- **Arrange-Act-Assert** - Follow AAA pattern consistently +- **No real API calls** - Always mock external dependencies +- **Test both success and failure paths** - Cover error scenarios +- **Mock at service boundaries** - Don't mock internal implementation details +- **Use proper cleanup** - Always restore stubs in afterEach - **Test command validation** - Verify flag validation and error messages -- **Clean up after tests** - Restore any mocked state - -## Best Practices - -### Test Organization -```typescript -// ✅ GOOD - Organize related tests -describe('AuthCommand', () => { - describe('login', () => { - it('should authenticate user'); - it('should save token'); - }); - - describe('logout', () => { - it('should clear token'); - it('should reset config'); - }); -}); -``` - -### Async Test Patterns -```typescript -// ✅ GOOD - Handle async operations properly -it('should complete async operation', async () => { - const promise = service.asyncMethod(); - expect(promise).to.be.instanceof(Promise); - - const result = await promise; - expect(result).to.equal('success'); -}); -``` - -### Isolation -```typescript -// ✅ GOOD - Ensure test isolation -describe('ConfigService', () => { - let service: ConfigService; - - beforeEach(() => { - service = new ConfigService(); - }); - - afterEach(() => { - // Clean up resources - }); -}); -``` diff --git a/.cursor/rules/typescript.mdc b/.cursor/rules/typescript.mdc index ea4d82a26..d3ff4774b 100644 --- a/.cursor/rules/typescript.mdc +++ b/.cursor/rules/typescript.mdc @@ -8,37 +8,42 @@ alwaysApply: false ## Configuration -### Standard Configuration (All Packages) +### Root Configuration ```json +// tsconfig.json - Baseline configuration { "compilerOptions": { - "declaration": true, - "importHelpers": true, + "strict": true, "module": "commonjs", + "target": "es2016", + "declaration": true, "outDir": "lib", - "rootDir": "src", - "strict": false, // Relaxed for compatibility - "target": "es2017", - "sourceMap": false, - "allowJs": true, // Mixed JS/TS support - "skipLibCheck": true, - "esModuleInterop": true - }, - "include": ["src/**/*"] + "rootDir": "src" + } } ``` -### Root Configuration +### Package-Level Variations ```json -// tsconfig.json - Baseline configuration +// Most packages override with: { "compilerOptions": { - "strict": false, - "module": "commonjs", + "strict": false, // ⚠️ Relaxed for legacy code + "noImplicitAny": true, // ✅ Still enforce type annotations "target": "es2017", - "declaration": true, - "outDir": "lib", - "rootDir": "src" + "allowJs": true // Mixed JS/TS support + } +} +``` + +### Modern Packages (Bootstrap, Variants) +```json +// TypeScript 5.x with stricter settings +{ + "compilerOptions": { + "strict": true, + "target": "es2020", + "moduleResolution": "node16" } } ``` @@ -46,46 +51,49 @@ alwaysApply: false ## Naming Conventions (Actual Usage) ### Files -- **Primary pattern**: `kebab-case.ts` (e.g., `base-command.ts`, `config-handler.ts`) -- **Single-word modules**: `index.ts`, `types.ts` -- **Commands**: Follow OCLIF topic structure (`cm/auth/login.ts`, `cm/config/region.ts`) +- **Primary pattern**: `kebab-case.ts` (`base-class.ts`, `import-config-handler.ts`) +- **Single-word modules**: `stack.ts`, `locales.ts`, `entries.ts` +- **Commands**: Follow OCLIF topic structure (`cm/stacks/import.ts`) ### Classes ```typescript // ✅ GOOD - PascalCase for classes -export default class ConfigCommand extends Command { } -export class AuthService { } -export class ValidationError extends Error { } +export class ImportCommand extends Command { } +export class BaseClass { } +export class ExportStack { } +export class ContentTypes { } ``` ### Functions and Methods ```typescript // ✅ GOOD - camelCase for functions -export async function loadConfig(): Promise { } -async validateInput(input: string): Promise { } +export async function fetchAllEntries(): Promise { } +async logMsgAndWaitIfRequired(): Promise { } createCommandContext(): CommandContext { } ``` ### Constants ```typescript // ✅ GOOD - SCREAMING_SNAKE_CASE for constants -const DEFAULT_REGION = 'us'; -const MAX_RETRIES = 3; +const DEFAULT_RATE_LIMIT = 5; +const MAX_RETRY_ATTEMPTS = 3; const API_BASE_URL = 'https://api.contentstack.io'; ``` ### Interfaces and Types ```typescript // ✅ GOOD - PascalCase for types -export interface CommandConfig { - region: string; - alias?: string; +export interface ModuleClassParams { + importConfig: ImportConfig; + stackAPIClient: ManagementStack; } -export type CommandResult = { - success: boolean; - message?: string; +export type ApiOptions = { + host?: string; + timeout?: number; }; + +export type EnvType = 'development' | 'staging' | 'production'; ``` ## Import/Export Patterns @@ -93,26 +101,27 @@ export type CommandResult = { ### ES Modules (Preferred) ```typescript // ✅ GOOD - ES import/export syntax -import { Command } from '@oclif/core'; -import type { CommandConfig } from '../types'; -import { loadConfig } from '../utils'; +import { Command } from '@contentstack/cli-command'; +import type { ImportConfig } from '../types'; +import { managementSDKClient } from '@contentstack/cli-utilities'; -export default class ConfigCommand extends Command { } -export { CommandConfig }; +export default class ImportCommand extends Command { } +export { ImportConfig, ApiOptions }; ``` ### Default Exports ```typescript // ✅ GOOD - Default export for commands and main classes -export default class ConfigCommand extends Command { } +export default class ImportCommand extends Command { } +export default class BaseClass { } ``` ### Named Exports ```typescript // ✅ GOOD - Named exports for utilities and types export async function delay(ms: number): Promise { } -export interface CommandOptions { } -export type ActionResult = 'success' | 'failure'; +export interface ConfigOptions { } +export type ModuleType = 'import' | 'export'; ``` ## Type Definitions @@ -120,15 +129,16 @@ export type ActionResult = 'success' | 'failure'; ### Local Types ```typescript // ✅ GOOD - Define types close to usage -export interface AuthOptions { - email: string; - password: string; - token?: string; +export interface ImportOptions { + stackApiKey: string; + dataDir: string; + rateLimit?: number; } -export type ConfigResult = { +export type BatchResult = { success: boolean; - config?: Record; + errors: Error[]; + processedCount: number; }; ``` @@ -136,36 +146,46 @@ export type ConfigResult = { ```typescript // ✅ GOOD - Organize types in dedicated files // src/types/index.ts -export interface CommandConfig { } -export interface AuthConfig { } -export type ConfigValue = string | number | boolean; +export interface ImportConfig { } +export interface ExportConfig { } +export type ModuleClassParams = { }; ``` -## Null Safety +## Strict Mode Compliance ### Function Return Types ```typescript // ✅ GOOD - Explicit return types -export async function getConfig(): Promise { - return await this.loadFromFile(); +export async function fetchEntries(): Promise { + return await this.stack.entry().query().find(); } -export function createDefaults(): CommandConfig { +export function createConfig(): ImportConfig { return { - region: 'us', - timeout: 30000, + stackApiKey: '', + dataDir: './data', }; } ``` -### Null/Undefined Handling +### Null Safety ```typescript // ✅ GOOD - Handle null/undefined explicitly -function processConfig(config: CommandConfig | null): void { - if (!config) { - throw new Error('Configuration is required'); +function processEntry(entry: Entry | null): void { + if (!entry) { + throw new Error('Entry is required'); } - // Process config safely + // Process entry safely +} +``` + +### Type Guards +```typescript +// ✅ GOOD - Use type guards for runtime checks +function isImportConfig(config: unknown): config is ImportConfig { + return typeof config === 'object' && + config !== null && + 'stackApiKey' in config; } ``` @@ -174,13 +194,14 @@ function processConfig(config: CommandConfig | null): void { ### Custom Error Classes ```typescript // ✅ GOOD - Typed error classes -export class ValidationError extends Error { +export class ContentstackApiError extends Error { constructor( message: string, - public readonly code?: string + public readonly statusCode?: number, + public readonly cause?: Error ) { super(message); - this.name = 'ValidationError'; + this.name = 'ContentstackApiError'; } } ``` @@ -188,59 +209,51 @@ export class ValidationError extends Error { ### Error Union Types ```typescript // ✅ GOOD - Model expected errors -type AuthResult = { +type ApiResult = { success: true; data: T; } | { success: false; error: string; + statusCode: number; }; ``` -## Strict Mode Adoption +## Migration Strategy -### Current Status -- Most packages use `strict: false` for compatibility -- Gradual migration path available -- Team working toward stricter TypeScript +### Gradual Strict Mode Adoption +```typescript +// ✅ ACCEPTABLE - Gradual migration approach +// @ts-ignore for legacy code during migration +// TODO: Remove @ts-ignore and fix types +// @ts-ignore +const legacyResult = oldApiCall(); +``` -### Gradual Adoption +### Type Assertions (Use Sparingly) ```typescript -// ✅ ACCEPTABLE - Comments for known issues -// TODO: Fix type issues in legacy code -const legacyData = unknownData as unknown; +// ⚠️ USE CAREFULLY - Type assertions when necessary +const config = unknownConfig as ImportConfig; + +// ✅ BETTER - Use type guards instead +if (isImportConfig(unknownConfig)) { + const config = unknownConfig; // TypeScript knows the type +} ``` ## Package-Specific Patterns -### Command Packages (auth, config) -- Extend `@oclif/core` Command -- Define command flags with `static flags` -- Use @oclif/core flag utilities -- Define command-specific types +### Command Packages +- Extend `@contentstack/cli-command` types +- Use OCLIF flag types from utilities +- Define command-specific interfaces -### Library Packages (command, utilities) +### Library Packages (Variants) - No OCLIF dependencies - Pure TypeScript interfaces -- Consumed by command packages -- Focus on type safety for exports - -### Main Package (contentstack) -- Aggregates command plugins -- May have common types -- Shared interfaces for plugin integration - -## Export Patterns - -### Package Exports (lib/index.js) -```typescript -// ✅ GOOD - Barrel exports for libraries -export { Command } from './command'; -export { loadConfig } from './config'; -export type { CommandConfig, AuthOptions } from './types'; -``` +- Consumed by other packages -### Entry Points -- Libraries export from `lib/index.js` -- Commands export directly as default classes -- Type definitions included via `types` field in package.json +### Test Files +- Use `any` sparingly for mock objects +- Prefer typed mocks when possible +- Test type safety with TypeScript compiler diff --git a/.cursor/skills/SKILL.md b/.cursor/skills/SKILL.md deleted file mode 100644 index db406d53e..000000000 --- a/.cursor/skills/SKILL.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: contentstack-cli-skills -description: Collection of project-specific skills for Contentstack CLI plugins monorepo development. Use when working with CLI commands, testing, framework utilities, or reviewing code changes. ---- - -# Contentstack CLI Skills - -Project-specific skills for the pnpm monorepo containing 12 CLI plugin packages. - -## Skills Overview - -| Skill | Purpose | Trigger | -|-------|---------|---------| -| **testing** | Testing patterns, TDD workflow, and test automation for CLI development | When writing tests or debugging test failures | -| **framework** | Core utilities, configuration, logging, and framework patterns | When working with utilities, config, or error handling | -| **contentstack-cli** | CLI commands, OCLIF patterns, authentication and configuration workflows | When implementing commands or integrating APIs | -| **code-review** | PR review guidelines and monorepo-aware checks | When reviewing code or pull requests | - -## Quick Links - -- **[Testing Skill](./testing/SKILL.md)** — TDD patterns, test structure, mocking strategies -- **[Framework Skill](./framework/SKILL.md)** — Utilities, configuration, logging, error handling -- **[Contentstack CLI Skill](./contentstack-cli/SKILL.md)** — Command development, API integration, auth/config patterns -- **[Code Review Skill](./code-review/SKILL.md)** — Review checklist with monorepo awareness - -## Repository Context - -- **Monorepo**: 12 pnpm workspace packages under `packages/` (all CLI plugins for content management) -- **Tech Stack**: TypeScript, OCLIF v4, Mocha+Chai, pnpm workspaces -- **Packages**: `@contentstack/cli-cm-*` scope (import, export, audit, bootstrap, branches, bulk-publish, clone, export-to-csv, import-setup, migration, seed, variants) -- **Dependencies**: All plugins depend on `@contentstack/cli-command` and `@contentstack/cli-utilities` -- **Build**: TypeScript → `lib/` directories, OCLIF manifest generation per plugin diff --git a/.cursor/skills/code-review/SKILL.md b/.cursor/skills/code-review/SKILL.md deleted file mode 100644 index bc647259c..000000000 --- a/.cursor/skills/code-review/SKILL.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -name: code-review -description: Automated PR review checklist covering security, performance, architecture, and code quality. Use when reviewing pull requests, examining code changes, or performing code quality assessments. ---- - -# Code Review Skill - -## Quick Reference - -For comprehensive review guidelines, see: -- **[Code Review Checklist](./references/code-review-checklist.md)** - Complete PR review guidelines with severity levels and checklists - -## Review Process - -### Severity Levels -- 🔴 **Critical**: Must fix before merge (security, correctness, breaking changes) -- 🟡 **Important**: Should fix (performance, maintainability, best practices) -- 🟢 **Suggestion**: Consider improving (style, optimization, readability) - -### Quick Review Categories - -1. **Security** - No hardcoded secrets, input validation, secure error handling -2. **Correctness** - Logic validation, error scenarios, data integrity -3. **Architecture** - Code organization, design patterns, modularity -4. **Performance** - Efficiency, resource management, concurrency -5. **Testing** - Test coverage, quality tests, TDD compliance -6. **Conventions** - TypeScript standards, code style, documentation -7. **Monorepo** - Cross-package imports, workspace dependencies, manifest validity - -## Quick Checklist Template - -```markdown -## Security Review -- [ ] No hardcoded secrets or tokens -- [ ] Input validation present -- [ ] Error handling secure (no sensitive data in logs) - -## Correctness Review -- [ ] Logic correctly implemented -- [ ] Edge cases handled -- [ ] Error scenarios covered -- [ ] Async/await chains correct - -## Architecture Review -- [ ] Proper code organization -- [ ] Design patterns followed -- [ ] Good modularity -- [ ] No circular dependencies - -## Performance Review -- [ ] Efficient implementation -- [ ] No unnecessary API calls -- [ ] Memory leaks avoided -- [ ] Concurrency handled correctly - -## Testing Review -- [ ] Adequate test coverage (80%+) -- [ ] Quality tests (not just passing) -- [ ] TDD compliance -- [ ] Both success and failure paths tested - -## Code Conventions -- [ ] TypeScript strict mode -- [ ] Consistent naming conventions -- [ ] No unused imports or variables -- [ ] Documentation adequate - -## Monorepo Checks -- [ ] Cross-package imports use published names -- [ ] Workspace dependencies declared correctly -- [ ] OCLIF manifest updated if commands changed -- [ ] No breaking changes to exported APIs -``` - -## Usage - -Use the comprehensive checklist guide for detailed review guidelines, common issues, severity assessment, and best practices for code quality in the Contentstack CLI monorepo. diff --git a/.cursor/skills/contentstack-cli/SKILL.md b/.cursor/skills/contentstack-cli/SKILL.md deleted file mode 100644 index df6691042..000000000 --- a/.cursor/skills/contentstack-cli/SKILL.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -name: contentstack-cli -description: Contentstack CLI development patterns, OCLIF commands, API integration, and authentication/configuration workflows. Use when working with Contentstack CLI plugins, OCLIF commands, CLI commands, or Contentstack API integration. ---- - -# Contentstack CLI Development - -## Quick Reference - -For comprehensive patterns, see: -- **[Contentstack Patterns](./references/contentstack-patterns.md)** - Complete CLI commands, API integration, and configuration patterns -- **[Framework Patterns](../framework/references/framework-patterns.md)** - Utilities, configuration, and error handling - -## Key Patterns Summary - -### OCLIF Command Structure -- Extend plugin-specific `BaseCommand` or `Command` from `@contentstack/cli-command` -- Validate flags early: `if (!flags['stack-api-key']) this.error('Stack API key is required')` -- Delegate to services/modules: commands handle CLI, services handle business logic -- Show progress: `cliux.success('✅ Operation completed')` -- Include command examples: `static examples = ['$ csdx cm:stacks:import -k -d ./data', '$ csdx cm:stacks:export -k ']` - -### Command Topics -- CM topic commands: `cm:stacks:import`, `cm:stacks:export`, `cm:stacks:audit`, `cm:stacks:clone`, etc. -- File pattern: `src/commands/cm/stacks/import.ts` → command `cm:stacks:import` -- Plugin structure: Each package defines commands in `oclif.commands` pointing to `./lib/commands` - -### Flag Patterns -```typescript -static flags: FlagInput = { - username: flags.string({ - char: 'u', - description: 'Email address', - required: false - }), - oauth: flags.boolean({ - description: 'Enable SSO', - default: false, - exclusive: ['username', 'password'] - }) -}; -``` - -### Logging and Error Handling -- Use structured logging: `log.debug('Message', { context: 'data' })` -- Include contextDetails: `handleAndLogError(error, { ...this.contextDetails, module: 'auth-login' })` -- User feedback: `cliux.success()`, `cliux.error()`, `throw new CLIError()` - -### I18N Messages -- Store user-facing strings in `messages/*.json` files -- Load with `messageHandler` from utilities -- Example: `messages/en.json` for English strings - -## Command Base Class Pattern - -Each plugin defines its own `BaseCommand` extending `@contentstack/cli-command`: - -```typescript -export abstract class BaseCommand extends Command { - protected sharedConfig = { basePath: process.cwd() }; - - static baseFlags: FlagInput = { - config: Flags.string({ - char: 'c', - description: 'Path to config file', - }), - 'data-dir': Flags.string({ - char: 'd', - description: 'Data directory path', - }), - }; - - async init(): Promise { - await super.init(); - const { args, flags } = await this.parse({ - flags: this.ctor.flags, - args: this.ctor.args, - }); - this.args = args; - this.flags = flags; - } -} -``` - -Specialized base commands extend this for domain-specific concerns (e.g., `AuditBaseCommand` for audit operations). - -## Plugin Development Patterns - -### Import Plugin Example -```typescript -// packages/contentstack-import/src/commands/cm/stacks/import.ts -export default class ImportCommand extends BaseCommand { - static id = 'cm:stacks:import'; - static description = 'Import content into a stack'; - - static flags: FlagInput = { - 'stack-api-key': Flags.string({ - char: 'k', - description: 'Stack API key', - required: true, - }), - 'data-dir': Flags.string({ - char: 'd', - description: 'Directory with import data', - required: true, - }), - }; - - async run(): Promise { - const { flags } = this; - const importService = new ImportService(flags); - await importService.import(); - cliux.success('✅ Import completed'); - } -} -``` - -### Service Layer Pattern -Services encapsulate business logic separate from CLI concerns: - -```typescript -export class ImportService { - async import(): Promise { - await this.validateInput(); - await this.loadData(); - await this.importContent(); - } -} -``` - -### Module Pattern -Complex domains split work across modules: - -```typescript -export class Entries { - async import(entries: any[]): Promise { - for (const entry of entries) { - await this.importEntry(entry); - } - } -} -``` - -## API Integration - -### Management SDK Client -```typescript -import { managementSDKClient } from '@contentstack/cli-utilities'; - -const client = await managementSDKClient({ - host: this.cmaHost, - skipTokenValidity: true -}); - -const stack = client.stack({ api_key: stackApiKey }); -const entries = await stack.entry().query().find(); -``` - -### Error Handling for API Calls -```typescript -try { - const result = await this.client.stack().entry().fetch(); -} catch (error) { - if (error.status === 401) { - throw new CLIError('Authentication failed. Please login again.'); - } else if (error.status === 404) { - throw new CLIError('Entry not found.'); - } - handleAndLogError(error, { - module: 'entry-fetch', - entryId: entryUid - }); -} -``` - -## Usage - -Reference the comprehensive patterns guide above for detailed implementations, examples, and best practices for CLI command development, authentication flows, configuration management, and API integration. diff --git a/.cursor/skills/framework/SKILL.md b/.cursor/skills/framework/SKILL.md deleted file mode 100644 index 80be284d9..000000000 --- a/.cursor/skills/framework/SKILL.md +++ /dev/null @@ -1,142 +0,0 @@ ---- -name: framework -description: Core utilities, configuration, logging, and framework patterns for CLI development. Use when working with utilities, configuration management, error handling, or core framework components. ---- - -# Framework Patterns - -## Quick Reference - -For comprehensive framework guidance, see: -- **[Framework Patterns](./references/framework-patterns.md)** - Complete utilities, configuration, logging, and framework patterns - -## Core Utilities from @contentstack/cli-utilities - -### Configuration Management -```typescript -import { configHandler } from '@contentstack/cli-utilities'; - -// Get config values -const region = configHandler.get('region'); -const email = configHandler.get('email'); -const authToken = configHandler.get('authenticationMethod'); - -// Set config values -configHandler.set('region', 'us'); -``` - -### Logging Framework -```typescript -import { log } from '@contentstack/cli-utilities'; - -// Use structured logging -log.debug('Debug message', { context: 'data' }); -log.info('Information message', { userId: '123' }); -log.warn('Warning message'); -log.error('Error message', { errorCode: 'ERR_001' }); -``` - -### Error Handling -```typescript -import { handleAndLogError, CLIError } from '@contentstack/cli-utilities'; - -try { - await operation(); -} catch (error) { - handleAndLogError(error, { - module: 'my-command', - command: 'cm:auth:login' - }); -} - -// Or throw CLI errors -throw new CLIError('User-friendly error message'); -``` - -### CLI UX / User Output -```typescript -import { cliux } from '@contentstack/cli-utilities'; - -// Success message -cliux.success('Operation completed successfully'); - -// Error message -cliux.error('Something went wrong'); - -// Print message with color -cliux.print('Processing...', { color: 'blue' }); - -// Prompt user for input -const response = await cliux.prompt('Enter region:'); - -// Show table -cliux.table([ - { name: 'Alice', region: 'us' }, - { name: 'Bob', region: 'eu' } -]); -``` - -### HTTP Client -```typescript -import { httpClient } from '@contentstack/cli-utilities'; - -// Make HTTP requests with built-in error handling -const response = await httpClient.request({ - url: 'https://api.contentstack.io/v3/stacks', - method: 'GET', - headers: { 'Authorization': `Bearer ${token}` } -}); -``` - -## Command Base Class - -```typescript -import { Command } from '@contentstack/cli-command'; - -export default class MyCommand extends Command { - static description = 'My command description'; - - static flags = { - region: flags.string({ - char: 'r', - description: 'Set region' - }) - }; - - async run(): Promise { - const { flags } = await this.parse(MyCommand); - // Command logic here - } -} -``` - -## Error Handling Patterns - -### With Context -```typescript -try { - const result = await this.client.stack().entry().fetch(); -} catch (error) { - handleAndLogError(error, { - module: 'auth-service', - command: 'cm:auth:login', - userId: this.contextDetails.userId, - email: this.contextDetails.email - }); -} -``` - -### Custom Errors -```typescript -if (response.status === 401) { - throw new CLIError('Authentication failed. Please login again.'); -} - -if (response.status === 429) { - throw new CLIError('Rate limited. Please try again later.'); -} -``` - -## Usage - -Reference the comprehensive patterns guide above for detailed implementations of configuration, logging, error handling, utilities, and dependency injection patterns. diff --git a/.cursor/skills/testing/SKILL.md b/.cursor/skills/testing/SKILL.md deleted file mode 100644 index d53591924..000000000 --- a/.cursor/skills/testing/SKILL.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -name: testing -description: Testing patterns, TDD workflow, and test automation for CLI development. Use when writing tests, implementing TDD, setting up test coverage, or debugging test failures. ---- - -# Testing Patterns - -## Quick Reference - -For comprehensive testing guidance, see: -- **[Testing Patterns](./references/testing-patterns.md)** - Complete testing best practices and TDD workflow -- See also `.cursor/rules/testing.mdc` for workspace-wide testing standards - -## TDD Workflow Summary - -**Simple RED-GREEN-REFACTOR:** -1. **RED** → Write failing test -2. **GREEN** → Make it pass with minimal code -3. **REFACTOR** → Improve code quality while keeping tests green - -## Key Testing Rules - -- **80% minimum coverage** (lines, branches, functions) -- **Class-based mocking** (no external libraries; extend and override methods) -- **Never make real API calls** in tests -- **Mock at service boundaries**, not implementation details -- **Test both success and failure paths** -- **Use descriptive test names**: "should [behavior] when [condition]" - -## Quick Test Template - -```typescript -describe('[ServiceName]', () => { - let service: [ServiceName]; - - beforeEach(() => { - service = new [ServiceName](); - }); - - afterEach(() => { - // Clean up any resources - }); - - it('should [expected behavior] when [condition]', async () => { - // Arrange - const input = { /* test data */ }; - - // Act - const result = await service.method(input); - - // Assert - expect(result).to.deep.equal(expectedOutput); - }); - - it('should throw error when [error condition]', async () => { - // Arrange & Act & Assert - await expect(service.failingMethod()) - .to.be.rejectedWith('Expected error message'); - }); -}); -``` - -## Common Mock Patterns - -### Class-Based Mocking -```typescript -// Mock a service by extending it -class MockContentstackClient extends ContentstackClient { - async fetch() { - return mockData; - } -} - -it('should use mocked client', async () => { - const mockClient = new MockContentstackClient(config); - const result = await mockClient.fetch(); - expect(result).to.deep.equal(mockData); -}); -``` - -### Constructor Injection -```typescript -class RateLimiter { - async execute(operation: () => Promise): Promise { - return operation(); - } -} - -class MyService { - constructor(private rateLimiter: RateLimiter) {} - - async doWork() { - return this.rateLimiter.execute(() => this.performWork()); - } -} - -it('should rate limit operations', () => { - const mockLimiter = { execute: () => Promise.resolve('result') }; - const service = new MyService(mockLimiter as any); - // test service behavior -}); -``` - -## Running Tests - -### Run all tests in workspace -```bash -pnpm test -``` - -### Run tests for specific package -```bash -pnpm --filter @contentstack/cli-auth test -pnpm --filter @contentstack/cli-config test -``` - -### Run tests with coverage -```bash -pnpm test:coverage -``` - -### Run tests in watch mode -```bash -pnpm test:watch -``` - -### Run specific test file -```bash -pnpm test -- test/unit/commands/auth/login.test.ts -``` - -## Test Organization - -### File Structure -- Mirror source structure: `test/unit/commands/auth/`, `test/unit/services/`, `test/unit/utils/` -- Use consistent naming: `[module-name].test.ts` -- Integration tests: `test/integration/` - -### Test Data Management -```typescript -// Create mock data factories in test/fixtures/ -const mockAuthToken = { token: 'abc123', expiresAt: Date.now() + 3600000 }; -const mockConfig = { region: 'us', email: 'test@example.com' }; -``` - -## Error Testing - -### Rate Limit Handling -```typescript -it('should handle rate limit errors', async () => { - const error = new Error('Rate limited'); - (error as any).status = 429; - - class MockClient { - fetch() { throw error; } - } - - try { - await new MockClient().fetch(); - expect.fail('Should have thrown'); - } catch (err: any) { - expect(err.status).to.equal(429); - } -}); -``` - -### Validation Error Testing -```typescript -it('should throw validation error for invalid input', () => { - expect(() => service.validateRegion('')) - .to.throw('Region is required'); -}); -``` - -## Coverage and Quality - -### Coverage Requirements -```json -"nyc": { - "check-coverage": true, - "lines": 80, - "functions": 80, - "branches": 80, - "statements": 80 -} -``` - -### Quality Checklist -- [ ] All public methods tested -- [ ] Error paths covered (success + failure) -- [ ] Edge cases included -- [ ] No real API calls -- [ ] Descriptive test names -- [ ] Minimal test setup -- [ ] Tests run < 5s per test file -- [ ] 80%+ coverage achieved - -## Usage - -Reference the comprehensive patterns guide above for detailed test structures, mocking strategies, error testing patterns, and coverage requirements. diff --git a/.github/config/release.json b/.github/config/release.json index 8bb034f84..db65f989c 100755 --- a/.github/config/release.json +++ b/.github/config/release.json @@ -1,12 +1,9 @@ { "releaseAll": true, "plugins": { + "asset-management": false, "variants": false, "query-export": false, - "utilities": false, - "command": false, - "config": false, - "auth": false, "export": false, "import": false, "clone": false, @@ -15,15 +12,11 @@ "migration": false, "seed": false, "bootstrap": false, - "bulk-publish": false, - "dev-dependencies": false, - "launch": false, "branches": false, "apps-cli": false, "content-type": false, "regex-validate": false, "tsgen": false, - "bulk-operations": false, - "core": false + "bulk-operations": false } } diff --git a/.github/workflows/release-production-plugins.yml b/.github/workflows/release-production-plugins.yml index 1eeaedd10..b551be82b 100644 --- a/.github/workflows/release-production-plugins.yml +++ b/.github/workflows/release-production-plugins.yml @@ -39,6 +39,15 @@ jobs: filename: .github/config/release.json prefix: release + # Asset Management + - name: Publishing asset-management (Production) + uses: JS-DevTools/npm-publish@v3 + with: + token: ${{ secrets.NPM_TOKEN }} + package: ./packages/contentstack-asset-management/package.json + access: public + tag: latest + # Variants - name: Publishing variants (Production) uses: JS-DevTools/npm-publish@v3 @@ -127,14 +136,6 @@ jobs: package: ./packages/contentstack-bootstrap/package.json tag: latest - # Bulk Publish - - name: Publishing bulk publish (Production) - uses: JS-DevTools/npm-publish@v3 - with: - token: ${{ secrets.NPM_TOKEN }} - package: ./packages/contentstack-bulk-publish/package.json - tag: latest - # Bulk Operations - name: Publishing bulk operations (Production) uses: JS-DevTools/npm-publish@v3 diff --git a/.github/workflows/tsgen-integration-test.yml b/.github/workflows/tsgen-integration-test.yml index 1d1affab1..0a9eb2a96 100644 --- a/.github/workflows/tsgen-integration-test.yml +++ b/.github/workflows/tsgen-integration-test.yml @@ -28,7 +28,7 @@ jobs: - name: Build tsgen plugin run: pnpm --filter contentstack-cli-tsgen run build - - name: Install Contentstack CLI (v1) + - name: Install Contentstack CLI run: npm i -g @contentstack/cli - name: Configure CLI region diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 0a869b158..326b8a4d0 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -22,66 +22,16 @@ jobs: node-version: '22.x' cache: 'pnpm' # optional but recommended - - name: Install dependencies for all plugins - run: | - NODE_ENV=PREPACK_MODE npm run bootstrap + - name: Install Dependencies + run: pnpm install --no-frozen-lockfile - name: Build all plugins - run: | - NODE_ENV=PREPACK_MODE npm run build - - - name: Run tests for Contentstack Import Plugin - working-directory: ./packages/contentstack-import - run: npm run test:unit - - - name: Run tests for Contentstack Export Plugin - working-directory: ./packages/contentstack-export - run: npm run test:unit - - - name: Run tests for Audit plugin - working-directory: ./packages/contentstack-audit - run: npm run test:unit - - - name: Run tests for Contentstack Migration - working-directory: ./packages/contentstack-migration - run: npm run test - - - name: Run tests for Contentstack Export To CSV - working-directory: ./packages/contentstack-export-to-csv - run: npm run test:unit - - - name: Run tests for Contentstack Bootstrap - working-directory: ./packages/contentstack-bootstrap - run: npm run test - - # - name: Run tests for Contentstack Import Setup - # working-directory: ./packages/contentstack-import-setup - # run: npm run test:unit - - - name: Run tests for Contentstack Branches - working-directory: ./packages/contentstack-branches - run: npm run test:unit - - - name: Run tests for Contentstack Query Export - working-directory: ./packages/contentstack-query-export - run: npm run test:unit - - - name: Run tests for Contentstack Content Type plugin - working-directory: ./packages/contentstack-content-type - run: npm run test:unit - - - name: Run tests for Contentstack Regex Validate plugin - working-directory: ./packages/contentstack-cli-cm-regex-validate - run: npm run test - - - name: Run tests for Contentstack Migrate RTE - working-directory: ./packages/contentstack-migrate-rte - run: npm run test - - - name: Run tests for Contentstack Bulk Operations - working-directory: ./packages/contentstack-bulk-operations - run: npm run test - - - name: Run tests for Contentstack Apps CLI - working-directory: ./packages/contentstack-apps-cli - run: npm run test:unit:report \ No newline at end of file + run: NODE_ENV=PREPACK_MODE pnpm -r --sort run build + + # Single run over every plugin's `test` (unit) script. --no-bail runs all packages even + # when one fails, and pnpm prints a per-package summary at the end, so failures are still + # easy to locate in the one log. --workspace-concurrency=1 keeps the output sequential and + # readable. Integration suites live under a separate `test:integration` script and do not + # run here; the tsgen integration suite has its own workflow (tsgen-integration-test.yml). + - name: Run unit tests for all plugins + run: pnpm -r --no-bail --workspace-concurrency=1 --filter './packages/*' run test \ No newline at end of file diff --git a/.talismanrc b/.talismanrc index 58ae8ba6b..52fd1b033 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,4 +1,10 @@ fileignoreconfig: - filename: pnpm-lock.yaml - checksum: 31e333d6769adbaae042c92ea0930fab168a0e06fc1bda406d49fd1042a7a9c7 + checksum: 8566e316dd7026214e8863568c72dcf946ba10648ac5c076a7c55215b5ab3422 +- filename: packages/contentstack-seed/src/commands/cm/stacks/seed.ts + checksum: ff6a2bf11defd3342bc5fcbca870b9f178a412de916a90f778ce3a2028501310 +- filename: packages/contentstack-seed/test/commands/cm/stacks/seed.test.ts + checksum: 1cd4716bc15029286b73d7d459ddc2083ee89aaecaba9211a2ef923e1469fc39 +- filename: packages/contentstack-migration/src/commands/cm/stacks/migration.ts + checksum: 529431473623cf6bbefb35bc898be2a60dcb453e0c9273ecb97923de658769b3 version: '1.0' diff --git a/AGENTS.md b/AGENTS.md index 565826b2c..2ebc39eb1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,13 +1,13 @@ # Contentstack CLI plugins – Agent guide -**Universal entry point** for contributors and AI agents. Detailed conventions live in **`skills/*/SKILL.md`** (per-package). +**Universal entry point** for contributors and AI agents. Detailed conventions live in **`skills/*/SKILL.md`**. ## What this repo is | Field | Detail | | --- | --- | | **Name:** | Contentstack CLI plugins (pnpm monorepo; root package name `csdx`) | -| **Purpose:** | OCLIF plugins that extend the Contentstack CLI (import/export, clone, migration, seed, audit, variants, Developer Hub apps, regex validation, etc.). | +| **Purpose:** | OCLIF plugins that extend the Contentstack CLI (import/export, clone, migration, migrate RTE, bulk operations, seed, audit, variants, Developer Hub apps, TypeScript codegen, etc.). | | **Out of scope (if any):** | The **core** CLI aggregation lives in the separate `cli` monorepo; this repo ships plugin packages only. | ## Tech stack (at a glance) @@ -17,7 +17,6 @@ | **Language** | TypeScript / JavaScript, Node **>= 18** (`engines` in root `package.json`) | | **Build** | pnpm workspaces (`packages/*`); per package: `tsc`, OCLIF manifest/readme where applicable → `lib/` | | **Tests** | Mocha + Chai; layouts under `packages/*/test/` (see [skills/testing/SKILL.md](skills/testing/SKILL.md)) | -| **Tests** | Mocha + Chai (most packages); Jest + ts-jest (`contentstack-cli-cm-regex-validate`); layouts under `packages/*/test/` | | **Lint / coverage** | ESLint in packages that define `lint` scripts; nyc where configured | | **Other** | OCLIF v4, Husky | @@ -49,27 +48,47 @@ CI: [.github/workflows/unit-test.yml](.github/workflows/unit-test.yml) and other - **v1 / v2:** Maintain on `v1-dev` (1.x CLI deps) and `v2-dev` / `v2-beta` (2.x beta deps) branches; align `@contentstack/cli-command` and `@contentstack/cli-utilities` versions with the target CLI line. - **Docs:** OCLIF / `app:*` commands → [contentstack-cli](skills/contentstack-cli/SKILL.md#apps-cli-commands-app); SDK, manifests, GraphQL, HTTP → [framework](skills/framework/SKILL.md#apps-cli-plugin-contentstackapps-cli) +## Tsgen plugin (`contentstack-cli-tsgen`) + +- **Package path:** [packages/contentstack-cli-tsgen](packages/contentstack-cli-tsgen) +- **npm name:** `contentstack-cli-tsgen` (unchanged for consumers) +- **Migrated from:** standalone `contentstack-cli-tsgen` repos — see [TSGEN-MIGRATION.md](TSGEN-MIGRATION.md) +- **v2 beta only:** `5.0.0-beta.0`+ on `feat/migrate-external-cli-plugins-v2` / `v2-beta`; requires CLI 2.x beta. +- **Docs:** `csdx tsgen` → [typescript-cli-tsgen](packages/contentstack-cli-tsgen/skills/typescript-cli-tsgen/SKILL.md); tests → [package testing skill](packages/contentstack-cli-tsgen/skills/testing/SKILL.md) + ## Content Type plugin (`contentstack-cli-content-type`) - **Package path:** [packages/contentstack-content-type](packages/contentstack-content-type) - **npm name:** `contentstack-cli-content-type` - **Migrated from:** [contentstack/contentstack-cli-content-type](https://github.com/contentstack/contentstack-cli-content-type) — see [CONTENT-TYPE-MIGRATION.md](CONTENT-TYPE-MIGRATION.md) -- **v1 / v2:** This branch carries the **v1 line** (`@contentstack/cli-command ^1.8.2`, `@contentstack/cli-utilities ^1.18.3`, npm tag `latest`). The v2-beta line lives on `v2-beta`. +- **v1 / v2:** Maintain on `v1-dev` / `main` (1.x CLI deps) and `v2-beta` (2.x beta deps) branches; align `@contentstack/cli-command` and `@contentstack/cli-utilities` versions with the target CLI line. - **Tests:** Jest + ts-jest (unlike most other packages which use Mocha + Chai) - **Docs:** 6 commands under `content-type:*` → [packages/contentstack-content-type/AGENTS.md](packages/contentstack-content-type/AGENTS.md) -- **v1 / v2:** This branch carries the **v1 line** (`@contentstack/cli-command ^1.8.2`, `@contentstack/cli-utilities ^1.18.3`). -- **Docs:** See [packages/contentstack-apps-cli/AGENTS.md](packages/contentstack-apps-cli/AGENTS.md) ## Regex Validate plugin (`@contentstack/cli-cm-regex-validate`) - **Package path:** [packages/contentstack-cli-cm-regex-validate](packages/contentstack-cli-cm-regex-validate) - **npm name:** `@contentstack/cli-cm-regex-validate` - **Migrated from:** [contentstack/cli-cm-regex-validate](https://github.com/contentstack/cli-cm-regex-validate) — see [REGEX-VALIDATE-MIGRATION.md](REGEX-VALIDATE-MIGRATION.md) -- **v1 / v2:** This branch carries the **v1 line** (`@contentstack/cli-command ^1.8.2`, `@contentstack/cli-utilities ^1.18.3`, version `1.0.0`, npm tag `latest`). +- **v1 / v2:** Maintain on `v1-dev` / `main` (v1 CLI deps) and `v2-beta` (`~2.0.0-beta.7` / `~2.0.0-beta.8`, version `2.0.0-beta.0`); align with target CLI line. - **Tests:** Jest + ts-jest (unlike most other packages which use Mocha + Chai) - **Command:** Single command `cm:stacks:validate-regex` (short name `RGXVLD`) - **Docs:** [packages/contentstack-cli-cm-regex-validate/AGENTS.md](packages/contentstack-cli-cm-regex-validate/AGENTS.md) +## Migrate RTE plugin (`@contentstack/cli-cm-migrate-rte`) + +- **Package path:** [packages/contentstack-migrate-rte](packages/contentstack-migrate-rte) +- **npm name:** `@contentstack/cli-cm-migrate-rte` (unchanged) +- **Migrated from:** [contentstack/cli-cm-migrate-rte](https://github.com/contentstack/cli-cm-migrate-rte) — see [MIGRATE-RTE-MIGRATION.md](MIGRATE-RTE-MIGRATION.md) +- **Command:** `csdx cm:entries:migrate-html-rte` — JS sources in `src/`; `pnpm --filter @contentstack/cli-cm-migrate-rte run build` (`oclif manifest`) and `test` (see [dev-workflow](skills/dev-workflow/SKILL.md)) + +## Bulk operations plugin (`@contentstack/cli-bulk-operations`) + +- **Package path:** [packages/contentstack-bulk-operations](packages/contentstack-bulk-operations) +- **npm name:** `@contentstack/cli-bulk-operations` (unchanged) +- **Migrated from:** [contentstack/cli-bulk-operations](https://github.com/contentstack/cli-bulk-operations) — see [BULK-OPERATIONS-MIGRATION.md](BULK-OPERATIONS-MIGRATION.md) (commands + repository) +- **Commands:** `csdx cm:stacks:bulk-entries`, `csdx cm:stacks:bulk-assets`, `csdx cm:stacks:bulk-taxonomies` — see [dev-workflow](skills/dev-workflow/SKILL.md) + ## Using Cursor (optional) If you use **Cursor**, [.cursor/rules/README.md](.cursor/rules/README.md) only points to **`AGENTS.md`**—same docs as everyone else. diff --git a/APPS-CLI-MIGRATION.md b/APPS-CLI-MIGRATION.md index d3b9af325..db2851072 100644 --- a/APPS-CLI-MIGRATION.md +++ b/APPS-CLI-MIGRATION.md @@ -2,44 +2,50 @@ ## Summary -The **@contentstack/apps-cli** plugin has moved from [contentstack/contentstack-apps-cli](https://github.com/contentstack/contentstack-apps-cli) into [contentstack/cli-plugins](https://github.com/contentstack/cli-plugins) at **`packages/contentstack-apps-cli`**. +The **@contentstack/apps-cli** plugin (`contentstack-apps-cli`) has moved from the standalone repository [contentstack/contentstack-apps-cli](https://github.com/contentstack/contentstack-apps-cli) into the [contentstack/cli-plugins](https://github.com/contentstack/cli-plugins) monorepo at **`packages/contentstack-apps-cli`**. -The **npm package name is unchanged**: `@contentstack/apps-cli`. +The **npm package name is unchanged**: `@contentstack/apps-cli`. Install and command usage stay the same. -## Repository and issues +## Repository and issue tracking | Before | After | | --- | --- | -| `github.com/contentstack/contentstack-apps-cli` | `github.com/contentstack/cli-plugins` → `packages/contentstack-apps-cli` | -| Issues on standalone repo | [cli-plugins issues](https://github.com/contentstack/cli-plugins/issues) | +| Source: `github.com/contentstack/contentstack-apps-cli` | Source: `github.com/contentstack/cli-plugins` → `packages/contentstack-apps-cli` | +| Issues: contentstack-apps-cli repo | Issues: [cli-plugins issues](https://github.com/contentstack/cli-plugins/issues) (label or mention `apps-cli` / `@contentstack/apps-cli`) | + +The standalone **contentstack-apps-cli** repository is **archived** after the first release from cli-plugins. Open PRs and bugs should be recreated or linked in cli-plugins. ## Version lines (1.x vs 2.x) -| CLI line | cli-plugins branch | Apps plugin | +| CLI line | cli-plugins branch | Apps plugin notes | | --- | --- | --- | -| **1.x** | `v1-dev` / `v1-beta` | Version **1.7.x**; `@contentstack/cli-command` ~1.8.2, `@contentstack/cli-utilities` ~1.18.x; chalk v4 | -| **2.x beta** | `v2-dev` / `v2-beta` | Version **2.0.0-beta.x**; 2.x beta core packages; chalk v5 | +| **1.x** | `v1-dev` / `v1-beta` | `@contentstack/cli-command` and `@contentstack/cli-utilities` on 1.x-compatible ranges | +| **2.x beta** | `v2-dev` / `v2-beta` | Align with 2.x beta core packages (same pattern as export, import, bootstrap) | -Develop and release each line on its branch. +Develop and release each line on its branch; do not mix 1.x and 2.x dependency pins in the same branch. ## Install (unchanged) ```bash csdx plugins:install @contentstack/apps-cli +# or +npm install -g @contentstack/apps-cli ``` -## Local development (cli-dev-workspace) +## Local development + +Clone [cli-dev-workspace](https://github.com/contentstack/cli-dev-workspace) (or cli-plugins only), then: ```bash -cd cli-dev-workspace +cd cli-plugins pnpm install pnpm --filter @contentstack/apps-cli run build -pnpm -C cli/packages/contentstack run build +pnpm --filter @contentstack/apps-cli test ``` -Core CLI must list `@contentstack/apps-cli` as `workspace:*` and register it in `oclif.plugins` — see [cli](https://github.com/contentstack/cli) `packages/contentstack/package.json`. +See [AGENTS.md](./AGENTS.md), [skills/contentstack-cli/SKILL.md](./skills/contentstack-cli/SKILL.md#apps-cli-commands-app), and [skills/framework/SKILL.md](./skills/framework/SKILL.md#apps-cli-plugin-contentstackapps-cli) for contributor docs. -## Contributor docs +## Related migrations -- [AGENTS.md](./AGENTS.md) -- [skills/contentstack-apps/SKILL.md](./skills/contentstack-apps/SKILL.md) +- Core CLI: [cli](https://github.com/contentstack/cli) monorepo +- Other external plugins (bulk operations, migrate-rte): same cli-plugins consolidation effort diff --git a/CHANGELOG.md b/CHANGELOG.md index 569097d77..bf2ef69a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ Please refer to the Contentstack Command-line Interface release notes [here](htt +## @contentstack/cli-bulk-operations +### Version: 2.0.0-beta.5 +#### Date: Jul-21-2025 +##### Breaking Change: + - Removed the api version flag from `cm:stacks:bulk-entries`. The NRP header value is now hardcoded at the SDK call site, so the flag is no longer needed. Any scripts or CI pipelines that pass this flag must remove it — it will cause an unrecognized-flag error after this release. +##### Fix: + - Force NRP header to version 3.2 on all entry and asset publish/unpublish requests. The header is injected per-call and does not affect other CMA requests. + #### Date: Feb-09-2025 ## cli - Refactor Endpoints Integration using Utils SDK in cli-cm-config v1.9.0 diff --git a/packages/contentstack-cli-cm-regex-validate/CODEOWNERS b/CODEOWNERS similarity index 100% rename from packages/contentstack-cli-cm-regex-validate/CODEOWNERS rename to CODEOWNERS diff --git a/CONTENT-TYPE-MIGRATION.md b/CONTENT-TYPE-MIGRATION.md new file mode 100644 index 000000000..83d4ef2ef --- /dev/null +++ b/CONTENT-TYPE-MIGRATION.md @@ -0,0 +1,76 @@ +# Content Type plugin migration: standalone repo → cli-plugins monorepo + +## Summary + +The **contentstack-cli-content-type** plugin has moved from the standalone repository [contentstack/contentstack-cli-content-type](https://github.com/contentstack/contentstack-cli-content-type) into the [contentstack/cli-plugins](https://github.com/contentstack/cli-plugins) monorepo at **`packages/contentstack-content-type`**. + +The **npm package name is unchanged**: `contentstack-cli-content-type`. Install and command usage stay the same. + +First release from the monorepo: **2.0.0-beta.0** (previously 1.4.6 from the standalone repo). + +## Repository and issue tracking + +| Before | After | +| --- | --- | +| Source: `github.com/contentstack/contentstack-cli-content-type` | Source: `github.com/contentstack/cli-plugins` → `packages/contentstack-content-type` | +| Issues: contentstack-cli-content-type repo | Issues: [cli-plugins issues](https://github.com/contentstack/cli-plugins/issues) (label or mention `content-type` / `contentstack-cli-content-type`) | + +The standalone **contentstack-cli-content-type** repository should be **archived** after the first release from cli-plugins. Open PRs and bugs should be recreated or linked in cli-plugins. + +## Version lines (1.x vs 2.x) + +| CLI line | cli-plugins branch | Plugin notes | +| --- | --- | --- | +| **1.x** | `v1-dev` / `main` | `@contentstack/cli-command ~1.8.2`, `@contentstack/cli-utilities ~1.18.3`; npm tag `latest` | +| **2.x beta** | `v2-dev` / `v2-beta` | Align with 2.x beta core packages; npm tag `beta` | + +Develop and release each line on its branch; do not mix 1.x and 2.x dependency pins in the same branch. + +## Install (unchanged) + +```bash +csdx plugins:install contentstack-cli-content-type +``` + +## Commands (unchanged) + +All 6 commands are identical to the standalone version: + +| Command | Description | +| --- | --- | +| `csdx content-type:list` | List all Content Types in a Stack | +| `csdx content-type:details` | Display Content Type fields, types, references, and paths | +| `csdx content-type:audit` | Display recent changes (audit log) for a Content Type | +| `csdx content-type:compare` | Compare two versions of a Content Type in the same Stack | +| `csdx content-type:compare-remote` | Compare the same Content Type across two Stacks | +| `csdx content-type:diagram` | Generate a visual diagram (SVG or DOT) of the Stack content model | + +## Local development + +Clone [cli-dev-workspace](https://github.com/contentstack/cli-dev-workspace) (or cli-plugins only), then: + +```bash +cd cli-plugins +pnpm install +pnpm --filter contentstack-cli-content-type run build +pnpm --filter contentstack-cli-content-type test +``` + +To link the plugin locally into your `csdx` installation: + +```bash +cd packages/contentstack-content-type +csdx plugins:link +``` + +See [packages/contentstack-content-type/AGENTS.md](./packages/contentstack-content-type/AGENTS.md) and the [skills/](./packages/contentstack-content-type/skills/) directory for contributor docs. + +## Test framework note + +This package uses **Jest + ts-jest** (unlike most other packages in this monorepo which use Mocha + Chai). Tests live under `packages/contentstack-content-type/tests/` and run via `pnpm test` or `pnpm run test:unit`. + +## Related migrations + +- Apps CLI: [APPS-CLI-MIGRATION.md](./APPS-CLI-MIGRATION.md) +- Tsgen plugin: [TSGEN-MIGRATION.md](./TSGEN-MIGRATION.md) +- Core CLI: [cli](https://github.com/contentstack/cli) monorepo diff --git a/MIGRATE-RTE-MIGRATION.md b/MIGRATE-RTE-MIGRATION.md index 595ef45a7..d46ea6917 100644 --- a/MIGRATE-RTE-MIGRATION.md +++ b/MIGRATE-RTE-MIGRATION.md @@ -17,8 +17,8 @@ The npm package name and command **`csdx cm:entries:migrate-html-rte`** are unch | CLI line | cli-plugins branch | Plugin notes | | --- | --- | --- | -| **1.x** | `v1-dev` / `v1-beta` | e.g. **1.6.x**; `@contentstack/cli-command` ~1.8.2, `@contentstack/cli-utilities` ~1.18.x; chalk v4 | -| **2.x beta** | `v2-dev` / `v2-beta` | e.g. **2.0.0-beta.x**; 2.x beta core packages; chalk v5 + `load-chalk` init hook | +| **1.x** | `v1-dev` / `v1-beta` | 1.x-compatible `cli-command` / `cli-utilities` | +| **2.x beta** | `v2-dev` / `v2-beta` | e.g. `2.0.0-beta.x`; uses `@contentstack/json-rte-serializer`, jsdom | ## Install @@ -37,4 +37,4 @@ pnpm --filter @contentstack/cli-cm-migrate-rte run build pnpm --filter @contentstack/cli-cm-migrate-rte test ``` -Core CLI: add `@contentstack/cli-cm-migrate-rte` to `cli/packages/contentstack` dependencies and `oclif.plugins` (use `workspace:*` in cli-dev-workspace until the monorepo package is published). +Core CLI: add `@contentstack/cli-cm-migrate-rte` to `cli/packages/contentstack` dependencies and `oclif.plugins` (use `workspace:*` in cli-dev-workspace). diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 000000000..41922466f --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,254 @@ +# Contentstack CLI Migration Guide: 1.x.x to 2.x.x-beta + +## Overview + +This guide helps you migrate from Contentstack CLI 1.x.x to the new 2.x.x-beta version. The new version introduces significant improvements in performance, user experience, and functionality. + +## Major Changes + +### 1. 🚀 TypeScript Module Support (Default) + +**What Changed:** +- Removed `export-info.json` support +- TypeScript modules are now the default for export and import operations +- Improved performance and reliability + +**Before (1.x.x):** +```bash +csdx cm:stacks:export -d "./export-data" -k bltxxxxxx +``` +The CLI generated an export-info.json file containing a contentVersion field: +contentVersion: 2 for TypeScript modules +contentVersion: 1 for JavaScript modules (default) +This version indicator helped the import process select the appropriate module structure, as TypeScript and JavaScript modules have different structures for assets, entries, and other components. + +**After (2.x.x-beta):** +```bash +csdx cm:stacks:export -d "./export-data" -k bltxxxxxx +``` +No export-info.json file is generated +TypeScript modules are used by default for all operations +Simplified export structure with consistent module formatting + +**Migration Action:** Remove `export-info.json` file generation logic from export plugin. + +### 2. 🌿 Main Branch Export (Default) + +**What Changed:** +- By default, only the main branch content is exported +- Consistent behavior with import operations +- Faster exports for most use cases + +**Before (1.x.x):** +- Exported all branches by default + +**After (2.x.x-beta):** +- Exports main branch by default +- Specify `--branch` for specific branch export + +**Examples:** + +```bash +# Export main branch (default behavior) +csdx cm:stacks:export -d "./export-data" -k bltxxxxxx + +# Export specific branch +csdx cm:stacks:export --branch feature-branch -d "./export-data" -k bltxxxxxx + +# Export using branch alias +csdx cm:stacks:export --branch-alias production -d "./export-data" -k bltxxxxxx +``` + +**Migration Action:** To export specific branches, add the `--branch` flag to your commands. + +### 3. 📊 Progress Manager UI (Default) + +**What Changed:** +- Visual Progress Manager is now the default UI for export, import, clone & seed operations +- Enhanced user experience with real-time progress tracking +- Console logs are available as an optional mode + +## New Progress Manager Interface + +### Default Mode: Visual Progress Manager + +When you run the export or import commands, a visual progress interface appears. + +``` +STACK: + ├─ Settings |████████████████████████████████████████| 100% | 1/1 | ✓ Complete (1/1) + ├─ Locale |████████████████████████████████████████| 100% | 1/1 | ✓ Complete (1/1) + +LOCALES: + └─ Locales |████████████████████████████████████████| 100% | 2/2 | ✓ Complete (2/2) + +CONTENT TYPES: + └─ Content types |████████████████████████████████████████| 100% | 6/6 | ✓ Complete (6/6) + +ENTRIES: + ├─ Entries |████████████████████████████████████████| 100% | 12/12 | ✓ Complete (12/12) +``` + +### Optional Mode: Console Logs + +For debugging or detailed logging, switch to console log mode: + +**Enable Console Logs:** +```bash +csdx config:set:log --show-console-logs +``` + +**Disable Console Logs (back to Progress Manager):** +```bash +csdx config:set:log --no-show-console-logs +``` + +**Console Log Output Example:** +``` +[2025-08-22 16:12:23] INFO: Exporting content from branch main +[2025-08-22 16:12:23] INFO: Started to export content, version is 2 +[2025-08-22 16:12:23] INFO: Exporting module: stack +[2025-08-22 16:12:24] INFO: Exporting stack settings +[2025-08-22 16:12:25] SUCCESS: Exported stack settings successfully! +``` + +### 4. 🏷️ Taxonomy Migration Deprecation + +**What Changed:** +- Taxonomy migration functionality has been deprecated in 2.x.x +- The taxonomy migration script examples have been removed + +**Before (1.x.x):** +```bash +csdx cm:stacks:migration -k b*******9ca0 --file-path "../contentstack-migration/examples/taxonomies/import-taxonomies.js" --config data-dir:'./data/Taxonomy Stack_taxonomies.csv' +``` +- Taxonomy migration supports only in version 1.x.x + +**After (2.x.x-beta):** +- Taxonomy migration is no longer supported through the migration plugin +- Use the standard import/export commands for taxonomy data migration + +**Migration Action:** use the import/export commands instead. + +### 5. 📝 Migrate RTE Plugin Separation + +**What Changed:** +- The migrate-rte plugin has been separated into a standalone plugin +- Requires separate installation to use RTE migration features +- Provides more flexibility and modular architecture + +**Before (1.x.x):** +- RTE migration was built into the core CLI package +- Available by default with CLI installation + +**After (2.x.x-beta):** +- RTE migration is a separate plugin that must be installed explicitly +- Install using one of the following methods: + +**Installation Methods:** + + +**Option 1: Using npm** +```bash +npm install -g @contentstack/cli-cm-migrate-rte +``` + +**Option 2: Using CLI Plugin Manager** +```bash +csdx plugins:install @contentstack/cli-cm-migrate-rte@2.0.0-beta +``` + +**Source repository:** Plugin code lives in [cli-plugins](https://github.com/contentstack/cli-plugins) at `packages/contentstack-migrate-rte` (formerly [cli-cm-migrate-rte](https://github.com/contentstack/cli-cm-migrate-rte)). See [MIGRATE-RTE-MIGRATION.md](./MIGRATE-RTE-MIGRATION.md). + +**Usage:** +After installation, RTE migration commands will be available through the CLI: +```bash +csdx cm:migrate-rte --help +``` + +**Migration Action:** Install the `@contentstack/cli-cm-migrate-rte` plugin separately if you need RTE migration functionality. + +### 6. 📦 Bulk Operations Command Consolidation + +**What Changed:** +- The bulk publish plugin has been consolidated into unified bulk operations commands +- 15 separate commands have been simplified into 2 commands with operation flags +- Enhanced functionality with new filtering and cross-publish capabilities + +**Impact:** +- Commands like `cm:entries:publish`, `cm:entries:unpublish`, `cm:assets:publish` have been replaced +- New unified commands: `cm:stacks:bulk-entries` and `cm:stacks:bulk-assets` +- Operation flag (`--operation`) is now required + +**Migration Action:** Refer to the detailed [Bulk Operations Migration Guide](./BULK-OPERATIONS-MIGRATION.md) for complete command mappings and examples. + +### 7. 📱 Apps CLI plugin repository move + +**What Changed:** +- The Apps CLI plugin (`@contentstack/apps-cli`) source moved from the standalone [contentstack-apps-cli](https://github.com/contentstack/contentstack-apps-cli) repository into this **cli-plugins** monorepo at `packages/contentstack-apps-cli` +- The npm package name and `csdx app:*` commands are unchanged + +**Migration Action:** For repository location, branching (1.x vs 2.x), and issue tracking, see the [Apps CLI Migration Guide](./APPS-CLI-MIGRATION.md). + +**Quick Example:** +```bash +# Before (1.x.x) +csdx cm:entries:publish --content-types blog --environments prod --locales en-us -k blt123 + +# After (2.x.x-beta) +csdx cm:stacks:bulk-entries --operation publish --content-types blog --environments prod --locales en-us -k blt123 +``` + +## Troubleshooting + +### Common Issues + +**1. Command not found errors:** +- Ensure you have installed the 2.x.x-beta version +- Clear npm cache: `npm cache clean --force` + +**2. Missing branch content:** +- Check if you need to specify the `--branch` flag for non-main branches +- Verify the branch exists in your stack + +**3. Progress display issues:** +- Try switching between console logs and progress manager modes +- Check terminal compatibility for progress bars + +**4. Performance differences:** +- The 2.x.x-beta version should be faster due to TypeScript modules +- If you are experiencing issues, switch to console log mode for debugging + +### Getting Help + +**Documentation:** +- [CLI Documentation](https://www.contentstack.com/docs/developers/cli) +- [API Reference](https://www.contentstack.com/docs/developers/apis) + +**Support:** +- [GitHub Issues](https://github.com/contentstack/cli/issues) + +## Benefits of 2.x.x-beta + +### 🚀 **Performance Improvements** +- Faster export/import operations with TypeScript modules +- Optimized branch handling +- Reduced memory usage + +### 🎯 **Better User Experience** +- Visual Progress Manager with real-time updates +- Cleaner command syntax +- More intuitive default behaviors + +### 🔧 **Enhanced Reliability** +- Improved error handling +- Better progress tracking +- More consistent behavior across commands + +### 📊 **Better Observability** +- Detailed progress information +- Clear success/failure indicators +- Optional detailed logging for debugging +--- + +**Need help with migration?** Contact our support team or visit our community forum for assistance. diff --git a/README.md b/README.md index cae98a050..2d59dd68a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Contentstack is a headless CMS with an API-first approach that puts content at t CLI supports content management scripts through which you can perform the following tasks: -- Bulk publish content +- Bulk publish content (`cm:stacks:bulk-*` via `@contentstack/cli-bulk-operations`) - Export content - Import content - Clone Stack @@ -22,7 +22,7 @@ CLI supports content management scripts through which you can perform the follow ## Installing CLI ### Prerequisites Contentstack account -Node.js version 16 or above +Node.js version 22 or above ### Installation To install CLI on your system, run the below command in your terminal: @@ -33,6 +33,18 @@ npm install -g @contentstack/cli To verify the installation, run `csdx` in the command window. +## Migration Guide + +If you're upgrading from CLI 1.x to 2.x.x-beta, please refer to our comprehensive [Migration Guide](./MIGRATION.md) for: + +- **Breaking changes** and new default behaviors +- **Step-by-step migration instructions** +- **New features** like TypeScript module support and Progress Manager UI +- **Command syntax updates** and configuration changes +- **Troubleshooting tips** for common migration issues + +📖 **[View Migration Guide →](./MIGRATION.md)** + ## Usage After the successful installation of CLI, use the `--help` parameter to display the help section of the CLI. You can even combine this parameter with a specific command to get the help section of that command. @@ -43,7 +55,7 @@ $ csdx --help ## Namespaces **auth**: To perform [authentication-related](/packages/contentstack-auth) activities -**cm**: To perform content management activities such as [bulk publish](/packages/contentstack-bulk-publish), [import](/packages/contentstack-import), and [export](/packages/contentstack-export), [export-to-csv] (/packages/contentstack-export-to-csv), [seed] (/packages/contentstack-seed) +**cm**: To perform content management activities such as [bulk operations](/packages/contentstack-bulk-operations), [import](/packages/contentstack-import), and [export](/packages/contentstack-export), [export-to-csv](/packages/contentstack-export-to-csv), [seed](/packages/contentstack-seed) **help**: To list the helpful commands in CLI @@ -51,11 +63,10 @@ $ csdx --help ## Documentation -To get a more detailed documentation for every command, visit the [CLI section](https://www.contentstack.com/docs/developers/cli) in our docs. +To get a more detailed documentation for every command, visit the [CLI section](https://www.contentstack.com/docs/headless-cms/cli) in our docs. ## Useful Plugins -- [Generate TypeScript typings from a Stack](https://github.com/Contentstack-Solutions/contentstack-cli-tsgen) +- [Generate TypeScript typings from a Stack](https://github.com/contentstack/cli-plugins/tree/main/packages/contentstack-cli-tsgen) (`contentstack-cli-tsgen`) - [Manage Content Types (list, details, audit, compare, diagram)](https://github.com/contentstack/cli-plugins/tree/main/packages/contentstack-content-type) (`contentstack-cli-content-type`) - [Validate regex fields in Content Types and Global Fields](https://github.com/contentstack/cli-plugins/tree/main/packages/contentstack-cli-cm-regex-validate) (`@contentstack/cli-cm-regex-validate`) -- [Generate TypeScript typings from a Stack](https://github.com/contentstack/cli-plugins/tree/v1-dev/packages/contentstack-cli-tsgen) (`contentstack-cli-tsgen`) diff --git a/REGEX-VALIDATE-MIGRATION.md b/REGEX-VALIDATE-MIGRATION.md index ee712fdf7..742d17fc2 100644 --- a/REGEX-VALIDATE-MIGRATION.md +++ b/REGEX-VALIDATE-MIGRATION.md @@ -53,4 +53,5 @@ This package uses **Jest + ts-jest** (unlike most other packages in this monorep ## Related migrations +- Content Type plugin: [CONTENT-TYPE-MIGRATION.md](./CONTENT-TYPE-MIGRATION.md) - Apps CLI: [APPS-CLI-MIGRATION.md](./APPS-CLI-MIGRATION.md) diff --git a/TSGEN-MIGRATION.md b/TSGEN-MIGRATION.md new file mode 100644 index 000000000..a57e865d6 --- /dev/null +++ b/TSGEN-MIGRATION.md @@ -0,0 +1,54 @@ +# Tsgen CLI migration: standalone repo → cli-plugins monorepo + +## Summary + +The **contentstack-cli-tsgen** plugin has moved from the standalone repositories [Contentstack-Solutions/contentstack-cli-tsgen](https://github.com/Contentstack-Solutions/contentstack-cli-tsgen) and [contentstack/contentstack-cli-tsgen](https://github.com/contentstack/contentstack-cli-tsgen) into the [contentstack/cli-plugins](https://github.com/contentstack/cli-plugins) monorepo at **`packages/contentstack-cli-tsgen`**. + +The **npm package name is unchanged**: `contentstack-cli-tsgen`. Install and command usage stay the same (`csdx tsgen`). + +## Repository and issue tracking + +| Before | After | +| --- | --- | +| Source: standalone `contentstack-cli-tsgen` repos | Source: `github.com/contentstack/cli-plugins` → `packages/contentstack-cli-tsgen` | +| Issues: standalone repo | Issues: [cli-plugins issues](https://github.com/contentstack/cli-plugins/issues) (label or mention `tsgen` / `contentstack-cli-tsgen`) | + +The standalone **contentstack-cli-tsgen** repository should be **archived** after the first release from cli-plugins. Open PRs and bugs should be recreated or linked in cli-plugins. + +## Version line (2.x beta only) + +| CLI line | cli-plugins branch | Tsgen plugin notes | +| --- | --- | --- | +| **2.x beta** | `feat/migrate-external-cli-plugins-v2` → `v2-beta` | `@contentstack/cli-command` and `@contentstack/cli-utilities` on `~2.0.0-beta.*`; first monorepo release **`5.0.0-beta.0`** | + +This migration does not maintain a `v1-dev` line for tsgen. + +## Install (unchanged) + +```bash +csdx plugins:install contentstack-cli-tsgen@beta +# or +npm install -g contentstack-cli-tsgen +``` + +Requires **Contentstack CLI 2.x beta** and a **delivery token** alias for `csdx tsgen`. + +## Local development + +Clone [cli-dev-workspace](https://github.com/contentstack/cli-dev-workspace) (or cli-plugins only), then: + +```bash +cd cli-plugins +pnpm install +pnpm --filter contentstack-cli-tsgen run build +cd packages/contentstack-cli-tsgen && csdx plugins:link +csdx tsgen --help +``` + +See [AGENTS.md](./AGENTS.md), package [AGENTS.md](./packages/contentstack-cli-tsgen/AGENTS.md), and [skills/typescript-cli-tsgen](./packages/contentstack-cli-tsgen/skills/typescript-cli-tsgen/SKILL.md) for contributor docs. + +## Related migrations + +- Core CLI: [cli](https://github.com/contentstack/cli) monorepo +- Apps CLI: [APPS-CLI-MIGRATION.md](./APPS-CLI-MIGRATION.md) +- Other external plugins: same cli-plugins consolidation effort diff --git a/packages/contentstack-apps-cli/README.md b/packages/contentstack-apps-cli/README.md index 24ab1e191..ef0fc8c48 100644 --- a/packages/contentstack-apps-cli/README.md +++ b/packages/contentstack-apps-cli/README.md @@ -1,3 +1,9 @@ +> **Source of truth:** [cli-plugins monorepo](https://github.com/contentstack/cli-plugins) — `packages/contentstack-apps-cli` +> Migrated from [contentstack-apps-cli](https://github.com/contentstack/contentstack-apps-cli). See [APPS-CLI-MIGRATION.md](../../APPS-CLI-MIGRATION.md). + + + + # @contentstack/apps-cli Contentstack lets you develop apps in your organization using the Developer Hub portal. With the Apps CLI plugin, Contentstack CLI allows you to perform the CRUD operations on your app in Developer Hub and then use the app in your organization or stack by installing or uninstalling your app as required. @@ -10,15 +16,15 @@ $ csdx plugins:install @contentstack/apps-cli ## How to use this plugin -This plugin requires you to be authenticated using [csdx auth:login](https://www.contentstack.com/docs/developers/cli/authenticate-with-the-cli/). +This plugin requires you to be authenticated using [csdx auth:login](https://www.contentstack.com/docs/headless-cms/cli-authentication). ```sh-session $ npm install -g @contentstack/apps-cli $ csdx COMMAND running command... -$ csdx (--version) -@contentstack/apps-cli/1.6.1 darwin-arm64 node-v22.21.1 +$ csdx (--version|-v) +@contentstack/apps-cli/2.0.0-beta.2 darwin-arm64 node-v18.20.2 $ csdx --help [COMMAND] USAGE $ csdx COMMAND @@ -130,7 +136,7 @@ EXAMPLES $ csdx app:delete --app-uid - $ csdx app:delete --app-uid --org + $ csdx app:delete --app-uid --org -d ./boilerplate ``` _See code: [src/commands/app/delete.ts](https://github.com/contentstack/cli-plugins/blob/main/packages/contentstack-apps-cli/src/commands/app/delete.ts)_ @@ -145,7 +151,7 @@ USAGE [--app-url ] [--launch-project existing|new] [-c ] FLAGS - -c, --config= [optional] Please enter the path of the config file. + -c, --config= Path to the optional config file. --app-uid= Provide the app UID of an existing app. --app-url= Please enter the URL of the app you want to deploy. --hosting-type=