From 73ec41a659e8c47d192222c933f881668bb1ec33 Mon Sep 17 00:00:00 2001 From: Erik Hughes Date: Mon, 3 Mar 2025 13:29:39 +0100 Subject: [PATCH 1/3] feat: package CLI --- packages/cli/README.md | 238 +++++++++++++++++++++++++++++- packages/cli/commands/features.ts | 10 +- packages/cli/commands/init.ts | 8 +- packages/cli/commands/new.ts | 2 +- packages/cli/package.json | 12 +- packages/cli/schema.json | 2 +- packages/cli/stores/config.ts | 6 +- packages/cli/utils/constants.ts | 8 +- packages/cli/utils/options.ts | 2 +- 9 files changed, 265 insertions(+), 23 deletions(-) diff --git a/packages/cli/README.md b/packages/cli/README.md index ecfe9dff..0ebb26e5 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -1 +1,237 @@ -# cli +# Bucket CLI + +Command-line interface for interacting with Bucket services. The CLI allows you to manage apps, features, authentication, and generate TypeScript types for your Bucket features. With this tool, you can streamline your feature flagging workflow directly from your terminal. + +## Installation + +You can install the Bucket CLI either locally to your project or globally on your system. + +### Local Installation (Recommended) + +Local installation is recommended for project-specific usage and ensures consistent CLI versions across your team. + +```bash +# npm +npm install --save-dev @bucketco/cli + +# yarn +yarn add --dev @bucketco/cli + +# pnpm +pnpm add --save-dev @bucketco/cli +``` + +When installed locally, use the CLI with npx: + +```bash +npx bucket +``` + +or as a `package.json` script + +```json +{ + "scripts": { + "bucket": "bucket" + } +} +``` + +### Global Installation + +Global installation makes the CLI available system-wide. + +```bash +# npm +npm install -g @bucketco/cli + +# yarn +yarn global add @bucketco/cli + +# pnpm +pnpm add -g @bucketco/cli +``` + +When installed globally, use the CLI directly: + +```bash +bucket +``` + +## Quick Start + +Get started quickly with the following commands: + +```bash +# Initialize CLI (if not setup), create a feature, and generate types all at once +bucket new "My Feature" + +# Or perform operations individually: + +# Initialize Bucket in your project +bucket init + +# Create a new feature +bucket features create "My Feature" + +# Generate TypeScript types for your features +bucket features types +``` + +## Configuration + +The CLI creates a `bucket.config.json` file in your project directory when you run `bucket init`. This file contains all the necessary settings for your Bucket integration. + +### Configuration File Structure + +Here's a comprehensive list of configuration options available in the `bucket.config.json` file: + +```json +{ + "$schema": "https://unpkg.com/@bucketco/cli@latest/schema.json", + "baseUrl": "https://app.bucket.co", + "apiUrl": "https://app.bucket.co/api", + "appId": "ap123456789", + "typesOutput": "gen/features.ts", + "keyFormat": "camelCase" +} +``` + +| Option | Description | Default | +| ------------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| `$schema` | Autocompletion for the config. `latest` can be replaced with a specific version. | "https://unpkg.com/@bucketco/cli@latest/schema.json" | +| `baseUrl` | Base URL for Bucket services. | "https://app.bucket.co" | +| `apiUrl` | API URL for Bucket services (overrides baseUrl for API calls). | "https://app.bucket.co/api" | +| `appId` | Your Bucket application ID. | Required | +| `typesOutput` | Path where TypeScript types will be generated. | "gen/features.ts" | +| `keyFormat` | Format for feature keys (options: custom, pascalCase, camelCase, snakeCaseUpper, snakeCaseLower, kebabCaseUpper, kebabCaseLower). | "custom" | + +You can override these settings using command-line options for individual commands. + +## Commands + +### `bucket init` + +Initialize a new Bucket configuration in your project. This creates a `bucket.config.json` file with your settings and prompts for any required information not provided via options. + +```bash +bucket init [--force] +``` + +Options: + +- `--force`: Overwrite existing configuration file if one exists +- `--app-id `: Set the application ID +- `--key-format `: Set the key format for features + +### `bucket new [featureName]` + +All-in-one command to get started quickly. This command combines `init`, feature creation, and type generation in a single step. Use this for the fastest way to get up and running with Bucket. + +```bash +bucket new "My Feature" [--key my-feature] [--app-id ap123456789] [--key-format custom] [--out gen/features.ts] +``` + +Options: + +- `--key`: Specific key for the feature +- `--app-id`: App ID to use +- `--key-format`: Format for feature keys (custom, snake, camel, etc.) +- `--out`: Path to generate TypeScript types + +If you prefer more control over each step, you can use the individual commands (`init`, `features create`, `features types`) instead. + +### `bucket login` + +Log in to your Bucket account. This will authenticate your CLI for subsequent operations and store credentials securely. + +```bash +bucket login +``` + +### `bucket logout` + +Log out from your Bucket account, removing stored credentials. + +```bash +bucket logout +``` + +### `bucket features` + +Manage your Bucket features with the following subcommands. + +#### `bucket features create [featureName]` + +Create a new feature in your Bucket app. The command guides you through the feature creation process with interactive prompts if options are not provided. + +```bash +bucket features create "My Feature" [--key my-feature] [--app-id ap123456789] [--key-format custom] +``` + +Options: + +- `--key`: Specific key for the feature +- `--app-id`: App ID to use +- `--key-format`: Format for feature keys + +#### `bucket features list` + +List all features for the current app. This helps you visualize what features are available and their current configurations. + +```bash +bucket features list [--app-id ap123456789] +``` + +Options: + +- `--app-id`: App ID to use + +#### `bucket features types` + +Generate TypeScript types for your features. This ensures type safety when using Bucket features in your TypeScript/JavaScript applications. + +```bash +bucket features types [--app-id ap123456789] [--out gen/features.ts] +``` + +Options: + +- `--app-id`: App ID to use +- `--out`: Path to generate TypeScript types + +### `bucket apps` + +Commands for managing Bucket apps. + +## Global Options + +These options can be used with any command: + +- `--debug`: Enable debug mode for verbose output +- `--base-url `: Set the base URL for Bucket API +- `--api-url `: Set the API URL directly (overrides base URL) +- `--help`: Display help information for a command + +## Development + +```bash +# Build the CLI +yarn build + +# Run the CLI locally +yarn bucket [command] + +# Lint and format code +yarn lint +yarn format +``` + +## Requirements + +- Node.js >=18.0.0 + +## License + +> MIT License +> Copyright (c) 2025 Bucket ApS diff --git a/packages/cli/commands/features.ts b/packages/cli/commands/features.ts index c36f54e1..825dd34a 100644 --- a/packages/cli/commands/features.ts +++ b/packages/cli/commands/features.ts @@ -80,7 +80,7 @@ export const listFeaturesAction = async () => { }; export const generateTypesAction = async () => { - const { baseUrl, appId, typesPath } = configStore.getConfig(); + const { baseUrl, appId, typesOutput } = configStore.getConfig(); let spinner: Ora | undefined; let featureKeys: string[] = []; @@ -103,9 +103,9 @@ export const generateTypesAction = async () => { spinner = ora("Generating feature types...").start(); const types = genDTS(featureKeys); const projectPath = configStore.getProjectPath(); - const outPath = isAbsolute(typesPath) - ? typesPath - : join(projectPath, typesPath); + const outPath = isAbsolute(typesOutput) + ? typesOutput + : join(projectPath, typesOutput); await mkdir(dirname(outPath), { recursive: true }); await writeFile(outPath, types); spinner.succeed( @@ -147,7 +147,7 @@ export function registerFeatureCommands(cli: Command) { // Update the config with the cli override values featuresCommand.hook("preAction", (_, command) => { const { appId, keyFormat, out } = command.opts(); - configStore.setConfig({ appId, keyFormat, typesPath: out }); + configStore.setConfig({ appId, keyFormat, typesOutput: out }); }); cli.addCommand(featuresCommand); diff --git a/packages/cli/commands/init.ts b/packages/cli/commands/init.ts index 7bba51e8..9d064973 100644 --- a/packages/cli/commands/init.ts +++ b/packages/cli/commands/init.ts @@ -6,7 +6,7 @@ import ora, { Ora } from "ora"; import { App, listApps } from "../services/bootstrap.js"; import { configStore } from "../stores/config.js"; -import { chalkBrand, DEFAULT_TYPES_PATH } from "../utils/constants.js"; +import { chalkBrand, DEFAULT_TYPES_OUTPUT } from "../utils/constants.js"; import { handleError } from "../utils/errors.js"; import { initOverrideOption } from "../utils/options.js"; @@ -69,16 +69,16 @@ export const initAction = async (args: InitArgs = {}) => { apps.find((app) => app.id === appId)?.featureKeyFormat ?? "custom"; // Get types output path - const typesPath = await input({ + const typesOutput = await input({ message: "Where should we generate the types?", - default: DEFAULT_TYPES_PATH, + default: DEFAULT_TYPES_OUTPUT, }); // Update config configStore.setConfig({ appId, keyFormat, - typesPath, + typesOutput, }); // Create config file diff --git a/packages/cli/commands/new.ts b/packages/cli/commands/new.ts index d3f0a13a..22abc7b9 100644 --- a/packages/cli/commands/new.ts +++ b/packages/cli/commands/new.ts @@ -46,6 +46,6 @@ export function registerNewCommand(cli: Command) { // Update the config with the cli override values cli.hook("preAction", (command) => { const { appId, keyFormat, out } = command.opts(); - configStore.setConfig({ appId, keyFormat, typesPath: out }); + configStore.setConfig({ appId, keyFormat, typesOutput: out }); }); } diff --git a/packages/cli/package.json b/packages/cli/package.json index c4e2b7b9..96bd376e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,10 +1,17 @@ { "name": "@bucketco/cli", - "version": "0.0.1", + "version": "0.1.0", "packageManager": "yarn@4.1.1", "description": "CLI for Bucket service", "main": "./dist/index.js", "type": "module", + "license": "MIT", + "author": "Bucket Co.", + "homepage": "https://docs.bucket.co/", + "repository": { + "type": "git", + "url": "https://github.com/bucketco/bucket-javascript-sdk.git" + }, "engines": { "node": ">=18.0.0" }, @@ -15,6 +22,9 @@ "dist", "schema.json" ], + "exports": { + ".": "./dist/index.js" + }, "scripts": { "build": "tsc", "bucket": "yarn build && node dist/index.js", diff --git a/packages/cli/schema.json b/packages/cli/schema.json index e8b54954..4d22ab5d 100644 --- a/packages/cli/schema.json +++ b/packages/cli/schema.json @@ -12,7 +12,7 @@ "appId": { "type": "string" }, - "typesPath": { + "typesOutput": { "type": "string" }, "keyFormat": { diff --git a/packages/cli/stores/config.ts b/packages/cli/stores/config.ts index 76cfa375..cd4a978b 100644 --- a/packages/cli/stores/config.ts +++ b/packages/cli/stores/config.ts @@ -8,7 +8,7 @@ import { CONFIG_FILE_NAME, DEFAULT_API_URL, DEFAULT_BASE_URL, - DEFAULT_TYPES_PATH, + DEFAULT_TYPES_OUTPUT, SCHEMA_URL, } from "../utils/constants.js"; import { ConfigValidationError, handleError } from "../utils/errors.js"; @@ -30,7 +30,7 @@ type Config = { baseUrl: string; apiUrl: string; appId: string | undefined; - typesPath: string; + typesOutput: string; keyFormat: KeyFormat; }; @@ -39,7 +39,7 @@ const defaultConfig: Config = { baseUrl: DEFAULT_BASE_URL, apiUrl: DEFAULT_API_URL, appId: undefined, - typesPath: DEFAULT_TYPES_PATH, + typesOutput: DEFAULT_TYPES_OUTPUT, keyFormat: "custom", }; diff --git a/packages/cli/utils/constants.ts b/packages/cli/utils/constants.ts index 7fe752f4..8d00b7bb 100644 --- a/packages/cli/utils/constants.ts +++ b/packages/cli/utils/constants.ts @@ -1,20 +1,16 @@ -import { createRequire } from "module"; import { join } from "path"; import chalk from "chalk"; -// https://github.com/nodejs/node/issues/51347#issuecomment-2111337854 -const packageJson = createRequire(import.meta.url)("../../package.json"); - export const CONFIG_FILE_NAME = "bucket.config.json"; export const AUTH_FILE = join( process.env.HOME ?? process.env.USERPROFILE ?? "", ".bucket-auth", ); -export const SCHEMA_URL = `https://unpkg.com/@bucketco/cli@${packageJson.version}/schema.json`; +export const SCHEMA_URL = `https://unpkg.com/@bucketco/cli@latest/schema.json`; export const DEFAULT_BASE_URL = "https://app.bucket.co"; export const DEFAULT_API_URL = `${DEFAULT_BASE_URL}/api`; -export const DEFAULT_TYPES_PATH = join("gen", "features.ts"); +export const DEFAULT_TYPES_OUTPUT = join("gen", "features.ts"); export const chalkBrand = chalk.hex("#847CFB"); diff --git a/packages/cli/utils/options.ts b/packages/cli/utils/options.ts index e07025b4..749e6553 100644 --- a/packages/cli/utils/options.ts +++ b/packages/cli/utils/options.ts @@ -28,7 +28,7 @@ export const initOverrideOption = new Option( export const typesOutOption = new Option( "-o, --out [path]", - `Output path for generated feature types. Falls back to typesPath value in ${CONFIG_FILE_NAME}.`, + `Output path for generated feature types. Falls back to typesOutput value in ${CONFIG_FILE_NAME}.`, ); export const keyFormatOption = new Option( From bd3a761db2b06de60417e9db09fedf2ee4c4bc4f Mon Sep 17 00:00:00 2001 From: Erik Hughes Date: Mon, 3 Mar 2025 14:20:12 +0100 Subject: [PATCH 2/3] fix: small readme tweaks --- packages/cli/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/cli/README.md b/packages/cli/README.md index 0ebb26e5..3cecc1f2 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -24,6 +24,7 @@ pnpm add --save-dev @bucketco/cli When installed locally, use the CLI with npx: ```bash +# npm npx bucket ``` @@ -37,6 +38,14 @@ or as a `package.json` script } ``` +```bash +# npm +npm bucket + +# yarn +yarn bucket +``` + ### Global Installation Global installation makes the CLI available system-wide. From 6dd79a7c0381399b54c8a335dd8a72d8a3496835 Mon Sep 17 00:00:00 2001 From: Erik Hughes Date: Mon, 3 Mar 2025 15:24:29 +0100 Subject: [PATCH 3/3] fix: PR comments --- packages/cli/README.md | 61 ++++++++++----------------------------- packages/cli/package.json | 2 +- 2 files changed, 16 insertions(+), 47 deletions(-) diff --git a/packages/cli/README.md b/packages/cli/README.md index 3cecc1f2..e3d136ed 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -2,13 +2,16 @@ Command-line interface for interacting with Bucket services. The CLI allows you to manage apps, features, authentication, and generate TypeScript types for your Bucket features. With this tool, you can streamline your feature flagging workflow directly from your terminal. -## Installation +## Quick Start -You can install the Bucket CLI either locally to your project or globally on your system. +Get started quickly by running the CLI directly: initializing the CLI, creating a feature, and generate the types all at once. -### Local Installation (Recommended) +```bash +# Initialize CLI (if not setup), create a feature, and generate types all at once +npx @bucketco/cli new +``` -Local installation is recommended for project-specific usage and ensures consistent CLI versions across your team. +or install it locally ```bash # npm @@ -16,68 +19,34 @@ npm install --save-dev @bucketco/cli # yarn yarn add --dev @bucketco/cli - -# pnpm -pnpm add --save-dev @bucketco/cli ``` -When installed locally, use the CLI with npx: - -```bash -# npm -npx bucket -``` - -or as a `package.json` script - -```json -{ - "scripts": { - "bucket": "bucket" - } -} -``` +then ```bash # npm -npm bucket +npx bucket new # yarn -yarn bucket +yarn bucket new ``` -### Global Installation +### Global installation -Global installation makes the CLI available system-wide. +You can also install the CLI globally adding the it to your PATH allowing you to use the shorthand `bucket` ```bash -# npm npm install -g @bucketco/cli -# yarn -yarn global add @bucketco/cli - -# pnpm -pnpm add -g @bucketco/cli -``` - -When installed globally, use the CLI directly: - -```bash bucket ``` -## Quick Start +### Individual commands -Get started quickly with the following commands: +Instead of running `new` you can call each step individually. ```bash -# Initialize CLI (if not setup), create a feature, and generate types all at once -bucket new "My Feature" - -# Or perform operations individually: - -# Initialize Bucket in your project +# Initialize Bucket in your project (if not already setup) bucket init # Create a new feature diff --git a/packages/cli/package.json b/packages/cli/package.json index 96bd376e..e90470d8 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -6,7 +6,7 @@ "main": "./dist/index.js", "type": "module", "license": "MIT", - "author": "Bucket Co.", + "author": "Bucket.", "homepage": "https://docs.bucket.co/", "repository": { "type": "git",