@fern-api/generator-cli 0.9.56 → 0.10.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.
Files changed (2) hide show
  1. package/dist/cli.js +234 -62
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -7166,7 +7166,7 @@ var require_require_directory = __commonJS({
7166
7166
  "../../node_modules/.pnpm/require-directory@2.1.1/node_modules/require-directory/index.js"(exports2, module2) {
7167
7167
  "use strict";
7168
7168
  var fs3 = require("fs");
7169
- var join18 = require("path").join;
7169
+ var join19 = require("path").join;
7170
7170
  var resolve8 = require("path").resolve;
7171
7171
  var dirname6 = require("path").dirname;
7172
7172
  var defaultOptions2 = {
@@ -7203,7 +7203,7 @@ var require_require_directory = __commonJS({
7203
7203
  }
7204
7204
  path5 = !path5 ? dirname6(m.filename) : resolve8(dirname6(m.filename), path5);
7205
7205
  fs3.readdirSync(path5).forEach(function(filename) {
7206
- var joined = join18(path5, filename), files, key, obj;
7206
+ var joined = join19(path5, filename), files, key, obj;
7207
7207
  if (fs3.statSync(joined).isDirectory() && options.recurse) {
7208
7208
  files = requireDirectory(m, joined, options);
7209
7209
  if (Object.keys(files).length) {
@@ -30483,9 +30483,9 @@ function resolve(...paths) {
30483
30483
  }
30484
30484
 
30485
30485
  // src/cli.ts
30486
- var import_fs17 = __toESM(require("fs"));
30486
+ var import_fs18 = __toESM(require("fs"));
30487
30487
  var import_promises19 = require("fs/promises");
30488
- var import_path26 = __toESM(require("path"));
30488
+ var import_path27 = __toESM(require("path"));
30489
30489
 
30490
30490
  // ../../node_modules/.pnpm/yargs@17.7.2/node_modules/yargs/build/lib/yerror.js
30491
30491
  var YError = class _YError extends Error {
@@ -40614,18 +40614,48 @@ var consolePipelineLogger = {
40614
40614
  };
40615
40615
 
40616
40616
  // src/pipeline/PostGenerationPipeline.ts
40617
- var import_child_process7 = require("child_process");
40617
+ var import_child_process8 = require("child_process");
40618
40618
 
40619
40619
  // src/pipeline/github/constants.ts
40620
40620
  var FERN_BOT_NAME2 = "fern-api";
40621
40621
  var FERN_BOT_EMAIL2 = "115122769+fern-api[bot]@users.noreply.github.com";
40622
40622
  var FERN_BOT_LOGIN2 = "fern-api[bot]";
40623
40623
 
40624
- // src/pipeline/steps/AutoVersionStep.ts
40624
+ // src/pipeline/github/stripGeneratedWorkflows.ts
40625
40625
  var import_child_process4 = require("child_process");
40626
- var import_fs15 = require("fs");
40626
+ var import_fs14 = require("fs");
40627
+ var import_path22 = require("path");
40628
+ var GITHUB_WORKFLOWS_DIR = ".github/workflows";
40629
+ function stripGeneratedWorkflows(outputDir, logger) {
40630
+ (0, import_fs14.rmSync)((0, import_path22.join)(outputDir, GITHUB_WORKFLOWS_DIR), { recursive: true, force: true });
40631
+ (0, import_child_process4.execFileSync)("git", ["rm", "-r", "-q", "--cached", "--ignore-unmatch", "--", GITHUB_WORKFLOWS_DIR], {
40632
+ cwd: outputDir,
40633
+ stdio: "pipe"
40634
+ });
40635
+ if (!hasTrackedWorkflows(outputDir)) {
40636
+ logger.debug(`Removed generated ${GITHUB_WORKFLOWS_DIR} (workflows disabled)`);
40637
+ return;
40638
+ }
40639
+ (0, import_child_process4.execFileSync)("git", ["checkout", "HEAD", "--", GITHUB_WORKFLOWS_DIR], { cwd: outputDir, stdio: "pipe" });
40640
+ logger.debug(`Restored ${GITHUB_WORKFLOWS_DIR} from HEAD (workflows disabled)`);
40641
+ }
40642
+ function hasTrackedWorkflows(outputDir) {
40643
+ try {
40644
+ const output = (0, import_child_process4.execFileSync)("git", ["ls-tree", "-r", "--name-only", "HEAD", "--", GITHUB_WORKFLOWS_DIR], {
40645
+ cwd: outputDir,
40646
+ stdio: "pipe"
40647
+ });
40648
+ return output.toString().trim().length > 0;
40649
+ } catch {
40650
+ return false;
40651
+ }
40652
+ }
40653
+
40654
+ // src/pipeline/steps/AutoVersionStep.ts
40655
+ var import_child_process5 = require("child_process");
40656
+ var import_fs16 = require("fs");
40627
40657
  var import_promises16 = require("fs/promises");
40628
- var import_path23 = require("path");
40658
+ var import_path24 = require("path");
40629
40659
 
40630
40660
  // ../commons/logging-execa/lib/loggingExeca.js
40631
40661
  var import_execa = __toESM(require_execa(), 1);
@@ -40683,9 +40713,9 @@ async function loggingExeca(logger, executable, args = [], { doNotPipeOutput = f
40683
40713
  }
40684
40714
 
40685
40715
  // src/autoversion/AutoVersioningService.ts
40686
- var import_fs14 = require("fs");
40716
+ var import_fs15 = require("fs");
40687
40717
  var import_promises15 = require("fs/promises");
40688
- var import_path22 = require("path");
40718
+ var import_path23 = require("path");
40689
40719
  var import_semver = __toESM(require_semver2());
40690
40720
  var AutoVersioningException = class extends Error {
40691
40721
  /**
@@ -41557,8 +41587,8 @@ var AutoVersioningService = class _AutoVersioningService {
41557
41587
  );
41558
41588
  return;
41559
41589
  }
41560
- const goModPath = (0, import_path22.join)(workingDirectory, "go.mod");
41561
- if (!(0, import_fs14.existsSync)(goModPath)) {
41590
+ const goModPath = (0, import_path23.join)(workingDirectory, "go.mod");
41591
+ if (!(0, import_fs15.existsSync)(goModPath)) {
41562
41592
  this.logger.debug(`No go.mod found in ${workingDirectory}, skipping Go module path update`);
41563
41593
  return;
41564
41594
  }
@@ -41628,7 +41658,7 @@ var AutoVersioningService = class _AutoVersioningService {
41628
41658
  const results = [];
41629
41659
  const entries2 = await (0, import_promises15.readdir)(dir);
41630
41660
  for (const entry of entries2) {
41631
- const fullPath = (0, import_path22.join)(dir, entry);
41661
+ const fullPath = (0, import_path23.join)(dir, entry);
41632
41662
  const entryStat = await (0, import_promises15.lstat)(fullPath);
41633
41663
  if (entryStat.isSymbolicLink()) {
41634
41664
  continue;
@@ -41660,7 +41690,7 @@ var AutoVersioningService = class _AutoVersioningService {
41660
41690
  * literals (e.g. the X-Fern-SDK-Name header value) in all .go files.
41661
41691
  */
41662
41692
  async addSuffixToGoFiles(repoRoot, modulePath, suffix) {
41663
- const goFiles = await this.walkDirectory(repoRoot, (filePath) => (0, import_path22.extname)(filePath) === ".go");
41693
+ const goFiles = await this.walkDirectory(repoRoot, (filePath) => (0, import_path23.extname)(filePath) === ".go");
41664
41694
  await this.processInParallel(goFiles, (filePath) => this.addSuffixToGoFile(filePath, modulePath, suffix));
41665
41695
  }
41666
41696
  /**
@@ -41706,7 +41736,7 @@ var AutoVersioningService = class _AutoVersioningService {
41706
41736
  async addSuffixToMarkdownFiles(repoRoot, modulePath, suffix) {
41707
41737
  const markdownFiles = await this.walkDirectory(
41708
41738
  repoRoot,
41709
- (filePath) => (0, import_path22.extname)(filePath).toLowerCase() === ".md"
41739
+ (filePath) => (0, import_path23.extname)(filePath).toLowerCase() === ".md"
41710
41740
  );
41711
41741
  await this.processInParallel(
41712
41742
  markdownFiles,
@@ -42181,7 +42211,8 @@ var AutoVersionStep = class extends BaseStep {
42181
42211
  };
42182
42212
  }
42183
42213
  async finalizeWithBump(params) {
42184
- const { service, language, mappedMagicVersion, previousVersion, analysis } = params;
42214
+ const { service, language, mappedMagicVersion, previousVersion } = params;
42215
+ const analysis = this.withChangelogFallback(params.analysis);
42185
42216
  const newVersion = incrementVersion(previousVersion, analysis.versionBump);
42186
42217
  this.logger.info(`AutoVersionStep: ${analysis.versionBump} bump: ${previousVersion} \u2192 ${newVersion}`);
42187
42218
  await service.replaceMagicVersion(this.outputDir, mappedMagicVersion, newVersion);
@@ -42235,7 +42266,8 @@ var AutoVersionStep = class extends BaseStep {
42235
42266
  * the bumped version but does NOT commit — GithubStep handles the commit.
42236
42267
  */
42237
42268
  async finalizeWithBumpNonReplay(params) {
42238
- const { service, language, mappedMagicVersion, previousVersion, analysis } = params;
42269
+ const { service, language, mappedMagicVersion, previousVersion } = params;
42270
+ const analysis = this.withChangelogFallback(params.analysis);
42239
42271
  const newVersion = incrementVersion(previousVersion, analysis.versionBump);
42240
42272
  this.logger.info(
42241
42273
  `AutoVersionStep (non-replay): ${analysis.versionBump} bump: ${previousVersion} \u2192 ${newVersion}`
@@ -42345,7 +42377,7 @@ var AutoVersionStep = class extends BaseStep {
42345
42377
  }
42346
42378
  async readVersionFromMetadata() {
42347
42379
  try {
42348
- const output = (0, import_child_process4.execFileSync)("git", ["show", "HEAD~1:.fern/metadata.json"], {
42380
+ const output = (0, import_child_process5.execFileSync)("git", ["show", "HEAD~1:.fern/metadata.json"], {
42349
42381
  cwd: this.outputDir,
42350
42382
  encoding: "utf-8",
42351
42383
  stdio: "pipe"
@@ -42388,7 +42420,7 @@ var AutoVersionStep = class extends BaseStep {
42388
42420
  */
42389
42421
  readVersionFromMetadataAtHead() {
42390
42422
  try {
42391
- const output = (0, import_child_process4.execFileSync)("git", ["show", "HEAD:.fern/metadata.json"], {
42423
+ const output = (0, import_child_process5.execFileSync)("git", ["show", "HEAD:.fern/metadata.json"], {
42392
42424
  cwd: this.outputDir,
42393
42425
  encoding: "utf-8",
42394
42426
  stdio: "pipe"
@@ -42406,11 +42438,11 @@ var AutoVersionStep = class extends BaseStep {
42406
42438
  * the diff, matching LocalTaskHandler.generateDiffFile() behavior.
42407
42439
  */
42408
42440
  gitDiffHead() {
42409
- (0, import_child_process4.execFileSync)("git", ["add", "-N", "."], {
42441
+ (0, import_child_process5.execFileSync)("git", ["add", "-N", "."], {
42410
42442
  cwd: this.outputDir,
42411
42443
  stdio: "pipe"
42412
42444
  });
42413
- return (0, import_child_process4.execFileSync)("git", ["diff", "HEAD", "--", ".", ":(exclude).fern/metadata.json"], {
42445
+ return (0, import_child_process5.execFileSync)("git", ["diff", "HEAD", "--", ".", ":(exclude).fern/metadata.json"], {
42414
42446
  cwd: this.outputDir,
42415
42447
  encoding: "utf-8",
42416
42448
  stdio: "pipe",
@@ -42449,7 +42481,7 @@ var AutoVersionStep = class extends BaseStep {
42449
42481
  return false;
42450
42482
  }
42451
42483
  try {
42452
- (0, import_child_process4.execFileSync)("git", ["cat-file", "-e", `${sha}^{commit}`], {
42484
+ (0, import_child_process5.execFileSync)("git", ["cat-file", "-e", `${sha}^{commit}`], {
42453
42485
  cwd: this.outputDir,
42454
42486
  stdio: "pipe"
42455
42487
  });
@@ -42467,7 +42499,7 @@ var AutoVersionStep = class extends BaseStep {
42467
42499
  const start = this.commitExists(currentGenerationSha) ? currentGenerationSha : "HEAD";
42468
42500
  let log;
42469
42501
  try {
42470
- log = (0, import_child_process4.execFileSync)("git", ["log", "--first-parent", "--format=%H%x00%s", start], {
42502
+ log = (0, import_child_process5.execFileSync)("git", ["log", "--first-parent", "--format=%H%x00%s", start], {
42471
42503
  cwd: this.outputDir,
42472
42504
  encoding: "utf-8",
42473
42505
  stdio: "pipe",
@@ -42509,7 +42541,7 @@ var AutoVersionStep = class extends BaseStep {
42509
42541
  }
42510
42542
  }
42511
42543
  gitDiff(from, to) {
42512
- return (0, import_child_process4.execFileSync)("git", ["diff", from, to, "--", ".", ":(exclude).fern/metadata.json"], {
42544
+ return (0, import_child_process5.execFileSync)("git", ["diff", from, to, "--", ".", ":(exclude).fern/metadata.json"], {
42513
42545
  cwd: this.outputDir,
42514
42546
  encoding: "utf-8",
42515
42547
  stdio: "pipe",
@@ -42522,12 +42554,12 @@ var AutoVersionStep = class extends BaseStep {
42522
42554
  const fullMessage = body.length > 0 ? `${COMMIT_MARKER} ${subject}
42523
42555
 
42524
42556
  ${body}` : `${COMMIT_MARKER} ${subject}`;
42525
- (0, import_child_process4.execFileSync)("git", ["add", "-A"], { cwd: this.outputDir, stdio: "pipe" });
42526
- (0, import_child_process4.execFileSync)("git", ["commit", "--allow-empty", "-m", fullMessage], {
42557
+ (0, import_child_process5.execFileSync)("git", ["add", "-A"], { cwd: this.outputDir, stdio: "pipe" });
42558
+ (0, import_child_process5.execFileSync)("git", ["commit", "--allow-empty", "-m", fullMessage], {
42527
42559
  cwd: this.outputDir,
42528
42560
  stdio: "pipe"
42529
42561
  });
42530
- return (0, import_child_process4.execFileSync)("git", ["rev-parse", "HEAD"], {
42562
+ return (0, import_child_process5.execFileSync)("git", ["rev-parse", "HEAD"], {
42531
42563
  cwd: this.outputDir,
42532
42564
  encoding: "utf-8",
42533
42565
  stdio: "pipe"
@@ -42535,13 +42567,33 @@ ${body}` : `${COMMIT_MARKER} ${subject}`;
42535
42567
  }
42536
42568
  async prependChangelogEntry(params) {
42537
42569
  const { version: version2, entry } = params;
42538
- const changelogPath = (0, import_path23.join)(this.outputDir, "changelog.md");
42570
+ const changelogPath = (0, import_path24.join)(this.outputDir, "changelog.md");
42539
42571
  let existing = "";
42540
- if ((0, import_fs15.existsSync)(changelogPath)) {
42572
+ if ((0, import_fs16.existsSync)(changelogPath)) {
42541
42573
  existing = await (0, import_promises16.readFile)(changelogPath, "utf-8");
42542
42574
  }
42543
42575
  await (0, import_promises16.writeFile)(changelogPath, prependChangelogBlock({ existingContent: existing, version: version2, entry }), "utf-8");
42544
42576
  }
42577
+ /**
42578
+ * MAJOR/MINOR bumps must ship a changelog entry. FAI occasionally returns a
42579
+ * bump with a populated `pr_description` / `version_bump_reason` but an empty
42580
+ * `changelog_entry`; reuse that text rather than writing a version-only block.
42581
+ */
42582
+ withChangelogFallback(analysis) {
42583
+ const fallback = resolveChangelogEntryFallbackWithSource(analysis);
42584
+ if (fallback == null) {
42585
+ if (analysis.versionBump !== "PATCH" && !hasText(analysis.changelogEntry)) {
42586
+ this.logger.warn(
42587
+ `AutoVersionStep: FAI returned a ${analysis.versionBump} bump without a changelog entry and no fallback text.`
42588
+ );
42589
+ }
42590
+ return analysis;
42591
+ }
42592
+ this.logger.warn(
42593
+ `AutoVersionStep: FAI returned a ${analysis.versionBump} bump without a changelog entry; using the ${fallback.source} instead.`
42594
+ );
42595
+ return { ...analysis, changelogEntry: fallback.text };
42596
+ }
42545
42597
  brandMessage(message) {
42546
42598
  if (this.config.isWhitelabel) {
42547
42599
  return message;
@@ -42572,10 +42624,7 @@ ${body}` : `${COMMIT_MARKER} ${subject}`;
42572
42624
  }
42573
42625
  async analyzeChunks(chunks, language, previousVersion) {
42574
42626
  const { client, VersionBump: VersionBump4 } = await this.loadBaml();
42575
- let bestBump = VersionBump4.NO_CHANGE;
42576
- let bestMessage = "";
42577
- let bestVersionBumpReason;
42578
- const changelogEntries = [];
42627
+ const chunkAnalyses = [];
42579
42628
  for (let i2 = 0; i2 < chunks.length; i2++) {
42580
42629
  const chunk = chunks[i2];
42581
42630
  if (!chunk) {
@@ -42591,20 +42640,22 @@ ${body}` : `${COMMIT_MARKER} ${subject}`;
42591
42640
  if (analysis.version_bump === VersionBump4.NO_CHANGE) {
42592
42641
  continue;
42593
42642
  }
42594
- const prev = bestBump;
42595
- bestBump = maxVersionBump(bestBump, analysis.version_bump);
42596
- if (bestBump !== prev) {
42597
- bestMessage = analysis.message;
42598
- bestVersionBumpReason = analysis.version_bump_reason;
42599
- }
42600
- const entry = analysis.changelog_entry?.trim();
42601
- if (entry) {
42602
- changelogEntries.push(entry);
42603
- }
42643
+ chunkAnalyses.push({
42644
+ versionBump: analysis.version_bump,
42645
+ message: analysis.message,
42646
+ changelogEntry: analysis.changelog_entry,
42647
+ versionBumpReason: analysis.version_bump_reason
42648
+ });
42604
42649
  }
42605
- if (bestBump === VersionBump4.NO_CHANGE) {
42650
+ if (chunkAnalyses.length === 0) {
42606
42651
  return null;
42607
42652
  }
42653
+ const { bestBump, bestMessage, bestVersionBumpReason, changelogEntries, usedBumpReasonAsEntry } = aggregateChunkAnalyses(chunkAnalyses);
42654
+ if (usedBumpReasonAsEntry) {
42655
+ this.logger.warn(
42656
+ `AutoVersionStep: no chunk produced a changelog entry for the ${bestBump} bump; using its version bump reason instead.`
42657
+ );
42658
+ }
42608
42659
  if (changelogEntries.length <= 1) {
42609
42660
  return {
42610
42661
  versionBump: bestBump,
@@ -42720,6 +42771,57 @@ ${body}` : `${COMMIT_MARKER} ${subject}`;
42720
42771
  return adapter;
42721
42772
  }
42722
42773
  };
42774
+ function aggregateChunkAnalyses(chunkAnalyses) {
42775
+ let bestBump = "NO_CHANGE";
42776
+ let bestMessage = "";
42777
+ let bestVersionBumpReason;
42778
+ const entries2 = [];
42779
+ for (const analysis of chunkAnalyses) {
42780
+ const prev = bestBump;
42781
+ bestBump = maxVersionBump(bestBump, analysis.versionBump);
42782
+ if (bestBump !== prev) {
42783
+ bestMessage = analysis.message;
42784
+ bestVersionBumpReason = analysis.versionBumpReason;
42785
+ }
42786
+ const text = analysis.changelogEntry?.trim();
42787
+ if (text) {
42788
+ entries2.push({ bump: analysis.versionBump, text });
42789
+ }
42790
+ }
42791
+ const changelogEntries = entries2.map((entry) => entry.text);
42792
+ const hasEntryAtBestBump = entries2.some((entry) => entry.bump === bestBump);
42793
+ const usedBumpReasonAsEntry = bestBump !== "PATCH" && !hasEntryAtBestBump && hasText(bestVersionBumpReason);
42794
+ if (usedBumpReasonAsEntry && bestVersionBumpReason != null) {
42795
+ changelogEntries.unshift(bestVersionBumpReason.trim());
42796
+ }
42797
+ return { bestBump, bestMessage, bestVersionBumpReason, changelogEntries, usedBumpReasonAsEntry };
42798
+ }
42799
+ function hasText(value) {
42800
+ return value != null && value.trim().length > 0;
42801
+ }
42802
+ function commitMessageBody(message) {
42803
+ const trimmed2 = message.trimEnd();
42804
+ const withoutTrailer = trimmed2.endsWith(FERN_TRAILER) ? trimmed2.slice(0, -FERN_TRAILER.length) : trimmed2;
42805
+ const [, ...rest] = withoutTrailer.split("\n");
42806
+ const body = rest.join("\n").trim();
42807
+ return body.length > 0 ? body : void 0;
42808
+ }
42809
+ function resolveChangelogEntryFallbackWithSource(analysis) {
42810
+ if (hasText(analysis.changelogEntry) || analysis.versionBump === "PATCH") {
42811
+ return void 0;
42812
+ }
42813
+ const candidates = [
42814
+ ["PR description", analysis.prDescription],
42815
+ ["version bump reason", analysis.versionBumpReason],
42816
+ ["commit message body", commitMessageBody(analysis.message)]
42817
+ ];
42818
+ for (const [source, text] of candidates) {
42819
+ if (hasText(text)) {
42820
+ return { source, text: text.trim() };
42821
+ }
42822
+ }
42823
+ return void 0;
42824
+ }
42723
42825
  var FAI_VERSION_BUMPS = ["MAJOR", "MINOR", "PATCH", "NO_CHANGE"];
42724
42826
  function isFaiAnalyzeResponse(value) {
42725
42827
  if (typeof value !== "object" || value == null) {
@@ -42736,7 +42838,7 @@ function nonEmpty(value) {
42736
42838
  }
42737
42839
 
42738
42840
  // src/pipeline/steps/GenerationCommitStep.ts
42739
- var import_child_process5 = require("child_process");
42841
+ var import_child_process6 = require("child_process");
42740
42842
  var GenerationCommitStep = class extends BaseStep {
42741
42843
  constructor(outputDir, logger, config, cliVersion, generatorVersions) {
42742
42844
  super(outputDir, logger);
@@ -42767,7 +42869,7 @@ var GenerationCommitStep = class extends BaseStep {
42767
42869
  const reason = error instanceof ReplayPrepareError ? error.reason : String(error);
42768
42870
  if (headBeforePrepare != null) {
42769
42871
  try {
42770
- (0, import_child_process5.execFileSync)("git", ["reset", "--hard", headBeforePrepare], {
42872
+ (0, import_child_process6.execFileSync)("git", ["reset", "--hard", headBeforePrepare], {
42771
42873
  cwd: this.outputDir,
42772
42874
  stdio: "pipe"
42773
42875
  });
@@ -42803,7 +42905,7 @@ var GenerationCommitStep = class extends BaseStep {
42803
42905
  };
42804
42906
  function tryRevParse(cwd2, rev) {
42805
42907
  try {
42806
- return (0, import_child_process5.execFileSync)("git", ["rev-parse", "--verify", rev], {
42908
+ return (0, import_child_process6.execFileSync)("git", ["rev-parse", "--verify", rev], {
42807
42909
  cwd: cwd2,
42808
42910
  encoding: "utf-8",
42809
42911
  stdio: "pipe"
@@ -42815,7 +42917,7 @@ function tryRevParse(cwd2, rev) {
42815
42917
 
42816
42918
  // src/pipeline/steps/GithubStep.ts
42817
42919
  var import_promises17 = require("fs/promises");
42818
- var import_path24 = require("path");
42920
+ var import_path25 = require("path");
42819
42921
 
42820
42922
  // src/pipeline/github/createReplayBranch.ts
42821
42923
  async function createReplayBranch(repository, branchName, commitMessage, replayConflictInfo, logger) {
@@ -43587,7 +43689,7 @@ var GithubStep = class extends BaseStep {
43587
43689
  }
43588
43690
  async ensureFernignore() {
43589
43691
  this.logger.debug("Checking for .fernignore file...");
43590
- const fernignorePath = (0, import_path24.join)(this.outputDir, ".fernignore");
43692
+ const fernignorePath = (0, import_path25.join)(this.outputDir, ".fernignore");
43591
43693
  try {
43592
43694
  await (0, import_promises17.access)(fernignorePath);
43593
43695
  this.logger.debug(".fernignore already exists");
@@ -43614,7 +43716,7 @@ var GithubStep = class extends BaseStep {
43614
43716
  if (entry.length === 0 && resolved.newVersion == null) {
43615
43717
  return false;
43616
43718
  }
43617
- const changelogPath = (0, import_path24.join)(this.outputDir, "changelog.md");
43719
+ const changelogPath = (0, import_path25.join)(this.outputDir, "changelog.md");
43618
43720
  let existing;
43619
43721
  try {
43620
43722
  existing = await (0, import_promises17.readFile)(changelogPath, "utf-8");
@@ -43732,7 +43834,7 @@ function resolveChangelogUrl({
43732
43834
  }
43733
43835
 
43734
43836
  // src/pipeline/steps/ReplayStep.ts
43735
- var import_child_process6 = require("child_process");
43837
+ var import_child_process7 = require("child_process");
43736
43838
  var ReplayStep = class extends BaseStep {
43737
43839
  constructor(outputDir, logger, config, cliVersion, generatorVersions) {
43738
43840
  super(outputDir, logger);
@@ -43859,7 +43961,7 @@ var ReplayStep = class extends BaseStep {
43859
43961
  */
43860
43962
  commitLockfileIfUncommitted() {
43861
43963
  try {
43862
- const status2 = (0, import_child_process6.execFileSync)("git", ["status", "--porcelain", "--", ".fern/replay.lock"], {
43964
+ const status2 = (0, import_child_process7.execFileSync)("git", ["status", "--porcelain", "--", ".fern/replay.lock"], {
43863
43965
  cwd: this.outputDir,
43864
43966
  encoding: "utf-8",
43865
43967
  stdio: ["pipe", "pipe", "pipe"]
@@ -43867,11 +43969,11 @@ var ReplayStep = class extends BaseStep {
43867
43969
  if (status2.length === 0) {
43868
43970
  return;
43869
43971
  }
43870
- (0, import_child_process6.execFileSync)("git", ["add", "--", ".fern/replay.lock"], {
43972
+ (0, import_child_process7.execFileSync)("git", ["add", "--", ".fern/replay.lock"], {
43871
43973
  cwd: this.outputDir,
43872
43974
  stdio: "pipe"
43873
43975
  });
43874
- (0, import_child_process6.execFileSync)(
43976
+ (0, import_child_process7.execFileSync)(
43875
43977
  "git",
43876
43978
  [
43877
43979
  "-c",
@@ -43891,6 +43993,66 @@ var ReplayStep = class extends BaseStep {
43891
43993
  }
43892
43994
  };
43893
43995
 
43996
+ // ../cli/generation/local-generation/docker-utils/lib/dockerHubOatLogin.js
43997
+ var DOCKERHUB_OAT_ENV_VAR = "DOCKERHUB_OAT";
43998
+ var DOCKERHUB_OAT_USERNAME_ENV_VAR = "DOCKERHUB_OAT_USERNAME";
43999
+ var DEFAULT_DOCKERHUB_OAT_USERNAME = "fernenterprise";
44000
+ var DOCKER_HUB_HOSTS = /* @__PURE__ */ new Set([
44001
+ "docker.io",
44002
+ "index.docker.io",
44003
+ "registry-1.docker.io",
44004
+ "registry.hub.docker.com"
44005
+ ]);
44006
+ function getDockerHubNamespace(imageName) {
44007
+ const parts = imageName.split("/");
44008
+ const [first2] = parts;
44009
+ if (first2 == null || parts.length < 2) {
44010
+ return void 0;
44011
+ }
44012
+ const host = first2.toLowerCase();
44013
+ const isRegistryHost = host.includes(".") || host.includes(":") || host === "localhost";
44014
+ if (!isRegistryHost) {
44015
+ return first2;
44016
+ }
44017
+ if (!DOCKER_HUB_HOSTS.has(host)) {
44018
+ return void 0;
44019
+ }
44020
+ return parts.length >= 3 ? parts[1] : void 0;
44021
+ }
44022
+ function resolveDockerHubOatLogin(imageName, env3 = process.env) {
44023
+ const token = env3[DOCKERHUB_OAT_ENV_VAR]?.trim();
44024
+ if (token == null || token === "") {
44025
+ return void 0;
44026
+ }
44027
+ const username = env3[DOCKERHUB_OAT_USERNAME_ENV_VAR]?.trim() || DEFAULT_DOCKERHUB_OAT_USERNAME;
44028
+ if (getDockerHubNamespace(imageName) !== username) {
44029
+ return void 0;
44030
+ }
44031
+ return { username, token };
44032
+ }
44033
+ async function ensureDockerHubOatLogin({ imageName, runner, logger, signal, env: env3 = process.env }) {
44034
+ const credentials = resolveDockerHubOatLogin(imageName, env3);
44035
+ if (credentials == null) {
44036
+ return;
44037
+ }
44038
+ logger?.debug(`Logging in to Docker Hub as ${credentials.username} with ${DOCKERHUB_OAT_ENV_VAR} to pull ${imageName}`);
44039
+ const { exitCode, stdout, stderr } = await loggingExeca(logger, runner ?? "docker", ["login", "--username", credentials.username, "--password-stdin"], {
44040
+ input: credentials.token,
44041
+ reject: false,
44042
+ doNotPipeOutput: true,
44043
+ secrets: [credentials.token],
44044
+ signal
44045
+ });
44046
+ if (exitCode !== 0) {
44047
+ if (signal?.aborted === true) {
44048
+ throw new Error(`Docker Hub login as ${credentials.username} was cancelled.`);
44049
+ }
44050
+ throw new Error(`Failed to log in to Docker Hub as ${credentials.username} using ${DOCKERHUB_OAT_ENV_VAR}. Check that the token is a valid organization access token for ${credentials.username} with pull access to ${imageName}.
44051
+ ${stdout}
44052
+ ${stderr}`);
44053
+ }
44054
+ }
44055
+
43894
44056
  // ../cli/generation/local-generation/docker-utils/lib/runDocker.js
43895
44057
  var import_promises18 = require("fs/promises");
43896
44058
  var import_tmp_promise3 = __toESM(require_tmp_promise(), 1);
@@ -43925,6 +44087,7 @@ async function pullImage(imageName, runner, signal) {
43925
44087
  }
43926
44088
  async function startContainer({ logger, imageName, runner }) {
43927
44089
  const containerRunner = runner ?? "docker";
44090
+ await ensureDockerHubOatLogin({ imageName, runner, logger });
43928
44091
  const tryStart = async () => {
43929
44092
  const { stdout, exitCode, stderr } = await loggingExeca(logger, containerRunner, ["run", "--user", "root", "-dit", "--entrypoint", "/bin/sh", imageName], {
43930
44093
  reject: false,
@@ -44053,8 +44216,8 @@ function createLogger4(log) {
44053
44216
  }
44054
44217
 
44055
44218
  // src/pipeline/steps/VerificationStep.ts
44056
- var import_fs16 = require("fs");
44057
- var import_path25 = require("path");
44219
+ var import_fs17 = require("fs");
44220
+ var import_path26 = require("path");
44058
44221
  var CONTAINER_WORKSPACE_PATH = "/workspace";
44059
44222
  var VERIFY_SCRIPT_RELATIVE_PATH = ".fern/verify.sh";
44060
44223
  var VERIFY_SCRIPT_CONTAINER_PATH = `${CONTAINER_WORKSPACE_PATH}/${VERIFY_SCRIPT_RELATIVE_PATH}`;
@@ -44070,8 +44233,8 @@ var VerificationStep = class extends BaseStep {
44070
44233
  generatorVersions;
44071
44234
  name = "verify";
44072
44235
  async execute(_context) {
44073
- const verifyScriptHostPath = (0, import_path25.join)(this.outputDir, VERIFY_SCRIPT_RELATIVE_PATH);
44074
- if (!(0, import_fs16.existsSync)(verifyScriptHostPath)) {
44236
+ const verifyScriptHostPath = (0, import_path26.join)(this.outputDir, VERIFY_SCRIPT_RELATIVE_PATH);
44237
+ if (!(0, import_fs17.existsSync)(verifyScriptHostPath)) {
44075
44238
  return { executed: true, success: true, skipped: true };
44076
44239
  }
44077
44240
  const validatorImage = this.deriveValidatorImage();
@@ -44250,8 +44413,8 @@ var PostGenerationPipeline = class {
44250
44413
  async run() {
44251
44414
  if (this.config.github?.enabled) {
44252
44415
  try {
44253
- (0, import_child_process7.execFileSync)("git", ["config", "user.name", FERN_BOT_NAME2], { cwd: this.config.outputDir });
44254
- (0, import_child_process7.execFileSync)("git", ["config", "user.email", FERN_BOT_EMAIL2], { cwd: this.config.outputDir });
44416
+ (0, import_child_process8.execFileSync)("git", ["config", "user.name", FERN_BOT_NAME2], { cwd: this.config.outputDir });
44417
+ (0, import_child_process8.execFileSync)("git", ["config", "user.email", FERN_BOT_EMAIL2], { cwd: this.config.outputDir });
44255
44418
  } catch {
44256
44419
  }
44257
44420
  }
@@ -44259,6 +44422,15 @@ var PostGenerationPipeline = class {
44259
44422
  success: true,
44260
44423
  steps: {}
44261
44424
  };
44425
+ if (this.config.github?.enabled && this.config.github.workflows === false) {
44426
+ try {
44427
+ stripGeneratedWorkflows(this.config.outputDir, this.logger);
44428
+ } catch (error) {
44429
+ result.success = false;
44430
+ result.errors = [`failed to strip generated workflows: ${extractErrorMessage(error)}`];
44431
+ return result;
44432
+ }
44433
+ }
44262
44434
  const pipelineContext = {
44263
44435
  previousStepResults: {}
44264
44436
  };
@@ -44761,9 +44933,9 @@ async function createWriteStream(outputPath) {
44761
44933
  }
44762
44934
  async function createWriteStreamFromFile(filepath) {
44763
44935
  if (!await doesPathExist(filepath)) {
44764
- await (0, import_promises19.mkdir)(import_path26.default.dirname(filepath), { recursive: true });
44936
+ await (0, import_promises19.mkdir)(import_path27.default.dirname(filepath), { recursive: true });
44765
44937
  }
44766
- return import_fs17.default.createWriteStream(filepath);
44938
+ return import_fs18.default.createWriteStream(filepath);
44767
44939
  }
44768
44940
  /*! Bundled license information:
44769
44941
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fern-api/generator-cli",
3
- "version": "0.9.56",
3
+ "version": "0.10.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/fern-api/fern.git",