dokku-compose 0.3.4 → 0.3.6

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.
Files changed (2) hide show
  1. package/dist/index.js +72 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@
4
4
  import { Command } from "commander";
5
5
  import * as fs3 from "fs";
6
6
  import * as yaml3 from "js-yaml";
7
+ import { createRequire } from "module";
7
8
 
8
9
  // src/core/config.ts
9
10
  import * as fs from "fs";
@@ -99,12 +100,17 @@ function loadConfig(filePath) {
99
100
 
100
101
  // src/core/dokku.ts
101
102
  import { execa } from "execa";
103
+ import { createHash } from "crypto";
104
+ import * as os from "os";
105
+ import * as path from "path";
102
106
  function createRunner(opts = {}) {
103
107
  const log = [];
108
+ const controlPath = opts.host ? path.join(os.tmpdir(), `dc-${createHash("sha1").update(opts.host).digest("hex").slice(0, 16)}.sock`) : null;
109
+ const sshControlFlags = controlPath ? ["-o", "ControlMaster=auto", "-o", `ControlPath=${controlPath}`, "-o", "ControlPersist=60"] : [];
104
110
  async function execDokku(args) {
105
111
  if (opts.host) {
106
112
  try {
107
- const result = await execa("ssh", [`dokku@${opts.host}`, ...args]);
113
+ const result = await execa("ssh", [...sshControlFlags, `dokku@${opts.host}`, ...args]);
108
114
  return { stdout: result.stdout, ok: true };
109
115
  } catch (e) {
110
116
  return { stdout: e.stdout ?? "", ok: false };
@@ -136,6 +142,13 @@ function createRunner(opts = {}) {
136
142
  if (opts.dryRun) return false;
137
143
  const { ok } = await execDokku(args);
138
144
  return ok;
145
+ },
146
+ async close() {
147
+ if (!opts.host || !controlPath) return;
148
+ try {
149
+ await execa("ssh", ["-O", "exit", "-o", `ControlPath=${controlPath}`, `dokku@${opts.host}`]);
150
+ } catch {
151
+ }
139
152
  }
140
153
  };
141
154
  }
@@ -175,7 +188,9 @@ async function destroyApp(runner, app) {
175
188
  }
176
189
  async function exportApps(runner) {
177
190
  const output = await runner.query("apps:list");
178
- return output.split("\n").map((s) => s.trim()).filter(Boolean);
191
+ return output.split("\n").map((s) => s.trim()).filter(
192
+ (s) => s && !s.startsWith("=====>")
193
+ );
179
194
  }
180
195
 
181
196
  // src/modules/domains.ts
@@ -261,9 +276,10 @@ async function ensureAppNetwork(runner, app, network) {
261
276
  await runner.run("network:set", app, "tld", network.tld);
262
277
  }
263
278
  }
279
+ var DOCKER_BUILTIN_NETWORKS = /* @__PURE__ */ new Set(["bridge", "host", "none"]);
264
280
  async function exportNetworks(runner) {
265
281
  const output = await runner.query("network:list");
266
- return output.split("\n").map((s) => s.trim()).filter(Boolean);
282
+ return output.split("\n").map((s) => s.trim()).filter((s) => s && !s.startsWith("=====>") && !DOCKER_BUILTIN_NETWORKS.has(s));
267
283
  }
268
284
  async function exportAppNetwork(runner, app) {
269
285
  const output = await runner.query("network:report", app);
@@ -470,7 +486,10 @@ async function exportAppNginx(runner, app) {
470
486
  const match = line.match(/^\s*Nginx\s+(.+?):\s*(.+?)\s*$/);
471
487
  if (match) {
472
488
  const key = match[1].toLowerCase().replace(/\s+/g, "-");
473
- result[key] = match[2];
489
+ if (key.startsWith("computed-") || key.startsWith("global-") || key === "last-visited-at") continue;
490
+ const value = match[2].trim();
491
+ if (!value) continue;
492
+ result[key] = value;
474
493
  }
475
494
  }
476
495
  return Object.keys(result).length > 0 ? result : void 0;
@@ -688,6 +707,9 @@ async function runDown(runner, config, appFilter, opts) {
688
707
  // src/commands/export.ts
689
708
  async function runExport(runner, opts) {
690
709
  const config = { apps: {} };
710
+ const versionOutput = await runner.query("version");
711
+ const versionMatch = versionOutput.match(/(\d+\.\d+\.\d+)/);
712
+ if (versionMatch) config.dokku = { version: versionMatch[1] };
691
713
  const apps = opts.appFilter?.length ? opts.appFilter : await exportApps(runner);
692
714
  const networks = await exportNetworks(runner);
693
715
  if (networks.length > 0) config.networks = networks;
@@ -887,7 +909,9 @@ function validate(filePath) {
887
909
  }
888
910
 
889
911
  // src/index.ts
890
- var program = new Command().name("dokku-compose").version("0.3.0");
912
+ var require2 = createRequire(import.meta.url);
913
+ var { version } = require2("../package.json");
914
+ var program = new Command().name("dokku-compose").version(version);
891
915
  function makeRunner(opts) {
892
916
  return createRunner({
893
917
  host: process.env.DOKKU_HOST,
@@ -897,10 +921,14 @@ function makeRunner(opts) {
897
921
  program.command("up [apps...]").description("Create/update apps and services to match config").option("-f, --file <path>", "Config file", "dokku-compose.yml").option("--dry-run", "Print commands without executing").option("--fail-fast", "Stop on first error").action(async (apps, opts) => {
898
922
  const config = loadConfig(opts.file);
899
923
  const runner = makeRunner(opts);
900
- await runUp(runner, config, apps);
901
- if (opts.dryRun) {
902
- console.log("\n# Commands that would run:");
903
- for (const cmd of runner.dryRunLog) console.log(`dokku ${cmd}`);
924
+ try {
925
+ await runUp(runner, config, apps);
926
+ if (opts.dryRun) {
927
+ console.log("\n# Commands that would run:");
928
+ for (const cmd of runner.dryRunLog) console.log(`dokku ${cmd}`);
929
+ }
930
+ } finally {
931
+ await runner.close();
904
932
  }
905
933
  });
906
934
  program.command("down [apps...]").description("Destroy apps and services (requires --force)").option("-f, --file <path>", "Config file", "dokku-compose.yml").option("--force", "Required to destroy apps").action(async (apps, opts) => {
@@ -910,7 +938,11 @@ program.command("down [apps...]").description("Destroy apps and services (requir
910
938
  }
911
939
  const config = loadConfig(opts.file);
912
940
  const runner = makeRunner({});
913
- await runDown(runner, config, apps, { force: true });
941
+ try {
942
+ await runDown(runner, config, apps, { force: true });
943
+ } finally {
944
+ await runner.close();
945
+ }
914
946
  });
915
947
  program.command("validate [file]").description("Validate dokku-compose.yml without touching the server").action((file = "dokku-compose.yml") => {
916
948
  const result = validate(file);
@@ -930,33 +962,45 @@ ${result.errors.length} error(s), ${result.warnings.length} warning(s)`);
930
962
  });
931
963
  program.command("export").description("Export server state to dokku-compose.yml format").option("--app <app>", "Export only a specific app").option("-o, --output <path>", "Write to file instead of stdout").action(async (opts) => {
932
964
  const runner = makeRunner({});
933
- const result = await runExport(runner, {
934
- appFilter: opts.app ? [opts.app] : void 0
935
- });
936
- const out = yaml3.dump(result, { lineWidth: 120 });
937
- if (opts.output) {
938
- fs3.writeFileSync(opts.output, out);
939
- console.error(`Written to ${opts.output}`);
940
- } else {
941
- process.stdout.write(out);
965
+ try {
966
+ const result = await runExport(runner, {
967
+ appFilter: opts.app ? [opts.app] : void 0
968
+ });
969
+ const out = yaml3.dump(result, { lineWidth: 120 });
970
+ if (opts.output) {
971
+ fs3.writeFileSync(opts.output, out);
972
+ console.error(`Written to ${opts.output}`);
973
+ } else {
974
+ process.stdout.write(out);
975
+ }
976
+ } finally {
977
+ await runner.close();
942
978
  }
943
979
  });
944
980
  program.command("diff").description("Show what is out of sync between config and server").option("-f, --file <path>", "Config file", "dokku-compose.yml").option("--verbose", "Show git-style +/- diff").action(async (opts) => {
945
981
  const desired = loadConfig(opts.file);
946
982
  const runner = makeRunner({});
947
- const current = await runExport(runner, {
948
- appFilter: Object.keys(desired.apps)
949
- });
950
- const diff = computeDiff(desired, current);
951
- const output = opts.verbose ? formatVerbose(diff) : formatSummary(diff);
952
- process.stdout.write(output);
953
- process.exit(diff.inSync ? 0 : 1);
983
+ try {
984
+ const current = await runExport(runner, {
985
+ appFilter: Object.keys(desired.apps)
986
+ });
987
+ const diff = computeDiff(desired, current);
988
+ const output = opts.verbose ? formatVerbose(diff) : formatSummary(diff);
989
+ process.stdout.write(output);
990
+ process.exit(diff.inSync ? 0 : 1);
991
+ } finally {
992
+ await runner.close();
993
+ }
954
994
  });
955
995
  program.command("ps [apps...]").description("Show status of configured apps").option("-f, --file <path>", "Config file", "dokku-compose.yml").action(async (apps, opts) => {
956
996
  const config = loadConfig(opts.file);
957
997
  const runner = makeRunner({});
958
- const { runPs } = await import("./ps-33II4UU3.js");
959
- await runPs(runner, config, apps);
998
+ try {
999
+ const { runPs } = await import("./ps-33II4UU3.js");
1000
+ await runPs(runner, config, apps);
1001
+ } finally {
1002
+ await runner.close();
1003
+ }
960
1004
  });
961
1005
  program.command("init [apps...]").description("Create a starter dokku-compose.yml").option("-f, --file <path>", "Config file", "dokku-compose.yml").action(async (apps, opts) => {
962
1006
  const { runInit } = await import("./init-GIXEVLNW.js");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dokku-compose",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Docker Compose for Dokku — declare your entire server in a single YAML file.",
5
5
  "main": "dist/index.js",
6
6
  "exports": "./dist/index.js",