@flisk-sh/flisk-import 0.9.0 → 0.10.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 CHANGED
@@ -12,6 +12,7 @@ flisk import . --yes # write service.json files and project setup
12
12
 
13
13
  - **Reads one file:** the root `docker-compose.yml`, or `compose.yaml`, `compose.yml` or `docker-compose.yaml` when that is absent. Not override files, nested Compose files, Dockerfiles on their own, `package.json`, or Procfiles.
14
14
  - **Writes:** one bring-your-own `service.json` per Compose service, plus `.flisk/project.json` if the repo is not a Flisk project yet. It never edits the Compose file or overwrites a `service.json` without `--force`.
15
+ - **Keeps the install's data:** each named volume gets `name`, the Docker volume `docker compose up` created (`<project>_<volume>`, its own `name:`, or an `external` volume), so `flisk up` mounts the same data with no copy (needs the Flisk release with flisk#2964).
15
16
  - **Keeps:** the service names (`db` stays `db`, so it stays the hostname), the build context and Dockerfile (or the image), the container port as written (3000, 80, 5432), `depends_on`, and an HTTP health path. Databases and brokers are private, with no proxy route.
16
17
  - **Runtime keys:** named volumes and bind mounts inside the project (`volumes`), `cap_add`, `cap_drop`, `init`, `read_only`, `user`, `security_opt` and `shm_size` (`container`), extra published ports (`extraPorts`, on 127.0.0.1 only), `network_mode: service:<name>` (`sidecarOf`) and `restart`.
17
18
  - **Environment:** values that cannot be secrets go into the committed `service.json` `env`: numbers, `true`/`false`, another imported service's address without a user, password or query (`http://invidious:3000`, `redis:6379`), and pure `${VAR}` references. Every other name, and any name that looks like a credential (`PASSWORD`, `TOKEN`, `KEY`, ...), goes into `secrets.required`, with its literal value copied to the project `.env`, which is added to `.gitignore`. Values in `.env` already are kept.
@@ -1,5 +1,5 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { dirname, isAbsolute, join, normalize } from "node:path/posix";
2
+ import { basename, dirname, isAbsolute, join, normalize } from "node:path/posix";
3
3
  import { isAlias, isMap, parseDocument, visit } from "yaml";
4
4
  import { HEALTH_CHECK_PATH_PATTERN } from "../flisk.js";
5
5
  import { registerDetector } from "../registry.js";
@@ -189,6 +189,26 @@ function volumeOf(entry, composeDir) {
189
189
  return undefined;
190
190
  return { source: resolved, target, ...(readOnly ? { readOnly } : {}), bind };
191
191
  }
192
+ /** Compose's project name: top-level `name`, else the directory name, lowercased with other characters dropped. */
193
+ function projectNameOf(root, absPath) {
194
+ const raw = isObj(root) && typeof root.name === "string" && !root.name.includes("$")
195
+ ? root.name
196
+ : basename(dirname(absPath));
197
+ const name = raw.toLowerCase().replace(/[^a-z0-9_-]/g, "");
198
+ return /^[a-z0-9]/.test(name) ? name : undefined;
199
+ }
200
+ /**
201
+ * The Docker name of a named volume, as `docker compose up` created it: its own `name:`, the key itself when it is
202
+ * `external`, else `<project>_<key>`. Undefined when the name uses Compose variables.
203
+ */
204
+ function dockerVolumeName(key, volumes, project) {
205
+ const def = isObj(volumes) ? volumes[key] : undefined;
206
+ if (isObj(def) && typeof def.name === "string")
207
+ return /^[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(def.name) ? def.name : undefined;
208
+ if (isObj(def) && (def.external === true || isObj(def.external)))
209
+ return key;
210
+ return project ? `${project}_${key}` : undefined;
211
+ }
192
212
  function envNames(environment) {
193
213
  if (Array.isArray(environment)) {
194
214
  return environment
@@ -358,6 +378,7 @@ registerDetector({
358
378
  if (!services || !isMap(doc.get("services", true))) {
359
379
  return { candidates, skips: [...skips, { ...base, reason: "no `services:` map" }] };
360
380
  }
381
+ const project = projectNameOf(root, absPath);
361
382
  for (const [name, raw] of Object.entries(services)) {
362
383
  if (!isObj(raw)) {
363
384
  skips.push({ ...base, reason: `service "${name}" is not a map` });
@@ -477,8 +498,11 @@ registerDetector({
477
498
  const volumes = [];
478
499
  for (const entry of Array.isArray(raw.volumes) ? raw.volumes : []) {
479
500
  const volume = volumeOf(entry, composeDir);
501
+ const dockerName = volume && !volume.bind
502
+ ? dockerVolumeName(volume.source, isObj(root) ? root.volumes : undefined, project)
503
+ : undefined;
480
504
  if (volume)
481
- volumes.push(volume);
505
+ volumes.push(dockerName ? { ...volume, name: dockerName } : volume);
482
506
  else
483
507
  skips.push({
484
508
  ...base,
package/dist/write.js CHANGED
@@ -276,10 +276,12 @@ export function planWrites(plan, force) {
276
276
  ...(sidecarOf ? { sidecarOf } : {}),
277
277
  ...(volumes.length
278
278
  ? {
279
- volumes: volumes.map(({ source, target, readOnly }) => ({
279
+ // `name` keeps the Docker volume the Compose install already has, so its data is used with no copy.
280
+ volumes: volumes.map(({ source, target, readOnly, name }) => ({
280
281
  source,
281
282
  target,
282
283
  ...(readOnly ? { readOnly } : {}),
284
+ ...(name ? { name } : {}),
283
285
  })),
284
286
  }
285
287
  : {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flisk-sh/flisk-import",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Import a repository's root docker-compose.yml into Flisk service.json files, or register its Tiltfile.",
5
5
  "type": "module",
6
6
  "license": "MIT",