Compare commits

..

8 Commits

Author SHA1 Message Date
jkunz 6f0928e7c7 v2.19.0
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-05-13 10:21:25 +00:00
jkunz 26effadcc9 feat(release): delegate docker target to tsdocker 2026-05-13 10:19:56 +00:00
jkunz c38e94bcf3 v2.18.1
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-05-10 14:41:49 +00:00
jkunz b9b51f29d1 fix(config): use inherited stdio for opencode handoff 2026-05-10 14:41:08 +00:00
jkunz a3ad48368d v2.18.0
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-05-10 13:43:05 +00:00
jkunz c10b764c0a feat(config): add opencode config fix 2026-05-10 13:42:57 +00:00
jkunz 7686504e4e v2.17.0
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-05-10 13:09:36 +00:00
jkunz d96b220703 feat(config): add guided configuration flows 2026-05-10 13:09:28 +00:00
10 changed files with 1491 additions and 86 deletions
+2 -1
View File
@@ -63,7 +63,8 @@
},
"docker": {
"enabled": false,
"images": []
"engine": "tsdocker",
"patterns": []
}
}
}
+26
View File
@@ -3,6 +3,32 @@
## 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
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@git.zone/cli",
"private": false,
"version": "2.16.1",
"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.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
@@ -87,7 +87,7 @@
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3",
"@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/smartupdate": "^2.0.6",
"prettier": "^3.8.1"
+35 -23
View File
@@ -81,8 +81,8 @@ importers:
specifier: ^4.0.21
version: 4.0.21
'@push.rocks/smartshell':
specifier: ^3.3.7
version: 3.3.7
specifier: ^3.5.0
version: 3.5.0
'@push.rocks/smartunique':
specifier: ^3.0.9
version: 3.0.9
@@ -1063,6 +1063,9 @@ packages:
'@push.rocks/smartdelay@3.0.5':
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':
resolution: {integrity: sha512-AAz/unmko0C+g+60odOoK32PE3Ci3YLoB+zfg1LGLyVRCthcdzjqa1C2Km0MfG7IyJQKPdj8J5HPubtpm3ZeaQ==}
@@ -1192,6 +1195,9 @@ packages:
'@push.rocks/smartpromise@4.2.3':
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':
resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==}
@@ -1222,8 +1228,8 @@ packages:
'@push.rocks/smartserve@2.0.1':
resolution: {integrity: sha512-YQb2qexfCzCqOlLWBBXKMg6xG4zahCPAxomz/KEKAwHtW6wMTtuHKSTSkRTQ0vl9jssLMAmRz2OyafiL9XGJXQ==}
'@push.rocks/smartshell@3.3.7':
resolution: {integrity: sha512-b3st2+FjHUVhZZRlXfw93+SQA0UMVlURqe55uVpWdjJX7jeGXTTeszuYygtiR99zC5iZ8WZhGDct3N2L1qc/qw==}
'@push.rocks/smartshell@3.5.0':
resolution: {integrity: sha512-Hx9TVvC/AWxZsnm1GDb+W4Fe58nf1FkKbSBABUgkxct4XRYugBI2z9Twnjm3R9vdRry8oy0enfR9NPVhisGaGA==}
'@push.rocks/smartspawn@3.0.3':
resolution: {integrity: sha512-DyrGPV69wwOiJgKkyruk5hS3UEGZ99xFAqBE9O2nM8VXCRLbbty3xt1Ug5Z092ZZmJYaaGMSnMw3ijyZJFCT0Q==}
@@ -3917,9 +3923,9 @@ packages:
engines: {node: '>= 8'}
hasBin: true
which@6.0.1:
resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==}
engines: {node: ^20.17.0 || >=22.9.0}
which@7.0.0:
resolution: {integrity: sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA==}
engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0}
hasBin: true
wordwrap@1.0.0:
@@ -4802,7 +4808,7 @@ snapshots:
'@push.rocks/smartlog': 3.2.1
'@push.rocks/smartlog-destination-local': 9.0.2
'@push.rocks/smartpath': 6.0.0
'@push.rocks/smartshell': 3.3.7
'@push.rocks/smartshell': 3.5.0
'@push.rocks/smarttime': 4.2.3
typedoc: 0.28.17(typescript@5.9.3)
typescript: 5.9.3
@@ -4832,7 +4838,7 @@ snapshots:
'@push.rocks/smartnpm': 2.0.6
'@push.rocks/smartpath': 6.0.0
'@push.rocks/smartrequest': 5.0.1
'@push.rocks/smartshell': 3.3.7
'@push.rocks/smartshell': 3.5.0
transitivePeerDependencies:
- '@nuxt/kit'
- aws-crt
@@ -4845,7 +4851,7 @@ snapshots:
'@git.zone/tsrun@2.0.1':
dependencies:
'@push.rocks/smartfile': 13.1.2
'@push.rocks/smartshell': 3.3.7
'@push.rocks/smartshell': 3.5.0
tsx: 4.21.0
'@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/smarts3': 5.3.0
'@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/smartwatch': 6.3.0
'@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/smartfs': 1.5.0
'@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)
zod: 3.25.76
transitivePeerDependencies:
@@ -5775,6 +5781,10 @@ snapshots:
dependencies:
'@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':
dependencies:
diff: 8.0.3
@@ -5818,7 +5828,7 @@ snapshots:
'@push.rocks/smartexit@2.0.3':
dependencies:
'@push.rocks/lik': 6.3.1
'@push.rocks/smartpromise': 4.2.3
'@push.rocks/smartpromise': 4.2.4
'@push.rocks/smartexpect@2.5.0':
dependencies:
@@ -5897,7 +5907,7 @@ snapshots:
'@push.rocks/smartfile': 11.2.7
'@push.rocks/smartpath': 6.0.0
'@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/smarttime': 4.2.3
'@types/diff': 8.0.0
@@ -5968,7 +5978,7 @@ snapshots:
'@push.rocks/smartmustache': 3.0.2
'@push.rocks/smartpnpm': 1.0.6
'@push.rocks/smartpromise': 4.2.3
'@push.rocks/smartshell': 3.3.7
'@push.rocks/smartshell': 3.5.0
'@tsclass/tsclass': 4.4.4
transitivePeerDependencies:
- supports-color
@@ -6159,14 +6169,16 @@ snapshots:
'@push.rocks/smartpnpm@1.0.6':
dependencies:
'@push.rocks/smartshell': 3.3.7
'@push.rocks/smartshell': 3.5.0
'@push.rocks/smartpromise@4.2.3': {}
'@push.rocks/smartpromise@4.2.4': {}
'@push.rocks/smartpuppeteer@2.0.5(typescript@5.9.3)':
dependencies:
'@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)
tree-kill: 1.2.2
transitivePeerDependencies:
@@ -6233,7 +6245,7 @@ snapshots:
'@push.rocks/smartinteract': 2.0.16
'@push.rocks/smartobject': 1.0.12
'@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/smartserve@2.0.1':
@@ -6249,13 +6261,13 @@ snapshots:
- bufferutil
- utf-8-validate
'@push.rocks/smartshell@3.3.7':
'@push.rocks/smartshell@3.5.0':
dependencies:
'@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartdelay': 3.1.0
'@push.rocks/smartexit': 2.0.3
'@push.rocks/smartpromise': 4.2.3
'@push.rocks/smartpromise': 4.2.4
'@types/which': 3.0.4
which: 6.0.1
which: 7.0.0
'@push.rocks/smartspawn@3.0.3':
dependencies:
@@ -9513,7 +9525,7 @@ snapshots:
dependencies:
isexe: 2.0.0
which@6.0.1:
which@7.0.0:
dependencies:
isexe: 4.0.0
+32 -5
View File
@@ -147,7 +147,7 @@ Targets decide what happens after that:
| --- | --- |
| `git` | Pushes the release commit and tags, often triggering remote CI release builds |
| `npm` | Publishes the package to configured npm registries |
| `docker` | Builds and pushes configured Docker images |
| `docker` | Delegates container builds and pushes to `tsdocker` |
```bash
# Preview the resolved release plan
@@ -205,7 +205,7 @@ The standard buckets are `Breaking Changes`, `Features`, `Fixes`, `Documentation
## 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
{
@@ -237,11 +237,21 @@ All CLI config lives under `@git.zone/cli` in `.smartconfig.json`.
"alreadyPublished": "success"
},
"docker": {
"enabled": false,
"images": []
"enabled": true,
"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"]
}
}
```
@@ -252,12 +262,29 @@ NPM registries belong only here:
@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:
```bash
# Show current @git.zone/cli config
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
gitzone config get release.targets.npm.registries
@@ -404,7 +431,7 @@ gitzone config show --json
## 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.
+1 -1
View File
@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@git.zone/cli',
version: '2.16.1',
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.'
}
+20 -2
View File
@@ -68,8 +68,10 @@ const migrateToV2 = (smartconfigJson: Record<string, any>): boolean => {
migrated = true;
}
if (isPlainObject(releaseConfig.docker) && !isPlainObject(targets.docker)) {
targets.docker = releaseConfig.docker;
if (isPlainObject(releaseConfig.docker)) {
targets.docker = isPlainObject(targets.docker)
? { ...releaseConfig.docker, ...targets.docker }
: releaseConfig.docker;
delete releaseConfig.docker;
migrated = true;
}
@@ -141,11 +143,27 @@ const migrateToV2 = (smartconfigJson: Record<string, any>): boolean => {
if (dockerTarget.enabled === undefined) {
dockerTarget.enabled = true;
}
dockerTarget.engine = "tsdocker";
}
delete releaseConfig.steps;
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) {
delete releaseConfig.changelog;
migrated = true;
+20 -3
View File
@@ -52,7 +52,12 @@ export interface IReleaseNpmTargetConfig {
export interface IReleaseDockerTargetConfig {
enabled?: boolean;
images?: string[];
engine?: "tsdocker";
patterns?: string[];
cached?: boolean;
parallel?: boolean | number;
context?: string;
noBuild?: boolean;
}
export interface IReleaseWorkflowConfig {
@@ -109,7 +114,12 @@ export interface IResolvedReleaseWorkflow {
npmAccessLevel: "public" | "private";
npmAlreadyPublished: "success" | "error";
dockerEnabled: boolean;
dockerImages: string[];
dockerEngine: "tsdocker";
dockerPatterns: string[];
dockerCached: boolean;
dockerParallel: boolean | number;
dockerContext?: string;
dockerNoBuild: boolean;
}
interface ICliWorkflowConfig {
@@ -382,6 +392,13 @@ export const resolveReleaseWorkflow = async (argvArg: any): Promise<IResolvedRel
npmAccessLevel: npmConfig.accessLevel || "public",
npmAlreadyPublished: npmConfig.alreadyPublished || "success",
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,
};
};
+1307 -26
View File
File diff suppressed because it is too large Load Diff
+46 -23
View File
@@ -107,7 +107,7 @@ export const run = async (argvArg: any) => {
npmResults.push(...(await runNpmTarget(smartshellInstance, workflow)));
}
if (workflow.targets.includes("docker")) {
dockerResults.push(...(await runDockerTarget(smartshellInstance, workflow, newVersion)));
dockerResults.push(...(await runDockerTarget(smartshellInstance, workflow)));
}
printReleaseSummary(newVersion, gitResults, npmResults, dockerResults);
@@ -262,31 +262,43 @@ async function runNpmTarget(
async function runDockerTarget(
smartshellInstance: plugins.smartshell.Smartshell,
workflow: IResolvedReleaseWorkflow,
newVersion: string,
): Promise<ITargetResult[]> {
if (!workflow.dockerEnabled) {
return [{ target: "docker", status: "skipped", message: "disabled" }];
}
if (workflow.dockerImages.length === 0) {
return [{ target: "docker", status: "failed", message: "no images configured" }];
}
const results: ITargetResult[] = [];
for (const imageTemplate of workflow.dockerImages) {
const image = imageTemplate.replaceAll("{{version}}", newVersion);
const buildResult = await smartshellInstance.exec(`docker build -t ${shellQuote(image)} .`);
if (buildResult.exitCode !== 0) {
results.push({ target: image, status: "failed", message: "docker build failed" });
continue;
}
const pushResult = await smartshellInstance.exec(`docker push ${shellQuote(image)}`);
results.push({
target: image,
status: pushResult.exitCode === 0 ? "success" : "failed",
message: pushResult.exitCode === 0 ? undefined : "docker push failed",
});
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),
}];
}
function buildTsdockerPushCommand(workflow: IResolvedReleaseWorkflow): string {
const commandParts = ["tsdocker", "push"];
if (workflow.dockerNoBuild) {
commandParts.push("--no-build");
}
return results;
if (workflow.dockerCached) {
commandParts.push("--cached");
}
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 {
@@ -315,11 +327,22 @@ function printReleasePlan(workflow: IResolvedReleaseWorkflow): void {
console.log(`npm registries: ${workflow.npmRegistries.length > 0 ? workflow.npmRegistries.join(", ") : "none"}`);
}
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("");
}
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(
newVersion: string,
gitResults: ITargetResult[],
@@ -365,7 +388,7 @@ export function showHelp(mode?: ICliMode): void {
{ flag: "-p, --push", description: "Enable the git release target" },
{ flag: "--target <names>", description: "Release only selected targets: git,npm,docker" },
{ 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: "--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(" --target <names> Release only selected targets: git,npm,docker");
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(" --major|--minor|--patch Override inferred semver level");
console.log(" --plan Show resolved workflow without mutating files");