@getmonoceros/workbench 1.6.0 → 1.6.2

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
@@ -2850,8 +2850,11 @@ async function assertSafeTargetDir(targetDir, expectedOrigin) {
2850
2850
  }
2851
2851
  return;
2852
2852
  }
2853
+ if (entries.length === 1 && entries[0] === ".monoceros") {
2854
+ return;
2855
+ }
2853
2856
  throw new Error(
2854
- `Refusing to materialize into non-empty directory ${targetDir} (no Monoceros state.json found). Delete the directory before re-running.`
2857
+ `Refusing to materialize into non-empty directory ${targetDir} (no Monoceros state.json found, and the directory has files we don't recognise). Delete the directory before re-running.`
2855
2858
  );
2856
2859
  }
2857
2860
  function warnOnDeprecatedFeatureRefs(containerFeatures, globalConfig, logger) {
@@ -3131,7 +3134,6 @@ import { consola as consola13 } from "consola";
3131
3134
  // src/init/index.ts
3132
3135
  import { existsSync as existsSync7, promises as fs10 } from "fs";
3133
3136
  import { consola as consola12 } from "consola";
3134
- import { parseDocument as parseDocument3 } from "yaml";
3135
3137
 
3136
3138
  // src/init/components.ts
3137
3139
  import { existsSync as existsSync5, promises as fs9 } from "fs";
@@ -3308,7 +3310,7 @@ var SCHEMA_HEADER = [
3308
3310
  "# under `features:` also accepts options not shown here \u2014 check",
3309
3311
  "# the feature's `devcontainer-feature.json` for the full list."
3310
3312
  ];
3311
- function generateComposedYml(name, components, lookupManifest) {
3313
+ function generateComposedYml(name, components, lookupManifest, repoUrls = []) {
3312
3314
  const merged = mergeComponents(components);
3313
3315
  const lines = [];
3314
3316
  for (const h of SCHEMA_HEADER) lines.push(h);
@@ -3339,9 +3341,17 @@ function generateComposedYml(name, components, lookupManifest) {
3339
3341
  }
3340
3342
  lines.push("");
3341
3343
  }
3344
+ if (repoUrls.length > 0) {
3345
+ renderReposBlock(
3346
+ lines,
3347
+ repoUrls,
3348
+ /* commented */
3349
+ false
3350
+ );
3351
+ }
3342
3352
  return ensureTrailingNewline(lines.join("\n"));
3343
3353
  }
3344
- function generateDocumentedYml(name, catalog, lookupManifest) {
3354
+ function generateDocumentedYml(name, catalog, lookupManifest, repoUrls = []) {
3345
3355
  const byCategory = groupByCategory(catalog);
3346
3356
  const lines = [];
3347
3357
  for (const h of SCHEMA_HEADER) lines.push(h);
@@ -3442,6 +3452,12 @@ function generateDocumentedYml(name, catalog, lookupManifest) {
3442
3452
  }
3443
3453
  lines.push("");
3444
3454
  }
3455
+ renderReposBlock(
3456
+ lines,
3457
+ repoUrls,
3458
+ /* commented */
3459
+ repoUrls.length === 0
3460
+ );
3445
3461
  return ensureTrailingNewline(lines.join("\n"));
3446
3462
  }
3447
3463
  var COMMENT_WIDTH = 72;
@@ -3497,6 +3513,57 @@ function emitHint(out, hint, description, linePrefix) {
3497
3513
  }
3498
3514
  out.push(`${linePrefix}${hint}:`);
3499
3515
  }
3516
+ function renderReposBlock(out, urls, commented) {
3517
+ out.push("# Repos \u2014 git repositories cloned into projects/ during");
3518
+ out.push("# post-create. HTTPS-only (ADR 0006). Provider auto-detected");
3519
+ out.push("# for github.com, gitlab.com, bitbucket.org; for any other host");
3520
+ out.push("# (self-hosted GitLab, Bitbucket Data Center, Gitea/Forgejo,");
3521
+ out.push("# GitHub Enterprise, \u2026) declare provider explicitly.");
3522
+ out.push("#");
3523
+ if (commented) {
3524
+ out.push("# repos:");
3525
+ out.push("# - url: https://github.com/<org>/<repo>.git");
3526
+ out.push(
3527
+ "# # path: <folder> # subfolder under projects/; default: URL-derived"
3528
+ );
3529
+ out.push(
3530
+ "# # provider: github # github | gitlab | bitbucket | gitea"
3531
+ );
3532
+ out.push(
3533
+ "# # git: # per-repo committer identity override"
3534
+ );
3535
+ out.push("# # user:");
3536
+ out.push("# # name: Your Name");
3537
+ out.push("# # email: you@example.com");
3538
+ out.push("");
3539
+ return;
3540
+ }
3541
+ out.push("repos:");
3542
+ for (const url of urls) {
3543
+ const derivedPath = deriveDefaultPath(url);
3544
+ out.push(` - url: ${url}`);
3545
+ out.push(
3546
+ ` # path: ${derivedPath} # subfolder under projects/; default: URL-derived (${derivedPath})`
3547
+ );
3548
+ out.push(
3549
+ " # provider: github # github | gitlab | bitbucket | gitea"
3550
+ );
3551
+ out.push(
3552
+ " # git: # per-repo committer identity override"
3553
+ );
3554
+ out.push(" # user:");
3555
+ out.push(" # name: Your Name");
3556
+ out.push(" # email: you@example.com");
3557
+ }
3558
+ out.push("");
3559
+ }
3560
+ function deriveDefaultPath(url) {
3561
+ let last = url;
3562
+ const slash = url.lastIndexOf("/");
3563
+ if (slash >= 0) last = url.slice(slash + 1);
3564
+ if (last.endsWith(".git")) last = last.slice(0, -4);
3565
+ return last || "repo";
3566
+ }
3500
3567
  function wrapToComment(text, width) {
3501
3568
  const words = text.split(/\s+/).filter((w) => w.length > 0);
3502
3569
  if (words.length === 0) return [""];
@@ -3621,15 +3688,14 @@ async function runInit(opts) {
3621
3688
  }
3622
3689
  const checkoutRoot = opts.workbenchRoot ?? workbenchCheckoutRoot();
3623
3690
  const lookup = (ref) => loadFeatureManifestSummary(ref, checkoutRoot);
3624
- let text;
3625
- const requested = opts.with ?? [];
3626
- if (requested.length === 0) {
3627
- text = generateDocumentedYml(opts.name, catalog, lookup);
3628
- } else {
3629
- const components = resolveComponents(catalog, requested);
3630
- text = generateComposedYml(opts.name, components, lookup);
3691
+ const reposRaw = (opts.withRepo ?? []).map((u) => u.trim()).filter((u) => u.length > 0);
3692
+ const repos = [];
3693
+ const seenRepoUrls = /* @__PURE__ */ new Set();
3694
+ for (const url of reposRaw) {
3695
+ if (seenRepoUrls.has(url)) continue;
3696
+ seenRepoUrls.add(url);
3697
+ repos.push(url);
3631
3698
  }
3632
- const repos = (opts.withRepo ?? []).map((u) => u.trim()).filter((u) => u.length > 0);
3633
3699
  if (repos.length > 0) {
3634
3700
  const offending = [];
3635
3701
  for (const url of repos) {
@@ -3653,12 +3719,14 @@ async function runInit(opts) {
3653
3719
  ].join("\n")
3654
3720
  );
3655
3721
  }
3656
- const doc = parseDocument3(text);
3657
- for (const url of repos) {
3658
- const path13 = deriveRepoName(url);
3659
- addRepoToDoc(doc, { url, path: path13 });
3660
- }
3661
- text = String(doc);
3722
+ }
3723
+ let text;
3724
+ const requested = opts.with ?? [];
3725
+ if (requested.length === 0) {
3726
+ text = generateDocumentedYml(opts.name, catalog, lookup, repos);
3727
+ } else {
3728
+ const components = resolveComponents(catalog, requested);
3729
+ text = generateComposedYml(opts.name, components, lookup, repos);
3662
3730
  }
3663
3731
  await fs10.mkdir(containerConfigsDir(home), { recursive: true });
3664
3732
  await fs10.writeFile(dest, text, "utf8");