oche-cli 0.3.0 → 0.4.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/README.md +9 -2
- package/dist/index.js +23 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ oche logs --stage prod # the running container's log: why it's crash-
|
|
|
33
33
|
oche logs --stage prod --failures # just the errors and the tail
|
|
34
34
|
oche logs --app api --build # the build log of the latest deployment instead
|
|
35
35
|
oche deployments # recent deployments per app: status, commit, how long, when
|
|
36
|
-
oche envs # which stages define each variable (names only)
|
|
36
|
+
oche envs # which stages define each variable, and which are empty (names only)
|
|
37
37
|
oche envs --stage prod --key DATABASE_URL
|
|
38
38
|
oche deploy --stage staging # redeploy (--force rebuilds without the cache); asks first
|
|
39
39
|
oche rollback --app api # the images Coolify can go back to
|
|
@@ -44,7 +44,14 @@ oche preflight --to prod # missing variables, and whether staging is he
|
|
|
44
44
|
|
|
45
45
|
Each one picks the app with `--app <name>` (or the start of its uuid) or `--stage prod|staging|dev`; with one app it needs neither, and with several it says which ones there are. `oche deploy` and `oche rollback` ask before they act unless you pass `-y`.
|
|
46
46
|
|
|
47
|
-
`oche envs`
|
|
47
|
+
`oche envs` marks each variable per stage: `✓` set, `∅` defined but empty, `·` not defined, `-` no app on that stage. A `∅` is counted as a problem, not a note: the key is there, so nothing complains, and the app reads it and gets nothing.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
VARIABLE dev staging prod
|
|
51
|
+
TURNSTILE_SECRET ∅ ∅ ∅ defined but empty
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`oche envs` never prints values. The server compares names, whether each key holds anything at all, and whether staging and production hold the same value, and sends only that. Log lines Coolify marks as holding secrets are left out too.
|
|
48
55
|
|
|
49
56
|
## Without a server: `oche pr`
|
|
50
57
|
|
package/dist/index.js
CHANGED
|
@@ -3371,7 +3371,7 @@ var program = new Command();
|
|
|
3371
3371
|
// package.json
|
|
3372
3372
|
var package_default = {
|
|
3373
3373
|
name: "oche-cli",
|
|
3374
|
-
version: "0.
|
|
3374
|
+
version: "0.4.0",
|
|
3375
3375
|
description: "Command-line client for Oche: promote dev \u2192 staging \u2192 main from your terminal.",
|
|
3376
3376
|
license: "MIT",
|
|
3377
3377
|
repository: {
|
|
@@ -3880,9 +3880,16 @@ ${data.instance.url}`));
|
|
|
3880
3880
|
var ISSUE_LABEL = {
|
|
3881
3881
|
"missing-in-prod": "missing in production",
|
|
3882
3882
|
"missing-in-staging": "missing in staging",
|
|
3883
|
+
"empty-value": "defined but empty",
|
|
3883
3884
|
"same-secret": "same value in staging and production"
|
|
3884
3885
|
};
|
|
3885
|
-
var issueText = (issue) => issue === null ? "" : issue === "missing-in-prod" ? c.red(ISSUE_LABEL[issue]) : c.yellow(ISSUE_LABEL[issue]);
|
|
3886
|
+
var issueText = (issue) => issue === null ? "" : issue === "missing-in-prod" || issue === "empty-value" ? c.red(ISSUE_LABEL[issue]) : c.yellow(ISSUE_LABEL[issue]);
|
|
3887
|
+
function legend() {
|
|
3888
|
+
const set = `${c.green("\u2713")} ${c.dim("set")}`;
|
|
3889
|
+
const empty = `${c.red("\u2205")} ${c.dim("defined but empty, so the app sees nothing")}`;
|
|
3890
|
+
const absent = `${c.red("\xB7")} ${c.dim("not defined")}`;
|
|
3891
|
+
return `${set} ${empty} ${absent} ${c.dim("- no app on that stage")}`;
|
|
3892
|
+
}
|
|
3886
3893
|
async function envsCommand(getClient, repoArg, opts) {
|
|
3887
3894
|
const repo = await resolveRepo(repoArg);
|
|
3888
3895
|
const { groups } = await (await getClient()).envs(repo);
|
|
@@ -3896,32 +3903,36 @@ async function envsCommand(getClient, repoArg, opts) {
|
|
|
3896
3903
|
}
|
|
3897
3904
|
kept.forEach((g, i) => {
|
|
3898
3905
|
if (i) print();
|
|
3899
|
-
|
|
3906
|
+
envGroupLines(g, opts.stage, !key).forEach((l) => print(l));
|
|
3900
3907
|
});
|
|
3901
|
-
print(
|
|
3908
|
+
print(`
|
|
3909
|
+
${legend()}`);
|
|
3910
|
+
print(c.dim("Oche compares names, and whether staging and production hold the same value. It never shows values."));
|
|
3902
3911
|
}
|
|
3903
|
-
function
|
|
3912
|
+
function envGroupLines(group, only, totals) {
|
|
3904
3913
|
const stages = STAGES.filter((s) => group.apps[s] && (!only || s === only));
|
|
3905
3914
|
const where = stages.map((s) => `${s}: ${group.apps[s].name}`).join(" \xB7 ");
|
|
3906
|
-
print(`${c.bold(group.label)} ${c.dim(where)}`);
|
|
3907
3915
|
const header = [["VARIABLE", c.dim("VARIABLE")], ...stages.map((s) => [s, c.dim(s)]), ""];
|
|
3908
3916
|
const rows = group.rows.map((r) => [
|
|
3909
3917
|
r.key,
|
|
3910
3918
|
...stages.map((s) => {
|
|
3911
3919
|
if (r.present[s] === void 0) return ["-", c.dim("-")];
|
|
3912
|
-
|
|
3920
|
+
if (!r.present[s]) return ["\xB7", c.red("\xB7")];
|
|
3921
|
+
return r.hasValue?.[s] === false ? ["\u2205", c.red("\u2205")] : ["\u2713", c.green("\u2713")];
|
|
3913
3922
|
}),
|
|
3914
3923
|
issueText(r.issue)
|
|
3915
3924
|
]);
|
|
3916
|
-
columns([header, ...rows])
|
|
3917
|
-
if (!totals) return;
|
|
3918
|
-
const { missingInProd, missingInStaging, sameSecret } = group.counts;
|
|
3925
|
+
const lines = [`${c.bold(group.label)} ${c.dim(where)}`, ...columns([header, ...rows])];
|
|
3926
|
+
if (!totals) return lines;
|
|
3927
|
+
const { missingInProd, missingInStaging, emptyValue, sameSecret } = group.counts;
|
|
3919
3928
|
const issues = [
|
|
3929
|
+
emptyValue ? c.red(`${emptyValue} defined but empty`) : "",
|
|
3920
3930
|
missingInProd ? c.red(`${missingInProd} missing in production`) : "",
|
|
3921
3931
|
missingInStaging ? c.yellow(`${missingInStaging} missing in staging`) : "",
|
|
3922
3932
|
sameSecret ? c.yellow(`${sameSecret} shared with staging`) : ""
|
|
3923
3933
|
].filter(Boolean);
|
|
3924
|
-
|
|
3934
|
+
lines.push(issues.length ? ` ${issues.join(c.dim(" \xB7 "))}` : c.dim(" in step across environments"));
|
|
3935
|
+
return lines;
|
|
3925
3936
|
}
|
|
3926
3937
|
async function deployCommand(getClient, repoArg, opts) {
|
|
3927
3938
|
const repo = await resolveRepo(repoArg);
|
|
@@ -5276,7 +5287,7 @@ function buildProgram() {
|
|
|
5276
5287
|
const npm = program2.command("npm").description("Publish this package to npm on every release");
|
|
5277
5288
|
npm.command("setup").description("Add the publish workflow and let npm trust it (uses your npm login)").argument(repoArg, repoHelp).option("-y, --yes", "don't ask for confirmation").option("--keep-existing", "keep a workflow that already publishes to npm instead of replacing it").option("--skip-pr", "only do the npm side; don't open the workflow PR").action((repo, opts) => npmSetupCommand(client, repo, opts));
|
|
5278
5289
|
npm.command("status", { isDefault: true }).description("Publishing setup, the npm version and the last run").argument(repoArg, repoHelp).option("--json", "print raw JSON").action((repo, opts) => npmStatusCommand(client, repo, opts));
|
|
5279
|
-
program2.command("envs").description("Which stages define each environment variable (names only, never values)").argument(repoArg, repoHelp).addOption(stageOption("only this stage's column")).option("--key <name>", "only variables whose name contains this").option("--json", "print raw JSON").action((repo, opts) => envsCommand(client, repo, opts));
|
|
5290
|
+
program2.command("envs").description("Which stages define each environment variable, and which are defined but empty (names only, never values)").argument(repoArg, repoHelp).addOption(stageOption("only this stage's column")).option("--key <name>", "only variables whose name contains this").option("--json", "print raw JSON").action((repo, opts) => envsCommand(client, repo, opts));
|
|
5280
5291
|
program2.command("deploy").description("Redeploy an app on Coolify").argument(repoArg, repoHelp).addOption(appOption).addOption(stageOption("the app deploying this stage")).option("--force", "rebuild without the build cache").option("-y, --yes", "don't ask for confirmation").option("--json", "print raw JSON").action((repo, opts) => deployCommand(client, repo, opts));
|
|
5281
5292
|
program2.command("rollback").description("List the images Coolify can roll an app back to, and roll back to one").argument(repoArg, repoHelp).addOption(appOption).addOption(stageOption("the app deploying this stage")).option("--to <commit>", "roll back to this image (a commit SHA from the list)").option("-y, --yes", "don't ask for confirmation").option("--json", "print raw JSON").action((repo, opts) => rollbackCommand(client, repo, opts));
|
|
5282
5293
|
program2.command("explain").description("Ask your Oche server's AI what broke a deployment").argument(repoArg, repoHelp).addOption(appOption).addOption(stageOption("the app deploying this stage")).option("--deployment <uuid>", "explain this deployment (default: the latest failed one)").option("--json", "print raw JSON").action((repo, opts) => explainCommand(client, repo, opts));
|