feat(cli): split commit and release into target-based workflows
This commit is contained in:
@@ -3,6 +3,8 @@ import * as plugins from './mod.plugins.js';
|
||||
export interface ICommitConfig {
|
||||
alwaysTest: boolean;
|
||||
alwaysBuild: boolean;
|
||||
confirmation: 'prompt' | 'auto' | 'plan';
|
||||
steps: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -15,7 +17,7 @@ export class CommitConfig {
|
||||
|
||||
constructor(cwd: string = process.cwd()) {
|
||||
this.cwd = cwd;
|
||||
this.config = { alwaysTest: false, alwaysBuild: false };
|
||||
this.config = { alwaysTest: false, alwaysBuild: false, confirmation: 'prompt', steps: ['analyze', 'changelog', 'commit'] };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,9 +36,19 @@ export class CommitConfig {
|
||||
const smartconfigInstance = new plugins.smartconfig.Smartconfig(this.cwd);
|
||||
const gitzoneConfig = smartconfigInstance.dataFor<any>('@git.zone/cli', {});
|
||||
|
||||
const alwaysTest = gitzoneConfig?.commit?.alwaysTest ?? false;
|
||||
const alwaysBuild = gitzoneConfig?.commit?.alwaysBuild ?? false;
|
||||
this.config = {
|
||||
alwaysTest: gitzoneConfig?.commit?.alwaysTest ?? false,
|
||||
alwaysBuild: gitzoneConfig?.commit?.alwaysBuild ?? false,
|
||||
alwaysTest,
|
||||
alwaysBuild,
|
||||
confirmation: gitzoneConfig?.commit?.confirmation ?? 'prompt',
|
||||
steps: gitzoneConfig?.commit?.steps || [
|
||||
'analyze',
|
||||
...(alwaysTest ? ['test'] : []),
|
||||
...(alwaysBuild ? ['build'] : []),
|
||||
'changelog',
|
||||
'commit',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,6 +78,8 @@ export class CommitConfig {
|
||||
// Update commit settings
|
||||
smartconfigData['@git.zone/cli'].commit.alwaysTest = this.config.alwaysTest;
|
||||
smartconfigData['@git.zone/cli'].commit.alwaysBuild = this.config.alwaysBuild;
|
||||
smartconfigData['@git.zone/cli'].commit.confirmation = this.config.confirmation;
|
||||
smartconfigData['@git.zone/cli'].commit.steps = this.config.steps;
|
||||
|
||||
// Write back to file
|
||||
await plugins.smartfs
|
||||
@@ -101,4 +115,20 @@ export class CommitConfig {
|
||||
public setAlwaysBuild(value: boolean): void {
|
||||
this.config.alwaysBuild = value;
|
||||
}
|
||||
|
||||
public getConfirmation(): 'prompt' | 'auto' | 'plan' {
|
||||
return this.config.confirmation;
|
||||
}
|
||||
|
||||
public setConfirmation(value: 'prompt' | 'auto' | 'plan'): void {
|
||||
this.config.confirmation = value;
|
||||
}
|
||||
|
||||
public getSteps(): string[] {
|
||||
return [...this.config.steps];
|
||||
}
|
||||
|
||||
public setSteps(steps: string[]): void {
|
||||
this.config.steps = [...steps];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,13 +35,11 @@ export class ReleaseConfig {
|
||||
public async load(): Promise<void> {
|
||||
const smartconfigInstance = new plugins.smartconfig.Smartconfig(this.cwd);
|
||||
const gitzoneConfig = smartconfigInstance.dataFor<any>('@git.zone/cli', {});
|
||||
|
||||
// Also check szci for backward compatibility
|
||||
const szciConfig = smartconfigInstance.dataFor<any>('@ship.zone/szci', {});
|
||||
const npmTarget = gitzoneConfig?.release?.targets?.npm || {};
|
||||
|
||||
this.config = {
|
||||
registries: gitzoneConfig?.release?.registries || [],
|
||||
accessLevel: gitzoneConfig?.release?.accessLevel || szciConfig?.npmAccessLevel || 'public',
|
||||
registries: npmTarget.registries || [],
|
||||
accessLevel: npmTarget.accessLevel || 'public',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -68,9 +66,18 @@ export class ReleaseConfig {
|
||||
smartconfigData['@git.zone/cli'].release = {};
|
||||
}
|
||||
|
||||
if (!smartconfigData['@git.zone/cli'].release.targets) {
|
||||
smartconfigData['@git.zone/cli'].release.targets = {};
|
||||
}
|
||||
|
||||
if (!smartconfigData['@git.zone/cli'].release.targets.npm) {
|
||||
smartconfigData['@git.zone/cli'].release.targets.npm = {};
|
||||
}
|
||||
|
||||
// Update registries and accessLevel
|
||||
smartconfigData['@git.zone/cli'].release.registries = this.config.registries;
|
||||
smartconfigData['@git.zone/cli'].release.accessLevel = this.config.accessLevel;
|
||||
smartconfigData['@git.zone/cli'].release.targets.npm.enabled = this.config.registries.length > 0;
|
||||
smartconfigData['@git.zone/cli'].release.targets.npm.registries = this.config.registries;
|
||||
smartconfigData['@git.zone/cli'].release.targets.npm.accessLevel = this.config.accessLevel;
|
||||
|
||||
// Write back to file
|
||||
await plugins.smartfs
|
||||
|
||||
+89
-28
@@ -1,4 +1,4 @@
|
||||
// gitzone config - manage release registry configuration
|
||||
// gitzone config - manage CLI smartconfig configuration
|
||||
|
||||
import * as plugins from "./mod.plugins.js";
|
||||
import { ReleaseConfig } from "./classes.releaseconfig.js";
|
||||
@@ -13,6 +13,10 @@ import {
|
||||
unsetCliConfigValueInData,
|
||||
writeSmartconfigFile,
|
||||
} from "../helpers.smartconfig.js";
|
||||
import {
|
||||
CURRENT_GITZONE_CLI_SCHEMA_VERSION,
|
||||
migrateSmartconfigData,
|
||||
} from "../helpers.smartconfigmigrations.js";
|
||||
|
||||
export { ReleaseConfig, CommitConfig };
|
||||
|
||||
@@ -99,6 +103,9 @@ export const run = async (argvArg: any) => {
|
||||
case "services":
|
||||
await handleServices(mode);
|
||||
break;
|
||||
case "migrate":
|
||||
await handleMigrate(value, mode);
|
||||
break;
|
||||
case "get":
|
||||
await handleGet(value, mode);
|
||||
break;
|
||||
@@ -138,10 +145,11 @@ async function handleInteractiveMenu(): Promise<void> {
|
||||
default: "show",
|
||||
choices: [
|
||||
{ name: "Show current configuration", value: "show" },
|
||||
{ name: "Add a registry", value: "add" },
|
||||
{ name: "Remove a registry", value: "remove" },
|
||||
{ name: "Clear all registries", value: "clear" },
|
||||
{ name: "Add an npm target registry", value: "add" },
|
||||
{ name: "Remove an npm target registry", value: "remove" },
|
||||
{ name: "Clear npm target registries", value: "clear" },
|
||||
{ name: "Set access level (public/private)", value: "access" },
|
||||
{ name: "Migrate smartconfig schema", value: "migrate" },
|
||||
{ name: "Configure commit options", value: "commit" },
|
||||
{ name: "Configure services", value: "services" },
|
||||
{ name: "Show help", value: "help" },
|
||||
@@ -166,6 +174,9 @@ async function handleInteractiveMenu(): Promise<void> {
|
||||
case "access":
|
||||
await handleAccessLevel(undefined, defaultCliMode);
|
||||
break;
|
||||
case "migrate":
|
||||
await handleMigrate(undefined, defaultCliMode);
|
||||
break;
|
||||
case "commit":
|
||||
await handleCommit(undefined, undefined, defaultCliMode);
|
||||
break;
|
||||
@@ -197,7 +208,7 @@ async function handleShow(mode: ICliMode): Promise<void> {
|
||||
"╭─────────────────────────────────────────────────────────────╮",
|
||||
);
|
||||
console.log(
|
||||
"│ Release Configuration │",
|
||||
"│ Release NPM Target Configuration │",
|
||||
);
|
||||
console.log(
|
||||
"╰─────────────────────────────────────────────────────────────╯",
|
||||
@@ -209,12 +220,12 @@ async function handleShow(mode: ICliMode): Promise<void> {
|
||||
console.log("");
|
||||
|
||||
if (registries.length === 0) {
|
||||
plugins.logger.log("info", "No release registries configured.");
|
||||
plugins.logger.log("info", "No npm target registries configured.");
|
||||
console.log("");
|
||||
console.log(" Run `gitzone config add <registry-url>` to add one.");
|
||||
console.log("");
|
||||
} else {
|
||||
plugins.logger.log("info", `Configured registries (${registries.length}):`);
|
||||
plugins.logger.log("info", `Configured npm target registries (${registries.length}):`);
|
||||
console.log("");
|
||||
registries.forEach((url, index) => {
|
||||
console.log(` ${index + 1}. ${url}`);
|
||||
@@ -224,7 +235,7 @@ async function handleShow(mode: ICliMode): Promise<void> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a registry URL
|
||||
* Add an npm target registry URL
|
||||
*/
|
||||
async function handleAdd(
|
||||
url: string | undefined,
|
||||
@@ -240,7 +251,7 @@ async function handleAdd(
|
||||
const response = await interactInstance.askQuestion({
|
||||
type: "input",
|
||||
name: "registryUrl",
|
||||
message: "Enter registry URL:",
|
||||
message: "Enter npm target registry URL:",
|
||||
default: "https://registry.npmjs.org",
|
||||
validate: (input: string) => {
|
||||
return !!(input && input.trim() !== "");
|
||||
@@ -263,7 +274,7 @@ async function handleAdd(
|
||||
});
|
||||
return;
|
||||
}
|
||||
plugins.logger.log("success", `Added registry: ${url}`);
|
||||
plugins.logger.log("success", `Added npm target registry: ${url}`);
|
||||
await formatSmartconfigWithDiff(mode);
|
||||
} else {
|
||||
plugins.logger.log("warn", `Registry already exists: ${url}`);
|
||||
@@ -271,7 +282,7 @@ async function handleAdd(
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a registry URL
|
||||
* Remove an npm target registry URL
|
||||
*/
|
||||
async function handleRemove(
|
||||
url: string | undefined,
|
||||
@@ -281,7 +292,7 @@ async function handleRemove(
|
||||
const registries = config.getRegistries();
|
||||
|
||||
if (registries.length === 0) {
|
||||
plugins.logger.log("warn", "No registries configured to remove.");
|
||||
plugins.logger.log("warn", "No npm target registries configured to remove.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -295,7 +306,7 @@ async function handleRemove(
|
||||
const response = await interactInstance.askQuestion({
|
||||
type: "list",
|
||||
name: "registryUrl",
|
||||
message: "Select registry to remove:",
|
||||
message: "Select npm target registry to remove:",
|
||||
choices: registries,
|
||||
default: registries[0],
|
||||
});
|
||||
@@ -315,7 +326,7 @@ async function handleRemove(
|
||||
});
|
||||
return;
|
||||
}
|
||||
plugins.logger.log("success", `Removed registry: ${url}`);
|
||||
plugins.logger.log("success", `Removed npm target registry: ${url}`);
|
||||
await formatSmartconfigWithDiff(mode);
|
||||
} else {
|
||||
plugins.logger.log("warn", `Registry not found: ${url}`);
|
||||
@@ -323,20 +334,20 @@ async function handleRemove(
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all registries
|
||||
* Clear all npm target registries
|
||||
*/
|
||||
async function handleClear(mode: ICliMode): Promise<void> {
|
||||
const config = await ReleaseConfig.fromCwd();
|
||||
|
||||
if (!config.hasRegistries()) {
|
||||
plugins.logger.log("info", "No registries to clear.");
|
||||
plugins.logger.log("info", "No npm target registries to clear.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Confirm before clearing
|
||||
const confirmed = mode.interactive
|
||||
? await plugins.smartinteract.SmartInteract.getCliConfirmation(
|
||||
"Clear all configured registries?",
|
||||
"Clear all configured npm target registries?",
|
||||
false,
|
||||
)
|
||||
: true;
|
||||
@@ -348,7 +359,7 @@ async function handleClear(mode: ICliMode): Promise<void> {
|
||||
printJson({ ok: true, action: "clear", registries: [] });
|
||||
return;
|
||||
}
|
||||
plugins.logger.log("success", "All registries cleared.");
|
||||
plugins.logger.log("success", "All npm target registries cleared.");
|
||||
await formatSmartconfigWithDiff(mode);
|
||||
} else {
|
||||
plugins.logger.log("info", "Operation cancelled.");
|
||||
@@ -473,6 +484,7 @@ async function handleCommitInteractive(config: CommitConfig): Promise<void> {
|
||||
const selected = (response as any).value || [];
|
||||
config.setAlwaysTest(selected.includes("alwaysTest"));
|
||||
config.setAlwaysBuild(selected.includes("alwaysBuild"));
|
||||
syncCommitStepsFromBooleans(config);
|
||||
await config.save();
|
||||
|
||||
plugins.logger.log("success", "Commit configuration updated");
|
||||
@@ -496,6 +508,7 @@ async function handleCommitSetting(
|
||||
} else if (setting === "alwaysBuild") {
|
||||
config.setAlwaysBuild(boolValue);
|
||||
}
|
||||
syncCommitStepsFromBooleans(config);
|
||||
|
||||
await config.save();
|
||||
if (mode.json) {
|
||||
@@ -506,6 +519,16 @@ async function handleCommitSetting(
|
||||
await formatSmartconfigWithDiff(mode);
|
||||
}
|
||||
|
||||
function syncCommitStepsFromBooleans(config: CommitConfig): void {
|
||||
config.setSteps([
|
||||
"analyze",
|
||||
...(config.getAlwaysTest() ? ["test"] : []),
|
||||
...(config.getAlwaysBuild() ? ["build"] : []),
|
||||
"changelog",
|
||||
"commit",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show help for commit subcommand
|
||||
*/
|
||||
@@ -636,6 +659,38 @@ async function handleUnset(
|
||||
plugins.logger.log("success", `Unset ${configPath}`);
|
||||
}
|
||||
|
||||
async function handleMigrate(
|
||||
rawTargetVersion: string | undefined,
|
||||
mode: ICliMode,
|
||||
): Promise<void> {
|
||||
const targetVersion = rawTargetVersion
|
||||
? Number(rawTargetVersion)
|
||||
: CURRENT_GITZONE_CLI_SCHEMA_VERSION;
|
||||
if (!Number.isInteger(targetVersion) || targetVersion < 1) {
|
||||
throw new Error("Migration target version must be a positive integer");
|
||||
}
|
||||
|
||||
const smartconfigData = await readSmartconfigFile();
|
||||
const result = migrateSmartconfigData(smartconfigData, targetVersion);
|
||||
if (result.migrated) {
|
||||
await writeSmartconfigFile(smartconfigData);
|
||||
}
|
||||
|
||||
if (mode.json) {
|
||||
printJson({ ok: true, action: "migrate", ...result });
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.migrated) {
|
||||
plugins.logger.log(
|
||||
"success",
|
||||
`Migrated .smartconfig.json from schema v${result.fromVersion} to v${result.toVersion}`,
|
||||
);
|
||||
} else {
|
||||
plugins.logger.log("info", `.smartconfig.json already at schema v${result.toVersion}`);
|
||||
}
|
||||
}
|
||||
|
||||
function parseConfigValue(rawValue: string): any {
|
||||
const trimmedValue = rawValue.trim();
|
||||
if (trimmedValue === "true") {
|
||||
@@ -676,21 +731,25 @@ export function showHelp(mode?: ICliMode): void {
|
||||
{ name: "get <path>", description: "Read a single config value" },
|
||||
{ name: "set <path> <value>", description: "Write a config value" },
|
||||
{ name: "unset <path>", description: "Delete a config value" },
|
||||
{ name: "add [url]", description: "Add a release registry" },
|
||||
{ name: "remove [url]", description: "Remove a release registry" },
|
||||
{ name: "clear", description: "Clear all release registries" },
|
||||
{ name: "add [url]", description: "Add an npm release target registry" },
|
||||
{ name: "remove [url]", description: "Remove an npm release target registry" },
|
||||
{ name: "clear", description: "Clear npm release target registries" },
|
||||
{
|
||||
name: "access [public|private]",
|
||||
description: "Set npm publish access level",
|
||||
description: "Set npm target publish access level",
|
||||
},
|
||||
{
|
||||
name: "commit <setting> <value>",
|
||||
description: "Set commit defaults",
|
||||
},
|
||||
{
|
||||
name: "migrate [version]",
|
||||
description: "Run version-targeted .smartconfig.json migrations",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
"gitzone config show --json",
|
||||
"gitzone config get release.accessLevel",
|
||||
"gitzone config get release.targets.npm.accessLevel",
|
||||
"gitzone config set cli.interactive false",
|
||||
"gitzone config set cli.output json",
|
||||
],
|
||||
@@ -708,13 +767,14 @@ export function showHelp(mode?: ICliMode): void {
|
||||
console.log(" get <path> Read a single config value");
|
||||
console.log(" set <path> <value> Write a config value");
|
||||
console.log(" unset <path> Delete a config value");
|
||||
console.log(" add [url] Add a registry URL");
|
||||
console.log(" remove [url] Remove a registry URL");
|
||||
console.log(" clear Clear all registries");
|
||||
console.log(" add [url] Add an npm target registry URL");
|
||||
console.log(" remove [url] Remove an npm target registry URL");
|
||||
console.log(" clear Clear npm target registries");
|
||||
console.log(
|
||||
" access [public|private] Set npm access level for publishing",
|
||||
" access [public|private] Set npm target access level for publishing",
|
||||
);
|
||||
console.log(" commit [setting] [value] Configure commit options");
|
||||
console.log(" migrate [version] Run version-targeted smartconfig migrations");
|
||||
console.log(
|
||||
" services Configure which services are enabled",
|
||||
);
|
||||
@@ -722,7 +782,7 @@ export function showHelp(mode?: ICliMode): void {
|
||||
console.log("Examples:");
|
||||
console.log(" gitzone config show");
|
||||
console.log(" gitzone config show --json");
|
||||
console.log(" gitzone config get release.accessLevel");
|
||||
console.log(" gitzone config get release.targets.npm.accessLevel");
|
||||
console.log(" gitzone config set cli.interactive false");
|
||||
console.log(" gitzone config set cli.output json");
|
||||
console.log(" gitzone config unset cli.output");
|
||||
@@ -732,6 +792,7 @@ export function showHelp(mode?: ICliMode): void {
|
||||
console.log(" gitzone config clear");
|
||||
console.log(" gitzone config access public");
|
||||
console.log(" gitzone config access private");
|
||||
console.log(" gitzone config migrate 2");
|
||||
console.log(" gitzone config commit # Interactive");
|
||||
console.log(" gitzone config commit alwaysTest true");
|
||||
console.log(" gitzone config services # Interactive");
|
||||
|
||||
Reference in New Issue
Block a user