release-please 14.12.0 → 14.13.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@
4
4
 
5
5
  [1]: https://www.npmjs.com/package/release-please?activeTab=versions
6
6
 
7
+ ## [14.13.1](https://github.com/googleapis/release-please/compare/v14.13.0...v14.13.1) (2022-10-14)
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * Updating a pull request uses overflow handler if body is too large ([#1702](https://github.com/googleapis/release-please/issues/1702)) ([f328511](https://github.com/googleapis/release-please/commit/f3285115a9c0e4a199f86038319bafd6d604d96a))
13
+
14
+ ## [14.13.0](https://github.com/googleapis/release-please/compare/v14.12.0...v14.13.0) (2022-10-13)
15
+
16
+
17
+ ### Features
18
+
19
+ * Handle extremely large pull request body fields ([#1689](https://github.com/googleapis/release-please/issues/1689)) ([ecc424d](https://github.com/googleapis/release-please/commit/ecc424db9a86e742eb6b4f6f9271a8eae13e4efc))
20
+
7
21
  ## [14.12.0](https://github.com/googleapis/release-please/compare/v14.11.2...v14.12.0) (2022-10-12)
8
22
 
9
23
 
package/README.md CHANGED
@@ -12,6 +12,9 @@ It does so by parsing your
12
12
  git history, looking for [Conventional Commit messages](https://www.conventionalcommits.org/),
13
13
  and creating release PRs.
14
14
 
15
+ It does not handle publication to package managers or handle complex branch
16
+ management.
17
+
15
18
  ## What's a Release PR?
16
19
 
17
20
  Rather than continuously releasing what's landed to your default branch,
@@ -11,6 +11,7 @@ import { Update } from './update';
11
11
  import { Release } from './release';
12
12
  import { GitHubFileContents } from '@google-automations/git-file-utils';
13
13
  import { Logger } from 'code-suggester/build/src/types';
14
+ import { PullRequestOverflowHandler } from './util/pull-request-overflow-handler';
14
15
  declare type RequestBuilderType = typeof request;
15
16
  declare type DefaultFunctionType = RequestBuilderType['defaults'];
16
17
  declare type RequestFunctionType = ReturnType<DefaultFunctionType>;
@@ -73,6 +74,10 @@ interface FileDiff {
73
74
  readonly originalContent: string | null;
74
75
  }
75
76
  export declare type ChangeSet = Map<string, FileDiff>;
77
+ interface CreatePullRequestOptions {
78
+ fork?: boolean;
79
+ draft?: boolean;
80
+ }
76
81
  export declare class GitHub {
77
82
  readonly repository: Repository;
78
83
  private octokit;
@@ -226,6 +231,7 @@ export declare class GitHub {
226
231
  * @param {string} path The path to the file in the repository
227
232
  * @param {string} branch The branch to fetch from
228
233
  * @returns {GitHubFileContents}
234
+ * @throws {FileNotFoundError} if the file cannot be found
229
235
  * @throws {GitHubAPIError} on other API errors
230
236
  */
231
237
  getFileContentsOnBranch(path: string, branch: string): Promise<GitHubFileContents>;
@@ -281,6 +287,8 @@ export declare class GitHub {
281
287
  /**
282
288
  * Open a pull request
283
289
  *
290
+ * @deprecated This logic is handled by the Manifest class now as it
291
+ * can be more complicated if the release notes are too big
284
292
  * @param {ReleasePullRequest} releasePullRequest Pull request data to update
285
293
  * @param {string} targetBranch The base branch of the pull request
286
294
  * @param {GitHubPR} options The pull request options
@@ -291,10 +299,17 @@ export declare class GitHub {
291
299
  fork?: boolean;
292
300
  skipLabeling?: boolean;
293
301
  }): Promise<PullRequest>;
294
- createPullRequest: (pullRequest: PullRequest, targetBranch: string, message: string, updates: Update[], options?: {
295
- fork?: boolean | undefined;
296
- draft?: boolean | undefined;
297
- } | undefined) => Promise<PullRequest>;
302
+ /**
303
+ * Open a pull request
304
+ *
305
+ * @param {PullRequest} pullRequest Pull request data to update
306
+ * @param {string} targetBranch The base branch of the pull request
307
+ * @param {string} message The commit message for the commit
308
+ * @param {Update[]} updates The files to update
309
+ * @param {CreatePullRequestOptions} options The pull request options
310
+ * @throws {GitHubAPIError} on an API error
311
+ */
312
+ createPullRequest: (pullRequest: PullRequest, targetBranch: string, message: string, updates: Update[], options?: CreatePullRequestOptions | undefined) => Promise<PullRequest>;
298
313
  /**
299
314
  * Fetch a pull request given the pull number
300
315
  * @param {number} number The pull request number
@@ -305,11 +320,17 @@ export declare class GitHub {
305
320
  * Update a pull request's title and body.
306
321
  * @param {number} number The pull request number
307
322
  * @param {ReleasePullRequest} releasePullRequest Pull request data to update
308
- * @param {}
323
+ * @param {string} targetBranch The target branch of the pull request
324
+ * @param {string} options.signoffUser Optional. Commit signoff message
325
+ * @param {boolean} options.fork Optional. Whether to open the pull request from
326
+ * a fork or not. Defaults to `false`
327
+ * @param {PullRequestOverflowHandler} options.pullRequestOverflowHandler Optional.
328
+ * Handles extra large pull request body messages.
309
329
  */
310
330
  updatePullRequest: (number: number, releasePullRequest: ReleasePullRequest, targetBranch: string, options?: {
311
331
  signoffUser?: string | undefined;
312
332
  fork?: boolean | undefined;
333
+ pullRequestOverflowHandler?: PullRequestOverflowHandler | undefined;
313
334
  } | undefined) => Promise<PullRequest>;
314
335
  /**
315
336
  * Given a set of proposed updates, build a changeset to suggest.
@@ -387,6 +408,43 @@ export declare class GitHub {
387
408
  * @param {string} previousTag Optional. Name of previous tag to analyze commits since
388
409
  */
389
410
  generateReleaseNotes(tagName: string, targetCommitish: string, previousTag?: string): Promise<string>;
411
+ /**
412
+ * Create a single file on a new branch based on an existing
413
+ * branch. This will force-push to that branch.
414
+ * @param {string} filename Filename with path in the repository
415
+ * @param {string} contents Contents of the file
416
+ * @param {string} newBranchName Name of the new branch
417
+ * @param {string} baseBranchName Name of the base branch (where
418
+ * new branch is forked from)
419
+ * @returns {string} HTML URL of the new file
420
+ */
421
+ createFileOnNewBranch(filename: string, contents: string, newBranchName: string, baseBranchName: string): Promise<string>;
422
+ /**
423
+ * Helper to fetch the SHA of a branch
424
+ * @param {string} branchName The name of the branch
425
+ * @return {string | undefined} Returns the SHA of the branch
426
+ * or undefined if it can't be found.
427
+ */
428
+ private getBranchSha;
429
+ /**
430
+ * Helper to fork a branch from an existing branch. Uses `force` so
431
+ * it will overwrite the contents of `targetBranchName` to match
432
+ * the current contents of `baseBranchName`.
433
+ *
434
+ * @param {string} targetBranchName The name of the new forked branch
435
+ * @param {string} baseBranchName The base branch from which to fork.
436
+ * @returns {string} The branch SHA
437
+ * @throws {ConfigurationError} if the base branch cannot be found.
438
+ */
439
+ private forkBranch;
440
+ /**
441
+ * Helper to create a new branch from a given SHA.
442
+ * @param {string} branchName The new branch name
443
+ * @param {string} branchSha The SHA of the branch
444
+ * @returns {string} The SHA of the new branch
445
+ */
446
+ private createNewBranch;
447
+ private updateBranchSha;
390
448
  }
391
449
  export declare const sleepInMs: (ms: number) => Promise<unknown>;
392
450
  export {};
@@ -130,6 +130,16 @@ class GitHub {
130
130
  this.logger.debug(`finding files by glob: ${glob}, ref: ${ref}, prefix: ${prefix}`);
131
131
  return await this.fileCache.findFilesByGlob(glob, ref, prefix);
132
132
  });
133
+ /**
134
+ * Open a pull request
135
+ *
136
+ * @param {PullRequest} pullRequest Pull request data to update
137
+ * @param {string} targetBranch The base branch of the pull request
138
+ * @param {string} message The commit message for the commit
139
+ * @param {Update[]} updates The files to update
140
+ * @param {CreatePullRequestOptions} options The pull request options
141
+ * @throws {GitHubAPIError} on an API error
142
+ */
133
143
  this.createPullRequest = wrapAsync(async (pullRequest, targetBranch, message, updates, options) => {
134
144
  // Update the files for the release if not already supplied
135
145
  const changes = await this.buildChangeSet(updates, targetBranch);
@@ -176,7 +186,12 @@ class GitHub {
176
186
  * Update a pull request's title and body.
177
187
  * @param {number} number The pull request number
178
188
  * @param {ReleasePullRequest} releasePullRequest Pull request data to update
179
- * @param {}
189
+ * @param {string} targetBranch The target branch of the pull request
190
+ * @param {string} options.signoffUser Optional. Commit signoff message
191
+ * @param {boolean} options.fork Optional. Whether to open the pull request from
192
+ * a fork or not. Defaults to `false`
193
+ * @param {PullRequestOverflowHandler} options.pullRequestOverflowHandler Optional.
194
+ * Handles extra large pull request body messages.
180
195
  */
181
196
  this.updatePullRequest = wrapAsync(async (number, releasePullRequest, targetBranch, options) => {
182
197
  // Update the files for the release if not already supplied
@@ -186,7 +201,9 @@ class GitHub {
186
201
  message = (0, signoff_commit_message_1.signoffCommitMessage)(message, options.signoffUser);
187
202
  }
188
203
  const title = releasePullRequest.title.toString();
189
- const body = releasePullRequest.body
204
+ const body = ((options === null || options === void 0 ? void 0 : options.pullRequestOverflowHandler)
205
+ ? await options.pullRequestOverflowHandler.handleOverflow(releasePullRequest)
206
+ : releasePullRequest.body)
190
207
  .toString()
191
208
  .slice(0, MAX_ISSUE_BODY_SIZE);
192
209
  const prNumber = await (0, code_suggester_1.createPullRequest)(this.octokit, changes, {
@@ -914,6 +931,7 @@ class GitHub {
914
931
  * @param {string} path The path to the file in the repository
915
932
  * @param {string} branch The branch to fetch from
916
933
  * @returns {GitHubFileContents}
934
+ * @throws {FileNotFoundError} if the file cannot be found
917
935
  * @throws {GitHubAPIError} on other API errors
918
936
  */
919
937
  async getFileContentsOnBranch(path, branch) {
@@ -963,6 +981,8 @@ class GitHub {
963
981
  /**
964
982
  * Open a pull request
965
983
  *
984
+ * @deprecated This logic is handled by the Manifest class now as it
985
+ * can be more complicated if the release notes are too big
966
986
  * @param {ReleasePullRequest} releasePullRequest Pull request data to update
967
987
  * @param {string} targetBranch The base branch of the pull request
968
988
  * @param {GitHubPR} options The pull request options
@@ -1060,6 +1080,119 @@ class GitHub {
1060
1080
  });
1061
1081
  return resp.data.body;
1062
1082
  }
1083
+ /**
1084
+ * Create a single file on a new branch based on an existing
1085
+ * branch. This will force-push to that branch.
1086
+ * @param {string} filename Filename with path in the repository
1087
+ * @param {string} contents Contents of the file
1088
+ * @param {string} newBranchName Name of the new branch
1089
+ * @param {string} baseBranchName Name of the base branch (where
1090
+ * new branch is forked from)
1091
+ * @returns {string} HTML URL of the new file
1092
+ */
1093
+ async createFileOnNewBranch(filename, contents, newBranchName, baseBranchName) {
1094
+ // create or update new branch to match base branch
1095
+ await this.forkBranch(newBranchName, baseBranchName);
1096
+ // use the single file upload API
1097
+ const { data: { content }, } = await this.octokit.repos.createOrUpdateFileContents({
1098
+ owner: this.repository.owner,
1099
+ repo: this.repository.repo,
1100
+ path: filename,
1101
+ // contents need to be base64 encoded
1102
+ content: Buffer.from(contents, 'binary').toString('base64'),
1103
+ message: 'Saving release notes',
1104
+ branch: newBranchName,
1105
+ });
1106
+ if (!(content === null || content === void 0 ? void 0 : content.html_url)) {
1107
+ throw new Error(`Failed to write to file: ${filename} on branch: ${newBranchName}`);
1108
+ }
1109
+ return content.html_url;
1110
+ }
1111
+ /**
1112
+ * Helper to fetch the SHA of a branch
1113
+ * @param {string} branchName The name of the branch
1114
+ * @return {string | undefined} Returns the SHA of the branch
1115
+ * or undefined if it can't be found.
1116
+ */
1117
+ async getBranchSha(branchName) {
1118
+ this.logger.debug(`Looking up SHA for branch: ${branchName}`);
1119
+ try {
1120
+ const { data: { object: { sha }, }, } = await this.octokit.git.getRef({
1121
+ owner: this.repository.owner,
1122
+ repo: this.repository.repo,
1123
+ ref: `heads/${branchName}`,
1124
+ });
1125
+ this.logger.debug(`SHA for branch: ${sha}`);
1126
+ return sha;
1127
+ }
1128
+ catch (e) {
1129
+ if (e instanceof request_error_1.RequestError && e.status === 404) {
1130
+ this.logger.debug(`Branch: ${branchName} does not exist`);
1131
+ return undefined;
1132
+ }
1133
+ throw e;
1134
+ }
1135
+ }
1136
+ /**
1137
+ * Helper to fork a branch from an existing branch. Uses `force` so
1138
+ * it will overwrite the contents of `targetBranchName` to match
1139
+ * the current contents of `baseBranchName`.
1140
+ *
1141
+ * @param {string} targetBranchName The name of the new forked branch
1142
+ * @param {string} baseBranchName The base branch from which to fork.
1143
+ * @returns {string} The branch SHA
1144
+ * @throws {ConfigurationError} if the base branch cannot be found.
1145
+ */
1146
+ async forkBranch(targetBranchName, baseBranchName) {
1147
+ const baseBranchSha = await this.getBranchSha(baseBranchName);
1148
+ if (!baseBranchSha) {
1149
+ // this is highly unlikely to be thrown as we will have
1150
+ // already attempted to read from the branch
1151
+ throw new errors_1.ConfigurationError(`Unable to find base branch: ${baseBranchName}`, 'core', `${this.repository.owner}/${this.repository.repo}`);
1152
+ }
1153
+ // see if newBranchName exists
1154
+ if (await this.getBranchSha(targetBranchName)) {
1155
+ // branch already exists, update it to the match the base branch
1156
+ const branchSha = await this.updateBranchSha(targetBranchName, baseBranchSha);
1157
+ this.logger.debug(`Updated ${targetBranchName} to match ${baseBranchName} at ${branchSha}`);
1158
+ return branchSha;
1159
+ }
1160
+ else {
1161
+ // branch does not exist, create a new branch from the base branch
1162
+ const branchSha = await this.createNewBranch(targetBranchName, baseBranchSha);
1163
+ this.logger.debug(`Forked ${targetBranchName} from ${baseBranchName} at ${branchSha}`);
1164
+ return branchSha;
1165
+ }
1166
+ }
1167
+ /**
1168
+ * Helper to create a new branch from a given SHA.
1169
+ * @param {string} branchName The new branch name
1170
+ * @param {string} branchSha The SHA of the branch
1171
+ * @returns {string} The SHA of the new branch
1172
+ */
1173
+ async createNewBranch(branchName, branchSha) {
1174
+ this.logger.debug(`Creating new branch: ${branchName} at ${branchSha}`);
1175
+ const { data: { object: { sha }, }, } = await this.octokit.git.createRef({
1176
+ owner: this.repository.owner,
1177
+ repo: this.repository.repo,
1178
+ ref: `refs/heads/${branchName}`,
1179
+ sha: branchSha,
1180
+ });
1181
+ this.logger.debug(`New branch: ${branchName} at ${sha}`);
1182
+ return sha;
1183
+ }
1184
+ async updateBranchSha(branchName, branchSha) {
1185
+ this.logger.debug(`Updating branch ${branchName} to ${branchSha}`);
1186
+ const { data: { object: { sha }, }, } = await this.octokit.git.updateRef({
1187
+ owner: this.repository.owner,
1188
+ repo: this.repository.repo,
1189
+ ref: `heads/${branchName}`,
1190
+ sha: branchSha,
1191
+ force: true,
1192
+ });
1193
+ this.logger.debug(`Updated branch: ${branchName} to ${sha}`);
1194
+ return sha;
1195
+ }
1063
1196
  }
1064
1197
  exports.GitHub = GitHub;
1065
1198
  /**
@@ -211,6 +211,7 @@ export declare class Manifest {
211
211
  readonly releaseSearchDepth: number;
212
212
  readonly commitSearchDepth: number;
213
213
  readonly logger: Logger;
214
+ private pullRequestOverflowHandler;
214
215
  /**
215
216
  * Create a Manifest from explicit config in code. This assumes that the
216
217
  * repository has a single component at the root path.
@@ -21,10 +21,11 @@ const tag_name_1 = require("./util/tag-name");
21
21
  const branch_name_1 = require("./util/branch-name");
22
22
  const pull_request_title_1 = require("./util/pull-request-title");
23
23
  const factory_1 = require("./factory");
24
- const pull_request_body_1 = require("./util/pull-request-body");
25
24
  const merge_1 = require("./plugins/merge");
26
25
  const release_please_manifest_1 = require("./updaters/release-please-manifest");
27
26
  const errors_1 = require("./errors");
27
+ const pull_request_overflow_handler_1 = require("./util/pull-request-overflow-handler");
28
+ const signoff_commit_message_1 = require("./util/signoff-commit-message");
28
29
  exports.DEFAULT_RELEASE_PLEASE_CONFIG = 'release-please-config.json';
29
30
  exports.DEFAULT_RELEASE_PLEASE_MANIFEST = '.release-please-manifest.json';
30
31
  exports.ROOT_PROJECT_PATH = '.';
@@ -100,6 +101,7 @@ class Manifest {
100
101
  repositoryConfig: this.repositoryConfig,
101
102
  manifestPath: this.manifestPath,
102
103
  }));
104
+ this.pullRequestOverflowHandler = new pull_request_overflow_handler_1.FilePullRequestOverflowHandler(this.github, this.logger);
103
105
  }
104
106
  /**
105
107
  * Create a Manifest from config files in the repository.
@@ -451,11 +453,16 @@ class Manifest {
451
453
  const openPullRequests = [];
452
454
  const generator = this.github.pullRequestIterator(this.targetBranch, 'OPEN', Number.MAX_SAFE_INTEGER, false);
453
455
  for await (const openPullRequest of generator) {
454
- if ((hasAllLabels(this.labels, openPullRequest.labels) ||
455
- hasAllLabels(this.snapshotLabels, openPullRequest.labels)) &&
456
- branch_name_1.BranchName.parse(openPullRequest.headBranchName, this.logger) &&
457
- pull_request_body_1.PullRequestBody.parse(openPullRequest.body, this.logger)) {
458
- openPullRequests.push(openPullRequest);
456
+ if (hasAllLabels(this.labels, openPullRequest.labels) ||
457
+ hasAllLabels(this.snapshotLabels, openPullRequest.labels)) {
458
+ const body = await this.pullRequestOverflowHandler.parseOverflow(openPullRequest);
459
+ if (body) {
460
+ // maybe replace with overflow body
461
+ openPullRequests.push({
462
+ ...openPullRequest,
463
+ body: body.toString(),
464
+ });
465
+ }
459
466
  }
460
467
  }
461
468
  this.logger.info(`found ${openPullRequests.length} open release pull requests.`);
@@ -467,9 +474,15 @@ class Manifest {
467
474
  const closedGenerator = this.github.pullRequestIterator(this.targetBranch, 'CLOSED', 200, false);
468
475
  for await (const closedPullRequest of closedGenerator) {
469
476
  if (hasAllLabels([exports.SNOOZE_LABEL], closedPullRequest.labels) &&
470
- branch_name_1.BranchName.parse(closedPullRequest.headBranchName, this.logger) &&
471
- pull_request_body_1.PullRequestBody.parse(closedPullRequest.body, this.logger)) {
472
- snoozedPullRequests.push(closedPullRequest);
477
+ branch_name_1.BranchName.parse(closedPullRequest.headBranchName, this.logger)) {
478
+ const body = await this.pullRequestOverflowHandler.parseOverflow(closedPullRequest);
479
+ if (body) {
480
+ // maybe replace with overflow body
481
+ snoozedPullRequests.push({
482
+ ...closedPullRequest,
483
+ body: body.toString(),
484
+ });
485
+ }
473
486
  }
474
487
  }
475
488
  this.logger.info(`found ${snoozedPullRequests.length} snoozed release pull requests.`);
@@ -486,10 +499,21 @@ class Manifest {
486
499
  if (snoozed) {
487
500
  return await this.maybeUpdateSnoozedPullRequest(snoozed, pullRequest);
488
501
  }
489
- const newPullRequest = await this.github.createReleasePullRequest(pullRequest, this.targetBranch, {
502
+ const body = await this.pullRequestOverflowHandler.handleOverflow(pullRequest);
503
+ const message = this.signoffUser
504
+ ? (0, signoff_commit_message_1.signoffCommitMessage)(pullRequest.title.toString(), this.signoffUser)
505
+ : pullRequest.title.toString();
506
+ const newPullRequest = await this.github.createPullRequest({
507
+ headBranchName: pullRequest.headRefName,
508
+ baseBranchName: this.targetBranch,
509
+ number: -1,
510
+ title: pullRequest.title.toString(),
511
+ body,
512
+ labels: this.skipLabeling ? [] : pullRequest.labels,
513
+ files: [],
514
+ }, this.targetBranch, message, pullRequest.updates, {
490
515
  fork: this.fork,
491
- signoffUser: this.signoffUser,
492
- skipLabeling: this.skipLabeling,
516
+ draft: pullRequest.draft,
493
517
  });
494
518
  return newPullRequest;
495
519
  }
@@ -503,6 +527,7 @@ class Manifest {
503
527
  const updatedPullRequest = await this.github.updatePullRequest(existing.number, pullRequest, this.targetBranch, {
504
528
  fork: this.fork,
505
529
  signoffUser: this.signoffUser,
530
+ pullRequestOverflowHandler: this.pullRequestOverflowHandler,
506
531
  });
507
532
  return updatedPullRequest;
508
533
  }
@@ -516,6 +541,7 @@ class Manifest {
516
541
  const updatedPullRequest = await this.github.updatePullRequest(snoozed.number, pullRequest, this.targetBranch, {
517
542
  fork: this.fork,
518
543
  signoffUser: this.signoffUser,
544
+ pullRequestOverflowHandler: this.pullRequestOverflowHandler,
519
545
  });
520
546
  // TODO: consider leaving the snooze label
521
547
  await this.github.removeIssueLabels([exports.SNOOZE_LABEL], snoozed.number);
@@ -529,12 +555,17 @@ class Manifest {
529
555
  continue;
530
556
  }
531
557
  this.logger.debug(`Found pull request #${pullRequest.number}: '${pullRequest.title}'`);
532
- const pullRequestBody = pull_request_body_1.PullRequestBody.parse(pullRequest.body, this.logger);
558
+ // if the pull request body overflows, handle it
559
+ const pullRequestBody = await this.pullRequestOverflowHandler.parseOverflow(pullRequest);
533
560
  if (!pullRequestBody) {
534
561
  this.logger.debug('could not parse pull request body as a release PR');
535
562
  continue;
536
563
  }
537
- yield pullRequest;
564
+ // replace with the complete fetched body
565
+ yield {
566
+ ...pullRequest,
567
+ body: pullRequestBody.toString(),
568
+ };
538
569
  }
539
570
  }
540
571
  /**
@@ -36,8 +36,10 @@ class PullRequestBody {
36
36
  return undefined;
37
37
  }
38
38
  let data = extractMultipleReleases(parts.content, logger);
39
+ let useComponents = true;
39
40
  if (data.length === 0) {
40
41
  data = extractSingleRelease(parts.content, logger);
42
+ useComponents = false;
41
43
  if (data.length === 0) {
42
44
  logger.warn('Failed to parse releases.');
43
45
  }
@@ -45,6 +47,7 @@ class PullRequestBody {
45
47
  return new PullRequestBody(data, {
46
48
  header: parts.header,
47
49
  footer: parts.footer,
50
+ useComponents,
48
51
  });
49
52
  }
50
53
  notes() {
@@ -0,0 +1,54 @@
1
+ import { PullRequestBody } from './pull-request-body';
2
+ import { GitHub } from '../github';
3
+ import { PullRequest } from '../pull-request';
4
+ import { Logger } from './logger';
5
+ import { ReleasePullRequest } from '../release-pull-request';
6
+ /**
7
+ * Interface for managing the pull request body contents when the content
8
+ * is too large to fit into a pull request.
9
+ */
10
+ export interface PullRequestOverflowHandler {
11
+ /**
12
+ * If a pull request's body is too big, store it somewhere and return
13
+ * a new pull request body with information about the new location.
14
+ * @param {ReleasePullRequest} pullRequest The candidate release pull request
15
+ * @returns {string} The new pull request body which may contain a link to
16
+ * the full content.
17
+ */
18
+ handleOverflow(pullRequest: ReleasePullRequest, maxSize?: number): Promise<string>;
19
+ /**
20
+ * Given a pull request, parse the pull request body from the pull request
21
+ * or storage if the body was too big to store in the pull request body.
22
+ * @param {PullRequest} pullRequest The pull request from GitHub
23
+ * @return {PullRequestBody} The parsed pull request body
24
+ */
25
+ parseOverflow(pullRequest: PullRequest): Promise<PullRequestBody | undefined>;
26
+ }
27
+ /**
28
+ * This implementation of PullRequestOverflowHandler stores the full release
29
+ * notes on a new git branch. The branch name is derived from the head branch
30
+ * name of the release pull request.
31
+ */
32
+ export declare class FilePullRequestOverflowHandler implements PullRequestOverflowHandler {
33
+ private github;
34
+ private logger;
35
+ constructor(github: GitHub, logger?: Logger);
36
+ /**
37
+ * Optionally store the full release notes into `release-notes.md` file
38
+ * on a new branch if they do not fit into the body of a pull request.
39
+ *
40
+ * The new release notes will have a link to the GitHub UI for that file
41
+ * which should render the release notes nicely.
42
+ * @param {ReleasePullRequest} pullRequest The candidate release pull request
43
+ * @returns {string} The new pull request body which contains a link to
44
+ * the full content.
45
+ */
46
+ handleOverflow(pullRequest: ReleasePullRequest, maxSize?: number): Promise<string>;
47
+ /**
48
+ * Given a pull request, retrieve the full release notes from the stored
49
+ * file if the body was too big to store in the pull request body.
50
+ * @param {PullRequest} pullRequest The pull request from GitHub
51
+ * @return {PullRequestBody} The parsed pull request body
52
+ */
53
+ parseOverflow(pullRequest: PullRequest): Promise<PullRequestBody | undefined>;
54
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ // Copyright 2022 Google LLC
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.FilePullRequestOverflowHandler = void 0;
17
+ const pull_request_body_1 = require("./pull-request-body");
18
+ const logger_1 = require("./logger");
19
+ const url_1 = require("url");
20
+ const MAX_ISSUE_BODY_SIZE = 65536;
21
+ const OVERFLOW_MESSAGE = 'This release is too large to preview in the pull request body. View the full release notes here:';
22
+ const OVERFLOW_MESSAGE_REGEX = new RegExp(`${OVERFLOW_MESSAGE} (?<url>.*)`);
23
+ const RELEASE_NOTES_FILENAME = 'release-notes.md';
24
+ const FILE_PATH_REGEX = new RegExp(`blob/(?<branchName>.*)/${RELEASE_NOTES_FILENAME}`);
25
+ /**
26
+ * This implementation of PullRequestOverflowHandler stores the full release
27
+ * notes on a new git branch. The branch name is derived from the head branch
28
+ * name of the release pull request.
29
+ */
30
+ class FilePullRequestOverflowHandler {
31
+ constructor(github, logger = logger_1.logger) {
32
+ this.github = github;
33
+ this.logger = logger;
34
+ }
35
+ /**
36
+ * Optionally store the full release notes into `release-notes.md` file
37
+ * on a new branch if they do not fit into the body of a pull request.
38
+ *
39
+ * The new release notes will have a link to the GitHub UI for that file
40
+ * which should render the release notes nicely.
41
+ * @param {ReleasePullRequest} pullRequest The candidate release pull request
42
+ * @returns {string} The new pull request body which contains a link to
43
+ * the full content.
44
+ */
45
+ async handleOverflow(pullRequest, maxSize = MAX_ISSUE_BODY_SIZE) {
46
+ const notes = pullRequest.body.toString();
47
+ if (notes.length > maxSize) {
48
+ const notesBranchName = `${pullRequest.headRefName}--release-notes`;
49
+ const url = await this.github.createFileOnNewBranch(RELEASE_NOTES_FILENAME, notes, notesBranchName, this.github.repository.defaultBranch);
50
+ return `${OVERFLOW_MESSAGE} ${url}`;
51
+ }
52
+ return notes;
53
+ }
54
+ /**
55
+ * Given a pull request, retrieve the full release notes from the stored
56
+ * file if the body was too big to store in the pull request body.
57
+ * @param {PullRequest} pullRequest The pull request from GitHub
58
+ * @return {PullRequestBody} The parsed pull request body
59
+ */
60
+ async parseOverflow(pullRequest) {
61
+ var _a, _b;
62
+ const match = pullRequest.body.match(OVERFLOW_MESSAGE_REGEX);
63
+ if ((_a = match === null || match === void 0 ? void 0 : match.groups) === null || _a === void 0 ? void 0 : _a.url) {
64
+ this.logger.info(`Pull request body overflows, parsing full body from: ${match.groups.url}`);
65
+ const url = new url_1.URL(match.groups.url);
66
+ const pathMatch = url.pathname.match(FILE_PATH_REGEX);
67
+ if ((_b = pathMatch === null || pathMatch === void 0 ? void 0 : pathMatch.groups) === null || _b === void 0 ? void 0 : _b.branchName) {
68
+ const fileContents = await this.github.getFileContentsOnBranch(RELEASE_NOTES_FILENAME, pathMatch.groups.branchName);
69
+ return pull_request_body_1.PullRequestBody.parse(fileContents.parsedContent);
70
+ }
71
+ this.logger.warn(`Could not parse branch from ${match.groups.url}`);
72
+ return pull_request_body_1.PullRequestBody.parse(pullRequest.body, this.logger);
73
+ }
74
+ return pull_request_body_1.PullRequestBody.parse(pullRequest.body, this.logger);
75
+ }
76
+ }
77
+ exports.FilePullRequestOverflowHandler = FilePullRequestOverflowHandler;
78
+ //# sourceMappingURL=pull-request-overflow-handler.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-please",
3
- "version": "14.12.0",
3
+ "version": "14.13.1",
4
4
  "description": "generate release PRs based on the conventionalcommits.org spec",
5
5
  "main": "./build/src/index.js",
6
6
  "bin": "./build/src/bin/release-please.js",
@@ -38,7 +38,7 @@
38
38
  }
39
39
  },
40
40
  "devDependencies": {
41
- "@octokit/types": "^7.0.0",
41
+ "@octokit/types": "^8.0.0",
42
42
  "@types/chai": "^4.1.7",
43
43
  "@types/diff": "^5.0.2",
44
44
  "@types/iarna__toml": "^2.0.1",