Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f0928e7c7 | |||
| 26effadcc9 | |||
| c38e94bcf3 | |||
| b9b51f29d1 | |||
| a3ad48368d | |||
| c10b764c0a | |||
| 7686504e4e | |||
| d96b220703 | |||
| 06f2de3230 | |||
| cc3128f07b | |||
| 358d677e72 | |||
| f421c5851d |
+2
-1
@@ -63,7 +63,8 @@
|
|||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"images": []
|
"engine": "tsdocker",
|
||||||
|
"patterns": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,44 @@
|
|||||||
## Pending
|
## Pending
|
||||||
|
|
||||||
|
|
||||||
|
## 2026-05-13 - 2.19.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Delegate Docker release targets to `tsdocker`.
|
||||||
|
- Replace Docker image template publishing with `tsdocker push` execution.
|
||||||
|
- Move Docker registry behavior to `@git.zone/tsdocker` config and validate removed image config as invalid.
|
||||||
|
|
||||||
|
## 2026-05-10 - 2.18.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- Run `gitzone config fix` opencode handoff with inherited terminal I/O.
|
||||||
|
|
||||||
|
## 2026-05-10 - 2.18.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Add `gitzone config fix` to invoke opencode for configuration repair.
|
||||||
|
|
||||||
|
## 2026-05-10 - 2.17.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Add guided project, CLI, release, and doctor flows to `gitzone config`.
|
||||||
|
|
||||||
|
## 2026-05-10 - 2.16.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- Prevent startup update checks from crashing when installed package metadata is incomplete.
|
||||||
|
|
||||||
|
## 2026-05-10 - 2.16.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Add `gitzone tools` for managing the global `@git.zone` toolchain from the main CLI.
|
||||||
|
|
||||||
## 2026-05-10 - 2.15.0
|
## 2026-05-10 - 2.15.0
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@git.zone/cli",
|
"name": "@git.zone/cli",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "2.15.0",
|
"version": "2.19.0",
|
||||||
"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.",
|
"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.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
"typings": "dist_ts/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
"@push.rocks/smartpath": "^6.0.0",
|
"@push.rocks/smartpath": "^6.0.0",
|
||||||
"@push.rocks/smartpromise": "^4.2.3",
|
"@push.rocks/smartpromise": "^4.2.3",
|
||||||
"@push.rocks/smartscaf": "^4.0.21",
|
"@push.rocks/smartscaf": "^4.0.21",
|
||||||
"@push.rocks/smartshell": "^3.3.7",
|
"@push.rocks/smartshell": "^3.5.0",
|
||||||
"@push.rocks/smartunique": "^3.0.9",
|
"@push.rocks/smartunique": "^3.0.9",
|
||||||
"@push.rocks/smartupdate": "^2.0.6",
|
"@push.rocks/smartupdate": "^2.0.6",
|
||||||
"prettier": "^3.8.1"
|
"prettier": "^3.8.1"
|
||||||
|
|||||||
Generated
+35
-23
@@ -81,8 +81,8 @@ importers:
|
|||||||
specifier: ^4.0.21
|
specifier: ^4.0.21
|
||||||
version: 4.0.21
|
version: 4.0.21
|
||||||
'@push.rocks/smartshell':
|
'@push.rocks/smartshell':
|
||||||
specifier: ^3.3.7
|
specifier: ^3.5.0
|
||||||
version: 3.3.7
|
version: 3.5.0
|
||||||
'@push.rocks/smartunique':
|
'@push.rocks/smartunique':
|
||||||
specifier: ^3.0.9
|
specifier: ^3.0.9
|
||||||
version: 3.0.9
|
version: 3.0.9
|
||||||
@@ -1063,6 +1063,9 @@ packages:
|
|||||||
'@push.rocks/smartdelay@3.0.5':
|
'@push.rocks/smartdelay@3.0.5':
|
||||||
resolution: {integrity: sha512-mUuI7kj2f7ztjpic96FvRIlf2RsKBa5arw81AHNsndbxO6asRcxuWL8dTVxouEIK8YsBUlj0AsrCkHhMbLQdHw==}
|
resolution: {integrity: sha512-mUuI7kj2f7ztjpic96FvRIlf2RsKBa5arw81AHNsndbxO6asRcxuWL8dTVxouEIK8YsBUlj0AsrCkHhMbLQdHw==}
|
||||||
|
|
||||||
|
'@push.rocks/smartdelay@3.1.0':
|
||||||
|
resolution: {integrity: sha512-59xveBMbWmbFhh/rqhQnYG/klg/VONG9hV8+RQ7ftqsNRkcmUT+VM5etAbODgAUvsF4lxK+xVR0tbZOo0kGhRQ==}
|
||||||
|
|
||||||
'@push.rocks/smartdiff@1.1.0':
|
'@push.rocks/smartdiff@1.1.0':
|
||||||
resolution: {integrity: sha512-AAz/unmko0C+g+60odOoK32PE3Ci3YLoB+zfg1LGLyVRCthcdzjqa1C2Km0MfG7IyJQKPdj8J5HPubtpm3ZeaQ==}
|
resolution: {integrity: sha512-AAz/unmko0C+g+60odOoK32PE3Ci3YLoB+zfg1LGLyVRCthcdzjqa1C2Km0MfG7IyJQKPdj8J5HPubtpm3ZeaQ==}
|
||||||
|
|
||||||
@@ -1192,6 +1195,9 @@ packages:
|
|||||||
'@push.rocks/smartpromise@4.2.3':
|
'@push.rocks/smartpromise@4.2.3':
|
||||||
resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==}
|
resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==}
|
||||||
|
|
||||||
|
'@push.rocks/smartpromise@4.2.4':
|
||||||
|
resolution: {integrity: sha512-8FUyYt94hOIY9mqHjitn4h69u0jbEtTF2RKKw2DpiTVFjpDTk9gXbVHZ/V+xEcBrN4mrzdQES0OiDmkNPoddEQ==}
|
||||||
|
|
||||||
'@push.rocks/smartpuppeteer@2.0.5':
|
'@push.rocks/smartpuppeteer@2.0.5':
|
||||||
resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==}
|
resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==}
|
||||||
|
|
||||||
@@ -1222,8 +1228,8 @@ packages:
|
|||||||
'@push.rocks/smartserve@2.0.1':
|
'@push.rocks/smartserve@2.0.1':
|
||||||
resolution: {integrity: sha512-YQb2qexfCzCqOlLWBBXKMg6xG4zahCPAxomz/KEKAwHtW6wMTtuHKSTSkRTQ0vl9jssLMAmRz2OyafiL9XGJXQ==}
|
resolution: {integrity: sha512-YQb2qexfCzCqOlLWBBXKMg6xG4zahCPAxomz/KEKAwHtW6wMTtuHKSTSkRTQ0vl9jssLMAmRz2OyafiL9XGJXQ==}
|
||||||
|
|
||||||
'@push.rocks/smartshell@3.3.7':
|
'@push.rocks/smartshell@3.5.0':
|
||||||
resolution: {integrity: sha512-b3st2+FjHUVhZZRlXfw93+SQA0UMVlURqe55uVpWdjJX7jeGXTTeszuYygtiR99zC5iZ8WZhGDct3N2L1qc/qw==}
|
resolution: {integrity: sha512-Hx9TVvC/AWxZsnm1GDb+W4Fe58nf1FkKbSBABUgkxct4XRYugBI2z9Twnjm3R9vdRry8oy0enfR9NPVhisGaGA==}
|
||||||
|
|
||||||
'@push.rocks/smartspawn@3.0.3':
|
'@push.rocks/smartspawn@3.0.3':
|
||||||
resolution: {integrity: sha512-DyrGPV69wwOiJgKkyruk5hS3UEGZ99xFAqBE9O2nM8VXCRLbbty3xt1Ug5Z092ZZmJYaaGMSnMw3ijyZJFCT0Q==}
|
resolution: {integrity: sha512-DyrGPV69wwOiJgKkyruk5hS3UEGZ99xFAqBE9O2nM8VXCRLbbty3xt1Ug5Z092ZZmJYaaGMSnMw3ijyZJFCT0Q==}
|
||||||
@@ -3917,9 +3923,9 @@ packages:
|
|||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
which@6.0.1:
|
which@7.0.0:
|
||||||
resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==}
|
resolution: {integrity: sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA==}
|
||||||
engines: {node: ^20.17.0 || >=22.9.0}
|
engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
wordwrap@1.0.0:
|
wordwrap@1.0.0:
|
||||||
@@ -4802,7 +4808,7 @@ snapshots:
|
|||||||
'@push.rocks/smartlog': 3.2.1
|
'@push.rocks/smartlog': 3.2.1
|
||||||
'@push.rocks/smartlog-destination-local': 9.0.2
|
'@push.rocks/smartlog-destination-local': 9.0.2
|
||||||
'@push.rocks/smartpath': 6.0.0
|
'@push.rocks/smartpath': 6.0.0
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
'@push.rocks/smarttime': 4.2.3
|
'@push.rocks/smarttime': 4.2.3
|
||||||
typedoc: 0.28.17(typescript@5.9.3)
|
typedoc: 0.28.17(typescript@5.9.3)
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
@@ -4832,7 +4838,7 @@ snapshots:
|
|||||||
'@push.rocks/smartnpm': 2.0.6
|
'@push.rocks/smartnpm': 2.0.6
|
||||||
'@push.rocks/smartpath': 6.0.0
|
'@push.rocks/smartpath': 6.0.0
|
||||||
'@push.rocks/smartrequest': 5.0.1
|
'@push.rocks/smartrequest': 5.0.1
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@nuxt/kit'
|
- '@nuxt/kit'
|
||||||
- aws-crt
|
- aws-crt
|
||||||
@@ -4845,7 +4851,7 @@ snapshots:
|
|||||||
'@git.zone/tsrun@2.0.1':
|
'@git.zone/tsrun@2.0.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartfile': 13.1.2
|
'@push.rocks/smartfile': 13.1.2
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
tsx: 4.21.0
|
tsx: 4.21.0
|
||||||
|
|
||||||
'@git.zone/tstest@3.3.2(socks@2.8.7)(typescript@5.9.3)':
|
'@git.zone/tstest@3.3.2(socks@2.8.7)(typescript@5.9.3)':
|
||||||
@@ -4870,7 +4876,7 @@ snapshots:
|
|||||||
'@push.rocks/smartrequest': 5.0.1
|
'@push.rocks/smartrequest': 5.0.1
|
||||||
'@push.rocks/smarts3': 5.3.0
|
'@push.rocks/smarts3': 5.3.0
|
||||||
'@push.rocks/smartserve': 2.0.1
|
'@push.rocks/smartserve': 2.0.1
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
'@push.rocks/smarttime': 4.2.3
|
'@push.rocks/smarttime': 4.2.3
|
||||||
'@push.rocks/smartwatch': 6.3.0
|
'@push.rocks/smartwatch': 6.3.0
|
||||||
'@types/ws': 8.18.1
|
'@types/ws': 8.18.1
|
||||||
@@ -5590,7 +5596,7 @@ snapshots:
|
|||||||
'@push.rocks/smartai': 2.0.0(typescript@5.9.3)(ws@8.19.0)(zod@3.25.76)
|
'@push.rocks/smartai': 2.0.0(typescript@5.9.3)(ws@8.19.0)(zod@3.25.76)
|
||||||
'@push.rocks/smartfs': 1.5.0
|
'@push.rocks/smartfs': 1.5.0
|
||||||
'@push.rocks/smartrequest': 5.0.1
|
'@push.rocks/smartrequest': 5.0.1
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
ai: 6.0.116(zod@3.25.76)
|
ai: 6.0.116(zod@3.25.76)
|
||||||
zod: 3.25.76
|
zod: 3.25.76
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -5775,6 +5781,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
|
|
||||||
|
'@push.rocks/smartdelay@3.1.0':
|
||||||
|
dependencies:
|
||||||
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
|
|
||||||
'@push.rocks/smartdiff@1.1.0':
|
'@push.rocks/smartdiff@1.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
diff: 8.0.3
|
diff: 8.0.3
|
||||||
@@ -5818,7 +5828,7 @@ snapshots:
|
|||||||
'@push.rocks/smartexit@2.0.3':
|
'@push.rocks/smartexit@2.0.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.3.1
|
'@push.rocks/lik': 6.3.1
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
|
|
||||||
'@push.rocks/smartexpect@2.5.0':
|
'@push.rocks/smartexpect@2.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5897,7 +5907,7 @@ snapshots:
|
|||||||
'@push.rocks/smartfile': 11.2.7
|
'@push.rocks/smartfile': 11.2.7
|
||||||
'@push.rocks/smartpath': 6.0.0
|
'@push.rocks/smartpath': 6.0.0
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
'@push.rocks/smartstring': 4.1.0
|
'@push.rocks/smartstring': 4.1.0
|
||||||
'@push.rocks/smarttime': 4.2.3
|
'@push.rocks/smarttime': 4.2.3
|
||||||
'@types/diff': 8.0.0
|
'@types/diff': 8.0.0
|
||||||
@@ -5968,7 +5978,7 @@ snapshots:
|
|||||||
'@push.rocks/smartmustache': 3.0.2
|
'@push.rocks/smartmustache': 3.0.2
|
||||||
'@push.rocks/smartpnpm': 1.0.6
|
'@push.rocks/smartpnpm': 1.0.6
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
'@tsclass/tsclass': 4.4.4
|
'@tsclass/tsclass': 4.4.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -6159,14 +6169,16 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartpnpm@1.0.6':
|
'@push.rocks/smartpnpm@1.0.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
|
|
||||||
'@push.rocks/smartpromise@4.2.3': {}
|
'@push.rocks/smartpromise@4.2.3': {}
|
||||||
|
|
||||||
|
'@push.rocks/smartpromise@4.2.4': {}
|
||||||
|
|
||||||
'@push.rocks/smartpuppeteer@2.0.5(typescript@5.9.3)':
|
'@push.rocks/smartpuppeteer@2.0.5(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
puppeteer: 24.35.0(typescript@5.9.3)
|
puppeteer: 24.35.0(typescript@5.9.3)
|
||||||
tree-kill: 1.2.2
|
tree-kill: 1.2.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -6233,7 +6245,7 @@ snapshots:
|
|||||||
'@push.rocks/smartinteract': 2.0.16
|
'@push.rocks/smartinteract': 2.0.16
|
||||||
'@push.rocks/smartobject': 1.0.12
|
'@push.rocks/smartobject': 1.0.12
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartshell': 3.3.7
|
'@push.rocks/smartshell': 3.5.0
|
||||||
'@push.rocks/smartyaml': 3.0.4
|
'@push.rocks/smartyaml': 3.0.4
|
||||||
|
|
||||||
'@push.rocks/smartserve@2.0.1':
|
'@push.rocks/smartserve@2.0.1':
|
||||||
@@ -6249,13 +6261,13 @@ snapshots:
|
|||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
'@push.rocks/smartshell@3.3.7':
|
'@push.rocks/smartshell@3.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.1.0
|
||||||
'@push.rocks/smartexit': 2.0.3
|
'@push.rocks/smartexit': 2.0.3
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.4
|
||||||
'@types/which': 3.0.4
|
'@types/which': 3.0.4
|
||||||
which: 6.0.1
|
which: 7.0.0
|
||||||
|
|
||||||
'@push.rocks/smartspawn@3.0.3':
|
'@push.rocks/smartspawn@3.0.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -9513,7 +9525,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
isexe: 2.0.0
|
isexe: 2.0.0
|
||||||
|
|
||||||
which@6.0.1:
|
which@7.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe: 4.0.0
|
isexe: 4.0.0
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ gitzone release
|
|||||||
| `format` | Plan or apply project formatting and standardization |
|
| `format` | Plan or apply project formatting and standardization |
|
||||||
| `config` | Inspect, update, and migrate `.smartconfig.json` |
|
| `config` | Inspect, update, and migrate `.smartconfig.json` |
|
||||||
| `services` | Manage local MongoDB, MinIO, and Elasticsearch containers |
|
| `services` | Manage local MongoDB, MinIO, and Elasticsearch containers |
|
||||||
|
| `tools` | Manage the global `@git.zone` toolchain |
|
||||||
| `template` | Scaffold projects from built-in templates |
|
| `template` | Scaffold projects from built-in templates |
|
||||||
| `meta` | Manage multi-repository workspaces |
|
| `meta` | Manage multi-repository workspaces |
|
||||||
| `open` | Open repository assets like CI pages |
|
| `open` | Open repository assets like CI pages |
|
||||||
@@ -67,6 +68,23 @@ gitzone release
|
|||||||
|
|
||||||
Global flags include `--help`, `--json`, `--plain`, `--agent`, `--no-interactive`, and `--no-check-updates`.
|
Global flags include `--help`, `--json`, `--plain`, `--agent`, `--no-interactive`, and `--no-check-updates`.
|
||||||
|
|
||||||
|
## Toolchain Management
|
||||||
|
|
||||||
|
`gitzone tools` replaces the former `gtools` command from `@git.zone/tools`. It manages globally installed `@git.zone` development tools through pnpm.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check installed @git.zone tools and update outdated packages
|
||||||
|
gitzone tools update
|
||||||
|
|
||||||
|
# Update without prompts
|
||||||
|
gitzone tools update -y
|
||||||
|
|
||||||
|
# Install missing managed @git.zone tools
|
||||||
|
gitzone tools install
|
||||||
|
```
|
||||||
|
|
||||||
|
`gitzone tools update` checks `@git.zone/cli` first. If the CLI itself needs an update, it updates `@git.zone/cli` and asks you to rerun the command before updating the rest of the toolchain.
|
||||||
|
|
||||||
## Commit Workflow
|
## Commit Workflow
|
||||||
|
|
||||||
`gitzone commit` creates one semantic source commit. It does not bump versions, create tags, publish packages, or push Docker images.
|
`gitzone commit` creates one semantic source commit. It does not bump versions, create tags, publish packages, or push Docker images.
|
||||||
@@ -129,7 +147,7 @@ Targets decide what happens after that:
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `git` | Pushes the release commit and tags, often triggering remote CI release builds |
|
| `git` | Pushes the release commit and tags, often triggering remote CI release builds |
|
||||||
| `npm` | Publishes the package to configured npm registries |
|
| `npm` | Publishes the package to configured npm registries |
|
||||||
| `docker` | Builds and pushes configured Docker images |
|
| `docker` | Delegates container builds and pushes to `tsdocker` |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Preview the resolved release plan
|
# Preview the resolved release plan
|
||||||
@@ -187,7 +205,7 @@ The standard buckets are `Breaking Changes`, `Features`, `Fixes`, `Documentation
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
All CLI config lives under `@git.zone/cli` in `.smartconfig.json`.
|
CLI workflow config lives under `@git.zone/cli` in `.smartconfig.json`. Docker build and registry behavior lives under `@git.zone/tsdocker` and is used by the Docker release target.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -219,11 +237,21 @@ All CLI config lives under `@git.zone/cli` in `.smartconfig.json`.
|
|||||||
"alreadyPublished": "success"
|
"alreadyPublished": "success"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"enabled": false,
|
"enabled": true,
|
||||||
"images": []
|
"engine": "tsdocker",
|
||||||
|
"patterns": [],
|
||||||
|
"cached": true,
|
||||||
|
"parallel": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"@git.zone/tsdocker": {
|
||||||
|
"registries": ["registry.gitlab.com"],
|
||||||
|
"registryRepoMap": {
|
||||||
|
"registry.gitlab.com": "myorg/myproject"
|
||||||
|
},
|
||||||
|
"platforms": ["linux/amd64", "linux/arm64"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -234,12 +262,29 @@ NPM registries belong only here:
|
|||||||
@git.zone/cli.release.targets.npm.registries
|
@git.zone/cli.release.targets.npm.registries
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Docker registries belong only here and should be registry hosts without `http://` or `https://`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
@git.zone/tsdocker.registries
|
||||||
|
```
|
||||||
|
|
||||||
Useful config commands:
|
Useful config commands:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Show current @git.zone/cli config
|
# Show current @git.zone/cli config
|
||||||
gitzone config show --json
|
gitzone config show --json
|
||||||
|
|
||||||
|
# Configure project basics, CLI behavior, and release targets interactively
|
||||||
|
gitzone config project
|
||||||
|
gitzone config cli
|
||||||
|
gitzone config release
|
||||||
|
|
||||||
|
# Validate schema, legacy keys, release targets, registries, and npm auth
|
||||||
|
gitzone config doctor
|
||||||
|
|
||||||
|
# Use opencode to repair configuration issues found by doctor
|
||||||
|
gitzone config fix
|
||||||
|
|
||||||
# Read the npm release target registries
|
# Read the npm release target registries
|
||||||
gitzone config get release.targets.npm.registries
|
gitzone config get release.targets.npm.registries
|
||||||
|
|
||||||
@@ -386,7 +431,7 @@ gitzone config show --json
|
|||||||
|
|
||||||
## License and Legal Information
|
## License and Legal Information
|
||||||
|
|
||||||
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./license) file.
|
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license](./license) file.
|
||||||
|
|
||||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/cli',
|
name: '@git.zone/cli',
|
||||||
version: '2.15.0',
|
version: '2.19.0',
|
||||||
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.'
|
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.'
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-2
@@ -2,6 +2,7 @@ import * as plugins from "./plugins.js";
|
|||||||
import * as paths from "./paths.js";
|
import * as paths from "./paths.js";
|
||||||
import { GitzoneConfig } from "./classes.gitzoneconfig.js";
|
import { GitzoneConfig } from "./classes.gitzoneconfig.js";
|
||||||
import { getRawCliMode } from "./helpers.climode.js";
|
import { getRawCliMode } from "./helpers.climode.js";
|
||||||
|
import { commitinfo } from "./00_commitinfo_data.js";
|
||||||
|
|
||||||
const gitzoneSmartcli = new plugins.smartcli.Smartcli();
|
const gitzoneSmartcli = new plugins.smartcli.Smartcli();
|
||||||
|
|
||||||
@@ -11,20 +12,29 @@ export let run = async () => {
|
|||||||
|
|
||||||
// get packageInfo
|
// get packageInfo
|
||||||
const projectInfo = new plugins.projectinfo.ProjectInfo(paths.packageDir);
|
const projectInfo = new plugins.projectinfo.ProjectInfo(paths.packageDir);
|
||||||
|
const projectInfoVersion = (projectInfo.npm as any)?.version;
|
||||||
|
const packageVersion =
|
||||||
|
typeof projectInfoVersion === "string" && projectInfoVersion.length > 0
|
||||||
|
? projectInfoVersion
|
||||||
|
: commitinfo.version;
|
||||||
|
|
||||||
// check for updates
|
// check for updates
|
||||||
if (rawCliMode.checkUpdates) {
|
if (rawCliMode.checkUpdates) {
|
||||||
const smartupdateInstance = new plugins.smartupdate.SmartUpdate();
|
const smartupdateInstance = new plugins.smartupdate.SmartUpdate();
|
||||||
|
try {
|
||||||
await smartupdateInstance.check(
|
await smartupdateInstance.check(
|
||||||
"gitzone",
|
"gitzone",
|
||||||
projectInfo.npm.version,
|
packageVersion,
|
||||||
"http://gitzone.gitlab.io/gitzone/changelog.html",
|
"http://gitzone.gitlab.io/gitzone/changelog.html",
|
||||||
);
|
);
|
||||||
|
} catch {
|
||||||
|
// Update checks must never block actual CLI commands.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (rawCliMode.output === "human") {
|
if (rawCliMode.output === "human") {
|
||||||
console.log("---------------------------------------------");
|
console.log("---------------------------------------------");
|
||||||
}
|
}
|
||||||
gitzoneSmartcli.addVersion(projectInfo.npm.version);
|
gitzoneSmartcli.addVersion(packageVersion);
|
||||||
|
|
||||||
// ======> Standard task <======
|
// ======> Standard task <======
|
||||||
|
|
||||||
@@ -137,6 +147,14 @@ export let run = async () => {
|
|||||||
modHelpers.run(argvArg);
|
modHelpers.run(argvArg);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manage the global @git.zone toolchain
|
||||||
|
*/
|
||||||
|
gitzoneSmartcli.addCommand("tools").subscribe(async (argvArg) => {
|
||||||
|
const modTools = await import("./mod_tools/index.js");
|
||||||
|
await modTools.run(argvArg);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* manage release configuration
|
* manage release configuration
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -68,8 +68,10 @@ const migrateToV2 = (smartconfigJson: Record<string, any>): boolean => {
|
|||||||
migrated = true;
|
migrated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPlainObject(releaseConfig.docker) && !isPlainObject(targets.docker)) {
|
if (isPlainObject(releaseConfig.docker)) {
|
||||||
targets.docker = releaseConfig.docker;
|
targets.docker = isPlainObject(targets.docker)
|
||||||
|
? { ...releaseConfig.docker, ...targets.docker }
|
||||||
|
: releaseConfig.docker;
|
||||||
delete releaseConfig.docker;
|
delete releaseConfig.docker;
|
||||||
migrated = true;
|
migrated = true;
|
||||||
}
|
}
|
||||||
@@ -141,11 +143,27 @@ const migrateToV2 = (smartconfigJson: Record<string, any>): boolean => {
|
|||||||
if (dockerTarget.enabled === undefined) {
|
if (dockerTarget.enabled === undefined) {
|
||||||
dockerTarget.enabled = true;
|
dockerTarget.enabled = true;
|
||||||
}
|
}
|
||||||
|
dockerTarget.engine = "tsdocker";
|
||||||
}
|
}
|
||||||
delete releaseConfig.steps;
|
delete releaseConfig.steps;
|
||||||
migrated = true;
|
migrated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isPlainObject(targets.docker)) {
|
||||||
|
if (targets.docker.images) {
|
||||||
|
delete targets.docker.images;
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
if (targets.docker.engine !== "tsdocker") {
|
||||||
|
targets.docker.engine = "tsdocker";
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(targets.docker.patterns)) {
|
||||||
|
targets.docker.patterns = [];
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (releaseConfig.changelog) {
|
if (releaseConfig.changelog) {
|
||||||
delete releaseConfig.changelog;
|
delete releaseConfig.changelog;
|
||||||
migrated = true;
|
migrated = true;
|
||||||
|
|||||||
+20
-3
@@ -52,7 +52,12 @@ export interface IReleaseNpmTargetConfig {
|
|||||||
|
|
||||||
export interface IReleaseDockerTargetConfig {
|
export interface IReleaseDockerTargetConfig {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
images?: string[];
|
engine?: "tsdocker";
|
||||||
|
patterns?: string[];
|
||||||
|
cached?: boolean;
|
||||||
|
parallel?: boolean | number;
|
||||||
|
context?: string;
|
||||||
|
noBuild?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IReleaseWorkflowConfig {
|
export interface IReleaseWorkflowConfig {
|
||||||
@@ -109,7 +114,12 @@ export interface IResolvedReleaseWorkflow {
|
|||||||
npmAccessLevel: "public" | "private";
|
npmAccessLevel: "public" | "private";
|
||||||
npmAlreadyPublished: "success" | "error";
|
npmAlreadyPublished: "success" | "error";
|
||||||
dockerEnabled: boolean;
|
dockerEnabled: boolean;
|
||||||
dockerImages: string[];
|
dockerEngine: "tsdocker";
|
||||||
|
dockerPatterns: string[];
|
||||||
|
dockerCached: boolean;
|
||||||
|
dockerParallel: boolean | number;
|
||||||
|
dockerContext?: string;
|
||||||
|
dockerNoBuild: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICliWorkflowConfig {
|
interface ICliWorkflowConfig {
|
||||||
@@ -382,6 +392,13 @@ export const resolveReleaseWorkflow = async (argvArg: any): Promise<IResolvedRel
|
|||||||
npmAccessLevel: npmConfig.accessLevel || "public",
|
npmAccessLevel: npmConfig.accessLevel || "public",
|
||||||
npmAlreadyPublished: npmConfig.alreadyPublished || "success",
|
npmAlreadyPublished: npmConfig.alreadyPublished || "success",
|
||||||
dockerEnabled,
|
dockerEnabled,
|
||||||
dockerImages: dockerConfig.images || [],
|
dockerEngine: "tsdocker",
|
||||||
|
dockerPatterns: Array.isArray(dockerConfig.patterns) ? dockerConfig.patterns : [],
|
||||||
|
dockerCached: dockerConfig.cached ?? false,
|
||||||
|
dockerParallel: dockerConfig.parallel ?? false,
|
||||||
|
dockerContext: typeof dockerConfig.context === "string" && dockerConfig.context.trim()
|
||||||
|
? dockerConfig.context.trim()
|
||||||
|
: undefined,
|
||||||
|
dockerNoBuild: dockerConfig.noBuild ?? false,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
+1306
-25
File diff suppressed because it is too large
Load Diff
+44
-21
@@ -107,7 +107,7 @@ export const run = async (argvArg: any) => {
|
|||||||
npmResults.push(...(await runNpmTarget(smartshellInstance, workflow)));
|
npmResults.push(...(await runNpmTarget(smartshellInstance, workflow)));
|
||||||
}
|
}
|
||||||
if (workflow.targets.includes("docker")) {
|
if (workflow.targets.includes("docker")) {
|
||||||
dockerResults.push(...(await runDockerTarget(smartshellInstance, workflow, newVersion)));
|
dockerResults.push(...(await runDockerTarget(smartshellInstance, workflow)));
|
||||||
}
|
}
|
||||||
|
|
||||||
printReleaseSummary(newVersion, gitResults, npmResults, dockerResults);
|
printReleaseSummary(newVersion, gitResults, npmResults, dockerResults);
|
||||||
@@ -262,31 +262,43 @@ async function runNpmTarget(
|
|||||||
async function runDockerTarget(
|
async function runDockerTarget(
|
||||||
smartshellInstance: plugins.smartshell.Smartshell,
|
smartshellInstance: plugins.smartshell.Smartshell,
|
||||||
workflow: IResolvedReleaseWorkflow,
|
workflow: IResolvedReleaseWorkflow,
|
||||||
newVersion: string,
|
|
||||||
): Promise<ITargetResult[]> {
|
): Promise<ITargetResult[]> {
|
||||||
if (!workflow.dockerEnabled) {
|
if (!workflow.dockerEnabled) {
|
||||||
return [{ target: "docker", status: "skipped", message: "disabled" }];
|
return [{ target: "docker", status: "skipped", message: "disabled" }];
|
||||||
}
|
}
|
||||||
if (workflow.dockerImages.length === 0) {
|
|
||||||
return [{ target: "docker", status: "failed", message: "no images configured" }];
|
const command = buildTsdockerPushCommand(workflow);
|
||||||
|
const result = await smartshellInstance.exec(command);
|
||||||
|
const output = `${result.stdout || ""}\n${(result as any).stderr || ""}\n${(result as any).combinedOutput || ""}`;
|
||||||
|
return [{
|
||||||
|
target: workflow.dockerPatterns.length > 0
|
||||||
|
? `tsdocker:${workflow.dockerPatterns.join(",")}`
|
||||||
|
: "tsdocker",
|
||||||
|
status: result.exitCode === 0 ? "success" : "failed",
|
||||||
|
message: result.exitCode === 0 ? undefined : firstMeaningfulLine(output),
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
const results: ITargetResult[] = [];
|
function buildTsdockerPushCommand(workflow: IResolvedReleaseWorkflow): string {
|
||||||
for (const imageTemplate of workflow.dockerImages) {
|
const commandParts = ["tsdocker", "push"];
|
||||||
const image = imageTemplate.replaceAll("{{version}}", newVersion);
|
if (workflow.dockerNoBuild) {
|
||||||
const buildResult = await smartshellInstance.exec(`docker build -t ${shellQuote(image)} .`);
|
commandParts.push("--no-build");
|
||||||
if (buildResult.exitCode !== 0) {
|
|
||||||
results.push({ target: image, status: "failed", message: "docker build failed" });
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const pushResult = await smartshellInstance.exec(`docker push ${shellQuote(image)}`);
|
if (workflow.dockerCached) {
|
||||||
results.push({
|
commandParts.push("--cached");
|
||||||
target: image,
|
|
||||||
status: pushResult.exitCode === 0 ? "success" : "failed",
|
|
||||||
message: pushResult.exitCode === 0 ? undefined : "docker push failed",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return results;
|
if (workflow.dockerParallel === true) {
|
||||||
|
commandParts.push("--parallel");
|
||||||
|
} else if (typeof workflow.dockerParallel === "number" && Number.isFinite(workflow.dockerParallel) && workflow.dockerParallel > 0) {
|
||||||
|
commandParts.push(`--parallel=${Math.floor(workflow.dockerParallel)}`);
|
||||||
|
}
|
||||||
|
if (workflow.dockerContext) {
|
||||||
|
commandParts.push(`--context=${shellQuote(workflow.dockerContext)}`);
|
||||||
|
}
|
||||||
|
for (const pattern of workflow.dockerPatterns) {
|
||||||
|
commandParts.push(shellQuote(pattern));
|
||||||
|
}
|
||||||
|
return commandParts.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAlreadyPublishedOutput(output: string): boolean {
|
function isAlreadyPublishedOutput(output: string): boolean {
|
||||||
@@ -315,11 +327,22 @@ function printReleasePlan(workflow: IResolvedReleaseWorkflow): void {
|
|||||||
console.log(`npm registries: ${workflow.npmRegistries.length > 0 ? workflow.npmRegistries.join(", ") : "none"}`);
|
console.log(`npm registries: ${workflow.npmRegistries.length > 0 ? workflow.npmRegistries.join(", ") : "none"}`);
|
||||||
}
|
}
|
||||||
if (workflow.targets.includes("docker")) {
|
if (workflow.targets.includes("docker")) {
|
||||||
console.log(`docker images: ${workflow.dockerImages.length > 0 ? workflow.dockerImages.join(", ") : "none"}`);
|
console.log(`docker engine: ${workflow.dockerEngine}`);
|
||||||
|
console.log(`docker patterns: ${workflow.dockerPatterns.length > 0 ? workflow.dockerPatterns.join(", ") : "all Dockerfiles"}`);
|
||||||
|
console.log(`docker options: ${formatDockerOptions(workflow)}`);
|
||||||
}
|
}
|
||||||
console.log("");
|
console.log("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatDockerOptions(workflow: IResolvedReleaseWorkflow): string {
|
||||||
|
const options: string[] = [];
|
||||||
|
if (workflow.dockerCached) options.push("cached");
|
||||||
|
if (workflow.dockerParallel) options.push(`parallel=${workflow.dockerParallel === true ? "true" : workflow.dockerParallel}`);
|
||||||
|
if (workflow.dockerNoBuild) options.push("no-build");
|
||||||
|
if (workflow.dockerContext) options.push(`context=${workflow.dockerContext}`);
|
||||||
|
return options.length > 0 ? options.join(", ") : "default";
|
||||||
|
}
|
||||||
|
|
||||||
function printReleaseSummary(
|
function printReleaseSummary(
|
||||||
newVersion: string,
|
newVersion: string,
|
||||||
gitResults: ITargetResult[],
|
gitResults: ITargetResult[],
|
||||||
@@ -365,7 +388,7 @@ export function showHelp(mode?: ICliMode): void {
|
|||||||
{ flag: "-p, --push", description: "Enable the git release target" },
|
{ flag: "-p, --push", description: "Enable the git release target" },
|
||||||
{ flag: "--target <names>", description: "Release only selected targets: git,npm,docker" },
|
{ flag: "--target <names>", description: "Release only selected targets: git,npm,docker" },
|
||||||
{ flag: "--npm", description: "Enable the npm release target" },
|
{ flag: "--npm", description: "Enable the npm release target" },
|
||||||
{ flag: "--docker", description: "Enable the Docker release target" },
|
{ flag: "--docker", description: "Enable the tsdocker release target" },
|
||||||
{ flag: "--no-publish", description: "Run release core and git target only" },
|
{ flag: "--no-publish", description: "Run release core and git target only" },
|
||||||
{ flag: "--plan", description: "Show resolved workflow without mutating files" },
|
{ flag: "--plan", description: "Show resolved workflow without mutating files" },
|
||||||
],
|
],
|
||||||
@@ -385,7 +408,7 @@ export function showHelp(mode?: ICliMode): void {
|
|||||||
console.log(" -p, --push Enable the git release target");
|
console.log(" -p, --push Enable the git release target");
|
||||||
console.log(" --target <names> Release only selected targets: git,npm,docker");
|
console.log(" --target <names> Release only selected targets: git,npm,docker");
|
||||||
console.log(" --npm Enable the npm release target");
|
console.log(" --npm Enable the npm release target");
|
||||||
console.log(" --docker Enable the Docker release target");
|
console.log(" --docker Enable the tsdocker release target");
|
||||||
console.log(" --no-publish Run release core and git target only");
|
console.log(" --no-publish Run release core and git target only");
|
||||||
console.log(" --major|--minor|--patch Override inferred semver level");
|
console.log(" --major|--minor|--patch Override inferred semver level");
|
||||||
console.log(" --plan Show resolved workflow without mutating files");
|
console.log(" --plan Show resolved workflow without mutating files");
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const commandSummaries: ICommandHelpSummary[] = [
|
|||||||
{ name: "format", description: "Plan or apply project formatting changes" },
|
{ name: "format", description: "Plan or apply project formatting changes" },
|
||||||
{ name: "config", description: "Read and change .smartconfig.json settings" },
|
{ name: "config", description: "Read and change .smartconfig.json settings" },
|
||||||
{ name: "services", description: "Manage or configure development services" },
|
{ name: "services", description: "Manage or configure development services" },
|
||||||
|
{ name: "tools", description: "Manage the global @git.zone toolchain" },
|
||||||
{ name: "template", description: "Create a project from a template" },
|
{ name: "template", description: "Create a project from a template" },
|
||||||
{ name: "open", description: "Open project assets and CI pages" },
|
{ name: "open", description: "Open project assets and CI pages" },
|
||||||
{ name: "docker", description: "Run Docker-related maintenance tasks" },
|
{ name: "docker", description: "Run Docker-related maintenance tasks" },
|
||||||
@@ -75,6 +76,7 @@ export let run = async (argvArg: any = {}) => {
|
|||||||
{ name: "Configure release settings", value: "config" },
|
{ name: "Configure release settings", value: "config" },
|
||||||
{ name: "Create from template", value: "template" },
|
{ name: "Create from template", value: "template" },
|
||||||
{ name: "Manage dev services (MongoDB, S3)", value: "services" },
|
{ name: "Manage dev services (MongoDB, S3)", value: "services" },
|
||||||
|
{ name: "Manage global @git.zone tools", value: "tools" },
|
||||||
{ name: "Open project assets", value: "open" },
|
{ name: "Open project assets", value: "open" },
|
||||||
{ name: "Show help", value: "help" },
|
{ name: "Show help", value: "help" },
|
||||||
],
|
],
|
||||||
@@ -113,6 +115,11 @@ export let run = async (argvArg: any = {}) => {
|
|||||||
await modServices.run({ _: ["services"] });
|
await modServices.run({ _: ["services"] });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "tools": {
|
||||||
|
const modTools = await import("../mod_tools/index.js");
|
||||||
|
await modTools.run({ _: ["tools"] });
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "open": {
|
case "open": {
|
||||||
const modOpen = await import("../mod_open/index.js");
|
const modOpen = await import("../mod_open/index.js");
|
||||||
await modOpen.run({ _: ["open"] });
|
await modOpen.run({ _: ["open"] });
|
||||||
@@ -196,6 +203,7 @@ export async function showHelp(
|
|||||||
console.log(" gitzone release --plan");
|
console.log(" gitzone release --plan");
|
||||||
console.log(" gitzone format plan --json");
|
console.log(" gitzone format plan --json");
|
||||||
console.log(" gitzone services set mongodb,minio");
|
console.log(" gitzone services set mongodb,minio");
|
||||||
|
console.log(" gitzone tools update");
|
||||||
console.log("");
|
console.log("");
|
||||||
console.log("Run gitzone <command> --help for command-specific usage.");
|
console.log("Run gitzone <command> --help for command-specific usage.");
|
||||||
console.log("");
|
console.log("");
|
||||||
@@ -231,6 +239,11 @@ async function showCommandHelp(
|
|||||||
modServices.showHelp(mode);
|
modServices.showHelp(mode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case "tools": {
|
||||||
|
const modTools = await import("../mod_tools/index.js");
|
||||||
|
modTools.showHelp(mode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
import * as plugins from "./mod.plugins.js";
|
||||||
|
|
||||||
|
export interface IInstalledPackage {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPackageUpdateInfo {
|
||||||
|
name: string;
|
||||||
|
currentVersion: string;
|
||||||
|
latestVersion: string;
|
||||||
|
needsUpdate: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPackageManagerInfo {
|
||||||
|
available: boolean;
|
||||||
|
currentVersion: string;
|
||||||
|
latestVersion: string | null;
|
||||||
|
needsUpdate: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PackageManagerUtil {
|
||||||
|
private shell = new plugins.smartshell.Smartshell({
|
||||||
|
executor: "bash",
|
||||||
|
});
|
||||||
|
|
||||||
|
public async detectPnpm(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const result = await this.shell.execSilent("pnpm --version 2>/dev/null");
|
||||||
|
return result.exitCode === 0 && Boolean(result.stdout.trim());
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getPnpmVersionInfo(): Promise<IPackageManagerInfo> {
|
||||||
|
const available = await this.detectPnpm();
|
||||||
|
if (!available) {
|
||||||
|
return {
|
||||||
|
available: false,
|
||||||
|
currentVersion: "unknown",
|
||||||
|
latestVersion: null,
|
||||||
|
needsUpdate: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentVersion = await this.getCurrentPnpmVersion();
|
||||||
|
const latestVersion = await this.getLatestVersion("pnpm", ["https://registry.npmjs.org"]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
available: true,
|
||||||
|
currentVersion,
|
||||||
|
latestVersion,
|
||||||
|
needsUpdate: latestVersion ? this.isNewerVersion(currentVersion, latestVersion) : false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getInstalledPackages(): Promise<IInstalledPackage[]> {
|
||||||
|
const packages: IInstalledPackage[] = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await this.shell.execSilent("pnpm list -g --depth=0 --json 2>/dev/null || true");
|
||||||
|
const output = result.stdout.trim();
|
||||||
|
if (!output) {
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = JSON.parse(output);
|
||||||
|
const dataArray = Array.isArray(data) ? data : [data];
|
||||||
|
for (const item of dataArray) {
|
||||||
|
const dependencies = item.dependencies || {};
|
||||||
|
for (const [name, info] of Object.entries(dependencies)) {
|
||||||
|
if (!name.startsWith("@git.zone/")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
packages.push({
|
||||||
|
name,
|
||||||
|
version: (info as any).version || "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getLatestVersion(
|
||||||
|
packageName: string,
|
||||||
|
registries = ["https://verdaccio.lossless.digital", "https://registry.npmjs.org"],
|
||||||
|
): Promise<string | null> {
|
||||||
|
for (const registry of registries) {
|
||||||
|
const latest = await this.getLatestVersionFromRegistry(registry, packageName);
|
||||||
|
if (latest) {
|
||||||
|
return latest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async installLatest(packageName: string): Promise<boolean> {
|
||||||
|
const packageSpecifier = `${packageName}@latest`;
|
||||||
|
console.log(` Installing ${packageSpecifier} via pnpm...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await this.shell.exec(`pnpm add -g ${shellQuote(packageSpecifier)}`);
|
||||||
|
return result.exitCode === 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public isNewerVersion(current: string, latest: string): boolean {
|
||||||
|
const currentParts = normalizeSemver(current);
|
||||||
|
const latestParts = normalizeSemver(latest);
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
|
||||||
|
const currentPart = currentParts[i] || 0;
|
||||||
|
const latestPart = latestParts[i] || 0;
|
||||||
|
if (latestPart > currentPart) return true;
|
||||||
|
if (latestPart < currentPart) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getCurrentPnpmVersion(): Promise<string> {
|
||||||
|
try {
|
||||||
|
const result = await this.shell.execSilent("pnpm --version 2>/dev/null");
|
||||||
|
const versionMatch = result.stdout.trim().match(/(\d+\.\d+\.\d+)/);
|
||||||
|
return versionMatch?.[1] || "unknown";
|
||||||
|
} catch {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getLatestVersionFromRegistry(
|
||||||
|
registry: string,
|
||||||
|
packageName: string,
|
||||||
|
): Promise<string | null> {
|
||||||
|
const encodedName = packageName.replace("/", "%2f");
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeout = setTimeout(() => controller.abort(), 8000);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${registry}/${encodedName}`, {
|
||||||
|
signal: controller.signal,
|
||||||
|
headers: {
|
||||||
|
accept: "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
const latest = (data as any)["dist-tags"]?.latest;
|
||||||
|
return typeof latest === "string" && latest.length > 0 ? latest : null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSemver(version: string): number[] {
|
||||||
|
return version
|
||||||
|
.replace(/^[^\d]*/, "")
|
||||||
|
.split(".")
|
||||||
|
.map((part) => parseInt(part, 10) || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shellQuote(value: string): string {
|
||||||
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
||||||
|
}
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
import * as plugins from "./mod.plugins.js";
|
||||||
|
import { commitinfo } from "../00_commitinfo_data.js";
|
||||||
|
import type { ICliMode } from "../helpers.climode.js";
|
||||||
|
import { getCliMode, printJson } from "../helpers.climode.js";
|
||||||
|
import {
|
||||||
|
PackageManagerUtil,
|
||||||
|
type IInstalledPackage,
|
||||||
|
type IPackageUpdateInfo,
|
||||||
|
} from "./classes.packagemanager.js";
|
||||||
|
|
||||||
|
export const GITZONE_PACKAGES = [
|
||||||
|
"@git.zone/cli",
|
||||||
|
"@git.zone/tsdoc",
|
||||||
|
"@git.zone/tsbuild",
|
||||||
|
"@git.zone/tstest",
|
||||||
|
"@git.zone/tspublish",
|
||||||
|
"@git.zone/tsbundle",
|
||||||
|
"@git.zone/tsdocker",
|
||||||
|
"@git.zone/tsview",
|
||||||
|
"@git.zone/tswatch",
|
||||||
|
"@git.zone/tsrust",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const run = async (argvArg: any = {}): Promise<void> => {
|
||||||
|
const mode = await getCliMode(argvArg);
|
||||||
|
const command = argvArg._?.[1] || "help";
|
||||||
|
|
||||||
|
if (mode.help || command === "help") {
|
||||||
|
showHelp(mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case "update":
|
||||||
|
await runUpdate(argvArg, mode);
|
||||||
|
break;
|
||||||
|
case "install":
|
||||||
|
await runInstall(argvArg, mode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
showHelp(mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function runUpdate(argvArg: any, mode: ICliMode): Promise<void> {
|
||||||
|
const verbose = Boolean(argvArg.v || argvArg.verbose);
|
||||||
|
const pmUtil = new PackageManagerUtil();
|
||||||
|
|
||||||
|
console.log("Scanning for installed @git.zone packages...\n");
|
||||||
|
|
||||||
|
const pnpmInfo = await pmUtil.getPnpmVersionInfo();
|
||||||
|
if (!pnpmInfo.available) {
|
||||||
|
console.log("pnpm is required for gitzone tools update, but it was not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Package manager:\n");
|
||||||
|
console.log(" Name Current Latest Status");
|
||||||
|
console.log(" ----------------------------------------------");
|
||||||
|
const latestPnpm = (pnpmInfo.latestVersion || "unknown").padEnd(12);
|
||||||
|
const pnpmStatus = pnpmInfo.latestVersion === null
|
||||||
|
? "? Version unknown"
|
||||||
|
: pnpmInfo.needsUpdate
|
||||||
|
? "Update available"
|
||||||
|
: "Up to date";
|
||||||
|
console.log(` ${"pnpm".padEnd(9)}${pnpmInfo.currentVersion.padEnd(12)}${latestPnpm}${pnpmStatus}`);
|
||||||
|
console.log("");
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
console.log("Using pnpm as the supported global package manager.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
const selfUpdated = await handleSelfUpdate(pmUtil, mode);
|
||||||
|
if (selfUpdated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const installedPackages = await pmUtil.getInstalledPackages();
|
||||||
|
const packageInfos = await getPackageUpdateInfos(pmUtil, installedPackages);
|
||||||
|
|
||||||
|
if (packageInfos.length === 0) {
|
||||||
|
console.log("No managed @git.zone packages found installed globally.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Installed @git.zone packages:\n");
|
||||||
|
console.log(" Package Current Latest Status");
|
||||||
|
console.log(" ------------------------------------------------------------");
|
||||||
|
for (const packageInfo of packageInfos) {
|
||||||
|
const status = packageInfo.latestVersion === "unknown"
|
||||||
|
? "? Version unknown"
|
||||||
|
: packageInfo.needsUpdate
|
||||||
|
? "Update available"
|
||||||
|
: "Up to date";
|
||||||
|
console.log(
|
||||||
|
` ${packageInfo.name.padEnd(28)}${packageInfo.currentVersion.padEnd(12)}${packageInfo.latestVersion.padEnd(12)}${status}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
console.log("");
|
||||||
|
|
||||||
|
await printMissingPackages(pmUtil, installedPackages);
|
||||||
|
|
||||||
|
const packagesToUpdate = packageInfos.filter((packageInfo) => packageInfo.needsUpdate);
|
||||||
|
if (packagesToUpdate.length === 0) {
|
||||||
|
console.log("All managed packages are up to date.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Found ${packagesToUpdate.length} package(s) with available updates.\n`);
|
||||||
|
|
||||||
|
if (!mode.yes && !mode.interactive) {
|
||||||
|
console.log("Run gitzone tools update -y to update without prompts.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shouldUpdate = mode.yes;
|
||||||
|
if (!shouldUpdate) {
|
||||||
|
const interactInstance = new plugins.smartinteract.SmartInteract();
|
||||||
|
const answer = await interactInstance.askQuestion({
|
||||||
|
type: "confirm",
|
||||||
|
name: "confirmUpdate",
|
||||||
|
message: "Do you want to update these packages?",
|
||||||
|
default: true,
|
||||||
|
});
|
||||||
|
shouldUpdate = answer.value === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldUpdate) {
|
||||||
|
console.log("Update cancelled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await installPackages(pmUtil, packagesToUpdate.map((packageInfo) => packageInfo.name), "updated");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runInstall(argvArg: any, mode: ICliMode): Promise<void> {
|
||||||
|
const verbose = Boolean(argvArg.v || argvArg.verbose);
|
||||||
|
const pmUtil = new PackageManagerUtil();
|
||||||
|
|
||||||
|
console.log("Scanning for missing @git.zone packages...\n");
|
||||||
|
|
||||||
|
const pnpmAvailable = await pmUtil.detectPnpm();
|
||||||
|
if (!pnpmAvailable) {
|
||||||
|
console.log("pnpm is required for gitzone tools install, but it was not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
console.log("Using pnpm as the supported global package manager.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
const installedPackages = await pmUtil.getInstalledPackages();
|
||||||
|
const installedNames = new Set(installedPackages.map((packageInfo) => packageInfo.name));
|
||||||
|
const missingPackages = GITZONE_PACKAGES.filter((packageName) => !installedNames.has(packageName));
|
||||||
|
|
||||||
|
if (missingPackages.length === 0) {
|
||||||
|
console.log("All managed @git.zone packages are already installed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Found ${missingPackages.length} missing package(s).\n`);
|
||||||
|
|
||||||
|
if (!mode.yes && !mode.interactive) {
|
||||||
|
await printPackageListWithLatest(pmUtil, missingPackages);
|
||||||
|
console.log("Run gitzone tools install -y to install all missing packages without prompts.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let selectedPackages = missingPackages;
|
||||||
|
if (!mode.yes) {
|
||||||
|
const choicesWithVersions: Array<{ name: string; value: string }> = [];
|
||||||
|
for (const packageName of missingPackages) {
|
||||||
|
const latest = await pmUtil.getLatestVersion(packageName);
|
||||||
|
choicesWithVersions.push({
|
||||||
|
name: `${packageName}${latest ? `@${latest}` : ""}`,
|
||||||
|
value: packageName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const interactInstance = new plugins.smartinteract.SmartInteract();
|
||||||
|
const answer = await interactInstance.askQuestion({
|
||||||
|
type: "checkbox",
|
||||||
|
name: "packages",
|
||||||
|
message: "Select packages to install:",
|
||||||
|
default: missingPackages,
|
||||||
|
choices: choicesWithVersions,
|
||||||
|
});
|
||||||
|
|
||||||
|
selectedPackages = answer.value as string[];
|
||||||
|
if (selectedPackages.length === 0) {
|
||||||
|
console.log("No packages selected. Nothing to install.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await installPackages(pmUtil, selectedPackages, "installed");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSelfUpdate(
|
||||||
|
pmUtil: PackageManagerUtil,
|
||||||
|
mode: ICliMode,
|
||||||
|
): Promise<boolean> {
|
||||||
|
console.log("Checking for gitzone self-update...\n");
|
||||||
|
const currentVersion = commitinfo.version;
|
||||||
|
const latestVersion = await pmUtil.getLatestVersion("@git.zone/cli");
|
||||||
|
|
||||||
|
if (!latestVersion || !pmUtil.isNewerVersion(currentVersion, latestVersion)) {
|
||||||
|
console.log(` @git.zone/cli ${currentVersion} Up to date\n`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` @git.zone/cli ${currentVersion} -> ${latestVersion} Update available\n`);
|
||||||
|
|
||||||
|
if (!mode.yes && !mode.interactive) {
|
||||||
|
console.log("Run gitzone tools update -y to update gitzone first.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shouldUpdate = mode.yes;
|
||||||
|
if (!shouldUpdate) {
|
||||||
|
const interactInstance = new plugins.smartinteract.SmartInteract();
|
||||||
|
const answer = await interactInstance.askQuestion({
|
||||||
|
type: "confirm",
|
||||||
|
name: "confirmSelfUpdate",
|
||||||
|
message: "Do you want to update gitzone itself first?",
|
||||||
|
default: true,
|
||||||
|
});
|
||||||
|
shouldUpdate = answer.value === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldUpdate) {
|
||||||
|
console.log("Skipping gitzone self-update.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const success = await pmUtil.installLatest("@git.zone/cli");
|
||||||
|
if (!success) {
|
||||||
|
console.log("\ngitzone self-update failed. Continuing with the current version.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\ngitzone has been updated. Re-run gitzone tools update to check remaining packages.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPackageUpdateInfos(
|
||||||
|
pmUtil: PackageManagerUtil,
|
||||||
|
installedPackages: IInstalledPackage[],
|
||||||
|
): Promise<IPackageUpdateInfo[]> {
|
||||||
|
const packageInfos: IPackageUpdateInfo[] = [];
|
||||||
|
for (const installedPackage of installedPackages) {
|
||||||
|
if (!GITZONE_PACKAGES.includes(installedPackage.name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const latestVersion = await pmUtil.getLatestVersion(installedPackage.name);
|
||||||
|
packageInfos.push({
|
||||||
|
name: installedPackage.name,
|
||||||
|
currentVersion: installedPackage.version,
|
||||||
|
latestVersion: latestVersion || "unknown",
|
||||||
|
needsUpdate: latestVersion
|
||||||
|
? pmUtil.isNewerVersion(installedPackage.version, latestVersion)
|
||||||
|
: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return packageInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function printMissingPackages(
|
||||||
|
pmUtil: PackageManagerUtil,
|
||||||
|
installedPackages: IInstalledPackage[],
|
||||||
|
): Promise<void> {
|
||||||
|
const installedNames = new Set(installedPackages.map((packageInfo) => packageInfo.name));
|
||||||
|
const missingPackages = GITZONE_PACKAGES.filter((packageName) => !installedNames.has(packageName));
|
||||||
|
if (missingPackages.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Not installed (managed @git.zone packages):\n");
|
||||||
|
await printPackageListWithLatest(pmUtil, missingPackages);
|
||||||
|
console.log("Run gitzone tools install to install missing packages.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function printPackageListWithLatest(
|
||||||
|
pmUtil: PackageManagerUtil,
|
||||||
|
packageNames: string[],
|
||||||
|
): Promise<void> {
|
||||||
|
console.log(" Package Latest");
|
||||||
|
console.log(" ----------------------------------------");
|
||||||
|
for (const packageName of packageNames) {
|
||||||
|
const latest = await pmUtil.getLatestVersion(packageName);
|
||||||
|
console.log(` ${packageName.padEnd(28)} ${latest || "unknown"}`);
|
||||||
|
}
|
||||||
|
console.log("");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function installPackages(
|
||||||
|
pmUtil: PackageManagerUtil,
|
||||||
|
packageNames: string[],
|
||||||
|
action: "installed" | "updated",
|
||||||
|
): Promise<void> {
|
||||||
|
let successCount = 0;
|
||||||
|
let failCount = 0;
|
||||||
|
|
||||||
|
for (const packageName of packageNames) {
|
||||||
|
const success = await pmUtil.installLatest(packageName);
|
||||||
|
if (success) {
|
||||||
|
console.log(` ${packageName} ${action} successfully`);
|
||||||
|
successCount++;
|
||||||
|
} else {
|
||||||
|
console.log(` ${packageName} failed`);
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("");
|
||||||
|
if (failCount === 0) {
|
||||||
|
console.log(`All ${successCount} package(s) ${action} successfully.`);
|
||||||
|
} else {
|
||||||
|
console.log(`${successCount} package(s) ${action}, ${failCount} failed.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showHelp(mode?: ICliMode): void {
|
||||||
|
if (mode?.json) {
|
||||||
|
printJson({
|
||||||
|
name: "gitzone tools",
|
||||||
|
usage: "gitzone tools <command> [options]",
|
||||||
|
commands: [
|
||||||
|
{ name: "update", description: "Check and update globally installed @git.zone packages" },
|
||||||
|
{ name: "install", description: "Install missing managed @git.zone packages" },
|
||||||
|
],
|
||||||
|
flags: [
|
||||||
|
{ flag: "-y, --yes", description: "Run without confirmation prompts" },
|
||||||
|
{ flag: "-v, --verbose", description: "Show package manager diagnostics" },
|
||||||
|
],
|
||||||
|
packageManager: "pnpm",
|
||||||
|
managedPackages: GITZONE_PACKAGES,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("");
|
||||||
|
console.log("Usage: gitzone tools <command> [options]");
|
||||||
|
console.log("");
|
||||||
|
console.log("Commands:");
|
||||||
|
console.log(" update Check and update globally installed @git.zone packages");
|
||||||
|
console.log(" install Install missing managed @git.zone packages");
|
||||||
|
console.log("");
|
||||||
|
console.log("Options:");
|
||||||
|
console.log(" -y, --yes Run without confirmation prompts");
|
||||||
|
console.log(" -v, --verbose Show package manager diagnostics");
|
||||||
|
console.log("");
|
||||||
|
console.log("Examples:");
|
||||||
|
console.log(" gitzone tools update");
|
||||||
|
console.log(" gitzone tools update -y");
|
||||||
|
console.log(" gitzone tools install");
|
||||||
|
console.log("");
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "../plugins.js";
|
||||||
Reference in New Issue
Block a user