@fern-api/generator-cli 0.9.5 → 0.9.6
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/api.d.ts +14 -0
- package/dist/api.js +113 -17
- package/dist/cli.js +115 -19
- package/package.json +2 -2
package/dist/api.d.ts
CHANGED
|
@@ -549,6 +549,16 @@ interface GithubStepConfig {
|
|
|
549
549
|
previousGenerationSha: string;
|
|
550
550
|
currentGenerationSha: string;
|
|
551
551
|
};
|
|
552
|
+
/** When true: separate PRs per generation, no-diff skip, automerge support, run_id in body */
|
|
553
|
+
automationMode?: boolean;
|
|
554
|
+
/** Enable GitHub automerge on the PR (only effective when automationMode && !hasBreakingChanges) */
|
|
555
|
+
autoMerge?: boolean;
|
|
556
|
+
/** Pre-computed: version bump is MAJOR (from --version AUTO AI analysis) */
|
|
557
|
+
hasBreakingChanges?: boolean;
|
|
558
|
+
/** Human-readable breaking changes summary for PR body (from autoVersioningPrDescription on MAJOR) */
|
|
559
|
+
breakingChangesSummary?: string;
|
|
560
|
+
/** FERN_RUN_ID for cross-repo correlation (set by GitHub Action) */
|
|
561
|
+
runId?: string;
|
|
552
562
|
}
|
|
553
563
|
interface PipelineResult {
|
|
554
564
|
success: boolean;
|
|
@@ -593,6 +603,10 @@ interface GithubStepResult extends StepResult {
|
|
|
593
603
|
prNumber?: number;
|
|
594
604
|
updatedExistingPr?: boolean;
|
|
595
605
|
generationBaseTagSha?: string;
|
|
606
|
+
/** True when generation produced no changes vs base branch — PR skipped */
|
|
607
|
+
skippedNoDiff?: boolean;
|
|
608
|
+
/** True when automerge was enabled on the PR */
|
|
609
|
+
autoMergeEnabled?: boolean;
|
|
596
610
|
}
|
|
597
611
|
interface StepResult {
|
|
598
612
|
executed: boolean;
|
package/dist/api.js
CHANGED
|
@@ -6022,6 +6022,24 @@ var ClonedRepository = class _ClonedRepository {
|
|
|
6022
6022
|
const result = await this.git.raw(["rev-parse", `${commitSha}^{tree}`]);
|
|
6023
6023
|
return result.trim();
|
|
6024
6024
|
}
|
|
6025
|
+
/**
|
|
6026
|
+
* Returns true if the working tree has uncommitted changes (staged or unstaged).
|
|
6027
|
+
*/
|
|
6028
|
+
async hasChanges() {
|
|
6029
|
+
await this.git.cwd(this.clonePath);
|
|
6030
|
+
const status2 = await this.git.status();
|
|
6031
|
+
return !status2.isClean();
|
|
6032
|
+
}
|
|
6033
|
+
/**
|
|
6034
|
+
* Compares the tree hash of HEAD against a ref (e.g. `origin/main`).
|
|
6035
|
+
* Returns true if the trees are identical (no content difference).
|
|
6036
|
+
* Useful for detecting no-diff after committing — if trees match, the commit is a no-op.
|
|
6037
|
+
*/
|
|
6038
|
+
async treeHashEquals(ref) {
|
|
6039
|
+
const headTree = await this.getHeadTreeHash();
|
|
6040
|
+
const refTree = await this.getCommitTreeHash(ref);
|
|
6041
|
+
return headTree === refTree;
|
|
6042
|
+
}
|
|
6025
6043
|
// This tag is a moving pointer (fern-generation-base--<generator>) that tracks the latest
|
|
6026
6044
|
// clean generation SHA. --force is required because: (1) the tag is intentionally overwritten
|
|
6027
6045
|
// each generation, and (2) --force-with-lease doesn't work for tags since git tag -f overwrites
|
|
@@ -10311,31 +10329,32 @@ var GithubStep = class extends BaseStep {
|
|
|
10311
10329
|
const baseBranch = this.config.branch ?? await repository.getDefaultBranch();
|
|
10312
10330
|
const octokit = new import_rest2.Octokit({ auth: this.config.token });
|
|
10313
10331
|
const { owner, repo } = parseRepository(this.config.uri);
|
|
10314
|
-
const existingPR = await findExistingUpdatablePR(octokit, owner, repo, baseBranch, this.logger);
|
|
10315
10332
|
let prBranch;
|
|
10316
10333
|
let isUpdatingExistingPR = false;
|
|
10317
10334
|
let generationBaseSha;
|
|
10335
|
+
let existingPR;
|
|
10336
|
+
if (!this.config.automationMode) {
|
|
10337
|
+
existingPR = await findExistingUpdatablePR(octokit, owner, repo, baseBranch, this.logger);
|
|
10338
|
+
}
|
|
10318
10339
|
if (existingPR != null) {
|
|
10319
10340
|
this.logger.info(
|
|
10320
10341
|
`Found existing updatable PR #${existingPR.number}, will update branch ${existingPR.headBranch}`
|
|
10321
10342
|
);
|
|
10322
10343
|
prBranch = existingPR.headBranch;
|
|
10323
10344
|
isUpdatingExistingPR = true;
|
|
10324
|
-
if (skipCommit) {
|
|
10325
|
-
generationBaseSha = await createReplayBranch(
|
|
10326
|
-
repository,
|
|
10327
|
-
prBranch,
|
|
10328
|
-
this.config.commitMessage,
|
|
10329
|
-
replayConflictInfo,
|
|
10330
|
-
this.logger
|
|
10331
|
-
);
|
|
10332
|
-
} else {
|
|
10333
|
-
await repository.checkoutRemoteBranch(prBranch);
|
|
10334
|
-
}
|
|
10335
10345
|
} else {
|
|
10336
|
-
this.logger.debug(
|
|
10346
|
+
this.logger.debug(
|
|
10347
|
+
this.config.automationMode ? `Automation mode: creating new branch ${newPrBranch}` : `No existing updatable PR found, creating new branch ${newPrBranch}`
|
|
10348
|
+
);
|
|
10337
10349
|
prBranch = newPrBranch;
|
|
10338
|
-
|
|
10350
|
+
}
|
|
10351
|
+
const branchAction = resolveBranchAction({
|
|
10352
|
+
automationMode: this.config.automationMode === true,
|
|
10353
|
+
skipCommit,
|
|
10354
|
+
existingPR
|
|
10355
|
+
});
|
|
10356
|
+
switch (branchAction) {
|
|
10357
|
+
case "replay-branch":
|
|
10339
10358
|
generationBaseSha = await createReplayBranch(
|
|
10340
10359
|
repository,
|
|
10341
10360
|
prBranch,
|
|
@@ -10343,8 +10362,16 @@ var GithubStep = class extends BaseStep {
|
|
|
10343
10362
|
replayConflictInfo,
|
|
10344
10363
|
this.logger
|
|
10345
10364
|
);
|
|
10346
|
-
|
|
10347
|
-
|
|
10365
|
+
break;
|
|
10366
|
+
case "create-from-head":
|
|
10367
|
+
await repository.createBranchFromHead(prBranch);
|
|
10368
|
+
break;
|
|
10369
|
+
case "checkout-remote":
|
|
10370
|
+
await repository.checkoutRemoteBranch(prBranch);
|
|
10371
|
+
break;
|
|
10372
|
+
default: {
|
|
10373
|
+
const _exhaustive = branchAction;
|
|
10374
|
+
throw new Error(`Unexpected branch action: ${String(_exhaustive)}`);
|
|
10348
10375
|
}
|
|
10349
10376
|
}
|
|
10350
10377
|
if (!skipCommit) {
|
|
@@ -10354,6 +10381,13 @@ var GithubStep = class extends BaseStep {
|
|
|
10354
10381
|
await repository.commitAllChanges(finalCommitMessage2);
|
|
10355
10382
|
this.logger.debug(`Committed changes to local copy of GitHub repository at ${this.outputDir}`);
|
|
10356
10383
|
}
|
|
10384
|
+
if (this.config.automationMode) {
|
|
10385
|
+
const noDiff = await repository.treeHashEquals(`origin/${baseBranch}`);
|
|
10386
|
+
if (noDiff) {
|
|
10387
|
+
this.logger.info("No changes detected after generation \u2014 skipping PR creation");
|
|
10388
|
+
return { executed: true, success: true, skippedNoDiff: true };
|
|
10389
|
+
}
|
|
10390
|
+
}
|
|
10357
10391
|
const result = {
|
|
10358
10392
|
executed: true,
|
|
10359
10393
|
success: true,
|
|
@@ -10388,7 +10422,8 @@ var GithubStep = class extends BaseStep {
|
|
|
10388
10422
|
this.config.versionBumpReason
|
|
10389
10423
|
);
|
|
10390
10424
|
const replaySection = formatReplayPrBody(replayResult, { branchName: prBranch, repoUri: this.config.uri });
|
|
10391
|
-
|
|
10425
|
+
let enrichedBody = replaySection != null ? prBody + "\n\n---\n\n" + replaySection : prBody;
|
|
10426
|
+
enrichedBody = enrichPrBodyForAutomation(enrichedBody, this.config);
|
|
10392
10427
|
if (isUpdatingExistingPR && existingPR != null) {
|
|
10393
10428
|
this.logger.info(`Updated existing pull request: ${existingPR.htmlUrl}`);
|
|
10394
10429
|
result.prUrl = existingPR.htmlUrl;
|
|
@@ -10419,6 +10454,23 @@ var GithubStep = class extends BaseStep {
|
|
|
10419
10454
|
this.logger.info(`Created pull request: ${pullRequest.html_url}`);
|
|
10420
10455
|
result.prUrl = pullRequest.html_url;
|
|
10421
10456
|
result.prNumber = pullRequest.number;
|
|
10457
|
+
if (shouldEnableAutomerge(this.config) && pullRequest.node_id) {
|
|
10458
|
+
try {
|
|
10459
|
+
await octokit.graphql(
|
|
10460
|
+
`mutation($pullRequestId: ID!) {
|
|
10461
|
+
enablePullRequestAutoMerge(input: {
|
|
10462
|
+
pullRequestId: $pullRequestId,
|
|
10463
|
+
mergeMethod: SQUASH
|
|
10464
|
+
}) { clientMutationId }
|
|
10465
|
+
}`,
|
|
10466
|
+
{ pullRequestId: pullRequest.node_id }
|
|
10467
|
+
);
|
|
10468
|
+
this.logger.info(`Enabled automerge on PR #${pullRequest.number}`);
|
|
10469
|
+
result.autoMergeEnabled = true;
|
|
10470
|
+
} catch (autoMergeError) {
|
|
10471
|
+
this.logger.warn(`Could not enable automerge: ${extractErrorMessage(autoMergeError)}`);
|
|
10472
|
+
}
|
|
10473
|
+
}
|
|
10422
10474
|
} catch (error) {
|
|
10423
10475
|
const message = extractErrorMessage(error);
|
|
10424
10476
|
if (message.includes("A pull request already exists for")) {
|
|
@@ -10431,6 +10483,7 @@ var GithubStep = class extends BaseStep {
|
|
|
10431
10483
|
return result;
|
|
10432
10484
|
}
|
|
10433
10485
|
async executePushMode(repository) {
|
|
10486
|
+
const baseBranch = this.config.branch ?? await repository.getDefaultBranch();
|
|
10434
10487
|
if (this.config.branch != null) {
|
|
10435
10488
|
this.logger.debug(`Checking out branch ${this.config.branch}`);
|
|
10436
10489
|
await repository.checkout(this.config.branch);
|
|
@@ -10440,6 +10493,13 @@ var GithubStep = class extends BaseStep {
|
|
|
10440
10493
|
const finalCommitMessage = this.config.commitMessage ?? "SDK Generation";
|
|
10441
10494
|
await repository.commitAllChanges(finalCommitMessage);
|
|
10442
10495
|
this.logger.debug(`Committed changes to local copy of GitHub repository at ${this.outputDir}`);
|
|
10496
|
+
if (this.config.automationMode) {
|
|
10497
|
+
const noDiff = await repository.treeHashEquals(`origin/${baseBranch}`);
|
|
10498
|
+
if (noDiff) {
|
|
10499
|
+
this.logger.info("No changes detected after generation \u2014 skipping push");
|
|
10500
|
+
return { executed: true, success: true, skippedNoDiff: true };
|
|
10501
|
+
}
|
|
10502
|
+
}
|
|
10443
10503
|
const result = {
|
|
10444
10504
|
executed: true,
|
|
10445
10505
|
success: true
|
|
@@ -10484,6 +10544,42 @@ var GithubStep = class extends BaseStep {
|
|
|
10484
10544
|
return void 0;
|
|
10485
10545
|
}
|
|
10486
10546
|
};
|
|
10547
|
+
function enrichPrBodyForAutomation(body, config) {
|
|
10548
|
+
if (!config.automationMode) {
|
|
10549
|
+
return body;
|
|
10550
|
+
}
|
|
10551
|
+
let result = body;
|
|
10552
|
+
if (config.hasBreakingChanges && config.breakingChangesSummary) {
|
|
10553
|
+
result += "\n\n---\n\n## \u26A0\uFE0F Breaking Changes\n\nThis release contains breaking changes that require manual review:\n\n" + config.breakingChangesSummary;
|
|
10554
|
+
}
|
|
10555
|
+
if (config.runId) {
|
|
10556
|
+
result += `
|
|
10557
|
+
|
|
10558
|
+
---
|
|
10559
|
+
|
|
10560
|
+
_Fern Run ID: \`${config.runId}\`_`;
|
|
10561
|
+
}
|
|
10562
|
+
return result;
|
|
10563
|
+
}
|
|
10564
|
+
function shouldEnableAutomerge(config) {
|
|
10565
|
+
return config.automationMode === true && config.autoMerge === true && config.hasBreakingChanges !== true;
|
|
10566
|
+
}
|
|
10567
|
+
function resolveBranchAction({
|
|
10568
|
+
automationMode,
|
|
10569
|
+
skipCommit,
|
|
10570
|
+
existingPR
|
|
10571
|
+
}) {
|
|
10572
|
+
if (skipCommit) {
|
|
10573
|
+
return "replay-branch";
|
|
10574
|
+
}
|
|
10575
|
+
if (automationMode) {
|
|
10576
|
+
return "create-from-head";
|
|
10577
|
+
}
|
|
10578
|
+
if (existingPR != null) {
|
|
10579
|
+
return "checkout-remote";
|
|
10580
|
+
}
|
|
10581
|
+
return "create-from-head";
|
|
10582
|
+
}
|
|
10487
10583
|
|
|
10488
10584
|
// src/replay/replay-run.ts
|
|
10489
10585
|
var import_replay = require("@fern-api/replay");
|
package/dist/cli.js
CHANGED
|
@@ -20098,7 +20098,7 @@ var init_diff3 = __esm({
|
|
|
20098
20098
|
}
|
|
20099
20099
|
});
|
|
20100
20100
|
|
|
20101
|
-
// ../../node_modules/.pnpm/@fern-api+replay@0.10.
|
|
20101
|
+
// ../../node_modules/.pnpm/@fern-api+replay@0.10.3/node_modules/@fern-api/replay/dist/index.js
|
|
20102
20102
|
var dist_exports = {};
|
|
20103
20103
|
__export(dist_exports, {
|
|
20104
20104
|
FERN_BOT_EMAIL: () => FERN_BOT_EMAIL2,
|
|
@@ -21063,7 +21063,7 @@ function status(outputDir) {
|
|
|
21063
21063
|
}
|
|
21064
21064
|
var import_fs6, import_path8, import_yaml, import_crypto, import_promises4, import_os, import_path9, import_fs7, import_path10, import_crypto2, import_fs8, import_path11, import_yaml2, import_crypto3, import_fs9, import_path12, import_fs10, __defProp3, __getOwnPropNames3, __esm3, __export3, GitClient_exports, GitClient, init_GitClient, HybridReconstruction_exports, init_HybridReconstruction, FERN_BOT_NAME2, FERN_BOT_EMAIL2, FERN_BOT_LOGIN2, FERN_SUPPORT_NAMES, LOCKFILE_HEADER, LockfileNotFoundError, LockfileManager, INFRASTRUCTURE_FILES, ReplayDetector, CONFLICT_OPENER, CONFLICT_SEPARATOR, CONFLICT_CLOSER, BINARY_EXTENSIONS, ReplayApplicator, ReplayCommitter, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES, GITATTRIBUTES_ENTRIES, EMPTY_RESULT;
|
|
21065
21065
|
var init_dist3 = __esm({
|
|
21066
|
-
"../../node_modules/.pnpm/@fern-api+replay@0.10.
|
|
21066
|
+
"../../node_modules/.pnpm/@fern-api+replay@0.10.3/node_modules/@fern-api/replay/dist/index.js"() {
|
|
21067
21067
|
"use strict";
|
|
21068
21068
|
init_esm4();
|
|
21069
21069
|
import_fs6 = require("fs");
|
|
@@ -25063,6 +25063,24 @@ var ClonedRepository = class _ClonedRepository {
|
|
|
25063
25063
|
const result = await this.git.raw(["rev-parse", `${commitSha}^{tree}`]);
|
|
25064
25064
|
return result.trim();
|
|
25065
25065
|
}
|
|
25066
|
+
/**
|
|
25067
|
+
* Returns true if the working tree has uncommitted changes (staged or unstaged).
|
|
25068
|
+
*/
|
|
25069
|
+
async hasChanges() {
|
|
25070
|
+
await this.git.cwd(this.clonePath);
|
|
25071
|
+
const status2 = await this.git.status();
|
|
25072
|
+
return !status2.isClean();
|
|
25073
|
+
}
|
|
25074
|
+
/**
|
|
25075
|
+
* Compares the tree hash of HEAD against a ref (e.g. `origin/main`).
|
|
25076
|
+
* Returns true if the trees are identical (no content difference).
|
|
25077
|
+
* Useful for detecting no-diff after committing — if trees match, the commit is a no-op.
|
|
25078
|
+
*/
|
|
25079
|
+
async treeHashEquals(ref) {
|
|
25080
|
+
const headTree = await this.getHeadTreeHash();
|
|
25081
|
+
const refTree = await this.getCommitTreeHash(ref);
|
|
25082
|
+
return headTree === refTree;
|
|
25083
|
+
}
|
|
25066
25084
|
// This tag is a moving pointer (fern-generation-base--<generator>) that tracks the latest
|
|
25067
25085
|
// clean generation SHA. --force is required because: (1) the tag is intentionally overwritten
|
|
25068
25086
|
// each generation, and (2) --force-with-lease doesn't work for tags since git tag -f overwrites
|
|
@@ -33135,31 +33153,32 @@ var GithubStep = class extends BaseStep {
|
|
|
33135
33153
|
const baseBranch = this.config.branch ?? await repository.getDefaultBranch();
|
|
33136
33154
|
const octokit = new Octokit2({ auth: this.config.token });
|
|
33137
33155
|
const { owner, repo } = parseRepository(this.config.uri);
|
|
33138
|
-
const existingPR = await findExistingUpdatablePR(octokit, owner, repo, baseBranch, this.logger);
|
|
33139
33156
|
let prBranch;
|
|
33140
33157
|
let isUpdatingExistingPR = false;
|
|
33141
33158
|
let generationBaseSha;
|
|
33159
|
+
let existingPR;
|
|
33160
|
+
if (!this.config.automationMode) {
|
|
33161
|
+
existingPR = await findExistingUpdatablePR(octokit, owner, repo, baseBranch, this.logger);
|
|
33162
|
+
}
|
|
33142
33163
|
if (existingPR != null) {
|
|
33143
33164
|
this.logger.info(
|
|
33144
33165
|
`Found existing updatable PR #${existingPR.number}, will update branch ${existingPR.headBranch}`
|
|
33145
33166
|
);
|
|
33146
33167
|
prBranch = existingPR.headBranch;
|
|
33147
33168
|
isUpdatingExistingPR = true;
|
|
33148
|
-
if (skipCommit) {
|
|
33149
|
-
generationBaseSha = await createReplayBranch(
|
|
33150
|
-
repository,
|
|
33151
|
-
prBranch,
|
|
33152
|
-
this.config.commitMessage,
|
|
33153
|
-
replayConflictInfo,
|
|
33154
|
-
this.logger
|
|
33155
|
-
);
|
|
33156
|
-
} else {
|
|
33157
|
-
await repository.checkoutRemoteBranch(prBranch);
|
|
33158
|
-
}
|
|
33159
33169
|
} else {
|
|
33160
|
-
this.logger.debug(
|
|
33170
|
+
this.logger.debug(
|
|
33171
|
+
this.config.automationMode ? `Automation mode: creating new branch ${newPrBranch}` : `No existing updatable PR found, creating new branch ${newPrBranch}`
|
|
33172
|
+
);
|
|
33161
33173
|
prBranch = newPrBranch;
|
|
33162
|
-
|
|
33174
|
+
}
|
|
33175
|
+
const branchAction = resolveBranchAction({
|
|
33176
|
+
automationMode: this.config.automationMode === true,
|
|
33177
|
+
skipCommit,
|
|
33178
|
+
existingPR
|
|
33179
|
+
});
|
|
33180
|
+
switch (branchAction) {
|
|
33181
|
+
case "replay-branch":
|
|
33163
33182
|
generationBaseSha = await createReplayBranch(
|
|
33164
33183
|
repository,
|
|
33165
33184
|
prBranch,
|
|
@@ -33167,8 +33186,16 @@ var GithubStep = class extends BaseStep {
|
|
|
33167
33186
|
replayConflictInfo,
|
|
33168
33187
|
this.logger
|
|
33169
33188
|
);
|
|
33170
|
-
|
|
33171
|
-
|
|
33189
|
+
break;
|
|
33190
|
+
case "create-from-head":
|
|
33191
|
+
await repository.createBranchFromHead(prBranch);
|
|
33192
|
+
break;
|
|
33193
|
+
case "checkout-remote":
|
|
33194
|
+
await repository.checkoutRemoteBranch(prBranch);
|
|
33195
|
+
break;
|
|
33196
|
+
default: {
|
|
33197
|
+
const _exhaustive = branchAction;
|
|
33198
|
+
throw new Error(`Unexpected branch action: ${String(_exhaustive)}`);
|
|
33172
33199
|
}
|
|
33173
33200
|
}
|
|
33174
33201
|
if (!skipCommit) {
|
|
@@ -33178,6 +33205,13 @@ var GithubStep = class extends BaseStep {
|
|
|
33178
33205
|
await repository.commitAllChanges(finalCommitMessage2);
|
|
33179
33206
|
this.logger.debug(`Committed changes to local copy of GitHub repository at ${this.outputDir}`);
|
|
33180
33207
|
}
|
|
33208
|
+
if (this.config.automationMode) {
|
|
33209
|
+
const noDiff = await repository.treeHashEquals(`origin/${baseBranch}`);
|
|
33210
|
+
if (noDiff) {
|
|
33211
|
+
this.logger.info("No changes detected after generation \u2014 skipping PR creation");
|
|
33212
|
+
return { executed: true, success: true, skippedNoDiff: true };
|
|
33213
|
+
}
|
|
33214
|
+
}
|
|
33181
33215
|
const result = {
|
|
33182
33216
|
executed: true,
|
|
33183
33217
|
success: true,
|
|
@@ -33212,7 +33246,8 @@ var GithubStep = class extends BaseStep {
|
|
|
33212
33246
|
this.config.versionBumpReason
|
|
33213
33247
|
);
|
|
33214
33248
|
const replaySection = formatReplayPrBody(replayResult, { branchName: prBranch, repoUri: this.config.uri });
|
|
33215
|
-
|
|
33249
|
+
let enrichedBody = replaySection != null ? prBody + "\n\n---\n\n" + replaySection : prBody;
|
|
33250
|
+
enrichedBody = enrichPrBodyForAutomation(enrichedBody, this.config);
|
|
33216
33251
|
if (isUpdatingExistingPR && existingPR != null) {
|
|
33217
33252
|
this.logger.info(`Updated existing pull request: ${existingPR.htmlUrl}`);
|
|
33218
33253
|
result.prUrl = existingPR.htmlUrl;
|
|
@@ -33243,6 +33278,23 @@ var GithubStep = class extends BaseStep {
|
|
|
33243
33278
|
this.logger.info(`Created pull request: ${pullRequest.html_url}`);
|
|
33244
33279
|
result.prUrl = pullRequest.html_url;
|
|
33245
33280
|
result.prNumber = pullRequest.number;
|
|
33281
|
+
if (shouldEnableAutomerge(this.config) && pullRequest.node_id) {
|
|
33282
|
+
try {
|
|
33283
|
+
await octokit.graphql(
|
|
33284
|
+
`mutation($pullRequestId: ID!) {
|
|
33285
|
+
enablePullRequestAutoMerge(input: {
|
|
33286
|
+
pullRequestId: $pullRequestId,
|
|
33287
|
+
mergeMethod: SQUASH
|
|
33288
|
+
}) { clientMutationId }
|
|
33289
|
+
}`,
|
|
33290
|
+
{ pullRequestId: pullRequest.node_id }
|
|
33291
|
+
);
|
|
33292
|
+
this.logger.info(`Enabled automerge on PR #${pullRequest.number}`);
|
|
33293
|
+
result.autoMergeEnabled = true;
|
|
33294
|
+
} catch (autoMergeError) {
|
|
33295
|
+
this.logger.warn(`Could not enable automerge: ${extractErrorMessage(autoMergeError)}`);
|
|
33296
|
+
}
|
|
33297
|
+
}
|
|
33246
33298
|
} catch (error) {
|
|
33247
33299
|
const message = extractErrorMessage(error);
|
|
33248
33300
|
if (message.includes("A pull request already exists for")) {
|
|
@@ -33255,6 +33307,7 @@ var GithubStep = class extends BaseStep {
|
|
|
33255
33307
|
return result;
|
|
33256
33308
|
}
|
|
33257
33309
|
async executePushMode(repository) {
|
|
33310
|
+
const baseBranch = this.config.branch ?? await repository.getDefaultBranch();
|
|
33258
33311
|
if (this.config.branch != null) {
|
|
33259
33312
|
this.logger.debug(`Checking out branch ${this.config.branch}`);
|
|
33260
33313
|
await repository.checkout(this.config.branch);
|
|
@@ -33264,6 +33317,13 @@ var GithubStep = class extends BaseStep {
|
|
|
33264
33317
|
const finalCommitMessage = this.config.commitMessage ?? "SDK Generation";
|
|
33265
33318
|
await repository.commitAllChanges(finalCommitMessage);
|
|
33266
33319
|
this.logger.debug(`Committed changes to local copy of GitHub repository at ${this.outputDir}`);
|
|
33320
|
+
if (this.config.automationMode) {
|
|
33321
|
+
const noDiff = await repository.treeHashEquals(`origin/${baseBranch}`);
|
|
33322
|
+
if (noDiff) {
|
|
33323
|
+
this.logger.info("No changes detected after generation \u2014 skipping push");
|
|
33324
|
+
return { executed: true, success: true, skippedNoDiff: true };
|
|
33325
|
+
}
|
|
33326
|
+
}
|
|
33267
33327
|
const result = {
|
|
33268
33328
|
executed: true,
|
|
33269
33329
|
success: true
|
|
@@ -33308,6 +33368,42 @@ var GithubStep = class extends BaseStep {
|
|
|
33308
33368
|
return void 0;
|
|
33309
33369
|
}
|
|
33310
33370
|
};
|
|
33371
|
+
function enrichPrBodyForAutomation(body, config) {
|
|
33372
|
+
if (!config.automationMode) {
|
|
33373
|
+
return body;
|
|
33374
|
+
}
|
|
33375
|
+
let result = body;
|
|
33376
|
+
if (config.hasBreakingChanges && config.breakingChangesSummary) {
|
|
33377
|
+
result += "\n\n---\n\n## \u26A0\uFE0F Breaking Changes\n\nThis release contains breaking changes that require manual review:\n\n" + config.breakingChangesSummary;
|
|
33378
|
+
}
|
|
33379
|
+
if (config.runId) {
|
|
33380
|
+
result += `
|
|
33381
|
+
|
|
33382
|
+
---
|
|
33383
|
+
|
|
33384
|
+
_Fern Run ID: \`${config.runId}\`_`;
|
|
33385
|
+
}
|
|
33386
|
+
return result;
|
|
33387
|
+
}
|
|
33388
|
+
function shouldEnableAutomerge(config) {
|
|
33389
|
+
return config.automationMode === true && config.autoMerge === true && config.hasBreakingChanges !== true;
|
|
33390
|
+
}
|
|
33391
|
+
function resolveBranchAction({
|
|
33392
|
+
automationMode,
|
|
33393
|
+
skipCommit,
|
|
33394
|
+
existingPR
|
|
33395
|
+
}) {
|
|
33396
|
+
if (skipCommit) {
|
|
33397
|
+
return "replay-branch";
|
|
33398
|
+
}
|
|
33399
|
+
if (automationMode) {
|
|
33400
|
+
return "create-from-head";
|
|
33401
|
+
}
|
|
33402
|
+
if (existingPR != null) {
|
|
33403
|
+
return "checkout-remote";
|
|
33404
|
+
}
|
|
33405
|
+
return "create-from-head";
|
|
33406
|
+
}
|
|
33311
33407
|
|
|
33312
33408
|
// src/replay/replay-run.ts
|
|
33313
33409
|
init_dist3();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fern-api/generator-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/fern-api/fern.git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"**"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@fern-api/replay": "0.10.
|
|
25
|
+
"@fern-api/replay": "0.10.3",
|
|
26
26
|
"@octokit/rest": "^22.0.1",
|
|
27
27
|
"es-toolkit": "^1.45.1",
|
|
28
28
|
"tmp-promise": "^3.0.3"
|