@git.zone/cli 2.2.2 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/templates/npmextra/npmextra.json +4 -2
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.gitzoneconfig.js +10 -4
- package/dist_ts/gitzone.cli.js +8 -1
- package/dist_ts/mod_commit/index.js +109 -7
- package/dist_ts/mod_commit/mod.ui.d.ts +14 -0
- package/dist_ts/mod_commit/mod.ui.js +56 -2
- package/dist_ts/mod_config/classes.releaseconfig.d.ts +60 -0
- package/dist_ts/mod_config/classes.releaseconfig.js +131 -0
- package/dist_ts/mod_config/index.d.ts +3 -0
- package/dist_ts/mod_config/index.js +253 -0
- package/dist_ts/mod_config/mod.plugins.d.ts +2 -0
- package/dist_ts/mod_config/mod.plugins.js +4 -0
- package/dist_ts/mod_format/format.npmextra.js +33 -1
- package/dist_ts/mod_format/index.d.ts +6 -0
- package/dist_ts/mod_format/index.js +34 -1
- package/dist_ts/mod_standard/index.d.ts +1 -1
- package/dist_ts/mod_standard/index.js +75 -27
- package/npmextra.json +12 -5
- package/package.json +33 -23
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.gitzoneconfig.ts +13 -5
- package/ts/gitzone.cli.ts +8 -0
- package/ts/mod_commit/index.ts +112 -8
- package/ts/mod_commit/mod.ui.ts +69 -1
- package/ts/mod_config/classes.releaseconfig.ts +166 -0
- package/ts/mod_config/index.ts +282 -0
- package/ts/mod_config/mod.plugins.ts +3 -0
- package/ts/mod_format/format.npmextra.ts +39 -0
- package/ts/mod_format/index.ts +42 -0
- package/ts/mod_standard/index.ts +78 -31
- package/dist_ts/gitzone.config.d.ts +0 -28
- package/dist_ts/gitzone.config.js +0 -21
- package/dist_ts/gitzone.monitor.d.ts +0 -1
- package/dist_ts/gitzone.monitor.js +0 -2
- package/dist_ts/gitzone.paths.d.ts +0 -4
- package/dist_ts/gitzone.paths.js +0 -6
- package/dist_ts/gitzone.plugins.d.ts +0 -10
- package/dist_ts/gitzone.plugins.js +0 -11
- package/dist_ts/mod_format/format.classes.project.d.ts +0 -8
- package/dist_ts/mod_format/format.classes.project.js +0 -20
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@git.zone/cli",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.6.1",
|
|
5
5
|
"description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.",
|
|
6
6
|
"main": "dist_ts/index.ts",
|
|
7
7
|
"typings": "dist_ts/index.d.ts",
|
|
@@ -10,6 +10,24 @@
|
|
|
10
10
|
"gitzone": "./cli.js",
|
|
11
11
|
"gzone": "./cli.js"
|
|
12
12
|
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "(npm run clean && npm run prepareTest && npm run testCli && npm run testFormat && npm run testCommit && npm run testDeprecate && npm run testVersion && npm run testReadme && npm run testUpdate && npm run testTemplateNpm && npm run testTemplateLit) && rm -rf test",
|
|
15
|
+
"build": "tsbuild tsfolders",
|
|
16
|
+
"clean": "(rm -rf test/)",
|
|
17
|
+
"prepareTest": "(git clone https://gitlab.com/sandboxzone/sandbox-npmts.git test/)",
|
|
18
|
+
"testBuild": "npm run build && rm -r dist/",
|
|
19
|
+
"testCli": "(cd test && node ../cli.ts.js)",
|
|
20
|
+
"testCommit": "(cd test && node ../cli.ts.js commit)",
|
|
21
|
+
"testDeprecate": "(cd test && node ../cli.ts.js deprecate)",
|
|
22
|
+
"testOpen": "(cd test && node ../cli.ts.js open ci)",
|
|
23
|
+
"testReadme": "(cd test && node ../cli.ts.js readme)",
|
|
24
|
+
"testFormat": "(cd test && node ../cli.ts.js format)",
|
|
25
|
+
"testTemplateNpm": "(rm -rf test/testtemplate_npm/ && mkdir test/testtemplate_npm && cd test/testtemplate_npm && node ../../cli.ts.js template npm)",
|
|
26
|
+
"testTemplateLit": "(rm -rf test/testtemplate_lit/ && mkdir test/testtemplate_lit && cd test/testtemplate_lit && node ../../cli.ts.js template lit)",
|
|
27
|
+
"testUpdate": "(cd test && node ../cli.ts.js update)",
|
|
28
|
+
"testVersion": "(cd test && node ../cli.ts.js -v)",
|
|
29
|
+
"buildDocs": "tsdoc"
|
|
30
|
+
},
|
|
13
31
|
"repository": {
|
|
14
32
|
"type": "git",
|
|
15
33
|
"url": "https://gitlab.com/gitzone/private/gitzone.git"
|
|
@@ -39,14 +57,14 @@
|
|
|
39
57
|
},
|
|
40
58
|
"homepage": "https://gitlab.com/gitzone/private/gitzone#readme",
|
|
41
59
|
"devDependencies": {
|
|
42
|
-
"@git.zone/tsbuild": "^4.0.
|
|
60
|
+
"@git.zone/tsbuild": "^4.0.2",
|
|
43
61
|
"@git.zone/tsrun": "^2.0.1",
|
|
44
62
|
"@git.zone/tstest": "^3.1.3",
|
|
45
63
|
"@push.rocks/smartdelay": "^3.0.5",
|
|
46
64
|
"@push.rocks/smartinteract": "^2.0.16",
|
|
47
65
|
"@push.rocks/smartnetwork": "^4.4.0",
|
|
48
66
|
"@push.rocks/smartshell": "^3.3.0",
|
|
49
|
-
"@types/node": "^
|
|
67
|
+
"@types/node": "^25.0.2"
|
|
50
68
|
},
|
|
51
69
|
"dependencies": {
|
|
52
70
|
"@git.zone/tsdoc": "^1.10.2",
|
|
@@ -62,7 +80,7 @@
|
|
|
62
80
|
"@push.rocks/smartfile": "^13.1.2",
|
|
63
81
|
"@push.rocks/smartfs": "^1.2.0",
|
|
64
82
|
"@push.rocks/smartgulp": "^3.0.4",
|
|
65
|
-
"@push.rocks/smartjson": "^
|
|
83
|
+
"@push.rocks/smartjson": "^6.0.0",
|
|
66
84
|
"@push.rocks/smartlegal": "^1.0.27",
|
|
67
85
|
"@push.rocks/smartlog": "^3.1.10",
|
|
68
86
|
"@push.rocks/smartlog-destination-local": "^9.0.2",
|
|
@@ -95,22 +113,14 @@
|
|
|
95
113
|
"browserslist": [
|
|
96
114
|
"last 1 chrome versions"
|
|
97
115
|
],
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"testFormat": "(cd test && node ../cli.ts.js format)",
|
|
110
|
-
"testTemplateNpm": "(rm -rf test/testtemplate_npm/ && mkdir test/testtemplate_npm && cd test/testtemplate_npm && node ../../cli.ts.js template npm)",
|
|
111
|
-
"testTemplateLit": "(rm -rf test/testtemplate_lit/ && mkdir test/testtemplate_lit && cd test/testtemplate_lit && node ../../cli.ts.js template lit)",
|
|
112
|
-
"testUpdate": "(cd test && node ../cli.ts.js update)",
|
|
113
|
-
"testVersion": "(cd test && node ../cli.ts.js -v)",
|
|
114
|
-
"buildDocs": "tsdoc"
|
|
115
|
-
}
|
|
116
|
-
}
|
|
116
|
+
"pnpm": {
|
|
117
|
+
"overrides": {},
|
|
118
|
+
"onlyBuiltDependencies": [
|
|
119
|
+
"esbuild",
|
|
120
|
+
"mongodb-memory-server",
|
|
121
|
+
"puppeteer",
|
|
122
|
+
"sharp"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
|
|
126
|
+
}
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@git.zone/cli',
|
|
6
|
-
version: '2.
|
|
6
|
+
version: '2.6.1',
|
|
7
7
|
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
|
|
8
8
|
}
|
|
@@ -40,11 +40,19 @@ export class GitzoneConfig {
|
|
|
40
40
|
public async readConfigFromCwd() {
|
|
41
41
|
const npmextraInstance = new plugins.npmextra.Npmextra(paths.cwd);
|
|
42
42
|
this.data = npmextraInstance.dataFor<IGitzoneConfigData>('@git.zone/cli', {});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
>('@ship.zone/szci', {
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
|
|
44
|
+
// Read szci config for backward compatibility
|
|
45
|
+
const szciConfig = npmextraInstance.dataFor<any>('@ship.zone/szci', {});
|
|
46
|
+
|
|
47
|
+
// Prefer accessLevel from @git.zone/cli.release, fallback to @ship.zone/szci.npmAccessLevel
|
|
48
|
+
const accessLevel =
|
|
49
|
+
(this.data as any)?.release?.accessLevel ||
|
|
50
|
+
szciConfig?.npmAccessLevel ||
|
|
51
|
+
'public';
|
|
52
|
+
|
|
53
|
+
this.data.npmciOptions = {
|
|
54
|
+
npmAccessLevel: accessLevel,
|
|
55
|
+
};
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
constructor() {}
|
package/ts/gitzone.cli.ts
CHANGED
|
@@ -131,6 +131,14 @@ export let run = async () => {
|
|
|
131
131
|
modHelpers.run(argvArg);
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* manage release configuration
|
|
136
|
+
*/
|
|
137
|
+
gitzoneSmartcli.addCommand('config').subscribe(async (argvArg) => {
|
|
138
|
+
const modConfig = await import('./mod_config/index.js');
|
|
139
|
+
await modConfig.run(argvArg);
|
|
140
|
+
});
|
|
141
|
+
|
|
134
142
|
/**
|
|
135
143
|
* manage development services (MongoDB, S3/MinIO)
|
|
136
144
|
*/
|
package/ts/mod_commit/index.ts
CHANGED
|
@@ -5,8 +5,35 @@ import * as paths from '../paths.js';
|
|
|
5
5
|
import { logger } from '../gitzone.logging.js';
|
|
6
6
|
import * as helpers from './mod.helpers.js';
|
|
7
7
|
import * as ui from './mod.ui.js';
|
|
8
|
+
import { ReleaseConfig } from '../mod_config/classes.releaseconfig.js';
|
|
8
9
|
|
|
9
10
|
export const run = async (argvArg: any) => {
|
|
11
|
+
// Check if release flag is set and validate registries early
|
|
12
|
+
const wantsRelease = !!(argvArg.r || argvArg.release);
|
|
13
|
+
const wantsBuild = !!(argvArg.b || argvArg.build);
|
|
14
|
+
let releaseConfig: ReleaseConfig | null = null;
|
|
15
|
+
|
|
16
|
+
if (wantsRelease) {
|
|
17
|
+
releaseConfig = await ReleaseConfig.fromCwd();
|
|
18
|
+
if (!releaseConfig.hasRegistries()) {
|
|
19
|
+
logger.log('error', 'No release registries configured.');
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(' Run `gitzone config add <registry-url>` to add registries.');
|
|
22
|
+
console.log('');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Print execution plan at the start
|
|
28
|
+
ui.printExecutionPlan({
|
|
29
|
+
autoAccept: !!(argvArg.y || argvArg.yes),
|
|
30
|
+
push: !!(argvArg.p || argvArg.push),
|
|
31
|
+
build: wantsBuild,
|
|
32
|
+
release: wantsRelease,
|
|
33
|
+
format: !!argvArg.format,
|
|
34
|
+
registries: releaseConfig?.getRegistries(),
|
|
35
|
+
});
|
|
36
|
+
|
|
10
37
|
if (argvArg.format) {
|
|
11
38
|
const formatMod = await import('../mod_format/index.js');
|
|
12
39
|
await formatMod.run();
|
|
@@ -56,6 +83,10 @@ export const run = async (argvArg: any) => {
|
|
|
56
83
|
name: 'pushToOrigin',
|
|
57
84
|
value: !!(argvArg.p || argvArg.push), // Only push if -p flag also provided
|
|
58
85
|
});
|
|
86
|
+
answerBucket.addAnswer({
|
|
87
|
+
name: 'createRelease',
|
|
88
|
+
value: wantsRelease,
|
|
89
|
+
});
|
|
59
90
|
} else {
|
|
60
91
|
// Warn if --yes was provided but we're requiring confirmation due to breaking change
|
|
61
92
|
if (isBreakingChange && (argvArg.y || argvArg.yes)) {
|
|
@@ -89,6 +120,12 @@ export const run = async (argvArg: any) => {
|
|
|
89
120
|
message: `Do you want to push this version now?`,
|
|
90
121
|
default: true,
|
|
91
122
|
},
|
|
123
|
+
{
|
|
124
|
+
type: 'confirm',
|
|
125
|
+
name: `createRelease`,
|
|
126
|
+
message: `Do you want to publish to npm registries?`,
|
|
127
|
+
default: wantsRelease,
|
|
128
|
+
},
|
|
92
129
|
]);
|
|
93
130
|
answerBucket = await commitInteract.runQueue();
|
|
94
131
|
}
|
|
@@ -111,8 +148,25 @@ export const run = async (argvArg: any) => {
|
|
|
111
148
|
sourceFilePaths: [],
|
|
112
149
|
});
|
|
113
150
|
|
|
114
|
-
//
|
|
115
|
-
|
|
151
|
+
// Load release config if user wants to release (interactively selected)
|
|
152
|
+
if (answerBucket.getAnswerFor('createRelease') && !releaseConfig) {
|
|
153
|
+
releaseConfig = await ReleaseConfig.fromCwd();
|
|
154
|
+
if (!releaseConfig.hasRegistries()) {
|
|
155
|
+
logger.log('error', 'No release registries configured.');
|
|
156
|
+
console.log('');
|
|
157
|
+
console.log(' Run `gitzone config add <registry-url>` to add registries.');
|
|
158
|
+
console.log('');
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Determine total steps based on options
|
|
164
|
+
const willPush = answerBucket.getAnswerFor('pushToOrigin') && !(process.env.CI === 'true');
|
|
165
|
+
const willRelease = answerBucket.getAnswerFor('createRelease') && releaseConfig?.hasRegistries();
|
|
166
|
+
let totalSteps = 5; // Base steps: commitinfo, changelog, staging, commit, version
|
|
167
|
+
if (wantsBuild) totalSteps += 2; // build step + verification step
|
|
168
|
+
if (willPush) totalSteps++;
|
|
169
|
+
if (willRelease) totalSteps++;
|
|
116
170
|
let currentStep = 0;
|
|
117
171
|
|
|
118
172
|
// Step 1: Baking commitinfo
|
|
@@ -173,18 +227,66 @@ export const run = async (argvArg: any) => {
|
|
|
173
227
|
const projectType = await helpers.detectProjectType();
|
|
174
228
|
const newVersion = await helpers.bumpProjectVersion(projectType, commitVersionType, currentStep, totalSteps);
|
|
175
229
|
|
|
176
|
-
// Step 6:
|
|
230
|
+
// Step 6: Run build (optional)
|
|
231
|
+
if (wantsBuild) {
|
|
232
|
+
currentStep++;
|
|
233
|
+
ui.printStep(currentStep, totalSteps, '🔨 Running build', 'in-progress');
|
|
234
|
+
const buildResult = await smartshellInstance.exec('pnpm build');
|
|
235
|
+
if (buildResult.exitCode !== 0) {
|
|
236
|
+
ui.printStep(currentStep, totalSteps, '🔨 Running build', 'error');
|
|
237
|
+
logger.log('error', 'Build failed. Aborting release.');
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
ui.printStep(currentStep, totalSteps, '🔨 Running build', 'done');
|
|
241
|
+
|
|
242
|
+
// Step 7: Verify no uncommitted changes
|
|
243
|
+
currentStep++;
|
|
244
|
+
ui.printStep(currentStep, totalSteps, '🔍 Verifying clean working tree', 'in-progress');
|
|
245
|
+
const statusResult = await smartshellInstance.exec('git status --porcelain');
|
|
246
|
+
if (statusResult.stdout.trim() !== '') {
|
|
247
|
+
ui.printStep(currentStep, totalSteps, '🔍 Verifying clean working tree', 'error');
|
|
248
|
+
logger.log('error', 'Build produced uncommitted changes. This usually means build output is not gitignored.');
|
|
249
|
+
logger.log('error', 'Uncommitted files:');
|
|
250
|
+
console.log(statusResult.stdout);
|
|
251
|
+
logger.log('error', 'Aborting release. Please ensure build artifacts are in .gitignore');
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
ui.printStep(currentStep, totalSteps, '🔍 Verifying clean working tree', 'done');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Step: Push to remote (optional)
|
|
177
258
|
const currentBranch = await helpers.detectCurrentBranch();
|
|
178
|
-
if (
|
|
179
|
-
answerBucket.getAnswerFor('pushToOrigin') &&
|
|
180
|
-
!(process.env.CI === 'true')
|
|
181
|
-
) {
|
|
259
|
+
if (willPush) {
|
|
182
260
|
currentStep++;
|
|
183
261
|
ui.printStep(currentStep, totalSteps, `🚀 Pushing to origin/${currentBranch}`, 'in-progress');
|
|
184
262
|
await smartshellInstance.exec(`git push origin ${currentBranch} --follow-tags`);
|
|
185
263
|
ui.printStep(currentStep, totalSteps, `🚀 Pushing to origin/${currentBranch}`, 'done');
|
|
186
264
|
}
|
|
187
265
|
|
|
266
|
+
// Step 7: Publish to npm registries (optional)
|
|
267
|
+
let releasedRegistries: string[] = [];
|
|
268
|
+
if (willRelease && releaseConfig) {
|
|
269
|
+
currentStep++;
|
|
270
|
+
const registries = releaseConfig.getRegistries();
|
|
271
|
+
ui.printStep(currentStep, totalSteps, `📦 Publishing to ${registries.length} registr${registries.length === 1 ? 'y' : 'ies'}`, 'in-progress');
|
|
272
|
+
|
|
273
|
+
const accessLevel = releaseConfig.getAccessLevel();
|
|
274
|
+
for (const registry of registries) {
|
|
275
|
+
try {
|
|
276
|
+
await smartshellInstance.exec(`npm publish --registry=${registry} --access=${accessLevel}`);
|
|
277
|
+
releasedRegistries.push(registry);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
logger.log('error', `Failed to publish to ${registry}: ${error}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (releasedRegistries.length === registries.length) {
|
|
284
|
+
ui.printStep(currentStep, totalSteps, `📦 Publishing to ${registries.length} registr${registries.length === 1 ? 'y' : 'ies'}`, 'done');
|
|
285
|
+
} else {
|
|
286
|
+
ui.printStep(currentStep, totalSteps, `📦 Publishing to ${registries.length} registr${registries.length === 1 ? 'y' : 'ies'}`, 'error');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
188
290
|
console.log(''); // Add spacing before summary
|
|
189
291
|
|
|
190
292
|
// Get commit SHA for summary
|
|
@@ -200,7 +302,9 @@ export const run = async (argvArg: any) => {
|
|
|
200
302
|
commitMessage: answerBucket.getAnswerFor('commitDescription'),
|
|
201
303
|
newVersion: newVersion,
|
|
202
304
|
commitSha: commitSha,
|
|
203
|
-
pushed:
|
|
305
|
+
pushed: willPush,
|
|
306
|
+
released: releasedRegistries.length > 0,
|
|
307
|
+
releasedRegistries: releasedRegistries.length > 0 ? releasedRegistries : undefined,
|
|
204
308
|
});
|
|
205
309
|
};
|
|
206
310
|
|
package/ts/mod_commit/mod.ui.ts
CHANGED
|
@@ -14,6 +14,17 @@ interface ICommitSummary {
|
|
|
14
14
|
commitSha?: string;
|
|
15
15
|
pushed: boolean;
|
|
16
16
|
repoUrl?: string;
|
|
17
|
+
released?: boolean;
|
|
18
|
+
releasedRegistries?: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface IExecutionPlanOptions {
|
|
22
|
+
autoAccept: boolean;
|
|
23
|
+
push: boolean;
|
|
24
|
+
build: boolean;
|
|
25
|
+
release: boolean;
|
|
26
|
+
format: boolean;
|
|
27
|
+
registries?: string[];
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
interface IRecommendation {
|
|
@@ -39,6 +50,54 @@ export function printHeader(title: string): void {
|
|
|
39
50
|
console.log('');
|
|
40
51
|
}
|
|
41
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Print execution plan at the start of commit
|
|
55
|
+
*/
|
|
56
|
+
export function printExecutionPlan(options: IExecutionPlanOptions): void {
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log('╭───────────────────────────────────────────────────────────────╮');
|
|
59
|
+
console.log('│ gitzone commit - Execution Plan │');
|
|
60
|
+
console.log('╰───────────────────────────────────────────────────────────────╯');
|
|
61
|
+
console.log('');
|
|
62
|
+
|
|
63
|
+
// Show active options
|
|
64
|
+
console.log(' Options:');
|
|
65
|
+
console.log(` Auto-accept ${options.autoAccept ? '✓ enabled (-y)' : '○ interactive mode'}`);
|
|
66
|
+
console.log(` Push to remote ${options.push ? '✓ enabled (-p)' : '○ disabled'}`);
|
|
67
|
+
console.log(` Build & verify ${options.build ? '✓ enabled (-b)' : '○ disabled'}`);
|
|
68
|
+
console.log(` Release to npm ${options.release ? '✓ enabled (-r)' : '○ disabled'}`);
|
|
69
|
+
if (options.format) {
|
|
70
|
+
console.log(` Format first ✓ enabled (--format)`);
|
|
71
|
+
}
|
|
72
|
+
console.log('');
|
|
73
|
+
|
|
74
|
+
// Show steps
|
|
75
|
+
console.log(' Steps:');
|
|
76
|
+
let stepNum = 1;
|
|
77
|
+
if (options.format) {
|
|
78
|
+
console.log(` ${stepNum++}. Format project files`);
|
|
79
|
+
}
|
|
80
|
+
console.log(` ${stepNum++}. Analyze repository changes`);
|
|
81
|
+
console.log(` ${stepNum++}. Bake commit info into code`);
|
|
82
|
+
console.log(` ${stepNum++}. Generate changelog.md`);
|
|
83
|
+
console.log(` ${stepNum++}. Stage and commit files`);
|
|
84
|
+
console.log(` ${stepNum++}. Bump version`);
|
|
85
|
+
if (options.build) {
|
|
86
|
+
console.log(` ${stepNum++}. Run build`);
|
|
87
|
+
console.log(` ${stepNum++}. Verify clean working tree`);
|
|
88
|
+
}
|
|
89
|
+
if (options.push) {
|
|
90
|
+
console.log(` ${stepNum++}. Push to remote`);
|
|
91
|
+
}
|
|
92
|
+
if (options.release) {
|
|
93
|
+
console.log(` ${stepNum++}. Publish to npm registries`);
|
|
94
|
+
if (options.registries && options.registries.length > 0) {
|
|
95
|
+
options.registries.forEach(r => console.log(` → ${r}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
console.log('');
|
|
99
|
+
}
|
|
100
|
+
|
|
42
101
|
/**
|
|
43
102
|
* Print a section with a border
|
|
44
103
|
*/
|
|
@@ -146,6 +205,13 @@ export function printSummary(summary: ICommitSummary): void {
|
|
|
146
205
|
lines.push(`Remote: ⊘ Not pushed (local only)`);
|
|
147
206
|
}
|
|
148
207
|
|
|
208
|
+
if (summary.released && summary.releasedRegistries && summary.releasedRegistries.length > 0) {
|
|
209
|
+
lines.push(`Published: ✓ Released to ${summary.releasedRegistries.length} registr${summary.releasedRegistries.length === 1 ? 'y' : 'ies'}`);
|
|
210
|
+
summary.releasedRegistries.forEach((registry) => {
|
|
211
|
+
lines.push(` → ${registry}`);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
149
215
|
if (summary.repoUrl && summary.commitSha) {
|
|
150
216
|
lines.push('');
|
|
151
217
|
lines.push(`View at: ${summary.repoUrl}/commit/${summary.commitSha}`);
|
|
@@ -153,7 +219,9 @@ export function printSummary(summary: ICommitSummary): void {
|
|
|
153
219
|
|
|
154
220
|
printSection('✅ Commit Summary', lines);
|
|
155
221
|
|
|
156
|
-
if (summary.
|
|
222
|
+
if (summary.released) {
|
|
223
|
+
console.log('🎉 All done! Your changes are committed, pushed, and released.\n');
|
|
224
|
+
} else if (summary.pushed) {
|
|
157
225
|
console.log('🎉 All done! Your changes are committed and pushed.\n');
|
|
158
226
|
} else {
|
|
159
227
|
console.log('✓ Commit created successfully.\n');
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import * as plugins from './mod.plugins.js';
|
|
2
|
+
|
|
3
|
+
export type TAccessLevel = 'public' | 'private';
|
|
4
|
+
|
|
5
|
+
export interface IReleaseConfig {
|
|
6
|
+
registries: string[];
|
|
7
|
+
accessLevel: TAccessLevel;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages release configuration stored in npmextra.json
|
|
12
|
+
* under @git.zone/cli.release namespace
|
|
13
|
+
*/
|
|
14
|
+
export class ReleaseConfig {
|
|
15
|
+
private cwd: string;
|
|
16
|
+
private config: IReleaseConfig;
|
|
17
|
+
|
|
18
|
+
constructor(cwd: string = process.cwd()) {
|
|
19
|
+
this.cwd = cwd;
|
|
20
|
+
this.config = { registries: [], accessLevel: 'public' };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a ReleaseConfig instance from current working directory
|
|
25
|
+
*/
|
|
26
|
+
public static async fromCwd(cwd: string = process.cwd()): Promise<ReleaseConfig> {
|
|
27
|
+
const instance = new ReleaseConfig(cwd);
|
|
28
|
+
await instance.load();
|
|
29
|
+
return instance;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Load configuration from npmextra.json
|
|
34
|
+
*/
|
|
35
|
+
public async load(): Promise<void> {
|
|
36
|
+
const npmextraInstance = new plugins.npmextra.Npmextra(this.cwd);
|
|
37
|
+
const gitzoneConfig = npmextraInstance.dataFor<any>('@git.zone/cli', {});
|
|
38
|
+
|
|
39
|
+
// Also check szci for backward compatibility
|
|
40
|
+
const szciConfig = npmextraInstance.dataFor<any>('@ship.zone/szci', {});
|
|
41
|
+
|
|
42
|
+
this.config = {
|
|
43
|
+
registries: gitzoneConfig?.release?.registries || [],
|
|
44
|
+
accessLevel: gitzoneConfig?.release?.accessLevel || szciConfig?.npmAccessLevel || 'public',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Save configuration to npmextra.json
|
|
50
|
+
*/
|
|
51
|
+
public async save(): Promise<void> {
|
|
52
|
+
const npmextraPath = plugins.path.join(this.cwd, 'npmextra.json');
|
|
53
|
+
let npmextraData: any = {};
|
|
54
|
+
|
|
55
|
+
// Read existing npmextra.json
|
|
56
|
+
if (await plugins.smartfs.file(npmextraPath).exists()) {
|
|
57
|
+
const content = await plugins.smartfs.file(npmextraPath).encoding('utf8').read();
|
|
58
|
+
npmextraData = JSON.parse(content as string);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Ensure @git.zone/cli namespace exists
|
|
62
|
+
if (!npmextraData['@git.zone/cli']) {
|
|
63
|
+
npmextraData['@git.zone/cli'] = {};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Ensure release object exists
|
|
67
|
+
if (!npmextraData['@git.zone/cli'].release) {
|
|
68
|
+
npmextraData['@git.zone/cli'].release = {};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Update registries and accessLevel
|
|
72
|
+
npmextraData['@git.zone/cli'].release.registries = this.config.registries;
|
|
73
|
+
npmextraData['@git.zone/cli'].release.accessLevel = this.config.accessLevel;
|
|
74
|
+
|
|
75
|
+
// Write back to file
|
|
76
|
+
await plugins.smartfs
|
|
77
|
+
.file(npmextraPath)
|
|
78
|
+
.encoding('utf8')
|
|
79
|
+
.write(JSON.stringify(npmextraData, null, 2));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get all configured registries
|
|
84
|
+
*/
|
|
85
|
+
public getRegistries(): string[] {
|
|
86
|
+
return [...this.config.registries];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Check if any registries are configured
|
|
91
|
+
*/
|
|
92
|
+
public hasRegistries(): boolean {
|
|
93
|
+
return this.config.registries.length > 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Add a registry URL
|
|
98
|
+
* @returns true if added, false if already exists
|
|
99
|
+
*/
|
|
100
|
+
public addRegistry(url: string): boolean {
|
|
101
|
+
const normalizedUrl = this.normalizeUrl(url);
|
|
102
|
+
|
|
103
|
+
if (this.config.registries.includes(normalizedUrl)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.config.registries.push(normalizedUrl);
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Remove a registry URL
|
|
113
|
+
* @returns true if removed, false if not found
|
|
114
|
+
*/
|
|
115
|
+
public removeRegistry(url: string): boolean {
|
|
116
|
+
const normalizedUrl = this.normalizeUrl(url);
|
|
117
|
+
const index = this.config.registries.indexOf(normalizedUrl);
|
|
118
|
+
|
|
119
|
+
if (index === -1) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.config.registries.splice(index, 1);
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Clear all registries
|
|
129
|
+
*/
|
|
130
|
+
public clearRegistries(): void {
|
|
131
|
+
this.config.registries = [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get the npm access level
|
|
136
|
+
*/
|
|
137
|
+
public getAccessLevel(): TAccessLevel {
|
|
138
|
+
return this.config.accessLevel;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Set the npm access level
|
|
143
|
+
*/
|
|
144
|
+
public setAccessLevel(level: TAccessLevel): void {
|
|
145
|
+
this.config.accessLevel = level;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Normalize a registry URL (ensure it has https:// prefix)
|
|
150
|
+
*/
|
|
151
|
+
private normalizeUrl(url: string): string {
|
|
152
|
+
let normalized = url.trim();
|
|
153
|
+
|
|
154
|
+
// Add https:// if no protocol specified
|
|
155
|
+
if (!normalized.startsWith('http://') && !normalized.startsWith('https://')) {
|
|
156
|
+
normalized = `https://${normalized}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Remove trailing slash
|
|
160
|
+
if (normalized.endsWith('/')) {
|
|
161
|
+
normalized = normalized.slice(0, -1);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return normalized;
|
|
165
|
+
}
|
|
166
|
+
}
|