camstack 0.5.3 → 0.6.0
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/dist/cli.js +63 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -178,6 +178,33 @@ function resolveAddonPath(arg) {
|
|
|
178
178
|
}
|
|
179
179
|
return null;
|
|
180
180
|
}
|
|
181
|
+
function readBuildScript(addonDir, scriptName) {
|
|
182
|
+
const pkgJsonPath = path2.join(addonDir, "package.json");
|
|
183
|
+
if (!fs2.existsSync(pkgJsonPath)) return null;
|
|
184
|
+
try {
|
|
185
|
+
const parsed = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf8"));
|
|
186
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
187
|
+
const scripts = parsed.scripts;
|
|
188
|
+
if (!scripts || typeof scripts !== "object") return null;
|
|
189
|
+
const val = scripts[scriptName];
|
|
190
|
+
return typeof val === "string" && val.length > 0 ? scriptName : null;
|
|
191
|
+
} catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function buildAddon(addonDir, scriptName) {
|
|
196
|
+
console.log(`[camstack] Building (npm run ${scriptName}) in ${addonDir}...`);
|
|
197
|
+
try {
|
|
198
|
+
execSync(`npm run ${scriptName}`, {
|
|
199
|
+
cwd: addonDir,
|
|
200
|
+
stdio: "inherit",
|
|
201
|
+
timeout: 5 * 6e4
|
|
202
|
+
});
|
|
203
|
+
} catch (err) {
|
|
204
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
205
|
+
throw new Error(`Build script "${scriptName}" failed in ${addonDir}: ${msg}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
181
208
|
function packAddon(addonDir) {
|
|
182
209
|
const pkgJsonPath = path2.join(addonDir, "package.json");
|
|
183
210
|
if (!fs2.existsSync(pkgJsonPath)) {
|
|
@@ -258,6 +285,18 @@ async function deployAddon(addonPath, opts) {
|
|
|
258
285
|
if (!fs2.existsSync(resolvedPath)) throw new Error(`File not found: ${resolvedPath}`);
|
|
259
286
|
tgzPath = resolvedPath;
|
|
260
287
|
} else {
|
|
288
|
+
const buildMode = opts.buildMode ?? "auto";
|
|
289
|
+
const scriptName = opts.buildScript ?? "build";
|
|
290
|
+
if (buildMode !== "skip") {
|
|
291
|
+
const declared = readBuildScript(resolvedPath, scriptName);
|
|
292
|
+
if (declared) {
|
|
293
|
+
buildAddon(resolvedPath, declared);
|
|
294
|
+
} else if (buildMode === "force") {
|
|
295
|
+
throw new Error(`Build mode "force" but no "${scriptName}" script declared in ${path2.join(resolvedPath, "package.json")}`);
|
|
296
|
+
} else {
|
|
297
|
+
console.log(`[camstack] No "${scriptName}" script \u2014 skipping build (use --build force to require one).`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
261
300
|
const packed = packAddon(resolvedPath);
|
|
262
301
|
tgzPath = packed.tgzPath;
|
|
263
302
|
cleanup = packed.cleanup;
|
|
@@ -935,7 +974,13 @@ function buildCommands() {
|
|
|
935
974
|
' path Path to addon dir, .tgz, or workspace name (e.g. "tailscale")',
|
|
936
975
|
' Default: "." (current dir)',
|
|
937
976
|
"",
|
|
938
|
-
"
|
|
977
|
+
"Build (only when path is a directory):",
|
|
978
|
+
" -b, --build <mode> `auto` (default \u2014 run build if declared),",
|
|
979
|
+
" `force` (require + run), or `skip`",
|
|
980
|
+
" --no-build Equivalent to --build skip",
|
|
981
|
+
" --build-script <n> npm script name (default: build)",
|
|
982
|
+
"",
|
|
983
|
+
"Target options:",
|
|
939
984
|
" -s, --server <url> Server URL (default: cached session from `camstack login`)",
|
|
940
985
|
" -t, --token <token> Auth token override ($CAMSTACK_TOKEN, then cached scoped token)",
|
|
941
986
|
" -n, --node <id> Push to a specific node. Mutually exclusive with --cluster",
|
|
@@ -1035,7 +1080,10 @@ async function runDeploy(args) {
|
|
|
1035
1080
|
server: { type: "string", short: "s" },
|
|
1036
1081
|
token: { type: "string", short: "t" },
|
|
1037
1082
|
node: { type: "string", short: "n" },
|
|
1038
|
-
cluster: { type: "boolean", short: "c" }
|
|
1083
|
+
cluster: { type: "boolean", short: "c" },
|
|
1084
|
+
build: { type: "string", short: "b" },
|
|
1085
|
+
"build-script": { type: "string" },
|
|
1086
|
+
"no-build": { type: "boolean" }
|
|
1039
1087
|
}, true);
|
|
1040
1088
|
if (!parsed) {
|
|
1041
1089
|
console.log(commandHelp("deploy"));
|
|
@@ -1055,11 +1103,23 @@ async function runDeploy(args) {
|
|
|
1055
1103
|
console.error("[camstack] Error: --node and --cluster are mutually exclusive.");
|
|
1056
1104
|
process.exit(1);
|
|
1057
1105
|
}
|
|
1106
|
+
const buildFlag = stringOpt(parsed.values, "build");
|
|
1107
|
+
const noBuild = boolOpt(parsed.values, "no-build");
|
|
1108
|
+
let buildMode = "auto";
|
|
1109
|
+
if (noBuild) buildMode = "skip";
|
|
1110
|
+
else if (buildFlag === "force" || buildFlag === "skip" || buildFlag === "auto") buildMode = buildFlag;
|
|
1111
|
+
else if (buildFlag) {
|
|
1112
|
+
console.error(`[camstack] Error: --build must be one of: auto, force, skip (got: ${buildFlag})`);
|
|
1113
|
+
process.exit(1);
|
|
1114
|
+
}
|
|
1115
|
+
const buildScript = stringOpt(parsed.values, "build-script");
|
|
1058
1116
|
await deployAddon(addonPath, {
|
|
1059
1117
|
serverUrl: server,
|
|
1060
1118
|
token,
|
|
1061
1119
|
...nodeId ? { nodeId } : {},
|
|
1062
|
-
...cluster ? { cluster: true } : {}
|
|
1120
|
+
...cluster ? { cluster: true } : {},
|
|
1121
|
+
buildMode,
|
|
1122
|
+
...buildScript ? { buildScript } : {}
|
|
1063
1123
|
});
|
|
1064
1124
|
}
|
|
1065
1125
|
function commandHelp(name) {
|