diff --git a/.cursor/commands/code-review.md b/.cursor/commands/code-review.md new file mode 100644 index 0000000..b31fa46 --- /dev/null +++ b/.cursor/commands/code-review.md @@ -0,0 +1,37 @@ +--- +name: code-review +description: PR-style review checklist for this CLI (tests, oclif, security, mocks) +--- + +# Code review + +Use this checklist against the current diff or branch. + +## Correctness and UX + +- [ ] Command behavior matches flags and prompts; edge cases handled +- [ ] User-facing strings use `messages` / `$t` where appropriate +- [ ] Logging uses project logger / `this.log` patterns, not ad hoc `console` unless intentional + +## Tests + +- [ ] New or changed behavior covered (success and failure where relevant) +- [ ] No committed `describe.only` / `it.only` / `test.skip` (`--forbid-only`) +- [ ] External I/O mocked (sinon + nock); no real API calls +- [ ] `nock.cleanAll()` and sandbox `restore()` in `afterEach` where used + +## TypeScript and style + +- [ ] Avoid unnecessary `any`; align with strict TS +- [ ] Follow existing naming (kebab-case files, PascalCase classes) + +## Security + +- [ ] No secrets, tokens, or internal URLs committed +- [ ] Auth continues to flow through `configHandler` / stubs in tests + +## Optional deep dives + +- `@skills/testing` — mock patterns +- `@skills/apps-cli-framework` — command structure +- `@skills/contentstack-apps` — API and manifest changes diff --git a/.cursor/commands/execute-tests.md b/.cursor/commands/execute-tests.md new file mode 100644 index 0000000..689b2e9 --- /dev/null +++ b/.cursor/commands/execute-tests.md @@ -0,0 +1,14 @@ +--- +name: execute-tests +description: Run tests by scope using this package's npm scripts and Mocha paths +--- + +# Execute tests + +- **All tests** — `npm test` (Mocha: `test/**/*.test.ts`, `--forbid-only`) +- **Unit tests with coverage** — `npm run test:unit:report` +- **Unit JSON report** — `npm run test:unit:report:json` +- **Single file** — `npx mocha --forbid-only "test/unit/commands/app/delete.test.ts"` (adjust path) +- **Directory** — `npx mocha --forbid-only "test/unit/commands/app/**/*.test.ts"` + +After changes, run `npm run lint` if needed (`posttest` runs lint after `npm test`). diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md new file mode 100644 index 0000000..9754ecb --- /dev/null +++ b/.cursor/rules/README.md @@ -0,0 +1,31 @@ +# Cursor rules for contentstack-apps-cli + +Rules in this directory load based on file context. Skills hold the long-form guidance. + +## Files + +| Rule | When it applies | +|------|-----------------| +| `dev-workflow.md` | Always (lightweight workflow + TDD) | +| `typescript.mdc` | TypeScript / TSX sources | +| `testing.mdc` | Test files under `test/**/*.test.ts` | +| `oclif-commands.mdc` | CLI commands and base command classes | +| `contentstack-apps.mdc` | Utils, factories, strategies, GraphQL, config, types, messages | + +## Expected combinations (examples) + +- Editing `src/commands/app/*.ts` — typically `dev-workflow`, `typescript`, `oclif-commands` +- Editing `test/unit/.../*.test.ts` — `dev-workflow`, `typescript`, `testing` +- Editing `src/util/*.ts` or `src/graphql/*.ts` — `dev-workflow`, `typescript`, `contentstack-apps` + +## Skills + +Project skills live in `.cursor/skills//SKILL.md`. Reference them in chat, for example: + +- `@skills/testing` +- `@skills/apps-cli-framework` +- `@skills/contentstack-apps` + +## Optional commands + +Slash-style workflows (if enabled in your Cursor setup) live in `.cursor/commands/`. diff --git a/.cursor/rules/contentstack-apps.mdc b/.cursor/rules/contentstack-apps.mdc new file mode 100644 index 0000000..d39fab1 --- /dev/null +++ b/.cursor/rules/contentstack-apps.mdc @@ -0,0 +1,21 @@ +--- +description: "Contentstack Apps CLI domain patterns and API integration" +globs: + - "src/util/**/*.ts" + - "src/factories/**/*.ts" + - "src/strategies/**/*.ts" + - "src/graphql/**/*.ts" + - "src/config/**/*.ts" + - "src/types/**/*.ts" + - "src/messages/**/*.ts" +alwaysApply: false +--- + +# Contentstack Apps / Developer Hub standards + +- Prefer existing utilities (`api-request-handler`, config, `getDeveloperHubUrl`) over ad hoc clients +- Respect region and auth expectations; tests must stub auth — never rely on real tokens in automated tests +- GraphQL queries live under `src/graphql/`; keep shapes aligned with Developer Hub usage in commands +- Handle transient failures thoughtfully where the codebase already uses retries or clear errors + +Domain detail: `@skills/contentstack-apps`. diff --git a/.cursor/rules/dev-workflow.md b/.cursor/rules/dev-workflow.md new file mode 100644 index 0000000..12103d3 --- /dev/null +++ b/.cursor/rules/dev-workflow.md @@ -0,0 +1,28 @@ +--- +description: "Core development workflow and TDD patterns - always applied" +globs: ["**/*.ts", "**/*.js", "**/*.json"] +alwaysApply: true +--- + +# Development Workflow + +## Quick reference + +For detailed patterns, use project skills (invoke in chat when relevant): + +- `@skills/testing` — Testing, TDD, Mocha, sinon, nock, `@oclif/test` +- `@skills/apps-cli-framework` — Base commands, oclif, `@contentstack/cli-utilities` +- `@skills/contentstack-apps` — Developer Hub, manifest, GraphQL, API utilities + +## TDD workflow — mandatory + +1. **RED** — Write one failing test +2. **GREEN** — Write minimal code to pass +3. **REFACTOR** — Improve code quality + +## Critical rules + +- No implementation before tests for new behavior +- Target high coverage; run `npm run test:unit:report` to measure (aim for ~80% on touched areas) +- TypeScript strict mode is enabled in `tsconfig.json` +- Do not commit `test.skip`, `describe.skip`, or `.only` (Mocha runs with `--forbid-only`) diff --git a/.cursor/rules/oclif-commands.mdc b/.cursor/rules/oclif-commands.mdc new file mode 100644 index 0000000..03674a5 --- /dev/null +++ b/.cursor/rules/oclif-commands.mdc @@ -0,0 +1,15 @@ +--- +description: "OCLIF command development patterns and CLI best practices" +globs: ["src/commands/**/*.ts", "src/base-command.ts", "src/app-cli-base-command.ts"] +alwaysApply: false +--- + +# OCLIF command standards + +- Extend `BaseCommand` / `AppCLIBaseCommand` for shared init, flags, SDKs, and logging +- Validate early: parse flags and check required inputs before heavy work +- Keep commands thin: orchestration and UX in the command; logic in utilities, factories, or strategies +- User feedback: use `this.log` / logger patterns from the base command stack; user-facing failures via `this.error` where appropriate +- Reuse `messages` / `$t` for consistent copy + +Details: `@skills/apps-cli-framework`. diff --git a/.cursor/rules/testing.mdc b/.cursor/rules/testing.mdc new file mode 100644 index 0000000..bf42921 --- /dev/null +++ b/.cursor/rules/testing.mdc @@ -0,0 +1,15 @@ +--- +description: "Testing patterns and TDD workflow" +globs: ["test/**/*.test.ts", "**/*.spec.ts"] +alwaysApply: false +--- + +# Testing standards + +- Exercise success and failure paths +- Mock external I/O: use **sinon** for modules and collaborators; use **nock** for HTTP — no real API calls in unit tests +- Stub at boundaries (`cliux`, `configHandler`, `fs`, SDK entry points) as existing tests do +- Prefer shared helpers in `test/unit/helpers/` (e.g. authentication stubs) over duplicating setup +- Do not commit `.only` or skips; full suite uses `mocha --forbid-only` + +Deep patterns: `@skills/testing`. diff --git a/.cursor/rules/typescript.mdc b/.cursor/rules/typescript.mdc new file mode 100644 index 0000000..5bdfb85 --- /dev/null +++ b/.cursor/rules/typescript.mdc @@ -0,0 +1,17 @@ +--- +description: "TypeScript strict mode standards and naming conventions" +globs: ["**/*.ts", "**/*.tsx"] +alwaysApply: false +--- + +# TypeScript standards + +- Prefer explicit return types on exported and public functions +- Avoid `any`; use narrow types, generics, or `unknown` with guards +- Strict null checks are enabled project-wide (`tsconfig.json`) +- Files: kebab-case (e.g. `app-cli-base-command.ts`) +- Classes: PascalCase +- Functions and methods: camelCase +- Constants: `SCREAMING_SNAKE_CASE` when truly immutable module-level constants + +For CLI and command typing patterns, see `@skills/apps-cli-framework`. diff --git a/.cursor/skills/apps-cli-framework/SKILL.md b/.cursor/skills/apps-cli-framework/SKILL.md new file mode 100644 index 0000000..fe8c878 --- /dev/null +++ b/.cursor/skills/apps-cli-framework/SKILL.md @@ -0,0 +1,34 @@ +--- +name: apps-cli-framework +description: >- + Oclif command structure for Contentstack Apps CLI using BaseCommand, + AppCLIBaseCommand, @contentstack/cli-command, and @contentstack/cli-utilities. + Use when adding flags, init/SDK setup, logging, or organizing command code. +--- + +# Apps CLI framework + +## Class hierarchy + +- **`BaseCommand`** (`src/base-command.ts`) — Extends `@contentstack/cli-command` `Command`. Centralizes `init`, `parse`, shared **flags** (`org`, `yes`), logger, `managementSdk` / `marketplaceAppSdk`, region/auth validation, and `messages` / `$t`. +- **`AppCLIBaseCommand`** (`src/app-cli-base-command.ts`) — For app-manifest workflows: loads `manifestData` from the default app JSON path after `super.init()`. + +New app-facing commands should extend the appropriate base and call `await super.init()` first. + +## Command responsibilities + +- **CLI layer**: flag definitions, prompts via `cliux`, progress via `this.log` / logger, user errors via `this.error` / framework patterns. +- **Business logic**: prefer `src/util/`, `src/factories/`, `src/strategies/` over large `run()` methods. + +## Flags and parse + +- Add static `flags` on the command class; inherit `baseFlags` from `BaseCommand` where org/skip-confirmation apply. +- Parse runs in `BaseCommand.init`; use `this.flags` / `this.args` after `init`. + +## Copy and i18n + +- Use **`messages`** and **`$t`** from `src/messages` for user-visible strings consistent with the rest of the CLI. + +## Errors + +- `BaseCommand.catch` handles some framework errors; prefer consistent, actionable messages for users. diff --git a/.cursor/skills/contentstack-apps/SKILL.md b/.cursor/skills/contentstack-apps/SKILL.md new file mode 100644 index 0000000..e4ddb07 --- /dev/null +++ b/.cursor/skills/contentstack-apps/SKILL.md @@ -0,0 +1,36 @@ +--- +name: contentstack-apps +description: >- + Contentstack Developer Hub apps, manifests, GraphQL, and HTTP helpers for this + CLI. Use when changing API calls, manifest handling, regions, or shared app + types. +--- + +# Contentstack Apps domain + +## Configuration + +- **`src/config/index.ts`** — Default filenames, Developer Hub base URL defaults, and related constants consumed by commands and `BaseCommand`. + +## Manifest and app data + +- App manifest shape and typings live under **`src/types/`** (e.g. `AppManifest`). +- Commands that need on-disk manifest use **`AppCLIBaseCommand`** and `config.defaultAppFileName`. + +## HTTP and APIs + +- **`src/util/api-request-handler.ts`** — Shared request/error handling patterns; prefer extending these utilities over raw `fetch` scattered in commands. +- **`src/util/inquirer.ts`** — `getDeveloperHubUrl()` and related helpers; tests often nock against the derived host. + +## GraphQL + +- Queries and fragments belong in **`src/graphql/queries.ts`** (or sibling files if the folder grows). Keep query strings aligned with Developer Hub expectations used by install/deploy/update flows. + +## Auth and region in tests + +- Production code expects region and auth from `@contentstack/cli-utilities` `configHandler`. +- Unit tests must stub these (see `stubAuthentication` in `test/unit/helpers/auth-stub-helper.ts`); never require real credentials. + +## Rate limits and retries + +- If adding new network calls, follow existing patterns for errors and retries in utilities rather than blocking the CLI without feedback. diff --git a/.cursor/skills/testing/SKILL.md b/.cursor/skills/testing/SKILL.md new file mode 100644 index 0000000..a2edcbc --- /dev/null +++ b/.cursor/skills/testing/SKILL.md @@ -0,0 +1,54 @@ +--- +name: testing +description: >- + Runs TDD and unit tests for this repo using Mocha, Chai, sinon, nock, and + @oclif/test. Use when writing or fixing tests, mocking HTTP or cliux, or + when the user asks about test structure, coverage, or forbid-only behavior. +--- + +# Testing (contentstack-apps-cli) + +## Stack + +- **Runner**: Mocha (`npm test`, `npm run test:unit:report`) +- **Assertions**: Chai `expect` +- **Modules**: sinon sandboxes for stubs/spies +- **HTTP**: nock — match hosts from `configHandler.get("region")` and Developer Hub URLs (see `getDeveloperHubUrl` in source) +- **CLI**: `runCommand([...])` from `@oclif/test` + +## TDD loop + +1. Add or adjust a single failing test that describes desired behavior. +2. Implement the smallest change to pass. +3. Refactor; keep tests green. Do not commit `.only` or `skip` (CI uses `--forbid-only`). + +## Sinon patterns + +- Create a sandbox per test file or per test: + +```typescript +let sandbox: sinon.SinonSandbox; +beforeEach(() => { + sandbox = sinon.createSandbox(); +}); +afterEach(() => { + sandbox.restore(); +}); +``` + +- Stub UI and side effects: `cliux.inquire`, `cliux.confirm`, `cliux.loader`, `fs.*`, `shelljs`, etc., following neighboring tests in the same command. +- Reuse **`test/unit/helpers/auth-stub-helper.ts`**: call `stubAuthentication(sandbox)` instead of copying `configHandler.get` stubs. + +## Nock patterns + +- Register expected HTTP calls on `region.cma`, Developer Hub base URL, or other hosts used by the command under test. +- In `afterEach`, call `nock.cleanAll()` (and restore sinon) to avoid bleed between tests. + +## Success and failure + +- Every behavior change should have at least one happy path and one error or guard-rail assertion (stderr, exit code, or message substring) where applicable. + +## Do not + +- Hit real Contentstack or Developer Hub APIs from unit tests +- Rely on real auth tokens or `.env` secrets in tests diff --git a/.talismanrc b/.talismanrc index e69de29..c792bbb 100644 --- a/.talismanrc +++ b/.talismanrc @@ -0,0 +1,4 @@ +fileignoreconfig: +- filename: .cursor/commands/code-review.md + checksum: ef8ba74b7f9c43203e04200241ab1690a359bc3a3735d158945437840d055d0e +version: "1.0" \ No newline at end of file