CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-release-it

Generic CLI tool to automate versioning and package publishing-related tasks.

Pending
Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

Release It!'s plugin system provides an extensible architecture for implementing release functionality. Plugins participate in a well-defined lifecycle and can communicate through shared context.

Capabilities

Base Plugin Class

Foundation class for all Release It! plugins with lifecycle hooks and utilities.

/**
 * Base plugin class providing lifecycle hooks and utilities
 * All Release It! plugins extend this class
 */
class Plugin {
  /**
   * Create plugin instance
   * @param options - Plugin configuration options
   */
  constructor(options: PluginOptions);
  
  /**
   * Check if plugin should be enabled
   * @param options - Plugin configuration options
   * @returns Boolean indicating if plugin is enabled
   */
  static isEnabled(options: any): boolean | Promise<boolean>;
  
  /**
   * Disable plugin and return null
   * @returns null to indicate plugin is disabled
   */
  static disablePlugin(): null;
  
  /** Initialize plugin - called once during startup */
  init(): void | Promise<void>;
  
  /** Get package/project name */
  getName(): string | Promise<string>;
  
  /** Get current/latest version */
  getLatestVersion(): string | Promise<string>;
  
  /** Get changelog content for the release */
  getChangelog(latestVersion?: string): string | Promise<string>;
  
  /** 
   * Get version increment suggestion
   * @param incrementBase - Base increment information
   * @returns Suggested increment (major/minor/patch/etc)
   */
  getIncrement(incrementBase: IncrementBase): string | Promise<string>;
  
  /**
   * Get incremented version for CI mode
   * @param incrementBase - Base increment information  
   * @returns New version string
   */
  getIncrementedVersionCI(incrementBase: IncrementBase): string | Promise<string>;
  
  /**
   * Get incremented version with user interaction
   * @param incrementBase - Base increment information
   * @returns New version string
   */
  getIncrementedVersion(incrementBase: IncrementBase): string | Promise<string>;
  
  /** Hook called before version bump */
  beforeBump(): void | Promise<void>;
  
  /**
   * Hook called to perform version bump
   * @param version - New version to bump to
   * @returns True if bump was performed, false to skip
   */
  bump(version: string): boolean | Promise<boolean>;
  
  /** Hook called before release operations */
  beforeRelease(): void | Promise<void>;
  
  /** 
   * Hook called to perform release operations
   * @returns True if release was performed, false to skip
   */
  release(): boolean | Promise<boolean>;
  
  /** Hook called after release operations */
  afterRelease(): void | Promise<void>;
  
  /**
   * Get plugin context with optional path
   * @param path - Optional dot-notation path to nested value
   * @returns Context value or entire context
   */
  getContext(path?: string): any;
  
  /**
   * Set plugin context by merging with existing
   * @param context - Context to merge
   */
  setContext(context: any): void;
  
  /**
   * Execute shell command with context interpolation
   * @param command - Command to execute
   * @param options - Execution options
   * @returns Promise resolving to command output
   */
  exec(command: string, options?: ExecOptions): Promise<string>;
  
  /**
   * Register interactive prompts for this plugin
   * @param prompts - Prompt definitions
   */
  registerPrompts(prompts: any): void;
  
  /**
   * Show interactive prompt
   * @param options - Prompt options
   * @returns Promise resolving to user input
   */
  showPrompt(options: PromptOptions): Promise<any>;
  
  /**
   * Execute step with spinner or prompt based on mode
   * @param options - Step execution options
   * @returns Promise resolving to step result
   */
  step(options: StepOptions): Promise<any>;
  
  /**
   * Get initial plugin options from configuration
   * @param options - Full configuration options
   * @param namespace - Plugin namespace
   * @returns Plugin-specific options
   */
  getInitialOptions(options: any, namespace: string): any;
}

interface PluginOptions {
  /** Plugin namespace for configuration */
  namespace: string;
  /** Plugin-specific options */
  options?: any;
  /** Dependency injection container */
  container?: DependencyContainer;
}

interface IncrementBase {
  /** Current latest version */
  latestVersion: string;
  /** Requested increment type */
  increment: string;
  /** Whether this is a pre-release */
  isPreRelease: boolean;
  /** Pre-release identifier */
  preReleaseId?: string;
  /** Pre-release base version */
  preReleaseBase?: string;
}

interface ExecOptions {
  /** Additional execution options */
  options?: any;
  /** Context for template interpolation */
  context?: any;
}

interface StepOptions {
  /** Whether step is enabled */
  enabled?: boolean;
  /** Task function to execute */
  task?: () => Promise<any>;
  /** Step label for display */
  label?: string;
  /** Prompt type for interactive mode */
  prompt?: string;
  /** Context for template interpolation */
  context?: any;
  /** Whether this is an external command */
  external?: boolean;
}

interface PromptOptions {
  /** Prompt type */
  type?: string;
  /** Prompt name/key */
  name?: string;
  /** Prompt message */
  message?: string;
  /** Available choices for select prompts */  
  choices?: any[];
  /** Default value */
  default?: any;
  /** Plugin namespace */
  namespace?: string;
  /** Value transformer function */
  transformer?: (value: any) => any;
}

interface DependencyContainer {
  /** Configuration instance */
  config?: any;
  /** Logger instance */
  log?: any;
  /** Shell executor instance */
  shell?: any;
  /** Spinner instance */
  spinner?: any;
  /** Prompt handler instance */
  prompt?: any;
}

Plugin Factory

Factory function for loading and instantiating plugins.

/**
 * Get plugin instances for the current configuration
 * @param config - Configuration instance
 * @param container - Dependency injection container
 * @returns Tuple of [internal plugins, external plugins]
 */
function getPlugins(
  config: Config, 
  container: DependencyContainer
): Promise<[Plugin[], Plugin[]]>;

Built-in Plugins

Release It! includes several built-in plugins:

Version Plugin

Manages version updates in files (package.json, etc.)

Git Plugin

Handles Git operations (commit, tag, push)

npm Plugin

Manages npm publishing and registry operations

GitHub Plugin

Creates GitHub releases and uploads assets

GitLab Plugin

Creates GitLab releases

Custom Plugin Development

/**
 * Example custom plugin implementation
 * Custom plugins extend the base Plugin class
 */
class CustomPlugin extends Plugin {
  constructor(options) {
    super(options);
    this.namespace = 'custom';
  }
  
  static isEnabled(options) {
    return options !== false;
  }
  
  async init() {
    // Plugin initialization logic
    this.log.info('Custom plugin initialized');
  }
  
  async beforeRelease() {
    // Custom pre-release logic
    await this.exec('custom-pre-release-command');
  }
  
  async release() {
    // Custom release logic
    const result = await this.step({
      enabled: this.options.deploy,
      task: () => this.deploy(),
      label: 'Custom deployment',
      prompt: 'deploy'
    });
    
    return result;
  }
  
  async deploy() {
    // Custom deployment logic
    const version = this.config.getContext('version');
    await this.exec(`deploy --version ${version}`);
  }
}

export default CustomPlugin;

Usage Examples:

// Using built-in plugins through configuration
const result = await runTasks({
  git: {
    commit: true,
    tag: true,
    push: true
  },
  npm: {
    publish: true
  },
  github: {
    release: true,
    assets: ['dist/*.zip']
  }
});

// Loading custom plugins
const result = await runTasks({
  plugins: {
    './custom-plugin.js': {
      deploy: true,
      environment: 'production'
    }
  }
});

Plugin Configuration

Each plugin accepts configuration through the main configuration object:

{
  "git": {
    "commit": true,
    "commitMessage": "Release ${version}",
    "tag": true,
    "push": true
  },
  "npm": {
    "publish": true,
    "tag": "latest"
  },
  "github": {
    "release": true,
    "releaseName": "Release ${version}",
    "assets": ["dist/*.zip", "docs/*.pdf"]
  },
  "plugins": {
    "@release-it/conventional-changelog": {
      "preset": "angular"
    },
    "./plugins/custom-notifier.js": {
      "webhook": "https://hooks.slack.com/..."
    }
  }
}

Plugin Lifecycle

The plugin lifecycle ensures coordinated execution:

  1. Plugin Discovery: Load internal and external plugins
  2. Initialization: Call init() on all plugins
  3. Version Resolution: Get current version and determine increment
  4. Pre-Bump Phase: Call beforeBump() hooks
  5. Bump Phase: Call bump(version) hooks
  6. Pre-Release Phase: Call beforeRelease() hooks
  7. Release Phase: Call release() hooks
  8. Post-Release Phase: Call afterRelease() hooks

Context Sharing

Plugins communicate through shared context:

// Plugin A sets context
this.setContext({ buildId: '12345' });

// Plugin B reads context  
const buildId = this.getContext('buildId');

// Global context access
const version = this.config.getContext('version');

Install with Tessl CLI

npx tessl i tessl/npm-release-it

docs

cli-interface.md

configuration.md

core-orchestration.md

git-operations.md

github-integration.md

gitlab-integration.md

index.md

npm-publishing.md

plugin-system.md

tile.json