@django-stack/cli 0.12.0 → 0.12.1

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/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as describeMove, A as activeProject, B as DEFAULT_STACK, C as CLI_VERSION, D as CAPTCHA_APP, E as generateSecret, F as projectStack, G as applies, H as NODE_FRONTENDS, I as projectUrls, J as pendingChoices, L as readLocalRun, M as composeOutput, N as findProjectDirectory, O as RUN_DOMAIN, P as parseProfiles, Q as chooseFreePorts, R as readProject, S as validateTimeZone, T as generateProjectSecrets, U as PROMPT_ORDER, V as NAMED_PRESETS, W as STACK_OPTIONS, X as stackOption, Y as resolvePreset, Z as DEV_PORTS, _ as toProjectName, at as dockerRunning, b as usesValkey, c as frontendPackageManager, ct as quoteEnvValue, d as lockFrontend, et as envPorts, f as normalizeDatabaseUrl, g as timeZones, h as setNotificationsApp, i as validateDomain, it as dockerNotRunning, j as compose, k as RUN_ENV, l as localS3, lt as setEnvValues, m as scaffold, n as postgresUrl, nt as runDoctor, o as LOCAL_S3, ot as isDockerDown, p as relativeDirectory, q as encodePreset, r as productionEnv$1, rt as checkTools, s as cacheEnv, st as parseEnv, t as missingS3, tt as portValues, u as lockBackend, v as umamiEnv, w as PACKAGE_NAME, x as validateProjectName, y as updateFrontendLock, z as runningServices } from "./production-1O8-1QUl.js";
2
+ import { $ as describeMove, A as activeProject, B as DEFAULT_STACK, C as CLI_VERSION, D as CAPTCHA_APP, E as generateSecret, F as projectStack, G as applies, H as NODE_FRONTENDS, I as projectUrls, J as pendingChoices, L as readLocalRun, M as composeOutput, N as findProjectDirectory, O as RUN_DOMAIN, P as parseProfiles, Q as chooseFreePorts, R as readProject, S as validateTimeZone, T as generateProjectSecrets, U as PROMPT_ORDER, V as NAMED_PRESETS, W as STACK_OPTIONS, X as stackOption, Y as resolvePreset, Z as DEV_PORTS, _ as toProjectName, at as dockerRunning, b as usesValkey, c as frontendPackageManager, ct as removeLeftovers, d as lockFrontend, dt as setEnvValues, et as envPorts, f as normalizeDatabaseUrl, g as timeZones, h as setNotificationsApp, i as validateDomain, it as dockerNotRunning, j as compose, k as RUN_ENV, l as localS3, lt as parseEnv, m as scaffold, n as postgresUrl, nt as runDoctor, o as LOCAL_S3, ot as isDockerDown, p as relativeDirectory, q as encodePreset, r as productionEnv$1, rt as checkTools, s as cacheEnv, st as leftoverVolumes, t as missingS3, tt as portValues, u as lockBackend, ut as quoteEnvValue, v as umamiEnv, w as PACKAGE_NAME, x as validateProjectName, y as updateFrontendLock, z as runningServices } from "./production-lgZRSpyw.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
5
5
  import { basename, delimiter, dirname, join, posix, relative, resolve, sep } from "node:path";
@@ -3978,6 +3978,24 @@ function checkComputer(checks = checkTools()) {
3978
3978
  });
3979
3979
  return !checks.some((check) => !check.ok && !check.warning);
3980
3980
  }
3981
+ /**
3982
+ * Docker keeps the volumes of a deleted project. A new project with the same
3983
+ * name would start on the old database, whose password is not the new one in
3984
+ * .env: "password authentication failed for user app". Offers to remove them.
3985
+ */
3986
+ async function handleLeftovers(name, interactive) {
3987
+ const volumes = leftoverVolumes(name);
3988
+ if (!volumes.length) return;
3989
+ const removeCommand = command("docker compose down --volumes");
3990
+ p.log.warn(`Docker still has the data of an earlier project named ${pc.bold(name)} (${volumes.join(", ")}). The new project gets a new database password, so it cannot start on that database.`);
3991
+ if (interactive && unwrap(await p.confirm({
3992
+ message: `Remove the data of the earlier ${name}? Its database and uploads are deleted for good.`,
3993
+ initialValue: false
3994
+ }))) {
3995
+ if (removeLeftovers(name, volumes)) p.log.success(`Removed the data of the earlier ${name}.`);
3996
+ else fail("Could not remove it. Stop what uses it, or choose another --name.");
3997
+ } else p.log.warn(`Run ${removeCommand} in the new project before you start it, or choose another --name.`);
3998
+ }
3981
3999
  async function init(directoryArgument, options) {
3982
4000
  const interactive = isInteractive(options.yes);
3983
4001
  intro("Create a project");
@@ -3999,6 +4017,7 @@ async function init(directoryArgument, options) {
3999
4017
  validate: (value) => validateProjectName(value ?? "")
4000
4018
  }));
4001
4019
  }
4020
+ if (dockerReady) await handleLeftovers(name, interactive);
4002
4021
  const stack = await chooseStack(options, interactive);
4003
4022
  if (!applies("analytics", stack) && stack.analytics !== "off") {
4004
4023
  if (options.fromCli("analytics")) fail("--analytics umami needs a frontend: a headless project has no pages to count.");
@@ -5066,6 +5085,12 @@ function nodeModulesVolume(project) {
5066
5085
  return;
5067
5086
  }
5068
5087
  }
5088
+ /** The backend packages `dstack update` upgrades without `--all`. */
5089
+ const BACKEND_PACKAGES = [
5090
+ "django-stack",
5091
+ "django-headless",
5092
+ "django-content-studio"
5093
+ ];
5069
5094
  /** `dstack update`: newer images, newer DjangoStack packages, and a restart of what was running. */
5070
5095
  async function update(options) {
5071
5096
  const project = open(options);
@@ -5074,16 +5099,12 @@ async function update(options) {
5074
5099
  const running = targets.filter((target) => runningServices(target).length > 0);
5075
5100
  const lock = join(project.directory, "backend", "uv.lock");
5076
5101
  if (existsSync(lock) && has("uv")) {
5077
- const args = options.all ? ["lock", "--upgrade"] : [
5078
- "lock",
5079
- "--upgrade-package",
5080
- "django-stack"
5081
- ];
5102
+ const args = options.all ? ["lock", "--upgrade"] : ["lock", ...BACKEND_PACKAGES.flatMap((name) => ["--upgrade-package", name])];
5082
5103
  if (spawnSync("uv", args, {
5083
5104
  cwd: join(project.directory, "backend"),
5084
5105
  stdio: "inherit"
5085
5106
  }).status !== 0) fail("uv could not update backend/uv.lock.");
5086
- p.log.success(options.all ? "Updated backend/uv.lock" : "Updated django-stack in backend/uv.lock");
5107
+ p.log.success(options.all ? "Updated backend/uv.lock" : `Updated ${BACKEND_PACKAGES.join(", ")} in backend/uv.lock`);
5087
5108
  } else if (existsSync(lock)) p.log.warn("uv is not installed, so backend/uv.lock stays as it is: https://docs.astral.sh/uv/");
5088
5109
  if (frontendPackageManager(project.directory)) {
5089
5110
  const lockfile = updateFrontendLock(project.directory, options.all);
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { B as DEFAULT_STACK, a as FRONTENDS, V as NAMED_PRESETS, W as STACK_OPTIONS, C as VERSION, s as cacheEnv, K as decodePreset, q as encodePreset, T as generateProjectSecrets, E as generateSecret, f as normalizeDatabaseUrl, st as parseEnv, J as pendingChoices, r as productionEnv, Y as resolvePreset, nt as runDoctor, m as scaffold, lt as setEnvValues, h as setNotificationsApp, _ as toProjectName, b as usesValkey, i as validateDomain, x as validateProjectName } from "./production-1O8-1QUl.js";
1
+ export { B as DEFAULT_STACK, a as FRONTENDS, V as NAMED_PRESETS, W as STACK_OPTIONS, C as VERSION, s as cacheEnv, K as decodePreset, q as encodePreset, T as generateProjectSecrets, E as generateSecret, f as normalizeDatabaseUrl, lt as parseEnv, J as pendingChoices, r as productionEnv, Y as resolvePreset, nt as runDoctor, m as scaffold, dt as setEnvValues, h as setNotificationsApp, _ as toProjectName, b as usesValkey, i as validateDomain, x as validateProjectName } from "./production-lgZRSpyw.js";
@@ -117,6 +117,40 @@ function dockerRunning(runCommand = run) {
117
117
  "{{.Server.Version}}"
118
118
  ]));
119
119
  }
120
+ /**
121
+ * The Docker volumes of an earlier Compose project with this name, such as
122
+ * `<name>_pgdata`. A new project with the same name would reuse them, and
123
+ * Postgres keeps the password of the data it was created with.
124
+ */
125
+ function leftoverVolumes(name, runCommand = run) {
126
+ return (runCommand("docker", [
127
+ "volume",
128
+ "ls",
129
+ "--quiet",
130
+ "--filter",
131
+ `label=com.docker.compose.project=${name}`
132
+ ]) ?? "").split("\n").filter(Boolean);
133
+ }
134
+ /** Removes the containers and volumes of the Compose project with this name. Returns whether it worked. */
135
+ function removeLeftovers(name, volumes, runCommand = run) {
136
+ const containers = (runCommand("docker", [
137
+ "ps",
138
+ "--all",
139
+ "--quiet",
140
+ "--filter",
141
+ `label=com.docker.compose.project=${name}`
142
+ ]) ?? "").split("\n").filter(Boolean);
143
+ if (containers.length && runCommand("docker", [
144
+ "rm",
145
+ "--force",
146
+ ...containers
147
+ ]) === void 0) return false;
148
+ return runCommand("docker", [
149
+ "volume",
150
+ "rm",
151
+ ...volumes
152
+ ]) !== void 0;
153
+ }
120
154
  /** Docker and Docker Compose, which run the project. */
121
155
  function checkDocker({ run: runCommand = run, platform = process.platform } = {}) {
122
156
  const client = parseVersion(runCommand("docker", ["--version"]));
@@ -1746,4 +1780,4 @@ function productionEnv(devEnv, options) {
1746
1780
  todo
1747
1781
  };
1748
1782
  }
1749
- export { describeMove as $, activeProject as A, DEFAULT_STACK as B, CLI_VERSION as C, CAPTCHA_APP as D, generateSecret as E, projectStack as F, applies as G, NODE_FRONTENDS as H, projectUrls as I, pendingChoices as J, decodePreset as K, readLocalRun as L, composeOutput as M, findProjectDirectory as N, RUN_DOMAIN as O, parseProfiles as P, chooseFreePorts as Q, readProject as R, validateTimeZone as S, generateProjectSecrets as T, PROMPT_ORDER as U, NAMED_PRESETS as V, STACK_OPTIONS as W, stackOption as X, resolvePreset as Y, DEV_PORTS as Z, toProjectName as _, FRONTENDS as a, dockerRunning as at, usesValkey as b, frontendPackageManager as c, quoteEnvValue as ct, lockFrontend as d, envPorts as et, normalizeDatabaseUrl as f, timeZones as g, setNotificationsApp as h, validateDomain as i, dockerNotRunning as it, compose as j, RUN_ENV as k, localS3 as l, setEnvValues as lt, scaffold as m, postgresUrl as n, runDoctor as nt, LOCAL_S3 as o, isDockerDown as ot, relativeDirectory as p, encodePreset as q, productionEnv as r, checkTools as rt, cacheEnv as s, parseEnv as st, missingS3 as t, portValues as tt, lockBackend as u, umamiEnv as v, PACKAGE_NAME as w, validateProjectName as x, updateFrontendLock as y, runningServices as z };
1783
+ export { describeMove as $, activeProject as A, DEFAULT_STACK as B, CLI_VERSION as C, CAPTCHA_APP as D, generateSecret as E, projectStack as F, applies as G, NODE_FRONTENDS as H, projectUrls as I, pendingChoices as J, decodePreset as K, readLocalRun as L, composeOutput as M, findProjectDirectory as N, RUN_DOMAIN as O, parseProfiles as P, chooseFreePorts as Q, readProject as R, validateTimeZone as S, generateProjectSecrets as T, PROMPT_ORDER as U, NAMED_PRESETS as V, STACK_OPTIONS as W, stackOption as X, resolvePreset as Y, DEV_PORTS as Z, toProjectName as _, FRONTENDS as a, dockerRunning as at, usesValkey as b, frontendPackageManager as c, removeLeftovers as ct, lockFrontend as d, setEnvValues as dt, envPorts as et, normalizeDatabaseUrl as f, timeZones as g, setNotificationsApp as h, validateDomain as i, dockerNotRunning as it, compose as j, RUN_ENV as k, localS3 as l, parseEnv as lt, scaffold as m, postgresUrl as n, runDoctor as nt, LOCAL_S3 as o, isDockerDown as ot, relativeDirectory as p, encodePreset as q, productionEnv as r, checkTools as rt, cacheEnv as s, leftoverVolumes as st, missingS3 as t, portValues as tt, lockBackend as u, quoteEnvValue as ut, umamiEnv as v, PACKAGE_NAME as w, validateProjectName as x, updateFrontendLock as y, runningServices as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@django-stack/cli",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "The production-ready batteries included Django stack. Create and manage DjangoStack projects: a Django backend, a frontend, Postgres and Docker Compose in one command.",
5
5
  "license": "MIT",
6
6
  "author": "Leon van der Grient",
@@ -5,7 +5,7 @@ description = "The Django backend of {{project_name}}."
5
5
  requires-python = ">=3.12"
6
6
  dependencies = [
7
7
  "Django>=6.1,<6.2",
8
- "django-stack[server,s3]>=0.12.0",
8
+ "django-stack[server,s3]>=0.12.1",
9
9
  "django-headless[schema]>=1.1.1",
10
10
  "django-content-studio[images,huey]>=1.11.0",
11
11
  ]
@@ -16,7 +16,7 @@
16
16
  "@astrojs/node": "^11.1.9",
17
17
  "@astrojs/rss": "^4.0.19",
18
18
  "@django-headless/client": "^1.1.1",
19
- "@django-stack/utils": "^0.12.0",
19
+ "@django-stack/utils": "^0.12.1",
20
20
  "astro": "^7.4.5"
21
21
  },
22
22
  "devDependencies": {
@@ -13,9 +13,9 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@django-headless/client": "^1.1.1",
16
- "@django-stack/next": "^0.12.0",
17
- "@django-stack/react": "^0.12.0",
18
- "@django-stack/utils": "^0.12.0",
16
+ "@django-stack/next": "^0.12.1",
17
+ "@django-stack/react": "^0.12.1",
18
+ "@django-stack/utils": "^0.12.1",
19
19
  "next": "^16.4.4",
20
20
  "react": "^19.3.1",
21
21
  "react-dom": "^19.3.1",
@@ -15,8 +15,8 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@django-headless/client": "^1.1.1",
18
- "@django-stack/utils": "^0.12.0",
19
- "@django-stack/vue": "^0.12.0",
18
+ "@django-stack/utils": "^0.12.1",
19
+ "@django-stack/vue": "^0.12.1",
20
20
  "nuxt": "^4.6.3",
21
21
  "nuxt-security": "^2.7.0",
22
22
  "vue": "^3.5.44",
@@ -19,8 +19,8 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@django-headless/client": "^1.1.1",
22
- "@django-stack/svelte": "^0.12.0",
23
- "@django-stack/utils": "^0.12.0"
22
+ "@django-stack/svelte": "^0.12.1",
23
+ "@django-stack/utils": "^0.12.1"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@sveltejs/adapter-node": "^6.0.1",