@qlover/fe-release
Version:
A tool for releasing front-end projects, supporting multiple release modes and configurations, simplifying the release process and improving efficiency.
1,904 lines (1,885 loc) • 73.7 kB
TypeScript
import { LifecycleExecutor, ExecutorContextInterface } from '@qlover/fe-corekit';
import { ScriptPlugin, ScriptContext, ScriptPluginProps, ScriptSharedInterface, ScriptContextInterface, FeReleaseConfig, ShellInterface } from '@qlover/scripts-context';
export { ScriptPlugin } from '@qlover/scripts-context';
import { CommitField } from 'gitlog';
import { LoggerInterface } from '@qlover/logger';
import { OptionValues } from 'commander';
/**
* @module PluginTuple
* @description Type-safe plugin tuple creation and handling
*
* This module provides utilities for creating and handling tuples that
* represent plugin configurations. It ensures type safety when working
* with plugin constructors and their parameters.
*
* Core Features:
* - Type-safe plugin class handling
* - Constructor parameter inference
* - Plugin tuple creation
*
* @example Basic usage
* ```typescript
* class MyPlugin extends ScriptPlugin {
* constructor(context: ScriptContext, config: { option: string }) {
* super(context);
* }
* }
*
* const pluginTuple = tuple(MyPlugin, { option: 'value' });
* // [MyPlugin, { option: 'value' }]
* ```
*
* @example Plugin name string
* ```typescript
* const pluginTuple = tuple('MyPlugin', { option: 'value' });
* // ['MyPlugin', { option: 'value' }]
* ```
*/
/**
* Plugin class constructor type
*
* Represents a constructor for a class that extends ScriptPlugin.
* Supports generic constructor arguments.
*
* @template T - Array type for constructor arguments
*
* @example
* ```typescript
* class MyPlugin extends ScriptPlugin {
* constructor(context: ScriptContext, config: { option: string }) {
* super(context);
* }
* }
*
* const PluginCtor: PluginClass = MyPlugin;
* ```
*/
type PluginClass<T extends unknown[] = any[]> = new (...args: T) => ScriptPlugin<ScriptContext<any>, ScriptPluginProps>;
/**
* Plugin constructor parameters type
*
* Extracts the constructor parameter types for a plugin class,
* excluding the first parameter (context). Uses TypeScript's
* conditional types and inference to extract parameter types.
*
* @template T - Plugin class type
*
* @example
* ```typescript
* class MyPlugin extends ScriptPlugin {
* constructor(
* context: ScriptContext,
* config: { option: string },
* extra: number
* ) {
* super(context);
* }
* }
*
* // Type: [{ option: string }, number]
* type Params = PluginConstructorParams<typeof MyPlugin>;
* ```
*/
type PluginConstructorParams<T extends PluginClass> = T extends new (first: any, ...args: infer P) => unknown ? P : never;
/**
* Plugin configuration tuple type
*
* Represents a tuple containing a plugin class (or name) and its
* constructor arguments. Used for plugin registration and loading.
*
* @template T - Plugin class type
*
* @example
* ```typescript
* class MyPlugin extends ScriptPlugin {
* constructor(context: ScriptContext, config: { option: string }) {
* super(context);
* }
* }
*
* // Type: [typeof MyPlugin, { option: string }]
* type Tuple = PluginTuple<typeof MyPlugin>;
*
* // Type: [string, { option: string }]
* type StringTuple = PluginTuple<'MyPlugin'>;
* ```
*/
type PluginTuple<T extends PluginClass> = [
T | string,
...PluginConstructorParams<T>
];
/**
* Creates a type-safe plugin configuration tuple
*
* Helper function for creating tuples that represent plugin
* configurations with proper type inference for constructor
* arguments.
*
* @template T - Plugin class type
* @param plugin - Plugin class or name
* @param args - Plugin constructor arguments
* @returns Plugin configuration tuple
*
* @example Class-based plugin
* ```typescript
* class MyPlugin extends ScriptPlugin {
* constructor(
* context: ScriptContext,
* config: { option: string },
* extra: number
* ) {
* super(context);
* }
* }
*
* const config = tuple(MyPlugin, { option: 'value' }, 42);
* // [MyPlugin, { option: 'value' }, 42]
* ```
*
* @example String-based plugin
* ```typescript
* const config = tuple('MyPlugin', { option: 'value' });
* // ['MyPlugin', { option: 'value' }]
* ```
*/
declare function tuple<T extends PluginClass>(plugin: T | string, ...args: PluginConstructorParams<T>): PluginTuple<T>;
/**
* @module ReleaseTask
* @description Task orchestration for release process
*
* This module provides the core task orchestration for the release process,
* managing plugin loading, execution order, and context handling. It serves
* as the main entry point for executing release operations.
*
* Core Features:
* - Plugin management and execution
* - Release context initialization
* - Task execution control
* - Environment-based control
*
* Default Plugins:
* - Workspaces: Monorepo workspace management
* - Changelog: Version and changelog management
* - GithubPR: Pull request creation and management
*
* @example Basic usage
* ```typescript
* // Initialize and execute
* const task = new ReleaseTask({
* rootPath: '/path/to/project',
* sourceBranch: 'main'
* });
*
* await task.exec();
* ```
*
* @example Custom plugins
* ```typescript
* import { tuple } from '@qlover/fe-release';
*
* // Add custom plugin
* class CustomPlugin extends ScriptPlugin {
* async onExec() {
* // Custom release logic
* }
* }
*
* const task = new ReleaseTask({}, new LifecycleExecutor<ReleaseContext>(), [
* tuple(CustomPlugin, { option: 'value' })
* ]);
*
* await task.exec();
* ```
*
* @example Environment control
* ```typescript
* // Skip release
* process.env.FE_RELEASE = 'false';
*
* const task = new ReleaseTask();
* try {
* await task.exec();
* } catch (e) {
* // Handle "Skip Release" error
* }
* ```
*/
/**
* Core task class for managing release operations
*
* Handles plugin orchestration, task execution, and context management
* for the release process. Supports both built-in and custom plugins.
*
* Features:
* - Plugin lifecycle management
* - Task execution control
* - Context initialization and access
* - Environment-based control
*
* @example Basic initialization
* ```typescript
* const task = new ReleaseTask({
* rootPath: '/path/to/project'
* });
* ```
*
* @example Custom executor
* ```typescript
* const executor = new LifecycleExecutor<ReleaseContext>({
* onError: (err) => console.error('Release failed:', err)
* });
*
* const task = new ReleaseTask({}, executor);
* ```
*
* @example Custom plugins
* ```typescript
* const task = new ReleaseTask(
* {}, // options
* new LifecycleExecutor<ReleaseContext>(),
* [
* tuple(CustomPlugin, { config: 'value' }),
* ...innerTuples // include default plugins
* ]
* );
* ```
*/
declare class ReleaseTask {
private executor;
private defaultTuples;
/**
* Release context instance
* @protected
*/
protected context: ReleaseContext;
/**
* Creates a new ReleaseTask instance
*
* Initializes the release context and sets up plugin configuration.
* Supports custom executors and plugin configurations.
*
* @param options - Release context configuration
* @param executor - Custom async executor (optional)
* @param defaultTuples - Plugin configuration tuples (optional)
*
* @example
* ```typescript
* // Basic initialization
* const task = new ReleaseTask({
* rootPath: '/path/to/project',
* sourceBranch: 'main'
* });
*
* // With custom executor and plugins
* const task = new ReleaseTask(
* { rootPath: '/path/to/project' },
* new LifecycleExecutor<ReleaseContext>(),
* [tuple(CustomPlugin, { option: 'value' })]
* );
* ```
*/
constructor(options?: Partial<ReleaseContextOptions>, executor?: LifecycleExecutor<ReleaseContext>, defaultTuples?: PluginTuple<PluginClass>[]);
/**
* Gets the current release context
*
* @returns Release context instance
*
* @example
* ```typescript
* const task = new ReleaseTask();
* const context = task.getContext();
*
* console.log(context.releaseEnv);
* console.log(context.sourceBranch);
* ```
*/
getContext(): ReleaseContext;
/**
* Loads and configures plugins for the release task
*
* Combines default and external plugins, initializes them with
* the current context, and configures special cases like the
* Workspaces plugin.
*
* Plugin Loading Process:
* 1. Merge default and external plugins
* 2. Initialize plugins with context
* 3. Configure special plugins
* 4. Add plugins to executor
*
* @param externalTuples - Additional plugin configurations
* @returns Array of initialized plugins
*
* @example Basic usage
* ```typescript
* const task = new ReleaseTask();
* const plugins = await task.usePlugins();
* ```
*
* @example Custom plugins
* ```typescript
* const task = new ReleaseTask();
* const plugins = await task.usePlugins([
* tuple(CustomPlugin, { option: 'value' })
* ]);
* ```
*/
usePlugins(externalTuples?: PluginTuple<PluginClass>[]): Promise<ScriptPlugin<ScriptContext<any>, ScriptPluginProps>[]>;
/**
* Executes the release task
*
* Internal method that runs the task through the executor.
* Preserves the context through the execution chain.
*
* @returns Execution result
* @internal
*/
run(): Promise<unknown>;
/**
* Main entry point for executing the release task
*
* Checks environment conditions, loads plugins, and executes
* the release process. Supports additional plugin configuration
* at execution time.
*
* Environment Control:
* - Checks FE_RELEASE environment variable
* - Skips release if FE_RELEASE=false
*
* @param externalTuples - Additional plugin configurations
* @returns Execution result
* @throws Error if release is skipped via environment variable
*
* @example Basic execution
* ```typescript
* const task = new ReleaseTask();
* await task.exec();
* ```
*
* @example With additional plugins
* ```typescript
* const task = new ReleaseTask();
* await task.exec([
* tuple(CustomPlugin, { option: 'value' })
* ]);
* ```
*
* @example Environment control
* ```typescript
* // Skip release
* process.env.FE_RELEASE = 'false';
*
* const task = new ReleaseTask();
* try {
* await task.exec();
* } catch (e) {
* if (e.message === 'Skip Release') {
* console.log('Release skipped via environment variable');
* }
* }
* ```
*/
exec(externalTuples?: PluginTuple<PluginClass>[]): Promise<unknown>;
}
type PackageJson$1 = Record<string, unknown>;
interface WorkspacesProps extends ScriptPluginProps {
/**
* Whether to skip workspaces
*
* @default `false`
*/
skip?: boolean;
/**
* Whether to skip checking the package.json file
*
* @default `false`
*/
skipCheckPackage?: boolean;
/**
* The workspace to publish
*/
workspace?: WorkspaceValue;
/**
* The workspaces to publish
* @private
*/
workspaces?: WorkspaceValue[];
/**
* The change labels
*
* from `changePackagesLabel`
*/
changeLabels?: string[];
/**
* The changed paths
* @private
*/
changedPaths?: string[];
/**
* The packages
* @private
*/
packages?: string[];
/**
* All project packages mapping
* @private
*/
projectWorkspaces?: WorkspaceValue[];
}
interface WorkspaceValue {
name: string;
version: string;
/**
* The relative path of the workspace
*/
path: string;
/**
* The absolute path of the workspace
*/
root: string;
/**
* The package.json of the workspace
*/
packageJson: PackageJson$1;
/**
* The tag name of the workspace
* @private
*/
tagName?: string;
/**
* The last tag name of the workspace
* @private
*/
lastTag?: string;
/**
* The changelog of the workspace
* @private
*/
changelog?: string;
}
type ReleaseParamsConfig = {
/**
* Max number of workspaces to include in the release name
*
* @default 3
*/
maxWorkspace?: number;
/**
* Multi-workspace separator
*
* @default '_'
*/
multiWorkspaceSeparator?: string;
/**
* Workspace version separator
*
* @default '@'
*/
workspaceVersionSeparator?: string;
/**
* The branch name for batch release
*
* @default `batch-${releaseName}-${length}-packages-${timestamp}`
*/
batchBranchName?: string;
/**
* The tag name for batch release
*
* @default `batch-${length}-packages-${timestamp}`
*/
batchTagName?: string;
/**
* The PR title for batch release
*
* default from feConfig.release.PRTitle
*
* @default `Release ${env} ${pkgName} ${tagName}`
*/
PRTitle?: string;
/**
* The PR body for batch release
*
* default from feConfig.release.PRBody
*/
PRBody?: string;
};
/**
* Base configuration for Git-related plugins
*
* Extends ScriptPluginProps with GitHub-specific configuration
* options for API access and timeouts.
*
* @example
* ```typescript
* const config: GitBaseProps = {
* tokenRef: 'CUSTOM_TOKEN',
* timeout: 5000
* };
* ```
*/
interface GitBaseProps extends ScriptPluginProps {
/**
* Environment variable name for GitHub API token
*
* The value of this environment variable will be used
* for GitHub API authentication.
*
* @default 'GITHUB_TOKEN'
*
* @example
* ```typescript
* process.env.CUSTOM_TOKEN = 'ghp_123...';
* const config = { tokenRef: 'CUSTOM_TOKEN' };
* ```
*/
tokenRef?: string;
/**
* Timeout for GitHub API requests in milliseconds
*
* Controls how long to wait for GitHub API responses
* before timing out.
*
* @example
* ```typescript
* const config = { timeout: 5000 }; // 5 seconds
* ```
*/
timeout?: number;
}
/**
* @module GithubPR
* @description GitHub Pull Request and Release Management
*
* This module provides functionality for managing GitHub pull requests
* and releases as part of the release process. It handles PR creation,
* release publishing, and changelog management.
*
* Core Features:
* - Pull request creation and management
* - Release publishing
* - Changelog integration
* - Tag management
* - Label management
* - Auto-merge support
*
* @example Basic usage
* ```typescript
* const plugin = new GithubPR(context, {
* releasePR: true,
* autoGenerate: true
* });
*
* await plugin.exec();
* ```
*
* @example Release publishing
* ```typescript
* const plugin = new GithubPR(context, {
* releasePR: false,
* makeLatest: true,
* preRelease: false
* });
*
* await plugin.exec();
* ```
*/
interface GithubPRProps extends ReleaseParamsConfig, GitBaseProps {
/**
* Whether to dry run the creation of the pull request
*
* - create pr
* - changeset publish
*
* @default `false`
*/
dryRunCreatePR?: boolean;
/**
* Whether to skip the release
*
* @default `false`
*/
skip?: boolean;
/**
* Whether to publish a PR
*
* @default `false`
*/
releasePR?: boolean;
/**
* The commit message of the release
*
* support WorkspaceValue
*
* @default 'chore(tag): {{name}} v${version}'
*/
commitMessage?: string;
/**
* The commit args of the release
*
* @default []
*/
commitArgs?: string[];
/**
* The release name of the release
*
* @default 'Release ${name} v${version}'
*/
releaseName?: string;
/**
* Whether to create a draft release
*
* @default false
*/
draft?: boolean;
/**
* Whether to create a pre-release
*
* @default false
*/
preRelease?: boolean;
/**
* Whether to auto-generate the release notes
*
* @default false
*/
autoGenerate?: boolean;
/**
* Whether to make the latest release
*
* @default true
*/
makeLatest?: boolean | 'true' | 'false' | 'legacy';
/**
* The release notes of the release
*
* @default undefined
*/
releaseNotes?: string;
/**
* The discussion category name of the release
*
* @default undefined
*/
discussionCategoryName?: string;
/**
* Whether to push the changed labels to the release PR
*
* @default false
*/
pushChangeLabels?: boolean;
}
/**
* @module FeReleaseTypes
* @description Type definitions for the fe-release framework
*
* This module provides TypeScript type definitions for the fe-release framework,
* including interfaces for release context, configuration, execution context,
* and various utility types.
*
* Type Categories:
* - Execution Context: Types for task execution and return values
* - Configuration: Types for release and workspace configuration
* - Plugin Types: Interfaces for GitHub PR and workspace plugins
* - Utility Types: Helper types like DeepPartial and PackageJson
*
* Design Considerations:
* - Type safety for plugin configuration
* - Extensible context interfaces
* - Backward compatibility support
* - Clear deprecation markers
* - Generic type constraints
*/
/**
* Extended execution context for release tasks
*
* Adds release-specific return value handling to the base executor context.
* Used to track and manage release task execution results.
*
* @example
* ```typescript
* const context: ExecutorReleaseContext = {
* returnValue: { githubToken: 'token123' },
* // ... other executor context properties
* };
* ```
*/
interface ExecutorReleaseContext extends ExecutorContextInterface<ReleaseContext> {
returnValue: ReleaseReturnValue;
}
/**
* Return value type for release tasks
*
* Defines the structure of data returned from release task execution.
* Includes GitHub token and allows for additional custom properties.
*
* @example
* ```typescript
* const returnValue: ReleaseReturnValue = {
* githubToken: 'github_pat_123',
* customData: { version: '1.0.0' }
* };
* ```
*/
type ReleaseReturnValue = {
githubToken?: string;
[key: string]: unknown;
};
/**
* Utility type for creating deep partial types
*
* Makes all properties in T optional recursively, useful for
* partial configuration objects and type-safe updates.
*
* @example
* ```typescript
* interface Config {
* deep: {
* nested: {
* value: string;
* }
* }
* }
*
* const partial: DeepPartial<Config> = {
* deep: {
* nested: {
* // All properties optional
* }
* }
* };
* ```
*/
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
/**
* Configuration interface for release process
*
* Extends shared script configuration with release-specific
* settings for GitHub PR and workspace management.
*
* @example
* ```typescript
* const config: ReleaseConfig = {
* githubPR: {
* owner: 'org',
* repo: 'repo',
* base: 'main'
* },
* workspaces: {
* packages: ['packages/*']
* }
* };
* ```
*/
interface ReleaseConfig extends ScriptSharedInterface {
githubPR?: GithubPRProps;
workspaces?: WorkspacesProps;
}
/**
* Options interface for release context
*
* Extends script context interface with release-specific configuration.
* Uses generic type parameter for custom configuration extensions.
*
* @example
* ```typescript
* interface CustomConfig extends ReleaseConfig {
* custom: {
* feature: boolean;
* }
* }
*
* const options: ReleaseContextOptions<CustomConfig> = {
* custom: {
* feature: true
* }
* };
* ```
*/
interface ReleaseContextOptions$1<T extends ReleaseConfig = ReleaseConfig> extends ScriptContextInterface<T> {
}
/**
* Configuration for a single execution step
*
* Defines a labeled, optionally enabled task with async execution.
* Used for creating structured, trackable release steps.
*
* @example
* ```typescript
* const step: StepOption<string> = {
* label: 'Update version',
* enabled: true,
* task: async () => {
* // Version update logic
* return 'Version updated to 1.0.0';
* }
* };
* ```
*/
type StepOption<T> = {
label: string;
enabled?: boolean;
task: () => Promise<T>;
};
/**
* Type alias for package.json structure
*
* Represents the structure of a package.json file with flexible
* key-value pairs. Used for package metadata handling.
*
* @example
* ```typescript
* const pkg: PackageJson = {
* name: 'my-package',
* version: '1.0.0',
* dependencies: {
* // ...
* }
* };
* ```
*/
type PackageJson = Record<string, unknown>;
/**
* Context interface for template processing
*
* Combines release context options with workspace values and
* adds template-specific properties. Includes deprecated fields
* with migration guidance.
*
* @example
* ```typescript
* const context: TemplateContext = {
* publishPath: './dist',
* env: 'production', // Deprecated
* branch: 'main', // Deprecated
* // ... other properties from ReleaseContextOptions
* };
* ```
*/
interface TemplateContext extends ReleaseContextOptions$1, WorkspaceValue {
publishPath: string;
/**
* @deprecated use `releaseEnv` from `shared`
*/
env: string;
/**
* @deprecated use `sourceBranch` from `shared`
*/
branch: string;
}
/**
* @module ReleaseContext
* @description Core context management for release operations
*
* This module provides the central context management for release operations,
* handling configuration, environment variables, workspace management, and
* package information. It extends the base ScriptContext with release-specific
* functionality.
*
* Core Features:
* - Environment variable management
* - Workspace configuration
* - Package.json access
* - Template context generation
* - Changeset CLI integration
*
* @example Basic usage
* ```typescript
* const context = new ReleaseContext('my-package', {
* rootPath: '/path/to/project',
* sourceBranch: 'main',
* releaseEnv: 'production'
* });
*
* // Access package info
* const version = context.getPkg('version');
*
* // Generate template context
* const templateData = context.getTemplateContext();
* ```
*
* @example Workspace management
* ```typescript
* // Set workspace configuration
* context.setWorkspaces([{
* name: 'package-a',
* version: '1.0.0',
* path: 'packages/a'
* }]);
*
* // Access workspace info
* const currentWorkspace = context.workspace;
* ```
*
* @example Changeset integration
* ```typescript
* // Run changeset commands
* await context.runChangesetsCli('version', ['--snapshot', 'alpha']);
* ```
*/
interface ReleaseContextOptions extends ScriptContextInterface<ReleaseContextConfig> {
}
interface ReleaseContextConfig extends FeReleaseConfig, ScriptSharedInterface {
/**
* The github PR of the project
* @private
*/
githubPR?: GithubPRProps;
/**
* The workspaces of the project
* @private
*/
workspaces?: WorkspacesProps;
/**
* The environment of the project
*
* default:
* - first, get from `FE_RELEASE_ENV`
* - second, get from `NODE_ENV`
* - `development`
*/
releaseEnv?: string;
/**
* Plugins
*/
plugins?: PluginTuple<PluginClass<unknown[]>>[];
/**
* The name of the repository
*/
repoName?: string;
/**
* The name of the author
*/
authorName?: string;
/**
* The current branch of the project
*/
currentBranch?: string;
}
/**
* Core context class for release operations
*
* Manages release-specific configuration, environment variables,
* workspace settings, and provides utilities for release operations.
*
* Features:
* - Automatic environment detection
* - Source branch management
* - Workspace configuration
* - Package.json access
* - Template context generation
* - Changeset CLI integration
*
* @example Basic initialization
* ```typescript
* const context = new ReleaseContext('my-package', {
* rootPath: '/path/to/project',
* sourceBranch: 'main'
* });
* ```
*
* @example Environment configuration
* ```typescript
* // With environment variables
* process.env.FE_RELEASE_ENV = 'staging';
* process.env.FE_RELEASE_BRANCH = 'develop';
*
* const context = new ReleaseContext('my-package', {});
* // context.releaseEnv === 'staging'
* // context.sourceBranch === 'develop'
* ```
*/
declare class ReleaseContext extends ScriptContext<ReleaseContextConfig> {
/**
* Creates a new ReleaseContext instance
*
* Initializes the context with provided options and sets up
* default values for required configuration:
* - rootPath: Defaults to current working directory
* - sourceBranch: Uses environment variables or default
* - releaseEnv: Uses environment variables or 'development'
*
* Environment Variable Priority:
* - sourceBranch: FE_RELEASE_BRANCH > FE_RELEASE_SOURCE_BRANCH > DEFAULT_SOURCE_BRANCH
* - releaseEnv: FE_RELEASE_ENV > NODE_ENV > 'development'
*
* @param name - Unique identifier for this release context
* @param options - Configuration options
*
* @example
* ```typescript
* const context = new ReleaseContext('web-app', {
* rootPath: '/projects/web-app',
* sourceBranch: 'main',
* releaseEnv: 'production'
* });
* ```
*/
constructor(name: string, options: Partial<ReleaseContextOptions>);
/**
* Gets the root path of the project
*
* @returns Absolute path to project root
*
* @example
* ```typescript
* const root = context.rootPath;
* // '/path/to/project'
* ```
*/
get rootPath(): string;
/**
* Gets the source branch for the release
*
* @returns Branch name to use as source
*
* @example
* ```typescript
* const branch = context.sourceBranch;
* // 'main' or custom branch name
* ```
*/
get sourceBranch(): string;
/**
* Gets the release environment
*
* @returns Environment name (e.g., 'development', 'production')
*
* @example
* ```typescript
* const env = context.releaseEnv;
* // 'development' or custom environment
* ```
*/
get releaseEnv(): string;
/**
* Gets all configured workspaces
*
* @returns Array of workspace configurations or undefined
*
* @example
* ```typescript
* const allWorkspaces = context.workspaces;
* // [{ name: 'pkg-a', version: '1.0.0', ... }]
* ```
*/
get workspaces(): WorkspaceValue[] | undefined;
/**
* Gets the current active workspace
*
* @returns Current workspace configuration or undefined
*
* @example
* ```typescript
* const current = context.workspace;
* // { name: 'pkg-a', version: '1.0.0', ... }
* ```
*/
get workspace(): WorkspaceValue | undefined;
/**
* Sets the workspace configurations
*
* Updates the workspace list while preserving other workspace settings
*
* @param workspaces - Array of workspace configurations
*
* @example
* ```typescript
* context.setWorkspaces([{
* name: 'pkg-a',
* version: '1.0.0',
* path: 'packages/a'
* }]);
* ```
*/
setWorkspaces(workspaces: WorkspaceValue[]): void;
/**
* Gets package.json data for the current workspace
*
* Provides type-safe access to package.json fields with optional
* path and default value support.
*
* @param key - Optional dot-notation path to specific field
* @param defaultValue - Default value if field not found
* @returns Package data of type T
* @throws Error if package.json not found
*
* @example Basic usage
* ```typescript
* // Get entire package.json
* const pkg = context.getPkg();
*
* // Get specific field
* const version = context.getPkg<string>('version');
*
* // Get nested field with default
* const script = context.getPkg<string>(
* 'scripts.build',
* 'echo "No build script"'
* );
* ```
*/
getPkg<T>(key?: string, defaultValue?: T): T;
/**
* Generates template context for string interpolation
*
* Combines context options, workspace data, and specific paths
* for use in template processing. Includes deprecated fields
* for backward compatibility.
*
* @returns Combined template context
*
* @example
* ```typescript
* const context = releaseContext.getTemplateContext();
* // {
* // publishPath: 'packages/my-pkg',
* // env: 'production', // deprecated
* // branch: 'main', // deprecated
* // releaseEnv: 'production', // use this instead
* // sourceBranch: 'main', // use this instead
* // ...other options
* // }
* ```
*/
getTemplateContext(): TemplateContext;
/**
* Executes changeset CLI commands
*
* Automatically detects and uses appropriate package manager
* (pnpm or npx) to run changeset commands.
*
* @param name - Changeset command name
* @param args - Optional command arguments
* @returns Command output
*
* @example Version bump
* ```typescript
* // Bump version with snapshot
* await context.runChangesetsCli('version', ['--snapshot', 'alpha']);
*
* // Create new changeset
* await context.runChangesetsCli('add');
*
* // Status check
* await context.runChangesetsCli('status');
* ```
*/
runChangesetsCli(name: string, args?: string[]): Promise<string>;
}
/**
* @module ReleaseLabel
* @description Release label management and file change detection
*
* This module provides utilities for managing release labels and detecting
* which packages have changed based on file paths. It supports custom
* comparison logic and label formatting.
*
* Core Features:
* - File change detection
* - Package path matching
* - Label generation
* - Custom comparison logic
*
* @example Basic usage
* ```typescript
* const label = new ReleaseLabel({
* changePackagesLabel: 'changed:${name}',
* packagesDirectories: ['packages/a', 'packages/b']
* });
*
* // Find changed packages
* const changed = label.pick(['packages/a/src/index.ts']);
* // ['packages/a']
*
* // Generate labels
* const labels = label.toChangeLabels(changed);
* // ['changed:packages/a']
* ```
*
* @example Custom comparison
* ```typescript
* const label = new ReleaseLabel({
* changePackagesLabel: 'changed:${name}',
* packagesDirectories: ['packages/a'],
* compare: (file, pkg) => file.includes(pkg)
* });
*
* const changed = label.pick(['src/packages/a/index.ts']);
* // ['packages/a']
* ```
*/
/**
* Function type for custom file path comparison
*
* Used to determine if a changed file belongs to a package.
* Default implementation checks if the file path starts with
* the package path.
*
* @param changedFilePath - Path of the changed file
* @param packagePath - Path of the package to check against
* @returns True if the file belongs to the package
*/
type ReleaseLabelCompare = (changedFilePath: string, packagePath: string) => boolean;
interface ReleaseLabelOptions {
/**
* The change packages label
*/
changePackagesLabel: string;
/**
* The packages directories
*/
packagesDirectories: string[];
compare?: ReleaseLabelCompare;
}
/**
* Core class for managing release labels and change detection
*
* Provides utilities for detecting changed packages and generating
* appropriate labels. Supports custom comparison logic and label
* formatting.
*
* Features:
* - File change detection
* - Package path matching
* - Label generation
* - Custom comparison logic
*
* @example Basic usage
* ```typescript
* const label = new ReleaseLabel({
* changePackagesLabel: 'changed:${name}',
* packagesDirectories: ['packages/a', 'packages/b']
* });
*
* // Find changed packages
* const changed = label.pick(['packages/a/src/index.ts']);
*
* // Generate labels
* const labels = label.toChangeLabels(changed);
* ```
*
* @example Custom comparison
* ```typescript
* const label = new ReleaseLabel({
* changePackagesLabel: 'changed:${name}',
* packagesDirectories: ['packages/a'],
* compare: (file, pkg) => file.includes(pkg)
* });
*
* const changed = label.pick(['src/packages/a/index.ts']);
* ```
*/
declare class ReleaseLabel {
private readonly options;
/**
* Creates a new ReleaseLabel instance
*
* @param options - Configuration options for label management
*
* @example
* ```typescript
* const label = new ReleaseLabel({
* // Label template with ${name} placeholder
* changePackagesLabel: 'changed:${name}',
*
* // Package directories to monitor
* packagesDirectories: ['packages/a', 'packages/b'],
*
* // Optional custom comparison logic
* compare: (file, pkg) => file.includes(pkg)
* });
* ```
*/
constructor(options: ReleaseLabelOptions);
/**
* Compares a changed file path against a package path
*
* Uses custom comparison function if provided, otherwise
* checks if the file path starts with the package path.
*
* @param changedFilePath - Path of the changed file
* @param packagePath - Path of the package to check against
* @returns True if the file belongs to the package
*
* @example
* ```typescript
* // Default comparison
* label.compare('packages/a/src/index.ts', 'packages/a');
* // true
*
* // Custom comparison
* const label = new ReleaseLabel({
* ...options,
* compare: (file, pkg) => file.includes(pkg)
* });
* label.compare('src/packages/a/index.ts', 'packages/a');
* // true
* ```
*/
compare(changedFilePath: string, packagePath: string): boolean;
/**
* Generates a change label for a single package
*
* Replaces ${name} placeholder in the label template with
* the package path.
*
* @param packagePath - Path of the package
* @param label - Optional custom label template
* @returns Formatted change label
*
* @example
* ```typescript
* // Default label template
* label.toChangeLabel('packages/a');
* // 'changed:packages/a'
*
* // Custom label template
* label.toChangeLabel('packages/a', 'modified:${name}');
* // 'modified:packages/a'
* ```
*/
toChangeLabel(packagePath: string, label?: string): string;
/**
* Generates change labels for multiple packages
*
* Maps each package path to a formatted change label.
*
* @param packages - Array of package paths
* @param label - Optional custom label template
* @returns Array of formatted change labels
*
* @example
* ```typescript
* // Default label template
* label.toChangeLabels(['packages/a', 'packages/b']);
* // ['changed:packages/a', 'changed:packages/b']
*
* // Custom label template
* label.toChangeLabels(
* ['packages/a', 'packages/b'],
* 'modified:${name}'
* );
* // ['modified:packages/a', 'modified:packages/b']
* ```
*/
toChangeLabels(packages: string[], label?: string): string[];
/**
* Identifies packages affected by changed files
*
* Checks each changed file against package paths to determine
* which packages have been modified.
*
* @param changedFiles - Array or Set of changed file paths
* @param packages - Optional array of package paths to check
* @returns Array of affected package paths
*
* @example
* ```typescript
* // Check against default packages
* label.pick(['packages/a/src/index.ts']);
* // ['packages/a']
*
* // Check specific packages
* label.pick(
* ['packages/a/index.ts', 'packages/b/test.ts'],
* ['packages/a', 'packages/c']
* );
* // ['packages/a']
*
* // Using Set of files
* label.pick(new Set(['packages/a/index.ts']));
* // ['packages/a']
* ```
*/
pick(changedFiles: Array<string> | Set<string>, packages?: string[]): string[];
}
/**
* @module ChangeLog
* @description Core interfaces for changelog generation
*
* This module provides the core interfaces and types for generating
* changelogs from Git commit history. It includes types for commit
* parsing, formatting, and changelog generation.
*
* Core Components:
* - Commit data structures
* - Changelog formatting
* - Git log options
* - Changelog generation
*
* @example Basic usage
* ```typescript
* class MyChangeLog implements ChangeLogInterface {
* async getCommits(options?: GitChangelogOptions): Promise<CommitValue[]> {
* // Implementation
* }
* }
*
* class MyFormatter implements ChangelogFormatter {
* format(commits: CommitValue[]): string[] {
* // Implementation
* }
* }
* ```
*/
/**
* Base commit type mapping Git commit fields
*
* Maps all available Git commit fields to optional string values.
* Uses the CommitField type from gitlog package to ensure type safety.
*
* Available fields include:
* - hash: Full commit hash
* - abbrevHash: Abbreviated commit hash
* - subject: Commit message subject
* - authorName: Author's name
* - authorDate: Author date
* - And many more from gitlog.CommitField
*
* @example
* ```typescript
* const commit: BaseCommit = {
* hash: 'abc123def456',
* abbrevHash: 'abc123',
* subject: 'feat: new feature',
* authorName: 'John Doe',
* authorDate: '2023-01-01'
* };
* ```
*/
type BaseCommit = {
[key in CommitField]: string | undefined;
};
/**
* Configuration options for changelog generation
*
* Provides comprehensive options for controlling how changelogs
* are generated from Git history, including commit range selection,
* formatting, and filtering.
*
* @example Basic usage
* ```typescript
* const options: GitChangelogOptions = {
* from: 'v1.0.0',
* to: 'v2.0.0',
* directory: 'packages/my-pkg',
* noMerges: true
* };
* ```
*
* @example Custom formatting
* ```typescript
* const options: GitChangelogOptions = {
* types: [
* { type: 'feat', section: '### Features' },
* { type: 'fix', section: '### Bug Fixes' }
* ],
* formatTemplate: '* ${commitlint.message} ${prLink}',
* commitBody: true
* };
* ```
*/
interface GitChangelogOptions {
/**
* Starting tag or commit reference
*
* Defines the start point for collecting commits.
* Can be a tag name, commit hash, or branch name.
*
* @example
* ```typescript
* from: 'v1.0.0' // Start from v1.0.0 tag
* from: 'abc123' // Start from specific commit
* ```
*/
from?: string;
/**
* Ending tag or commit reference
*
* Defines the end point for collecting commits.
* Can be a tag name, commit hash, or branch name.
*
* @example
* ```typescript
* to: 'v2.0.0' // End at v2.0.0 tag
* to: 'main' // End at main branch
* ```
*/
to?: string;
/**
* Directory to collect commits from
*
* Limits commit collection to changes in specified directory.
* Useful for monorepo package-specific changelogs.
*
* @example
* ```typescript
* directory: 'packages/my-pkg' // Only changes in this directory
* ```
*/
directory?: string;
/**
* Git commit fields to include
*
* Specifies which Git commit fields to retrieve.
* @default ["abbrevHash", "hash", "subject", "authorName", "authorDate"]
*
* @example
* ```typescript
* fields: ['hash', 'subject', 'authorName']
* ```
*/
fields?: CommitField[];
/**
* Whether to exclude merge commits
*
* When true, merge commits are filtered out from the changelog.
* @default true
*
* @example
* ```typescript
* noMerges: true // Exclude merge commits
* noMerges: false // Include merge commits
* ```
*/
noMerges?: boolean;
/**
* Commit type configurations
*
* Defines how different commit types should be handled and
* formatted in the changelog.
*
* @example
* ```typescript
* types: [
* { type: 'feat', section: '### Features' },
* { type: 'fix', section: '### Bug Fixes' },
* { type: 'chore', hidden: true } // Skip chore commits
* ]
* ```
*/
types?: {
type: string;
section?: string;
hidden?: boolean;
}[];
/**
* Template for formatting commit entries
*
* Supports variables from CommitValue properties and adds:
* - ${scopeHeader}: Formatted scope
* - ${commitLink}: Commit hash link
* - ${prLink}: PR number link
*
* @default '\n- ${scopeHeader} ${commitlint.message} ${commitLink} ${prLink}'
*
* @example
* ```typescript
* formatTemplate: '* ${commitlint.message} (${commitLink})'
* ```
*/
formatTemplate?: string;
/**
* Whether to include commit message body
*
* When true, includes the full commit message body
* in the changelog entry.
*
* @since 2.3.0
* @default false
*
* @example
* ```typescript
* commitBody: true // Include full commit message
* ```
*/
commitBody?: boolean;
}
/**
* Parsed conventional commit data
*
* Represents a commit message parsed according to the
* conventional commit specification.
*
* Format: type(scope): message
*
* @example
* ```typescript
* const commit: Commitlint = {
* type: 'feat',
* scope: 'api',
* message: 'add new endpoint',
* body: 'Adds support for new API endpoint\n\nBREAKING CHANGE: API format changed'
* };
* ```
*/
interface Commitlint {
/** Commit type (e.g., 'feat', 'fix') */
type?: string;
/** Commit scope (e.g., 'api', 'core') */
scope?: string;
/** Main commit message */
message: string;
/**
* Commit message body with title removed
* @since 2.3.0
*/
body?: string;
}
/**
* Complete commit information
*
* Combines Git commit data, parsed conventional commit info,
* and PR metadata into a single value object.
*
* @example
* ```typescript
* const commit: CommitValue = {
* base: {
* hash: 'abc123',
* subject: 'feat(api): new endpoint (#123)'
* },
* commitlint: {
* type: 'feat',
* scope: 'api',
* message: 'new endpoint'
* },
* commits: [],
* prNumber: '123'
* };
* ```
*/
interface CommitValue {
/** Raw Git commit information */
base: BaseCommit;
/** Parsed conventional commit data */
commitlint: Commitlint;
/** Sub-commits (for merge commits) */
commits: CommitValue[];
/** Associated pull request number */
prNumber?: string;
}
/**
* Interface for changelog formatting
*
* Defines the contract for classes that format commit data
* into changelog entries.
*
* @example
* ```typescript
* class MarkdownFormatter implements ChangelogFormatter {
* format(commits: CommitValue[]): string[] {
* return commits.map(commit =>
* `- ${commit.commitlint.message} (#${commit.prNumber})`
* );
* }
* }
* ```
*/
interface ChangelogFormatter {
/**
* Formats commits into changelog entries
*
* @param commits - Array of commits to format
* @param options - Optional formatting options
* @returns Array of formatted changelog lines
*/
format<Opt extends GitChangelogOptions>(commits: unknown[], options?: Opt): string[];
}
/**
* Interface for changelog generation
*
* Defines the contract for classes that generate changelogs
* from Git history.
*
* @example
* ```typescript
* class GitChangelog implements ChangeLogInterface {
* async getCommits(options?: GitChangelogOptions): Promise<CommitValue[]> {
* // Get commits from Git and parse them
* const commits = await gitlog(options);
* return commits.map(commit => ({
* base: commit,
* commitlint: parseCommit(commit.subject),
* commits: []
* }));
* }
* }
* ```
*/
interface ChangeLogInterface {
/**
* Retrieves and parses Git commits
*
* @param options - Optional Git log options
* @returns Promise resolving to array of parsed commits
*/
getCommits(options?: GitChangelogOptions): Promise<CommitValue[]>;
}
/**
* @module GitChangelog
* @description Git-based changelog generation and commit parsing
*
* This module provides functionality for generating changelogs from Git
* history, parsing commit messages according to conventional commit format,
* and managing commit metadata.
*
* Core Features:
* - Git log retrieval
* - Conventional commit parsing
* - Changelog generation
* - Tag resolution
* - PR number extraction
*
* @example Basic usage
* ```typescript
* const changelog = new GitChangelog({
* shell,
* logger,
* directory: 'packages/my-pkg'
* });
*
* // Get commits between tags
* const commits = await changelog.getCommits({
* from: 'v1.0.0',
* to: 'v2.0.0'
* });
* ```
*
* @example Commit parsing
* ```typescript
* const changelog = new GitChangelog({ shell, logger });
*
* // Parse conventional commit
* const commit = changelog.parseCommitlint(
* 'feat(api): add new endpoint',
* 'Detailed description\n\nBREAKING CHANGE: API format changed'
* );
* // {
* // type: 'feat',
* // scope: 'api',
* // message: 'add new endpoint',
* // body: ' Detailed description\n\n BREAKING CHANGE: API format changed'
* // }
* ```
*/
/**
* Complete list of available Git commit fields
*
* These fields can be used when retrieving commit information
* to specify which data should be included in the output.
*
* @example
* ```typescript
* const commits = await changelog.getGitLog({
* fields: CHANGELOG_ALL_FIELDS
* });
* ```
*/
declare const CHANGELOG_ALL_FIELDS: CommitField[];
interface GitChangelogProps extends GitChangelogOptions {
shell: ShellInterface;
logger: LoggerInterface;
}
/**
* Core class for Git-based changelog generation
*
* Provides functionality for retrieving and parsing Git commit history,
* generating changelogs, and managing commit metadata. Implements the
* ChangeLogInterface for standardized changelog generation.
*
* Features:
* - Git log retrieval with flexible options
* - Conventional commit parsing
* - Tag resolution and validation
* - PR number extraction
* - Commit body formatting
*
* @example Basic usage
* ```typescript
* const changelog = new GitChangelog({
* shell,
* logger,
* directory: 'packages/my-pkg'
* });
*
* // Get commits with parsed metadata
* const commits = await changelog.getCommits({
* from: 'v1.0.0',
* to: 'v2.0.0',
* noMerges: true
* });
* ```
*
* @example Custom commit parsing
* ```typescript
* const changelog = new GitChangelog({ shell, logger });
*
* // Create commit value from hash and message
* const commit = changelog.toCommitValue(
* 'abc1234',
* 'feat(api): new endpoint (#123)'
* );
* // {
* // base: { hash: 'abc1234', ... },
* // commitlint: { type: 'feat', scope: 'api', ... },
* // prNumber: '123'
* // }
* ```
*/
declare class GitChangelog implements ChangeLogInterface {
protected options: GitChangelogProps;
/**
* Creates a new GitChangelog instance
*
* @param options - Configuration options including shell and logger
*
* @example
* ```typescript
* const changelog = new GitChangelog({
* shell: new Shell(),
* logger: new Logger(),
* directory: 'packages/my-pkg',
* noMerges: true
* });
* ```
*/
constructor(options: GitChangelogProps);
/**
* Retrieves Git commit history with specified options
*
* Fetches commit information between specified tags or commits,
* with support for filtering and field selection.
*
* @param options - Configuration options for Git log retrieval
* @returns Array of commit objects with requested fields
*
* @example Basic usage
* ```typescript
* const commits = await changelog.getGitLog({
* from: 'v1.0.0',
* to: 'v2.0.0',
* directory: 'packages/my-pkg',
* noMerges: true
* });
* ```
*
* @example Custom fields
* ```typescript
* const commits = await changelog.getGitLog({
* fields: ['hash', 'subject', 'authorName'],
* directory: 'src'
* });
* ```
*/
getGitLog(options?: GitChangelogOptions): Promise<BaseCommit[]>;
/**
* Retrieves and parses Git commits with metadata
*
* Gets commit history and enhances it with parsed conventional
* commit information and PR metadata.
*
* @override
* @param options - Configuration options for Git log retrieval