@bensandee/tooling 0.57.2 → 0.57.3

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/bin.mjs +53 -5
  2. package/package.json +1 -1
package/dist/bin.mjs CHANGED
@@ -880,6 +880,13 @@ function detectDockerPackages(executor, cwd, repoName) {
880
880
  const packages = [];
881
881
  const seen = /* @__PURE__ */ new Set();
882
882
  if (packageDirs.length > 0) {
883
+ const rootConvention = findRootDockerfile(executor, cwd);
884
+ const rootOverride = overrides["."];
885
+ const rootDocker = mergeDockerConfig(rootConvention, rootOverride);
886
+ if (rootDocker) {
887
+ packages.push(createDockerPackage(executor, cwd, ".", repoName, rootDocker));
888
+ seen.add(".");
889
+ }
883
890
  for (const dir of packageDirs) {
884
891
  const convention = findConventionDockerfile(executor, cwd, dir);
885
892
  const override = overrides[dir];
@@ -1800,7 +1807,7 @@ async function generatePackageJson(ctx) {
1800
1807
  const devDeps = { ...ROOT_DEV_DEPS };
1801
1808
  if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
1802
1809
  devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.10.2";
1803
- devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.57.2";
1810
+ devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.57.3";
1804
1811
  if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.12.0";
1805
1812
  if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = {
1806
1813
  "@changesets/cli": "2.31.0",
@@ -4711,7 +4718,7 @@ async function runGenerators(ctx) {
4711
4718
  function generateMigratePrompt(results, config, detected) {
4712
4719
  const sections = [];
4713
4720
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
4714
- sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.57.2 repo:sync\` on ${timestamp}_\n`);
4721
+ sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.57.3 repo:sync\` on ${timestamp}_\n`);
4715
4722
  const changed = results.filter((r) => r.action === "created" || r.action === "updated" || r.action === "archived");
4716
4723
  if (changed.length > 0) {
4717
4724
  const items = changed.map((r) => {
@@ -6509,8 +6516,18 @@ const ComposePortSchema = z.union([z.string(), z.looseObject({
6509
6516
  published: z.union([z.string(), z.number()]),
6510
6517
  target: z.union([z.string(), z.number()]).optional()
6511
6518
  })]);
6519
+ /**
6520
+ * Compose `build:` accepts either a string shorthand (the build context path,
6521
+ * with `dockerfile` defaulting to `Dockerfile`) or an object with `context`
6522
+ * and/or `dockerfile`. We capture both forms.
6523
+ */
6524
+ const ComposeBuildSchema = z.union([z.string(), z.looseObject({
6525
+ context: z.string().optional(),
6526
+ dockerfile: z.string().optional()
6527
+ })]);
6512
6528
  const ComposeServiceSchema = z.looseObject({
6513
6529
  image: z.string().optional(),
6530
+ build: ComposeBuildSchema.optional(),
6514
6531
  ports: z.array(ComposePortSchema).optional(),
6515
6532
  healthcheck: z.unknown().optional()
6516
6533
  });
@@ -6533,6 +6550,20 @@ function detectComposeFiles(cwd) {
6533
6550
  files: []
6534
6551
  };
6535
6552
  }
6553
+ /**
6554
+ * Resolve a service's `build:` stanza to an absolute Dockerfile path.
6555
+ * Compose spec: bare-string shorthand sets the context; `dockerfile` defaults
6556
+ * to `Dockerfile`; both context and dockerfile default to `.` and `Dockerfile`
6557
+ * respectively when absent. The dockerfile path is resolved relative to the
6558
+ * build context, which is itself relative to the compose file's directory.
6559
+ */
6560
+ function resolveBuildDockerfile(composeFileDir, build) {
6561
+ if (build === void 0) return void 0;
6562
+ if (typeof build === "string") return path.resolve(composeFileDir, build, "Dockerfile");
6563
+ const context = build.context ?? ".";
6564
+ const dockerfile = build.dockerfile ?? "Dockerfile";
6565
+ return path.resolve(composeFileDir, context, dockerfile);
6566
+ }
6536
6567
  /** Parse a single port mapping string and extract the host port. */
6537
6568
  function parsePortString(port) {
6538
6569
  const withoutProtocol = port.split("/")[0];
@@ -6583,9 +6614,11 @@ function parseComposeServices(cwd, composeFiles) {
6583
6614
  break;
6584
6615
  }
6585
6616
  }
6617
+ const buildDockerfile = resolveBuildDockerfile(cwd, service.build);
6586
6618
  serviceMap.set(name, {
6587
6619
  name,
6588
6620
  image: existing?.image ?? service.image,
6621
+ buildDockerfile: existing?.buildDockerfile ?? buildDockerfile,
6589
6622
  hostPort,
6590
6623
  hasHealthcheck: existing?.hasHealthcheck ?? service.healthcheck !== void 0
6591
6624
  });
@@ -6616,6 +6649,17 @@ function extractComposeImageNames(services) {
6616
6649
  return [...names];
6617
6650
  }
6618
6651
  /**
6652
+ * Extract absolute Dockerfile paths from services that use `build:` rather
6653
+ * than (or alongside) `image:`. Used by `docker:check` to recognize that a
6654
+ * compose service builds a known Docker package even when no `image:` tag
6655
+ * is set.
6656
+ */
6657
+ function extractComposeBuildDockerfiles(services) {
6658
+ const paths = /* @__PURE__ */ new Set();
6659
+ for (const service of services) if (service.buildDockerfile) paths.add(service.buildDockerfile);
6660
+ return [...paths];
6661
+ }
6662
+ /**
6619
6663
  * Whether a service's image refers to an image this repo builds locally.
6620
6664
  * Matches the bare image name (variables/tag stripped) against the list of
6621
6665
  * detected Docker package image names, using the same exact-or-suffix match
@@ -6790,9 +6834,13 @@ const dockerCheckCommand = defineCommand({
6790
6834
  if (rootPkg?.name) {
6791
6835
  const dockerPackages = detectDockerPackages(fileReader, cwd, rootPkg.name);
6792
6836
  const composeImages = extractComposeImageNames(services);
6837
+ const composeBuildDockerfiles = new Set(extractComposeBuildDockerfiles(services));
6793
6838
  for (const pkg of dockerPackages) {
6794
6839
  locallyBuiltImageNames.push(pkg.imageName);
6795
- if (!composeImages.some((img) => img === pkg.imageName || img.endsWith(`/${pkg.imageName}`))) log.warn(`Docker package "${pkg.dir}" (image: ${pkg.imageName}) is not referenced in any compose service.`);
6840
+ const matchesImage = composeImages.some((img) => img === pkg.imageName || img.endsWith(`/${pkg.imageName}`));
6841
+ const pkgDockerfileAbs = path.resolve(cwd, pkg.docker.dockerfile);
6842
+ const matchesBuild = composeBuildDockerfiles.has(pkgDockerfileAbs);
6843
+ if (!matchesImage && !matchesBuild) log.warn(`Docker package "${pkg.dir}" (image: ${pkg.imageName}) is not referenced in any compose service.`);
6796
6844
  }
6797
6845
  }
6798
6846
  }
@@ -8125,7 +8173,7 @@ const out = (msg) => console.log(msg);
8125
8173
  const main = defineCommand({
8126
8174
  meta: {
8127
8175
  name: "bst",
8128
- version: "0.57.2",
8176
+ version: "0.57.3",
8129
8177
  description: "Bootstrap and maintain standardized TypeScript project tooling"
8130
8178
  },
8131
8179
  subCommands: {
@@ -8197,7 +8245,7 @@ const main = defineCommand({
8197
8245
  })
8198
8246
  }
8199
8247
  });
8200
- console.log(`@bensandee/tooling v0.57.2`);
8248
+ console.log(`@bensandee/tooling v0.57.3`);
8201
8249
  async function run() {
8202
8250
  await runMain(main);
8203
8251
  process.exit(process.exitCode ?? 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bensandee/tooling",
3
- "version": "0.57.2",
3
+ "version": "0.57.3",
4
4
  "description": "CLI tool to bootstrap and maintain standardized TypeScript project tooling",
5
5
  "license": "MIT",
6
6
  "repository": {