@fern-api/generator-cli 0.9.36 → 0.9.37
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/cli.js +251 -29
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -41181,32 +41181,30 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41181
41181
|
name = "autoVersion";
|
|
41182
41182
|
async execute(context) {
|
|
41183
41183
|
const prepared = context.previousStepResults.generationCommit?.preparedReplay;
|
|
41184
|
-
if (
|
|
41185
|
-
|
|
41186
|
-
"AutoVersionStep:
|
|
41187
|
-
|
|
41188
|
-
|
|
41189
|
-
|
|
41190
|
-
|
|
41191
|
-
|
|
41192
|
-
|
|
41193
|
-
|
|
41194
|
-
|
|
41195
|
-
|
|
41196
|
-
|
|
41197
|
-
|
|
41198
|
-
|
|
41184
|
+
if (prepared) {
|
|
41185
|
+
if (prepared.flow === "skip-application") {
|
|
41186
|
+
this.logger.info("AutoVersionStep: replay flow is skip-application; skipping autoversion.");
|
|
41187
|
+
return { executed: true, success: true };
|
|
41188
|
+
}
|
|
41189
|
+
const language = this.config.language;
|
|
41190
|
+
const mappedMagicVersion = mapMagicVersionForLanguage(MAGIC_VERSION, language);
|
|
41191
|
+
const service = new AutoVersioningService({ logger: this.toTaskLogger() });
|
|
41192
|
+
if (prepared.previousGenerationSha == null) {
|
|
41193
|
+
return await this.handleFirstGeneration({ service, language, mappedMagicVersion, commit: true });
|
|
41194
|
+
}
|
|
41195
|
+
return await this.handleNormalFlow({
|
|
41196
|
+
prepared,
|
|
41197
|
+
service,
|
|
41198
|
+
language,
|
|
41199
|
+
mappedMagicVersion,
|
|
41200
|
+
previousGenerationSha: prepared.previousGenerationSha
|
|
41201
|
+
});
|
|
41199
41202
|
}
|
|
41200
|
-
|
|
41201
|
-
|
|
41202
|
-
service,
|
|
41203
|
-
language,
|
|
41204
|
-
mappedMagicVersion,
|
|
41205
|
-
previousGenerationSha: prepared.previousGenerationSha
|
|
41206
|
-
});
|
|
41203
|
+
this.logger.info("AutoVersionStep: running in non-replay mode (git diff HEAD).");
|
|
41204
|
+
return await this.handleNonReplayFlow();
|
|
41207
41205
|
}
|
|
41208
41206
|
async handleFirstGeneration(params) {
|
|
41209
|
-
const { service, language, mappedMagicVersion } = params;
|
|
41207
|
+
const { service, language, mappedMagicVersion, commit } = params;
|
|
41210
41208
|
const initialVersion = this.config.baseVersion ?? (mappedMagicVersion.startsWith("v") ? "v0.0.1" : "0.0.1");
|
|
41211
41209
|
if (!isValidSemver(initialVersion)) {
|
|
41212
41210
|
const errorMessage = `AutoVersionStep: baseVersion ${JSON.stringify(initialVersion)} is not a valid semver string (expected e.g. "1.2.3" or "v1.2.3"). Refusing to run to avoid shell injection into the placeholder-rewrite step.`;
|
|
@@ -41223,7 +41221,7 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41223
41221
|
await service.addGoMajorVersionSuffix(this.outputDir, initialVersion);
|
|
41224
41222
|
}
|
|
41225
41223
|
const commitMessage = this.brandMessage("Initial SDK generation");
|
|
41226
|
-
const commitSha = this.commitAutoversion(commitMessage);
|
|
41224
|
+
const commitSha = commit ? this.commitAutoversion(commitMessage) : void 0;
|
|
41227
41225
|
return {
|
|
41228
41226
|
executed: true,
|
|
41229
41227
|
success: true,
|
|
@@ -41242,7 +41240,7 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41242
41240
|
baseVersion: this.config.baseVersion
|
|
41243
41241
|
});
|
|
41244
41242
|
if (previousVersion == null) {
|
|
41245
|
-
return await this.handleFirstGeneration({ service, language, mappedMagicVersion });
|
|
41243
|
+
return await this.handleFirstGeneration({ service, language, mappedMagicVersion, commit: true });
|
|
41246
41244
|
}
|
|
41247
41245
|
if (rawDiff.trim().length === 0) {
|
|
41248
41246
|
this.logger.info(
|
|
@@ -41323,6 +41321,106 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41323
41321
|
analysis
|
|
41324
41322
|
});
|
|
41325
41323
|
}
|
|
41324
|
+
/**
|
|
41325
|
+
* Non-replay autoversion: diffs HEAD (committed SDK) vs the working tree
|
|
41326
|
+
* (freshly generated files). Does NOT commit — GithubStep will commit all
|
|
41327
|
+
* changes (including the rewritten placeholder) in a single generation commit.
|
|
41328
|
+
*/
|
|
41329
|
+
async handleNonReplayFlow() {
|
|
41330
|
+
const language = this.config.language;
|
|
41331
|
+
const mappedMagicVersion = mapMagicVersionForLanguage(MAGIC_VERSION, language);
|
|
41332
|
+
const service = new AutoVersioningService({ logger: this.toTaskLogger() });
|
|
41333
|
+
const rawDiff = this.gitDiffHead();
|
|
41334
|
+
const previousVersion = await this.resolvePreviousVersionNonReplay({
|
|
41335
|
+
service,
|
|
41336
|
+
rawDiff,
|
|
41337
|
+
mappedMagicVersion,
|
|
41338
|
+
baseVersion: this.config.baseVersion
|
|
41339
|
+
});
|
|
41340
|
+
if (previousVersion == null) {
|
|
41341
|
+
return await this.handleFirstGeneration({ service, language, mappedMagicVersion, commit: false });
|
|
41342
|
+
}
|
|
41343
|
+
if (rawDiff.trim().length === 0) {
|
|
41344
|
+
this.logger.info(`AutoVersionStep: empty diff (non-replay); rewriting placeholder to ${previousVersion}.`);
|
|
41345
|
+
return await this.finalizeNoChangeNonReplay({
|
|
41346
|
+
service,
|
|
41347
|
+
language,
|
|
41348
|
+
mappedMagicVersion,
|
|
41349
|
+
previousVersion,
|
|
41350
|
+
reason: "no diff between generations"
|
|
41351
|
+
});
|
|
41352
|
+
}
|
|
41353
|
+
const cleanedDiff = service.cleanDiffForAI(rawDiff, mappedMagicVersion);
|
|
41354
|
+
const rawBytes = Buffer.byteLength(rawDiff, "utf-8");
|
|
41355
|
+
const cleanedBytes = Buffer.byteLength(cleanedDiff, "utf-8");
|
|
41356
|
+
this.logger.debug(
|
|
41357
|
+
`AutoVersionStep (non-replay): raw=${formatSizeKB(rawBytes)}KB (${countFilesInDiff(rawDiff)} files), cleaned=${formatSizeKB(cleanedBytes)}KB (${countFilesInDiff(cleanedDiff)} files)`
|
|
41358
|
+
);
|
|
41359
|
+
if (cleanedDiff.trim().length === 0) {
|
|
41360
|
+
this.logger.info(
|
|
41361
|
+
`AutoVersionStep: cleaned diff empty (non-replay); rewriting placeholder to ${previousVersion}.`
|
|
41362
|
+
);
|
|
41363
|
+
return await this.finalizeNoChangeNonReplay({
|
|
41364
|
+
service,
|
|
41365
|
+
language,
|
|
41366
|
+
mappedMagicVersion,
|
|
41367
|
+
previousVersion,
|
|
41368
|
+
reason: "no semantic changes"
|
|
41369
|
+
});
|
|
41370
|
+
}
|
|
41371
|
+
if (cleanedBytes > MAX_RAW_DIFF_BYTES) {
|
|
41372
|
+
this.logger.warn(
|
|
41373
|
+
`AutoVersionStep (non-replay): diff too large (${formatSizeKB(cleanedBytes)}KB). Falling back to PATCH.`
|
|
41374
|
+
);
|
|
41375
|
+
return await this.finalizeWithBumpNonReplay({
|
|
41376
|
+
service,
|
|
41377
|
+
language,
|
|
41378
|
+
mappedMagicVersion,
|
|
41379
|
+
previousVersion,
|
|
41380
|
+
analysis: { versionBump: "PATCH", message: this.brandMessage("SDK regeneration") }
|
|
41381
|
+
});
|
|
41382
|
+
}
|
|
41383
|
+
let analysis;
|
|
41384
|
+
try {
|
|
41385
|
+
if (this.config.ai == null && this.config.fernToken != null) {
|
|
41386
|
+
analysis = await this.analyzeViaFaiService(cleanedDiff, language, previousVersion);
|
|
41387
|
+
} else {
|
|
41388
|
+
const chunks = service.chunkDiff(cleanedDiff, MAX_AI_DIFF_BYTES);
|
|
41389
|
+
const cappedChunks = chunks.slice(0, MAX_CHUNKS);
|
|
41390
|
+
const skippedChunks = chunks.length - cappedChunks.length;
|
|
41391
|
+
if (chunks.length > 1) {
|
|
41392
|
+
this.logger.info(
|
|
41393
|
+
`AutoVersionStep (non-replay): split diff into ${chunks.length} chunks` + (skippedChunks > 0 ? ` (capped at ${MAX_CHUNKS}, skipping ${skippedChunks})` : "")
|
|
41394
|
+
);
|
|
41395
|
+
}
|
|
41396
|
+
analysis = cappedChunks.length <= 1 ? await this.analyzeSingle(cleanedDiff, language, previousVersion) : await this.analyzeChunks(cappedChunks, language, previousVersion);
|
|
41397
|
+
}
|
|
41398
|
+
} catch (error) {
|
|
41399
|
+
this.logger.warn(
|
|
41400
|
+
`AutoVersionStep (non-replay): FAI analysis failed (${String(error)}); falling back to PATCH bump.`
|
|
41401
|
+
);
|
|
41402
|
+
analysis = { versionBump: "PATCH", message: this.brandMessage("SDK regeneration") };
|
|
41403
|
+
}
|
|
41404
|
+
if (analysis == null) {
|
|
41405
|
+
this.logger.info(
|
|
41406
|
+
`AutoVersionStep (non-replay): FAI returned NO_CHANGE; rewriting placeholder to ${previousVersion}.`
|
|
41407
|
+
);
|
|
41408
|
+
return await this.finalizeNoChangeNonReplay({
|
|
41409
|
+
service,
|
|
41410
|
+
language,
|
|
41411
|
+
mappedMagicVersion,
|
|
41412
|
+
previousVersion,
|
|
41413
|
+
reason: "FAI returned NO_CHANGE"
|
|
41414
|
+
});
|
|
41415
|
+
}
|
|
41416
|
+
return await this.finalizeWithBumpNonReplay({
|
|
41417
|
+
service,
|
|
41418
|
+
language,
|
|
41419
|
+
mappedMagicVersion,
|
|
41420
|
+
previousVersion,
|
|
41421
|
+
analysis
|
|
41422
|
+
});
|
|
41423
|
+
}
|
|
41326
41424
|
/**
|
|
41327
41425
|
* Terminal path for runs that determine no semver bump is needed. The
|
|
41328
41426
|
* current working tree still contains `0.0.0-fern-placeholder` from this
|
|
@@ -41380,6 +41478,98 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41380
41478
|
commitSha
|
|
41381
41479
|
};
|
|
41382
41480
|
}
|
|
41481
|
+
/**
|
|
41482
|
+
* Non-replay variant of finalizeNoChange. Rewrites the placeholder to
|
|
41483
|
+
* `previousVersion` but does NOT commit — GithubStep handles the commit.
|
|
41484
|
+
*/
|
|
41485
|
+
async finalizeNoChangeNonReplay(params) {
|
|
41486
|
+
const { service, language, mappedMagicVersion, previousVersion, reason } = params;
|
|
41487
|
+
if (!isValidSemver(previousVersion)) {
|
|
41488
|
+
const errorMessage = `AutoVersionStep: resolved previousVersion ${JSON.stringify(previousVersion)} is not a valid semver string. Refusing to rewrite placeholder to avoid shell injection.`;
|
|
41489
|
+
this.logger.error(errorMessage);
|
|
41490
|
+
return { executed: true, success: false, errorMessage };
|
|
41491
|
+
}
|
|
41492
|
+
await service.replaceMagicVersion(this.outputDir, mappedMagicVersion, previousVersion);
|
|
41493
|
+
if (language === "go") {
|
|
41494
|
+
await service.addGoMajorVersionSuffix(this.outputDir, previousVersion);
|
|
41495
|
+
}
|
|
41496
|
+
const commitMessage = this.brandMessage(`SDK regeneration (no semver change: ${reason})`);
|
|
41497
|
+
return {
|
|
41498
|
+
executed: true,
|
|
41499
|
+
success: true,
|
|
41500
|
+
version: previousVersion,
|
|
41501
|
+
previousVersion,
|
|
41502
|
+
versionBump: "NO_CHANGE",
|
|
41503
|
+
commitMessage
|
|
41504
|
+
};
|
|
41505
|
+
}
|
|
41506
|
+
/**
|
|
41507
|
+
* Non-replay variant of finalizeWithBump. Rewrites the placeholder to
|
|
41508
|
+
* the bumped version but does NOT commit — GithubStep handles the commit.
|
|
41509
|
+
*/
|
|
41510
|
+
async finalizeWithBumpNonReplay(params) {
|
|
41511
|
+
const { service, language, mappedMagicVersion, previousVersion, analysis } = params;
|
|
41512
|
+
const newVersion = incrementVersion(previousVersion, analysis.versionBump);
|
|
41513
|
+
this.logger.info(
|
|
41514
|
+
`AutoVersionStep (non-replay): ${analysis.versionBump} bump: ${previousVersion} \u2192 ${newVersion}`
|
|
41515
|
+
);
|
|
41516
|
+
await service.replaceMagicVersion(this.outputDir, mappedMagicVersion, newVersion);
|
|
41517
|
+
if (language === "go") {
|
|
41518
|
+
await service.addGoMajorVersionSuffix(this.outputDir, newVersion);
|
|
41519
|
+
}
|
|
41520
|
+
if (analysis.changelogEntry && analysis.changelogEntry.trim().length > 0) {
|
|
41521
|
+
await this.prependChangelogEntry({ version: newVersion, entry: analysis.changelogEntry });
|
|
41522
|
+
}
|
|
41523
|
+
return {
|
|
41524
|
+
executed: true,
|
|
41525
|
+
success: true,
|
|
41526
|
+
version: newVersion,
|
|
41527
|
+
commitMessage: analysis.message,
|
|
41528
|
+
changelogEntry: analysis.changelogEntry,
|
|
41529
|
+
previousVersion,
|
|
41530
|
+
versionBump: analysis.versionBump,
|
|
41531
|
+
prDescription: analysis.prDescription,
|
|
41532
|
+
versionBumpReason: analysis.versionBumpReason
|
|
41533
|
+
};
|
|
41534
|
+
}
|
|
41535
|
+
/**
|
|
41536
|
+
* Resolves the previous version for non-replay mode. Reads HEAD:.fern/metadata.json
|
|
41537
|
+
* (not HEAD~1, since no generation commit exists yet) as the primary fallback.
|
|
41538
|
+
*/
|
|
41539
|
+
async resolvePreviousVersionNonReplay(params) {
|
|
41540
|
+
const { service, rawDiff, mappedMagicVersion, baseVersion } = params;
|
|
41541
|
+
if (baseVersion != null && isValidSemver(baseVersion)) {
|
|
41542
|
+
this.logger.debug(
|
|
41543
|
+
`AutoVersionStep (non-replay): previous version from pipeline baseVersion: ${baseVersion}`
|
|
41544
|
+
);
|
|
41545
|
+
return this.normalizeVersionPrefix(baseVersion, mappedMagicVersion);
|
|
41546
|
+
}
|
|
41547
|
+
try {
|
|
41548
|
+
const extracted = service.extractPreviousVersion(rawDiff, mappedMagicVersion);
|
|
41549
|
+
if (extracted != null) {
|
|
41550
|
+
this.logger.debug(`AutoVersionStep (non-replay): previous version from diff: ${extracted}`);
|
|
41551
|
+
return extracted;
|
|
41552
|
+
}
|
|
41553
|
+
} catch (error) {
|
|
41554
|
+
if (!(error instanceof AutoVersioningException) || !error.magicVersionAbsent) {
|
|
41555
|
+
throw error;
|
|
41556
|
+
}
|
|
41557
|
+
this.logger.info("AutoVersionStep (non-replay): magic version not in diff; trying metadata + git tags.");
|
|
41558
|
+
}
|
|
41559
|
+
const metadataVersion = this.readVersionFromMetadataAtHead();
|
|
41560
|
+
if (metadataVersion != null) {
|
|
41561
|
+
return this.normalizeVersionPrefix(metadataVersion, mappedMagicVersion);
|
|
41562
|
+
}
|
|
41563
|
+
try {
|
|
41564
|
+
const tagVersion = await service.getLatestVersionFromGitTags(this.outputDir);
|
|
41565
|
+
if (tagVersion != null) {
|
|
41566
|
+
return this.normalizeVersionPrefix(tagVersion, mappedMagicVersion);
|
|
41567
|
+
}
|
|
41568
|
+
} catch (error) {
|
|
41569
|
+
this.logger.debug(`AutoVersionStep (non-replay): git-tags fallback failed (${String(error)}); ignoring.`);
|
|
41570
|
+
}
|
|
41571
|
+
return null;
|
|
41572
|
+
}
|
|
41383
41573
|
async resolvePreviousVersion(params) {
|
|
41384
41574
|
const { service, rawDiff, mappedMagicVersion, baseVersion } = params;
|
|
41385
41575
|
if (baseVersion != null && isValidSemver(baseVersion)) {
|
|
@@ -41429,6 +41619,42 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41429
41619
|
const stripped = version2.startsWith("v") ? version2.slice(1) : version2;
|
|
41430
41620
|
return mappedMagicVersion.startsWith("v") ? `v${stripped}` : stripped;
|
|
41431
41621
|
}
|
|
41622
|
+
/**
|
|
41623
|
+
* Reads the sdkVersion from the committed (HEAD) .fern/metadata.json.
|
|
41624
|
+
* Used by the non-replay path where no generation commit exists yet,
|
|
41625
|
+
* so HEAD is the unmodified SDK repository.
|
|
41626
|
+
*/
|
|
41627
|
+
readVersionFromMetadataAtHead() {
|
|
41628
|
+
try {
|
|
41629
|
+
const output = (0, import_child_process4.execFileSync)("git", ["show", "HEAD:.fern/metadata.json"], {
|
|
41630
|
+
cwd: this.outputDir,
|
|
41631
|
+
encoding: "utf-8",
|
|
41632
|
+
stdio: "pipe"
|
|
41633
|
+
});
|
|
41634
|
+
const parsed = JSON.parse(output);
|
|
41635
|
+
return parsed.sdkVersion ?? void 0;
|
|
41636
|
+
} catch (error) {
|
|
41637
|
+
this.logger.debug(`AutoVersionStep: failed to read HEAD:.fern/metadata.json (${String(error)})`);
|
|
41638
|
+
return void 0;
|
|
41639
|
+
}
|
|
41640
|
+
}
|
|
41641
|
+
/**
|
|
41642
|
+
* Computes a diff between HEAD (committed SDK) and the working tree (new
|
|
41643
|
+
* generation). Marks untracked files as intent-to-add so they appear in
|
|
41644
|
+
* the diff, matching LocalTaskHandler.generateDiffFile() behavior.
|
|
41645
|
+
*/
|
|
41646
|
+
gitDiffHead() {
|
|
41647
|
+
(0, import_child_process4.execFileSync)("git", ["add", "-N", "."], {
|
|
41648
|
+
cwd: this.outputDir,
|
|
41649
|
+
stdio: "pipe"
|
|
41650
|
+
});
|
|
41651
|
+
return (0, import_child_process4.execFileSync)("git", ["diff", "HEAD", "--", ".", ":(exclude).fern/metadata.json"], {
|
|
41652
|
+
cwd: this.outputDir,
|
|
41653
|
+
encoding: "utf-8",
|
|
41654
|
+
stdio: "pipe",
|
|
41655
|
+
maxBuffer: 256 * 1024 * 1024
|
|
41656
|
+
});
|
|
41657
|
+
}
|
|
41432
41658
|
gitDiff(from, to) {
|
|
41433
41659
|
return (0, import_child_process4.execFileSync)("git", ["diff", from, to, "--", ".", ":(exclude).fern/metadata.json"], {
|
|
41434
41660
|
cwd: this.outputDir,
|
|
@@ -42903,10 +43129,6 @@ var PostGenerationPipeline = class {
|
|
|
42903
43129
|
);
|
|
42904
43130
|
replayEnabled = false;
|
|
42905
43131
|
}
|
|
42906
|
-
if (autoVersionEnabled && !replayEnabled) {
|
|
42907
|
-
this.logger.warn("AutoVersion requires Replay to be enabled. Disabling AutoVersion for this run.");
|
|
42908
|
-
autoVersionEnabled = false;
|
|
42909
|
-
}
|
|
42910
43132
|
if (replayEnabled && config.replay != null) {
|
|
42911
43133
|
this.steps.push(
|
|
42912
43134
|
new GenerationCommitStep(
|