@qlover/fe-release
Version:
A tool for releasing front-end projects, supporting multiple release modes and configurations, simplifying the release process and improving efficiency.
562 lines (542 loc) • 15.2 kB
TypeScript
import { FeScriptContextOptions, Shell, FeReleaseConfig, FeScriptContext } from '@qlover/scripts-context';
import { AsyncExecutor, ExecutorContext, ExecutorPlugin } from '@qlover/fe-corekit';
import { LoggerInterface } from '@qlover/logger';
import { Env } from '@qlover/env-loader';
import { CommitField } from 'gitlog';
import { OptionValues } from 'commander';
declare class ReleaseTask {
private executor;
private defaultTuples;
protected context: ReleaseContext;
constructor(options?: ReleaseContextOptions, executor?: AsyncExecutor, defaultTuples?: PluginTuple<PluginClass>[]);
getContext(): ReleaseContext;
usePlugins(externalTuples?: PluginTuple<PluginClass>[]): Promise<Plugin[]>;
run(): Promise<unknown>;
exec(externalTuples?: PluginTuple<PluginClass>[]): Promise<unknown>;
}
interface WorkspacesProps {
/**
* 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;
/**
* 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;
};
interface GitBaseProps {
/**
* The token for the GitHub API
*
* @default `GITHUB_TOKEN`
*/
tokenRef?: string;
/**
* The timeout for the GitHub API
*/
timeout?: number;
}
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;
}
interface ExecutorReleaseContext extends ExecutorContext<ReleaseContext> {
returnValue: ReleaseReturnValue;
}
type ReleaseReturnValue = {
githubToken?: string;
[key: string]: unknown;
};
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
interface ReleaseConfig {
githubPR?: GithubPRProps;
workspaces?: WorkspacesProps;
}
interface ReleaseContextOptions<T extends ReleaseConfig = ReleaseConfig> extends Omit<FeScriptContextOptions<T>, 'constructor'> {
shared?: SharedReleaseOptions;
}
type StepOption<T> = {
label: string;
enabled?: boolean;
task: () => Promise<T>;
};
type PackageJson = Record<string, unknown>;
interface TemplateContext extends SharedReleaseOptions, WorkspaceValue {
publishPath: string;
/**
* @deprecated use `releaseEnv` from `shared`
*/
env: string;
/**
* @deprecated use `sourceBranch` from `shared`
*/
branch: string;
}
declare abstract class Plugin<Props = unknown> implements ExecutorPlugin<ReleaseContext> {
protected context: ReleaseContext;
readonly pluginName: string;
protected props: Props;
readonly onlyOne = true;
constructor(context: ReleaseContext, pluginName: string, props?: Props);
getInitialProps(props?: Props): Props;
get logger(): LoggerInterface;
get shell(): Shell;
get options(): Props;
getEnv(key: string, defaultValue?: string): string | undefined;
enabled(_name: string, _context: ExecutorReleaseContext): boolean;
getConfig<T>(keys?: string | string[], defaultValue?: T): T;
setConfig(config: DeepPartial<Props>): void;
onBefore?(_context: ExecutorReleaseContext): void | Promise<void>;
onExec?(_context: ExecutorReleaseContext): void | Promise<void>;
onSuccess?(_context: ExecutorReleaseContext): void | Promise<void>;
onError?(_context: ExecutorReleaseContext): void | Promise<void>;
/**
* run a step
*
* this will log the step and return the result of the task
*
* @param label - the label of the step
* @param task - the task to run
* @returns the result of the task
*/
step<T>({ label, task }: StepOption<T>): Promise<T>;
}
/**
* Represents a class that extends Plugin.
*/
type PluginClass<T extends unknown[] = any[]> = new (...args: T) => Plugin;
/**
* Represents the constructor parameters for a specific Plugin class, excluding the first parameter.
* This assumes that the constructor parameters are known and can be inferred.
*/
type PluginConstructorParams<T extends PluginClass> = T extends new (first: any, ...args: infer P) => unknown ? P : never;
type PluginTuple<T extends PluginClass> = [
T | string,
...PluginConstructorParams<T>
];
declare function tuple<T extends PluginClass>(plugin: T | string, ...args: PluginConstructorParams<T>): PluginTuple<T>;
/**
* This is the shared options for the release.
*
* extends `FeReleaseConfig`
*/
interface SharedReleaseOptions extends FeReleaseConfig {
/**
* The source branch of the project
*
* default:
* - first, get from `FE_RELEASE_SOURCE_BRANCH`
* - second, get from `FE_RELEASE_BRANCH`
* - `master`
*
*/
sourceBranch?: string;
/**
* The environment of the project
*
* default:
* - first, get from `FE_RELEASE_ENV`
* - second, get from `NODE_ENV`
* - `development`
*/
releaseEnv?: string;
/**
* The root path of the project
*
* @default `process.cwd()`
*/
rootPath?: 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;
}
declare class ReleaseContext<T extends ReleaseConfig = ReleaseConfig> extends FeScriptContext<T> {
protected readonly _env: Env;
/**
* Shared Config
*/
shared: SharedReleaseOptions;
constructor(context: ReleaseContextOptions<T>);
private getDefaultShreadOptions;
get rootPath(): string;
get sourceBranch(): string;
get releaseEnv(): string;
get env(): Env;
get workspaces(): WorkspaceValue[] | undefined;
get workspace(): WorkspaceValue | undefined;
setWorkspaces(workspaces: WorkspaceValue[]): void;
setConfig(config: DeepPartial<ReleaseConfig>): void;
getConfig<T = unknown>(key: string | string[], defaultValue?: T): T;
setShared(shared: Partial<SharedReleaseOptions>): void;
getPkg<T>(key?: string, defaultValue?: T): T;
getTemplateContext(): TemplateContext;
runChangesetsCli(name: string, args?: string[]): Promise<string>;
}
type ReleaseLabelCompare = (changedFilePath: string, packagePath: string) => boolean;
interface ReleaseLabelOptions {
/**
* The change packages label
*/
changePackagesLabel: string;
/**
* The packages directories
*/
packagesDirectories: string[];
compare?: ReleaseLabelCompare;
}
declare class ReleaseLabel {
private readonly options;
constructor(options: ReleaseLabelOptions);
compare(changedFilePath: string, packagePath: string): boolean;
toChangeLabel(packagePath: string, label?: string): string;
toChangeLabels(packages: string[], label?: string): string[];
pick(changedFiles: Array<string> | Set<string>, packages?: string[]): string[];
}
type BaseCommit = {
[key in CommitField]: string | undefined;
};
interface GitChangelogOptions {
/**
* start tag
*/
from?: string;
/**
* end tag
*/
to?: string;
/**
* log directory
*/
directory?: string;
/**
* gitlog default fields
* @default ["abbrevHash", "hash", "subject", "authorName", "authorDate"]
*/
fileds?: CommitField[];
/**
* not include merge commit
* @default true
*/
noMerges?: boolean;
/**
* custom commit type
*/
types?: {
type: string;
section?: string;
hidden?: boolean;
}[];
/**
* custom commit format
*
* - support `CommitValue` properties
* - add scopeHeader, commitLink, prLink
*
* @default '\n- ${scopeHeader} ${commitlint.message} ${commitLink} ${prLink}'
*/
formatTemplate?: string;
/**
* whether to include commit body
* @since 2.3.0
* @default false
*/
commitBody?: boolean;
}
interface Commitlint {
type?: string;
scope?: string;
message: string;
/**
* commit body, remove repeat title
* @since 2.3.0
*/
body?: string;
}
interface CommitValue {
/**
* git log base info
*/
base: BaseCommit;
/**
* parsed commitlint info
*/
commitlint: Commitlint;
/**
* parsed commitlint info
*/
commits: CommitValue[];
/**
* pr number
*/
prNumber?: string;
}
interface ChangelogFormatter {
format<Opt extends GitChangelogOptions>(commits: unknown[], options?: Opt): string[];
}
interface ChangeLogInterface {
getCommits(options?: GitChangelogOptions): Promise<CommitValue[]>;
}
declare const CHANGELOG_ALL_FIELDS: CommitField[];
interface GitChangelogProps extends GitChangelogOptions {
shell: Shell;
logger: LoggerInterface;
}
declare class GitChangelog implements ChangeLogInterface {
protected options: GitChangelogProps;
constructor(options: GitChangelogProps);
/**
* Get the git log
*
* @param options
* @returns
*/
getGitLog(options?: GitChangelogOptions): Promise<BaseCommit[]>;
getCommits(options?: GitChangelogOptions): Promise<CommitValue[]>;
protected createBaseCommit(message: string, target?: Partial<BaseCommit>): BaseCommit;
/**
* Tabify the body
*
* @since 2.3.2
* @param body
* @param size
* @returns
*/
tabify(body: string, size?: number): string;
parseCommitlint(subject: string, rawBody?: string): Commitlint;
toCommitValue(hash: string, message: string): CommitValue;
protected resolveTag(tag?: string, fallback?: string): Promise<string>;
}
interface Options extends GitChangelogOptions {
repoUrl?: string;
}
declare class GitChangelogFormatter implements ChangelogFormatter {
protected options: Options & {
shell: Shell;
};
constructor(options: Options & {
shell: Shell;
});
format(commits: CommitValue[], options?: Options): string[];
formatCommit(commit: CommitValue, options?: Options): string;
foramtLink(target: string, url?: string): string;
formatCommitLink(target: string, url?: string): string;
formatScope(scope: string): string;
}
interface GithubChangelogProps extends GitChangelogProps {
mergePRcommit?: boolean;
githubRootPath?: string;
}
declare function load<T>(pluginName: string): Promise<[string, T]>;
declare function loaderPluginsFromPluginTuples<T extends Plugin<unknown>>(context: ReleaseContext, pluginsTuples: PluginTuple<PluginClass>[], maxLimit?: number): Promise<T[]>;
type ConstructorType<T, Args extends unknown[]> = (new (...args: Args) => T) | ((...args: Args) => T);
declare function factory<T, Args extends unknown[]>(Constructor: ConstructorType<T, Args>, ...args: Args): T;
declare function reduceOptions(opts: OptionValues, commonKey?: string): OptionValues;
export { CHANGELOG_ALL_FIELDS, GitChangelog, GitChangelogFormatter, Plugin, ReleaseContext, ReleaseLabel, ReleaseTask, factory, load, loaderPluginsFromPluginTuples, reduceOptions, tuple };
export type { ConstructorType, DeepPartial, ExecutorReleaseContext, GitChangelogProps, GithubChangelogProps, Options, PackageJson, PluginClass, PluginConstructorParams, PluginTuple, ReleaseConfig, ReleaseContextOptions, ReleaseLabelCompare, ReleaseLabelOptions, ReleaseReturnValue, StepOption, TemplateContext };