@fern-api/generator-cli 0.9.26 → 0.9.27

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 (3) hide show
  1. package/dist/api.js +12 -1
  2. package/dist/cli.js +392 -68
  3. package/package.json +1 -1
package/dist/api.js CHANGED
@@ -6362,6 +6362,15 @@ async function cloneRepository({ githubRepository, installationToken, targetDire
6362
6362
  });
6363
6363
  }
6364
6364
 
6365
+ // ../commons/github/lib/getGithubApiBaseUrl.js
6366
+ function getGithubApiBaseUrl(repositoryUri) {
6367
+ const { remote } = parseRepository(repositoryUri);
6368
+ if (remote === DEFAULT_REMOTE) {
6369
+ return void 0;
6370
+ }
6371
+ return `https://${remote}/api/v3`;
6372
+ }
6373
+
6365
6374
  // src/readme/ReadmeGenerator.ts
6366
6375
  var import_compat = require("es-toolkit/compat");
6367
6376
  var import_string2 = require("es-toolkit/string");
@@ -10069,8 +10078,10 @@ var GitHub = class {
10069
10078
  await this.restoreFiles(repository, fernIgnoreFiles);
10070
10079
  await repository.commit("SDK Generation");
10071
10080
  await repository.push();
10081
+ const apiBaseUrl = getGithubApiBaseUrl(this.githubConfig.uri);
10072
10082
  const octokit = new import_rest.Octokit({
10073
- auth: this.githubConfig.token
10083
+ auth: this.githubConfig.token,
10084
+ ...apiBaseUrl != null ? { baseUrl: apiBaseUrl } : {}
10074
10085
  });
10075
10086
  const parsedRepo = parseRepository(this.githubConfig.uri);
10076
10087
  const { owner, repo } = parsedRepo;
package/dist/cli.js CHANGED
@@ -4186,10 +4186,10 @@ var require_tmp_promise = __commonJS({
4186
4186
  "../../node_modules/.pnpm/tmp-promise@3.0.3/node_modules/tmp-promise/index.js"(exports2, module2) {
4187
4187
  "use strict";
4188
4188
  var { promisify } = require("util");
4189
- var tmp3 = require_tmp();
4190
- module2.exports.fileSync = tmp3.fileSync;
4189
+ var tmp4 = require_tmp();
4190
+ module2.exports.fileSync = tmp4.fileSync;
4191
4191
  var fileWithOptions = promisify(
4192
- (options, cb) => tmp3.file(
4192
+ (options, cb) => tmp4.file(
4193
4193
  options,
4194
4194
  (err, path5, fd, cleanup) => err ? cb(err) : cb(void 0, { path: path5, fd, cleanup: promisify(cleanup) })
4195
4195
  )
@@ -4203,9 +4203,9 @@ var require_tmp_promise = __commonJS({
4203
4203
  await cleanup();
4204
4204
  }
4205
4205
  };
4206
- module2.exports.dirSync = tmp3.dirSync;
4206
+ module2.exports.dirSync = tmp4.dirSync;
4207
4207
  var dirWithOptions = promisify(
4208
- (options, cb) => tmp3.dir(
4208
+ (options, cb) => tmp4.dir(
4209
4209
  options,
4210
4210
  (err, path5, cleanup) => err ? cb(err) : cb(void 0, { path: path5, cleanup: promisify(cleanup) })
4211
4211
  )
@@ -4219,10 +4219,10 @@ var require_tmp_promise = __commonJS({
4219
4219
  await cleanup();
4220
4220
  }
4221
4221
  };
4222
- module2.exports.tmpNameSync = tmp3.tmpNameSync;
4223
- module2.exports.tmpName = promisify(tmp3.tmpName);
4224
- module2.exports.tmpdir = tmp3.tmpdir;
4225
- module2.exports.setGracefulCleanup = tmp3.setGracefulCleanup;
4222
+ module2.exports.tmpNameSync = tmp4.tmpNameSync;
4223
+ module2.exports.tmpName = promisify(tmp4.tmpName);
4224
+ module2.exports.tmpdir = tmp4.tmpdir;
4225
+ module2.exports.setGracefulCleanup = tmp4.setGracefulCleanup;
4226
4226
  }
4227
4227
  });
4228
4228
 
@@ -7035,15 +7035,15 @@ var require_sync = __commonJS({
7035
7035
  var { readdirSync: readdirSync2, statSync: statSync4 } = require("fs");
7036
7036
  module2.exports = function(start, callback) {
7037
7037
  let dir = resolve8(".", start);
7038
- let tmp3, stats = statSync4(dir);
7038
+ let tmp4, stats = statSync4(dir);
7039
7039
  if (!stats.isDirectory()) {
7040
7040
  dir = dirname5(dir);
7041
7041
  }
7042
7042
  while (true) {
7043
- tmp3 = callback(dir, readdirSync2(dir));
7044
- if (tmp3) return resolve8(dir, tmp3);
7045
- dir = dirname5(tmp3 = dir);
7046
- if (tmp3 === dir) break;
7043
+ tmp4 = callback(dir, readdirSync2(dir));
7044
+ if (tmp4) return resolve8(dir, tmp4);
7045
+ dir = dirname5(tmp4 = dir);
7046
+ if (tmp4 === dir) break;
7047
7047
  }
7048
7048
  };
7049
7049
  }
@@ -7078,7 +7078,7 @@ var require_require_directory = __commonJS({
7078
7078
  "../../node_modules/.pnpm/require-directory@2.1.1/node_modules/require-directory/index.js"(exports2, module2) {
7079
7079
  "use strict";
7080
7080
  var fs3 = require("fs");
7081
- var join15 = require("path").join;
7081
+ var join16 = require("path").join;
7082
7082
  var resolve8 = require("path").resolve;
7083
7083
  var dirname5 = require("path").dirname;
7084
7084
  var defaultOptions2 = {
@@ -7115,7 +7115,7 @@ var require_require_directory = __commonJS({
7115
7115
  }
7116
7116
  path5 = !path5 ? dirname5(m.filename) : resolve8(dirname5(m.filename), path5);
7117
7117
  fs3.readdirSync(path5).forEach(function(filename) {
7118
- var joined = join15(path5, filename), files, key, obj;
7118
+ var joined = join16(path5, filename), files, key, obj;
7119
7119
  if (fs3.statSync(joined).isDirectory() && options.recurse) {
7120
7120
  files = requireDirectory(m, joined, options);
7121
7121
  if (Object.keys(files).length) {
@@ -22939,17 +22939,17 @@ function overlayRegions(currentGenLines, locInCurrentGen, workingTreeLines, locI
22939
22939
  }
22940
22940
  async function unifiedDiff(beforeContent, afterContent, filePath) {
22941
22941
  if (beforeContent === afterContent) return "";
22942
- const tmp3 = await (0, import_promises6.mkdtemp)((0, import_path11.join)((0, import_os3.tmpdir)(), "fern-replay-pp-"));
22942
+ const tmp4 = await (0, import_promises6.mkdtemp)((0, import_path11.join)((0, import_os3.tmpdir)(), "fern-replay-pp-"));
22943
22943
  try {
22944
- const beforePath = (0, import_path11.join)(tmp3, "before");
22945
- const afterPath = (0, import_path11.join)(tmp3, "after");
22944
+ const beforePath = (0, import_path11.join)(tmp4, "before");
22945
+ const afterPath = (0, import_path11.join)(tmp4, "after");
22946
22946
  await (0, import_promises6.writeFile)(beforePath, beforeContent, "utf-8");
22947
22947
  await (0, import_promises6.writeFile)(afterPath, afterContent, "utf-8");
22948
22948
  const raw = await runGitDiffNoIndex(beforePath, afterPath);
22949
22949
  if (!raw.trim()) return "";
22950
22950
  return rewriteDiffHeaders(raw, filePath);
22951
22951
  } finally {
22952
- await (0, import_promises6.rm)(tmp3, { recursive: true, force: true });
22952
+ await (0, import_promises6.rm)(tmp4, { recursive: true, force: true });
22953
22953
  }
22954
22954
  }
22955
22955
  function runGitDiffNoIndex(beforePath, afterPath) {
@@ -27301,9 +27301,9 @@ var require_path_key = __commonJS({
27301
27301
  }
27302
27302
  });
27303
27303
 
27304
- // ../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/util/resolveCommand.js
27304
+ // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
27305
27305
  var require_resolveCommand = __commonJS({
27306
- "../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
27306
+ "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
27307
27307
  "use strict";
27308
27308
  var path5 = require("path");
27309
27309
  var which = require_which();
@@ -27343,9 +27343,9 @@ var require_resolveCommand = __commonJS({
27343
27343
  }
27344
27344
  });
27345
27345
 
27346
- // ../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/util/escape.js
27346
+ // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js
27347
27347
  var require_escape = __commonJS({
27348
- "../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/util/escape.js"(exports2, module2) {
27348
+ "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js"(exports2, module2) {
27349
27349
  "use strict";
27350
27350
  var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
27351
27351
  function escapeCommand(arg) {
@@ -27396,9 +27396,9 @@ var require_shebang_command = __commonJS({
27396
27396
  }
27397
27397
  });
27398
27398
 
27399
- // ../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/util/readShebang.js
27399
+ // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
27400
27400
  var require_readShebang = __commonJS({
27401
- "../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/util/readShebang.js"(exports2, module2) {
27401
+ "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports2, module2) {
27402
27402
  "use strict";
27403
27403
  var fs3 = require("fs");
27404
27404
  var shebangCommand = require_shebang_command();
@@ -27418,9 +27418,9 @@ var require_readShebang = __commonJS({
27418
27418
  }
27419
27419
  });
27420
27420
 
27421
- // ../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/parse.js
27421
+ // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
27422
27422
  var require_parse2 = __commonJS({
27423
- "../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
27423
+ "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
27424
27424
  "use strict";
27425
27425
  var path5 = require("path");
27426
27426
  var resolveCommand = require_resolveCommand();
@@ -27480,9 +27480,9 @@ var require_parse2 = __commonJS({
27480
27480
  }
27481
27481
  });
27482
27482
 
27483
- // ../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/enoent.js
27483
+ // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.js
27484
27484
  var require_enoent = __commonJS({
27485
- "../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/lib/enoent.js"(exports2, module2) {
27485
+ "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.js"(exports2, module2) {
27486
27486
  "use strict";
27487
27487
  var isWin = process.platform === "win32";
27488
27488
  function notFoundError(original, syscall) {
@@ -27530,9 +27530,9 @@ var require_enoent = __commonJS({
27530
27530
  }
27531
27531
  });
27532
27532
 
27533
- // ../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/index.js
27533
+ // ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.js
27534
27534
  var require_cross_spawn = __commonJS({
27535
- "../../node_modules/.pnpm/cross-spawn@7.0.5/node_modules/cross-spawn/index.js"(exports2, module2) {
27535
+ "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.js"(exports2, module2) {
27536
27536
  "use strict";
27537
27537
  var cp2 = require("child_process");
27538
27538
  var parse3 = require_parse2();
@@ -29638,9 +29638,9 @@ function resolve(...paths) {
29638
29638
  }
29639
29639
 
29640
29640
  // src/cli.ts
29641
- var import_fs15 = __toESM(require("fs"));
29642
- var import_promises15 = require("fs/promises");
29643
- var import_path21 = __toESM(require("path"));
29641
+ var import_fs16 = __toESM(require("fs"));
29642
+ var import_promises16 = require("fs/promises");
29643
+ var import_path22 = __toESM(require("path"));
29644
29644
 
29645
29645
  // ../../node_modules/.pnpm/yargs@17.7.2/node_modules/yargs/build/lib/yerror.js
29646
29646
  var YError = class _YError extends Error {
@@ -30953,15 +30953,15 @@ var import_path3 = require("path");
30953
30953
  var import_fs2 = require("fs");
30954
30954
  function sync_default(start, callback) {
30955
30955
  let dir = (0, import_path3.resolve)(".", start);
30956
- let tmp3, stats = (0, import_fs2.statSync)(dir);
30956
+ let tmp4, stats = (0, import_fs2.statSync)(dir);
30957
30957
  if (!stats.isDirectory()) {
30958
30958
  dir = (0, import_path3.dirname)(dir);
30959
30959
  }
30960
30960
  while (true) {
30961
- tmp3 = callback(dir, (0, import_fs2.readdirSync)(dir));
30962
- if (tmp3) return (0, import_path3.resolve)(dir, tmp3);
30963
- dir = (0, import_path3.dirname)(tmp3 = dir);
30964
- if (tmp3 === dir) break;
30961
+ tmp4 = callback(dir, (0, import_fs2.readdirSync)(dir));
30962
+ if (tmp4) return (0, import_path3.resolve)(dir, tmp4);
30963
+ dir = (0, import_path3.dirname)(tmp4 = dir);
30964
+ if (tmp4 === dir) break;
30965
30965
  }
30966
30966
  }
30967
30967
 
@@ -31728,6 +31728,15 @@ function getUserAgent() {
31728
31728
  return "<environment undetectable>";
31729
31729
  }
31730
31730
 
31731
+ // ../commons/github/lib/getGithubApiBaseUrl.js
31732
+ function getGithubApiBaseUrl(repositoryUri) {
31733
+ const { remote } = parseRepository(repositoryUri);
31734
+ if (remote === DEFAULT_REMOTE) {
31735
+ return void 0;
31736
+ }
31737
+ return `https://${remote}/api/v3`;
31738
+ }
31739
+
31731
31740
  // ../../node_modules/.pnpm/before-after-hook@4.0.0/node_modules/before-after-hook/lib/register.js
31732
31741
  function register(state, name, method, options) {
31733
31742
  if (typeof method !== "function") {
@@ -31993,23 +32002,23 @@ function getValues(context, operator, key, modifier) {
31993
32002
  });
31994
32003
  }
31995
32004
  } else {
31996
- const tmp3 = [];
32005
+ const tmp4 = [];
31997
32006
  if (Array.isArray(value)) {
31998
32007
  value.filter(isDefined).forEach(function(value2) {
31999
- tmp3.push(encodeValue(operator, value2));
32008
+ tmp4.push(encodeValue(operator, value2));
32000
32009
  });
32001
32010
  } else {
32002
32011
  Object.keys(value).forEach(function(k2) {
32003
32012
  if (isDefined(value[k2])) {
32004
- tmp3.push(encodeUnreserved(k2));
32005
- tmp3.push(encodeValue(operator, value[k2].toString()));
32013
+ tmp4.push(encodeUnreserved(k2));
32014
+ tmp4.push(encodeValue(operator, value[k2].toString()));
32006
32015
  }
32007
32016
  });
32008
32017
  }
32009
32018
  if (isKeyOperator(operator)) {
32010
- result.push(encodeUnreserved(key) + "=" + tmp3.join(","));
32011
- } else if (tmp3.length !== 0) {
32012
- result.push(tmp3.join(","));
32019
+ result.push(encodeUnreserved(key) + "=" + tmp4.join(","));
32020
+ } else if (tmp4.length !== 0) {
32021
+ result.push(tmp4.join(","));
32013
32022
  }
32014
32023
  }
32015
32024
  }
@@ -32044,8 +32053,8 @@ function expand2(template2, context) {
32044
32053
  expression = expression.substr(1);
32045
32054
  }
32046
32055
  expression.split(/,/g).forEach(function(variable) {
32047
- var tmp3 = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable);
32048
- values.push(getValues(context, operator, tmp3[1], tmp3[2] || tmp3[3]));
32056
+ var tmp4 = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable);
32057
+ values.push(getValues(context, operator, tmp4[1], tmp4[2] || tmp4[3]));
32049
32058
  });
32050
32059
  if (operator && operator !== "+") {
32051
32060
  var separator = ",";
@@ -35418,8 +35427,10 @@ var GitHub = class {
35418
35427
  await this.restoreFiles(repository, fernIgnoreFiles);
35419
35428
  await repository.commit("SDK Generation");
35420
35429
  await repository.push();
35430
+ const apiBaseUrl = getGithubApiBaseUrl(this.githubConfig.uri);
35421
35431
  const octokit = new Octokit2({
35422
- auth: this.githubConfig.token
35432
+ auth: this.githubConfig.token,
35433
+ ...apiBaseUrl != null ? { baseUrl: apiBaseUrl } : {}
35423
35434
  });
35424
35435
  const parsedRepo = parseRepository(this.githubConfig.uri);
35425
35436
  const { owner, repo } = parsedRepo;
@@ -41383,13 +41394,20 @@ async function createReplayBranch(repository, branchName, commitMessage, replayC
41383
41394
  }
41384
41395
  const parentSha = replayConflictInfo.previousGenerationSha;
41385
41396
  await repository.createBranchFromHead(branchName);
41386
- const genTreeHash = await repository.getCommitTreeHash(replayConflictInfo.currentGenerationSha);
41387
- const tagCommitSha = await repository.commitTree(
41388
- genTreeHash,
41389
- parentSha,
41390
- `[fern-generated] ${commitMessage ?? "Update SDK"}`
41391
- );
41392
- return tagCommitSha;
41397
+ try {
41398
+ const genTreeHash = await repository.getCommitTreeHash(replayConflictInfo.currentGenerationSha);
41399
+ const tagCommitSha = await repository.commitTree(
41400
+ genTreeHash,
41401
+ parentSha,
41402
+ `[fern-generated] ${commitMessage ?? "Update SDK"}`
41403
+ );
41404
+ return tagCommitSha;
41405
+ } catch (error) {
41406
+ logger.warn(
41407
+ `Could not create fern-generation-base tag commit: parent ${parentSha} is unreachable in this clone (likely on a squash-merged + deleted branch). Continuing without tag update. Underlying error: ${String(error)}`
41408
+ );
41409
+ return void 0;
41410
+ }
41393
41411
  }
41394
41412
 
41395
41413
  // src/pipeline/github/findExistingUpdatablePR.ts
@@ -41781,8 +41799,8 @@ var GithubStep = class extends BaseStep {
41781
41799
  }
41782
41800
  async executePullRequestMode(repository, newPrBranch, skipCommit, replayConflictInfo, replayResult, resolved) {
41783
41801
  const baseBranch = this.config.branch ?? await repository.getDefaultBranch();
41784
- const octokit = new Octokit2({ auth: this.config.token });
41785
- const { owner, repo } = parseRepository(this.config.uri);
41802
+ const octokit = this.createOctokit();
41803
+ const { owner, repo, remote } = parseRepository(this.config.uri);
41786
41804
  let prBranch;
41787
41805
  let isUpdatingExistingPR = false;
41788
41806
  let generationBaseSha;
@@ -41861,7 +41879,7 @@ var GithubStep = class extends BaseStep {
41861
41879
  logger: this.logger
41862
41880
  });
41863
41881
  const pushedBranch = await repository.getCurrentBranch();
41864
- result.branchUrl = `https://github.com/${this.config.uri}/tree/${pushedBranch}`;
41882
+ result.branchUrl = `https://${remote}/${owner}/${repo}/tree/${pushedBranch}`;
41865
41883
  this.logger.info(`Pushed branch: ${result.branchUrl}`);
41866
41884
  if (generationBaseSha != null) {
41867
41885
  try {
@@ -41876,7 +41894,7 @@ var GithubStep = class extends BaseStep {
41876
41894
  }
41877
41895
  }
41878
41896
  const headSha = await repository.getHeadSha();
41879
- const changelogUrl = resolved.changelogEntry ? `https://github.com/${this.config.uri}/blob/${headSha}/changelog.md` : void 0;
41897
+ const changelogUrl = resolved.changelogEntry ? `https://${remote}/${owner}/${repo}/blob/${headSha}/changelog.md` : void 0;
41880
41898
  const { prTitle, prBody } = parseCommitMessageForPR(
41881
41899
  resolved.commitMessage,
41882
41900
  resolved.changelogEntry,
@@ -41970,8 +41988,8 @@ var GithubStep = class extends BaseStep {
41970
41988
  success: true
41971
41989
  };
41972
41990
  if (!this.config.previewMode) {
41973
- const octokit = new Octokit2({ auth: this.config.token });
41974
- const { owner, repo } = parseRepository(this.config.uri);
41991
+ const octokit = this.createOctokit();
41992
+ const { owner, repo, remote } = parseRepository(this.config.uri);
41975
41993
  await pushSignedCommit({
41976
41994
  repository,
41977
41995
  octokit,
@@ -41983,11 +42001,18 @@ var GithubStep = class extends BaseStep {
41983
42001
  logger: this.logger
41984
42002
  });
41985
42003
  const pushedBranch = await repository.getCurrentBranch();
41986
- result.branchUrl = `https://github.com/${this.config.uri}/tree/${pushedBranch}`;
42004
+ result.branchUrl = `https://${remote}/${owner}/${repo}/tree/${pushedBranch}`;
41987
42005
  this.logger.info(`Pushed branch: ${result.branchUrl}`);
41988
42006
  }
41989
42007
  return result;
41990
42008
  }
42009
+ createOctokit() {
42010
+ const opts = { auth: this.config.token };
42011
+ if (this.config.apiBaseUrl != null) {
42012
+ opts.baseUrl = this.config.apiBaseUrl;
42013
+ }
42014
+ return new Octokit2(opts);
42015
+ }
41991
42016
  async ensureFernignore() {
41992
42017
  this.logger.debug("Checking for .fernignore file...");
41993
42018
  const fernignorePath = (0, import_path20.join)(this.outputDir, ".fernignore");
@@ -42206,6 +42231,278 @@ var ReplayStep = class extends BaseStep {
42206
42231
  }
42207
42232
  };
42208
42233
 
42234
+ // ../cli/generation/local-generation/docker-utils/lib/runDocker.js
42235
+ var import_promises15 = require("fs/promises");
42236
+ var import_tmp_promise3 = __toESM(require_tmp_promise(), 1);
42237
+ async function pullImage(imageName, runner, signal) {
42238
+ await loggingExeca(void 0, runner ?? "docker", ["pull", imageName], {
42239
+ all: true,
42240
+ doNotPipeOutput: true,
42241
+ signal
42242
+ });
42243
+ }
42244
+ async function startContainer({ logger, imageName, runner }) {
42245
+ const containerRunner = runner ?? "docker";
42246
+ const tryStart = async () => {
42247
+ const { stdout, exitCode, stderr } = await loggingExeca(logger, containerRunner, ["run", "--user", "root", "-dit", "--entrypoint", "/bin/sh", imageName], {
42248
+ reject: false,
42249
+ doNotPipeOutput: true
42250
+ });
42251
+ if (exitCode == null) {
42252
+ throw new Error(`Container runtime '${containerRunner}' is not installed or not found on PATH.
42253
+ Error details: ${stderr || stdout || "No output"}`);
42254
+ }
42255
+ if (exitCode !== 0) {
42256
+ throw new Error(`Failed to start container from image ${imageName}.
42257
+ ${stdout}
42258
+ ${stderr}`);
42259
+ }
42260
+ return stdout.trim();
42261
+ };
42262
+ try {
42263
+ return await tryStart();
42264
+ } catch (e) {
42265
+ if (e instanceof Error && e.message.includes("No such image")) {
42266
+ await pullImage(imageName, runner);
42267
+ return await tryStart();
42268
+ }
42269
+ throw e;
42270
+ }
42271
+ }
42272
+ async function execInContainer({ logger, containerId, command, runner, writeLogsToFile = true, reject = true }) {
42273
+ const containerRunner = runner ?? "docker";
42274
+ const { stdout, stderr, exitCode } = await loggingExeca(logger, containerRunner, ["exec", "--user", "root", containerId, ...command], {
42275
+ reject: false,
42276
+ all: true,
42277
+ doNotPipeOutput: true
42278
+ });
42279
+ const logs = stdout + stderr;
42280
+ if (writeLogsToFile) {
42281
+ const tmpFile = await import_tmp_promise3.default.file();
42282
+ await (0, import_promises15.writeFile)(tmpFile.path, logs);
42283
+ logger.info(`Generator logs here: ${tmpFile.path}`);
42284
+ }
42285
+ const resolvedExitCode = exitCode ?? 1;
42286
+ if (reject && resolvedExitCode !== 0) {
42287
+ throw new Error(`Container exec exited with code ${resolvedExitCode}.
42288
+ ${stdout}
42289
+ ${stderr}`);
42290
+ }
42291
+ return { stdout, stderr, exitCode: resolvedExitCode };
42292
+ }
42293
+ async function copyToContainer({ logger, containerId, hostPath, containerPath, runner }) {
42294
+ const containerRunner = runner ?? "docker";
42295
+ const { exitCode, stdout, stderr } = await loggingExeca(logger, containerRunner, ["cp", hostPath, `${containerId}:${containerPath}`], {
42296
+ reject: false,
42297
+ doNotPipeOutput: true
42298
+ });
42299
+ if (exitCode !== 0) {
42300
+ throw new Error(`Failed to copy ${hostPath} to container ${containerId}:${containerPath}.
42301
+ ${stdout}
42302
+ ${stderr}`);
42303
+ }
42304
+ }
42305
+ async function stopContainer({ logger, containerId, runner }) {
42306
+ const containerRunner = runner ?? "docker";
42307
+ await loggingExeca(logger, containerRunner, ["rm", "-f", containerId], {
42308
+ reject: false,
42309
+ doNotPipeOutput: true
42310
+ });
42311
+ }
42312
+
42313
+ // ../cli/logger/lib/LogLevel.js
42314
+ var LogLevel2 = {
42315
+ Trace: "trace",
42316
+ Debug: "debug",
42317
+ Info: "info",
42318
+ Warn: "warn",
42319
+ Error: "error"
42320
+ };
42321
+ var LOG_LEVELS = Object.values(LogLevel2);
42322
+
42323
+ // ../cli/logger/lib/createLogger.js
42324
+ var LoggerImpl = class {
42325
+ log;
42326
+ enabled;
42327
+ constructor(log, enabled = true) {
42328
+ this.log = log;
42329
+ this.enabled = enabled;
42330
+ }
42331
+ disable() {
42332
+ this.enabled = false;
42333
+ }
42334
+ enable() {
42335
+ this.enabled = true;
42336
+ }
42337
+ debug(...args) {
42338
+ if (this.enabled) {
42339
+ this.log(LogLevel2.Debug, ...args);
42340
+ }
42341
+ }
42342
+ info(...args) {
42343
+ if (this.enabled) {
42344
+ this.log(LogLevel2.Info, ...args);
42345
+ }
42346
+ }
42347
+ warn(...args) {
42348
+ if (this.enabled) {
42349
+ this.log(LogLevel2.Warn, ...args);
42350
+ }
42351
+ }
42352
+ error(...args) {
42353
+ if (this.enabled) {
42354
+ this.log(LogLevel2.Error, ...args);
42355
+ }
42356
+ }
42357
+ trace(...args) {
42358
+ if (this.enabled) {
42359
+ this.log(LogLevel2.Trace, ...args);
42360
+ }
42361
+ }
42362
+ };
42363
+ function createLogger4(log) {
42364
+ return new LoggerImpl(log);
42365
+ }
42366
+
42367
+ // src/pipeline/steps/VerificationStep.ts
42368
+ var import_fs15 = require("fs");
42369
+ var import_path21 = require("path");
42370
+ var CONTAINER_WORKSPACE_PATH = "/workspace";
42371
+ var VERIFY_SCRIPT_RELATIVE_PATH = ".fern/verify.sh";
42372
+ var VERIFY_SCRIPT_CONTAINER_PATH = `${CONTAINER_WORKSPACE_PATH}/${VERIFY_SCRIPT_RELATIVE_PATH}`;
42373
+ var VerificationStep = class extends BaseStep {
42374
+ constructor(outputDir, logger, config, generatorName, generatorVersions) {
42375
+ super(outputDir, logger);
42376
+ this.config = config;
42377
+ this.generatorName = generatorName;
42378
+ this.generatorVersions = generatorVersions;
42379
+ }
42380
+ config;
42381
+ generatorName;
42382
+ generatorVersions;
42383
+ name = "verify";
42384
+ async execute(_context) {
42385
+ const verifyScriptHostPath = (0, import_path21.join)(this.outputDir, VERIFY_SCRIPT_RELATIVE_PATH);
42386
+ if (!(0, import_fs15.existsSync)(verifyScriptHostPath)) {
42387
+ return { executed: true, success: true, skipped: true };
42388
+ }
42389
+ const validatorImage = this.deriveValidatorImage();
42390
+ if (validatorImage == null) {
42391
+ const message = "Cannot derive validator image: generatorName and generatorVersions are required to compute the `{generatorImage}-validator:{version}` tag.";
42392
+ this.logger.error(message);
42393
+ return {
42394
+ executed: true,
42395
+ success: false,
42396
+ skipped: false,
42397
+ errorMessage: message
42398
+ };
42399
+ }
42400
+ const runner = this.config.runner ?? "docker";
42401
+ const dockerLogger = createDockerLoggerAdapter(this.logger);
42402
+ let containerId;
42403
+ try {
42404
+ try {
42405
+ containerId = await startContainer({
42406
+ logger: dockerLogger,
42407
+ imageName: validatorImage,
42408
+ runner
42409
+ });
42410
+ } catch (error) {
42411
+ const message = `Failed to start verification container from image ${validatorImage}: ${extractErrorMessage(error)}`;
42412
+ this.logger.error(message);
42413
+ return {
42414
+ executed: true,
42415
+ success: false,
42416
+ skipped: false,
42417
+ errorMessage: message
42418
+ };
42419
+ }
42420
+ try {
42421
+ await copyToContainer({
42422
+ logger: dockerLogger,
42423
+ containerId,
42424
+ hostPath: `${this.outputDir}/.`,
42425
+ containerPath: CONTAINER_WORKSPACE_PATH,
42426
+ runner
42427
+ });
42428
+ } catch (error) {
42429
+ const message = `Failed to copy workspace into verification container: ${extractErrorMessage(error)}`;
42430
+ this.logger.error(message);
42431
+ return {
42432
+ executed: true,
42433
+ success: false,
42434
+ skipped: false,
42435
+ errorMessage: message
42436
+ };
42437
+ }
42438
+ const { stdout, stderr, exitCode } = await execInContainer({
42439
+ logger: dockerLogger,
42440
+ containerId,
42441
+ command: ["bash", VERIFY_SCRIPT_CONTAINER_PATH],
42442
+ runner,
42443
+ writeLogsToFile: false,
42444
+ reject: false
42445
+ });
42446
+ if (exitCode !== 0) {
42447
+ const capturedStderr = stderr.length > 0 ? stderr : stdout;
42448
+ this.logger.error(
42449
+ `Verification failed (exit code ${exitCode}) for image ${validatorImage}.
42450
+ ${capturedStderr}`
42451
+ );
42452
+ return {
42453
+ executed: true,
42454
+ success: false,
42455
+ skipped: false,
42456
+ stderr: capturedStderr,
42457
+ errorMessage: `Verification script exited with code ${exitCode}`
42458
+ };
42459
+ }
42460
+ this.logger.info(`Verification succeeded for image ${validatorImage}`);
42461
+ return { executed: true, success: true, skipped: false };
42462
+ } finally {
42463
+ if (containerId != null) {
42464
+ try {
42465
+ await stopContainer({ logger: dockerLogger, containerId, runner });
42466
+ } catch (error) {
42467
+ this.logger.debug(
42468
+ `Best-effort cleanup: failed to stop verification container ${containerId}: ${extractErrorMessage(error)}`
42469
+ );
42470
+ }
42471
+ }
42472
+ }
42473
+ }
42474
+ deriveValidatorImage() {
42475
+ if (this.generatorName == null) {
42476
+ return void 0;
42477
+ }
42478
+ const version2 = this.generatorVersions?.[this.generatorName];
42479
+ if (version2 == null) {
42480
+ return void 0;
42481
+ }
42482
+ return `${this.generatorName}-validator:${version2}`;
42483
+ }
42484
+ };
42485
+ function createDockerLoggerAdapter(pipelineLogger) {
42486
+ return createLogger4((level, ...args) => {
42487
+ const message = args.join(" ");
42488
+ switch (level) {
42489
+ case LogLevel2.Trace:
42490
+ case LogLevel2.Debug:
42491
+ pipelineLogger.debug(message);
42492
+ return;
42493
+ case LogLevel2.Info:
42494
+ pipelineLogger.info(message);
42495
+ return;
42496
+ case LogLevel2.Warn:
42497
+ pipelineLogger.warn(message);
42498
+ return;
42499
+ case LogLevel2.Error:
42500
+ pipelineLogger.error(message);
42501
+ return;
42502
+ }
42503
+ });
42504
+ }
42505
+
42209
42506
  // src/pipeline/PostGenerationPipeline.ts
42210
42507
  var PostGenerationPipeline = class {
42211
42508
  constructor(config, logger = consolePipelineLogger) {
@@ -42250,6 +42547,17 @@ var PostGenerationPipeline = class {
42250
42547
  )
42251
42548
  );
42252
42549
  }
42550
+ if (config.verify?.enabled) {
42551
+ this.steps.push(
42552
+ new VerificationStep(
42553
+ config.outputDir,
42554
+ this.logger,
42555
+ config.verify,
42556
+ config.generatorName,
42557
+ config.generatorVersions
42558
+ )
42559
+ );
42560
+ }
42253
42561
  if (config.github?.enabled) {
42254
42562
  this.steps.push(new GithubStep(config.outputDir, this.logger, config.github));
42255
42563
  }
@@ -42288,12 +42596,25 @@ var PostGenerationPipeline = class {
42288
42596
  pipelineContext.previousStepResults.autoVersion = stepResult;
42289
42597
  } else if (step.name === "fernignore") {
42290
42598
  result.steps.fernignore = stepResult;
42599
+ } else if (step.name === "verify") {
42600
+ const verifyResult = stepResult;
42601
+ result.steps.verify = verifyResult;
42602
+ pipelineContext.previousStepResults.verify = verifyResult;
42291
42603
  } else if (step.name === "github") {
42292
42604
  result.steps.github = stepResult;
42293
42605
  }
42294
42606
  if (!stepResult.success) {
42295
42607
  result.success = false;
42296
42608
  result.errors = result.errors ?? [];
42609
+ if (step.name === "verify") {
42610
+ const verifyResult = stepResult;
42611
+ if (verifyResult.stderr != null && verifyResult.stderr.length > 0) {
42612
+ result.errors.push(verifyResult.stderr);
42613
+ } else {
42614
+ result.errors.push(verifyResult.errorMessage ?? `${step.name} step failed`);
42615
+ }
42616
+ break;
42617
+ }
42297
42618
  result.errors.push(stepResult.errorMessage ?? `${step.name} step failed`);
42298
42619
  }
42299
42620
  } catch (error) {
@@ -42301,6 +42622,9 @@ var PostGenerationPipeline = class {
42301
42622
  result.errors = result.errors ?? [];
42302
42623
  const errorMessage = extractErrorMessage(error);
42303
42624
  result.errors.push(`${step.name} step error: ${errorMessage}`);
42625
+ if (step.name === "verify") {
42626
+ break;
42627
+ }
42304
42628
  }
42305
42629
  }
42306
42630
  return result;
@@ -42331,7 +42655,7 @@ void yargs_default(hideBin(process.argv)).scriptName(process.env.CLI_NAME ?? "ge
42331
42655
  const readmeConfig = await loadReadmeConfig({
42332
42656
  absolutePathToConfig: resolve(wd, argv.config)
42333
42657
  });
42334
- const originalReadmeContent = argv.originalReadme != null ? await (0, import_promises15.readFile)(argv.originalReadme, "utf8") : void 0;
42658
+ const originalReadmeContent = argv.originalReadme != null ? await (0, import_promises16.readFile)(argv.originalReadme, "utf8") : void 0;
42335
42659
  await generateReadmeToStream({
42336
42660
  originalReadmeContent,
42337
42661
  readmeConfig,
@@ -42459,7 +42783,7 @@ void yargs_default(hideBin(process.argv)).scriptName(process.env.CLI_NAME ?? "ge
42459
42783
  try {
42460
42784
  const wd = cwd();
42461
42785
  const configValue = argv.config;
42462
- const configContent = configValue === STDIN_MARKER ? await readStdin() : configValue.trimStart().startsWith("{") ? configValue : await (0, import_promises15.readFile)(resolve(wd, configValue), "utf-8");
42786
+ const configContent = configValue === STDIN_MARKER ? await readStdin() : configValue.trimStart().startsWith("{") ? configValue : await (0, import_promises16.readFile)(resolve(wd, configValue), "utf-8");
42463
42787
  let config;
42464
42788
  try {
42465
42789
  config = JSON.parse(configContent);
@@ -42755,9 +43079,9 @@ async function createWriteStream(outputPath) {
42755
43079
  }
42756
43080
  async function createWriteStreamFromFile(filepath) {
42757
43081
  if (!await doesPathExist(filepath)) {
42758
- await (0, import_promises15.mkdir)(import_path21.default.dirname(filepath), { recursive: true });
43082
+ await (0, import_promises16.mkdir)(import_path22.default.dirname(filepath), { recursive: true });
42759
43083
  }
42760
- return import_fs15.default.createWriteStream(filepath);
43084
+ return import_fs16.default.createWriteStream(filepath);
42761
43085
  }
42762
43086
  /*! Bundled license information:
42763
43087
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fern-api/generator-cli",
3
- "version": "0.9.26",
3
+ "version": "0.9.27",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/fern-api/fern.git",