release-please 14.11.2 → 14.13.0

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.0](https://github.com/googleapis/release-please/compare/v14.12.0...v14.13.0) (2022-10-13)
8
+
9
+
10
+ ### Features
11
+
12
+ * 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))
13
+
14
+ ## [14.12.0](https://github.com/googleapis/release-please/compare/v14.11.2...v14.12.0) (2022-10-12)
15
+
16
+
17
+ ### Features
18
+
19
+ * Added expo strategy and updater ([#1646](https://github.com/googleapis/release-please/issues/1646)) ([9cb84cb](https://github.com/googleapis/release-please/commit/9cb84cb18211c61ed94d856b936fff30036b0988))
20
+
7
21
  ## [14.11.2](https://github.com/googleapis/release-please/compare/v14.11.1...v14.11.2) (2022-10-11)
8
22
 
9
23
 
package/README.md CHANGED
@@ -141,6 +141,7 @@ Release Please automates releases for the following flavors of repositories:
141
141
  | `krm-blueprint` | [A kpt package, with 1 or more KRM files and a CHANGELOG.md](https://github.com/GoogleCloudPlatform/blueprints/tree/main/catalog/project) |
142
142
  | `maven` | [Strategy for Maven projects, generates SNAPSHOT version after each release and updates `pom.xml` automatically](docs/java.md) |
143
143
  | `node` | [A Node.js repository, with a package.json and CHANGELOG.md](https://github.com/yargs/yargs) |
144
+ | `expo` | [An Expo based React Native repository, with a package.json, app.json and CHANGELOG.md](https://github.com/yargs/yargs) |
144
145
  | `ocaml` | [An OCaml repository, containing 1 or more opam or esy files and a CHANGELOG.md](https://github.com/grain-lang/binaryen.ml) |
145
146
  | `php` | A repository with a composer.json and a CHANGELOG.md |
146
147
  | `python` | [A Python repository, with a setup.py, setup.cfg, CHANGELOG.md](https://github.com/googleapis/python-storage) and optionally a pyproject.toml and a <project>/\_\_init\_\_.py |
@@ -45,6 +45,7 @@ const helm_1 = require("./strategies/helm");
45
45
  const elixir_1 = require("./strategies/elixir");
46
46
  const dart_1 = require("./strategies/dart");
47
47
  const node_1 = require("./strategies/node");
48
+ const expo_1 = require("./strategies/expo");
48
49
  const always_bump_patch_1 = require("./versioning-strategies/always-bump-patch");
49
50
  const service_pack_1 = require("./versioning-strategies/service-pack");
50
51
  const dependency_manifest_1 = require("./versioning-strategies/dependency-manifest");
@@ -81,6 +82,7 @@ const releasers = {
81
82
  }),
82
83
  'krm-blueprint': options => new krm_blueprint_1.KRMBlueprint(options),
83
84
  node: options => new node_1.Node(options),
85
+ expo: options => new expo_1.Expo(options),
84
86
  ocaml: options => new ocaml_1.OCaml(options),
85
87
  php: options => new php_1.PHP(options),
86
88
  'php-yoshi': options => new php_yoshi_1.PHPYoshi(options),
@@ -73,6 +73,10 @@ interface FileDiff {
73
73
  readonly originalContent: string | null;
74
74
  }
75
75
  export declare type ChangeSet = Map<string, FileDiff>;
76
+ interface CreatePullRequestOptions {
77
+ fork?: boolean;
78
+ draft?: boolean;
79
+ }
76
80
  export declare class GitHub {
77
81
  readonly repository: Repository;
78
82
  private octokit;
@@ -226,6 +230,7 @@ export declare class GitHub {
226
230
  * @param {string} path The path to the file in the repository
227
231
  * @param {string} branch The branch to fetch from
228
232
  * @returns {GitHubFileContents}
233
+ * @throws {FileNotFoundError} if the file cannot be found
229
234
  * @throws {GitHubAPIError} on other API errors
230
235
  */
231
236
  getFileContentsOnBranch(path: string, branch: string): Promise<GitHubFileContents>;
@@ -281,6 +286,8 @@ export declare class GitHub {
281
286
  /**
282
287
  * Open a pull request
283
288
  *
289
+ * @deprecated This logic is handled by the Manifest class now as it
290
+ * can be more complicated if the release notes are too big
284
291
  * @param {ReleasePullRequest} releasePullRequest Pull request data to update
285
292
  * @param {string} targetBranch The base branch of the pull request
286
293
  * @param {GitHubPR} options The pull request options
@@ -291,10 +298,17 @@ export declare class GitHub {
291
298
  fork?: boolean;
292
299
  skipLabeling?: boolean;
293
300
  }): 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>;
301
+ /**
302
+ * Open a pull request
303
+ *
304
+ * @param {PullRequest} pullRequest Pull request data to update
305
+ * @param {string} targetBranch The base branch of the pull request
306
+ * @param {string} message The commit message for the commit
307
+ * @param {Update[]} updates The files to update
308
+ * @param {CreatePullRequestOptions} options The pull request options
309
+ * @throws {GitHubAPIError} on an API error
310
+ */
311
+ createPullRequest: (pullRequest: PullRequest, targetBranch: string, message: string, updates: Update[], options?: CreatePullRequestOptions | undefined) => Promise<PullRequest>;
298
312
  /**
299
313
  * Fetch a pull request given the pull number
300
314
  * @param {number} number The pull request number
@@ -387,6 +401,43 @@ export declare class GitHub {
387
401
  * @param {string} previousTag Optional. Name of previous tag to analyze commits since
388
402
  */
389
403
  generateReleaseNotes(tagName: string, targetCommitish: string, previousTag?: string): Promise<string>;
404
+ /**
405
+ * Create a single file on a new branch based on an existing
406
+ * branch. This will force-push to that branch.
407
+ * @param {string} filename Filename with path in the repository
408
+ * @param {string} contents Contents of the file
409
+ * @param {string} newBranchName Name of the new branch
410
+ * @param {string} baseBranchName Name of the base branch (where
411
+ * new branch is forked from)
412
+ * @returns {string} HTML URL of the new file
413
+ */
414
+ createFileOnNewBranch(filename: string, contents: string, newBranchName: string, baseBranchName: string): Promise<string>;
415
+ /**
416
+ * Helper to fetch the SHA of a branch
417
+ * @param {string} branchName The name of the branch
418
+ * @return {string | undefined} Returns the SHA of the branch
419
+ * or undefined if it can't be found.
420
+ */
421
+ private getBranchSha;
422
+ /**
423
+ * Helper to fork a branch from an existing branch. Uses `force` so
424
+ * it will overwrite the contents of `targetBranchName` to match
425
+ * the current contents of `baseBranchName`.
426
+ *
427
+ * @param {string} targetBranchName The name of the new forked branch
428
+ * @param {string} baseBranchName The base branch from which to fork.
429
+ * @returns {string} The branch SHA
430
+ * @throws {ConfigurationError} if the base branch cannot be found.
431
+ */
432
+ private forkBranch;
433
+ /**
434
+ * Helper to create a new branch from a given SHA.
435
+ * @param {string} branchName The new branch name
436
+ * @param {string} branchSha The SHA of the branch
437
+ * @returns {string} The SHA of the new branch
438
+ */
439
+ private createNewBranch;
440
+ private updateBranchSha;
390
441
  }
391
442
  export declare const sleepInMs: (ms: number) => Promise<unknown>;
392
443
  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);
@@ -914,6 +924,7 @@ class GitHub {
914
924
  * @param {string} path The path to the file in the repository
915
925
  * @param {string} branch The branch to fetch from
916
926
  * @returns {GitHubFileContents}
927
+ * @throws {FileNotFoundError} if the file cannot be found
917
928
  * @throws {GitHubAPIError} on other API errors
918
929
  */
919
930
  async getFileContentsOnBranch(path, branch) {
@@ -963,6 +974,8 @@ class GitHub {
963
974
  /**
964
975
  * Open a pull request
965
976
  *
977
+ * @deprecated This logic is handled by the Manifest class now as it
978
+ * can be more complicated if the release notes are too big
966
979
  * @param {ReleasePullRequest} releasePullRequest Pull request data to update
967
980
  * @param {string} targetBranch The base branch of the pull request
968
981
  * @param {GitHubPR} options The pull request options
@@ -1060,6 +1073,119 @@ class GitHub {
1060
1073
  });
1061
1074
  return resp.data.body;
1062
1075
  }
1076
+ /**
1077
+ * Create a single file on a new branch based on an existing
1078
+ * branch. This will force-push to that branch.
1079
+ * @param {string} filename Filename with path in the repository
1080
+ * @param {string} contents Contents of the file
1081
+ * @param {string} newBranchName Name of the new branch
1082
+ * @param {string} baseBranchName Name of the base branch (where
1083
+ * new branch is forked from)
1084
+ * @returns {string} HTML URL of the new file
1085
+ */
1086
+ async createFileOnNewBranch(filename, contents, newBranchName, baseBranchName) {
1087
+ // create or update new branch to match base branch
1088
+ await this.forkBranch(newBranchName, baseBranchName);
1089
+ // use the single file upload API
1090
+ const { data: { content }, } = await this.octokit.repos.createOrUpdateFileContents({
1091
+ owner: this.repository.owner,
1092
+ repo: this.repository.repo,
1093
+ path: filename,
1094
+ // contents need to be base64 encoded
1095
+ content: Buffer.from(contents, 'binary').toString('base64'),
1096
+ message: 'Saving release notes',
1097
+ branch: newBranchName,
1098
+ });
1099
+ if (!(content === null || content === void 0 ? void 0 : content.html_url)) {
1100
+ throw new Error(`Failed to write to file: ${filename} on branch: ${newBranchName}`);
1101
+ }
1102
+ return content.html_url;
1103
+ }
1104
+ /**
1105
+ * Helper to fetch the SHA of a branch
1106
+ * @param {string} branchName The name of the branch
1107
+ * @return {string | undefined} Returns the SHA of the branch
1108
+ * or undefined if it can't be found.
1109
+ */
1110
+ async getBranchSha(branchName) {
1111
+ this.logger.debug(`Looking up SHA for branch: ${branchName}`);
1112
+ try {
1113
+ const { data: { object: { sha }, }, } = await this.octokit.git.getRef({
1114
+ owner: this.repository.owner,
1115
+ repo: this.repository.repo,
1116
+ ref: `heads/${branchName}`,
1117
+ });
1118
+ this.logger.debug(`SHA for branch: ${sha}`);
1119
+ return sha;
1120
+ }
1121
+ catch (e) {
1122
+ if (e instanceof request_error_1.RequestError && e.status === 404) {
1123
+ this.logger.debug(`Branch: ${branchName} does not exist`);
1124
+ return undefined;
1125
+ }
1126
+ throw e;
1127
+ }
1128
+ }
1129
+ /**
1130
+ * Helper to fork a branch from an existing branch. Uses `force` so
1131
+ * it will overwrite the contents of `targetBranchName` to match
1132
+ * the current contents of `baseBranchName`.
1133
+ *
1134
+ * @param {string} targetBranchName The name of the new forked branch
1135
+ * @param {string} baseBranchName The base branch from which to fork.
1136
+ * @returns {string} The branch SHA
1137
+ * @throws {ConfigurationError} if the base branch cannot be found.
1138
+ */
1139
+ async forkBranch(targetBranchName, baseBranchName) {
1140
+ const baseBranchSha = await this.getBranchSha(baseBranchName);
1141
+ if (!baseBranchSha) {
1142
+ // this is highly unlikely to be thrown as we will have
1143
+ // already attempted to read from the branch
1144
+ throw new errors_1.ConfigurationError(`Unable to find base branch: ${baseBranchName}`, 'core', `${this.repository.owner}/${this.repository.repo}`);
1145
+ }
1146
+ // see if newBranchName exists
1147
+ if (await this.getBranchSha(targetBranchName)) {
1148
+ // branch already exists, update it to the match the base branch
1149
+ const branchSha = await this.updateBranchSha(targetBranchName, baseBranchSha);
1150
+ this.logger.debug(`Updated ${targetBranchName} to match ${baseBranchName} at ${branchSha}`);
1151
+ return branchSha;
1152
+ }
1153
+ else {
1154
+ // branch does not exist, create a new branch from the base branch
1155
+ const branchSha = await this.createNewBranch(targetBranchName, baseBranchSha);
1156
+ this.logger.debug(`Forked ${targetBranchName} from ${baseBranchName} at ${branchSha}`);
1157
+ return branchSha;
1158
+ }
1159
+ }
1160
+ /**
1161
+ * Helper to create a new branch from a given SHA.
1162
+ * @param {string} branchName The new branch name
1163
+ * @param {string} branchSha The SHA of the branch
1164
+ * @returns {string} The SHA of the new branch
1165
+ */
1166
+ async createNewBranch(branchName, branchSha) {
1167
+ this.logger.debug(`Creating new branch: ${branchName} at ${branchSha}`);
1168
+ const { data: { object: { sha }, }, } = await this.octokit.git.createRef({
1169
+ owner: this.repository.owner,
1170
+ repo: this.repository.repo,
1171
+ ref: `refs/heads/${branchName}`,
1172
+ sha: branchSha,
1173
+ });
1174
+ this.logger.debug(`New branch: ${branchName} at ${sha}`);
1175
+ return sha;
1176
+ }
1177
+ async updateBranchSha(branchName, branchSha) {
1178
+ this.logger.debug(`Updating branch ${branchName} to ${branchSha}`);
1179
+ const { data: { object: { sha }, }, } = await this.octokit.git.updateRef({
1180
+ owner: this.repository.owner,
1181
+ repo: this.repository.repo,
1182
+ ref: `heads/${branchName}`,
1183
+ sha: branchSha,
1184
+ force: true,
1185
+ });
1186
+ this.logger.debug(`Updated branch: ${branchName} to ${sha}`);
1187
+ return sha;
1188
+ }
1063
1189
  }
1064
1190
  exports.GitHub = GitHub;
1065
1191
  /**
@@ -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
  }
@@ -529,12 +553,17 @@ class Manifest {
529
553
  continue;
530
554
  }
531
555
  this.logger.debug(`Found pull request #${pullRequest.number}: '${pullRequest.title}'`);
532
- const pullRequestBody = pull_request_body_1.PullRequestBody.parse(pullRequest.body, this.logger);
556
+ // if the pull request body overflows, handle it
557
+ const pullRequestBody = await this.pullRequestOverflowHandler.parseOverflow(pullRequest);
533
558
  if (!pullRequestBody) {
534
559
  this.logger.debug('could not parse pull request body as a release PR');
535
560
  continue;
536
561
  }
537
- yield pullRequest;
562
+ // replace with the complete fetched body
563
+ yield {
564
+ ...pullRequest,
565
+ body: pullRequestBody.toString(),
566
+ };
538
567
  }
539
568
  }
540
569
  /**
@@ -0,0 +1,15 @@
1
+ import { BuildUpdatesOptions } from './base';
2
+ import { Node } from './node';
3
+ import { Update } from '../update';
4
+ import { Version } from '../version';
5
+ /**
6
+ * Strategy for building Expo based React Native projects. This strategy extends
7
+ * the Node strategy to additionally update the `app.json` file of a project.
8
+ */
9
+ export declare class Expo extends Node {
10
+ protected buildUpdates(options: BuildUpdatesOptions): Promise<Update[]>;
11
+ /**
12
+ * Determine the Expo SDK version by parsing the package.json dependencies.
13
+ */
14
+ getExpoSDKVersion(): Promise<Version>;
15
+ }
@@ -0,0 +1,51 @@
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.Expo = void 0;
17
+ const node_1 = require("./node");
18
+ const app_json_1 = require("../updaters/expo/app-json");
19
+ const version_1 = require("../version");
20
+ /**
21
+ * Strategy for building Expo based React Native projects. This strategy extends
22
+ * the Node strategy to additionally update the `app.json` file of a project.
23
+ */
24
+ class Expo extends node_1.Node {
25
+ async buildUpdates(options) {
26
+ const version = options.newVersion;
27
+ const updates = await super.buildUpdates(options);
28
+ const expoSDKVersion = await this.getExpoSDKVersion();
29
+ updates.push({
30
+ path: this.addPath('app.json'),
31
+ createIfMissing: false,
32
+ updater: new app_json_1.AppJson({ version, expoSDKVersion }),
33
+ });
34
+ return updates;
35
+ }
36
+ /**
37
+ * Determine the Expo SDK version by parsing the package.json dependencies.
38
+ */
39
+ async getExpoSDKVersion() {
40
+ var _a, _b, _c, _d;
41
+ const pkgJsonContents = await this.getPkgJsonContents();
42
+ const pkg = JSON.parse(pkgJsonContents.parsedContent);
43
+ return version_1.Version.parse(((_a = pkg.dependencies) === null || _a === void 0 ? void 0 : _a.expo) ||
44
+ ((_b = pkg.devDependencies) === null || _b === void 0 ? void 0 : _b.expo) ||
45
+ ((_c = pkg.peerDependencies) === null || _c === void 0 ? void 0 : _c.expo) ||
46
+ ((_d = pkg.optionalDependencies) === null || _d === void 0 ? void 0 : _d.expo) ||
47
+ '0.0.0');
48
+ }
49
+ }
50
+ exports.Expo = Expo;
51
+ //# sourceMappingURL=expo.js.map
@@ -1,9 +1,10 @@
1
1
  import { BaseStrategy, BuildUpdatesOptions } from './base';
2
2
  import { Update } from '../update';
3
+ import { GitHubFileContents } from '@google-automations/git-file-utils';
3
4
  export declare class Node extends BaseStrategy {
4
5
  private pkgJsonContents?;
5
6
  protected buildUpdates(options: BuildUpdatesOptions): Promise<Update[]>;
6
7
  getDefaultPackageName(): Promise<string | undefined>;
7
8
  protected normalizeComponent(component: string | undefined): string;
8
- private getPkgJsonContents;
9
+ protected getPkgJsonContents(): Promise<GitHubFileContents>;
9
10
  }
@@ -0,0 +1,31 @@
1
+ import { Logger } from '../../util/logger';
2
+ import { DefaultUpdater, UpdateOptions } from '../default';
3
+ import { Version } from '../../version';
4
+ export interface AppJson {
5
+ expo: {
6
+ version: string;
7
+ ios?: {
8
+ buildNumber?: string;
9
+ };
10
+ android?: {
11
+ versionCode?: string;
12
+ };
13
+ };
14
+ }
15
+ export interface AppJsonOptions extends UpdateOptions {
16
+ expoSDKVersion: Version;
17
+ }
18
+ /**
19
+ * This updates a React Natve Expo project app.json file's main, ios and android
20
+ * versions. All values except the `android.versionCode` are standard semver
21
+ * version numbers. For the `android.versionCode`, the semver number is used as
22
+ * the basis for the `versionCode`.
23
+ */
24
+ export declare class AppJson extends DefaultUpdater {
25
+ expoSDKVersion: Version;
26
+ constructor(options: AppJsonOptions);
27
+ /**
28
+ * Given initial file contents, return updated contents.
29
+ */
30
+ updateContent(content: string, logger?: Logger): string;
31
+ }
@@ -0,0 +1,67 @@
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.AppJson = void 0;
17
+ const json_stringify_1 = require("../../util/json-stringify");
18
+ const logger_1 = require("../../util/logger");
19
+ const default_1 = require("../default");
20
+ /**
21
+ * This updates a React Natve Expo project app.json file's main, ios and android
22
+ * versions. All values except the `android.versionCode` are standard semver
23
+ * version numbers. For the `android.versionCode`, the semver number is used as
24
+ * the basis for the `versionCode`.
25
+ */
26
+ class AppJson extends default_1.DefaultUpdater {
27
+ constructor(options) {
28
+ super(options);
29
+ this.expoSDKVersion = options.expoSDKVersion;
30
+ }
31
+ /**
32
+ * Given initial file contents, return updated contents.
33
+ */
34
+ updateContent(content, logger = logger_1.logger) {
35
+ var _a, _b;
36
+ const parsed = JSON.parse(content);
37
+ logger.info(`updating Expo version from ${parsed.expo.version} to ${this.version}`);
38
+ parsed.expo.version = this.version.toString();
39
+ if ((_a = parsed.expo.ios) === null || _a === void 0 ? void 0 : _a.buildNumber) {
40
+ logger.info(`updating iOS version from ${parsed.expo.ios.buildNumber} to ${this.version}`);
41
+ parsed.expo.ios.buildNumber = this.version.toString();
42
+ }
43
+ if ((_b = parsed.expo.android) === null || _b === void 0 ? void 0 : _b.versionCode) {
44
+ // Android versionCode
45
+ // https://developer.android.com/studio/publish/versioning#appversioning
46
+ let expoMajorVersion = 0;
47
+ try {
48
+ expoMajorVersion = this.expoSDKVersion.major;
49
+ }
50
+ catch (e) {
51
+ // Rethrow with a nice error message.
52
+ throw new Error('Unable to determine the Expo SDK version for this project. Make sure that the expo package is installed for your project.');
53
+ }
54
+ // Implements the `versionCode` strategy described by Maxi Rosson
55
+ // @see https://medium.com/@maxirosson/versioning-android-apps-d6ec171cfd82
56
+ const versionCode = expoMajorVersion * 10000000 +
57
+ this.version.major * 10000 +
58
+ this.version.minor * 100 +
59
+ this.version.patch;
60
+ logger.info(`updating Android version from ${parsed.expo.android.versionCode} to ${versionCode}`);
61
+ parsed.expo.android.versionCode = versionCode.toString();
62
+ }
63
+ return (0, json_stringify_1.jsonStringify)(parsed, content);
64
+ }
65
+ }
66
+ exports.AppJson = AppJson;
67
+ //# sourceMappingURL=app-json.js.map
@@ -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.11.2",
3
+ "version": "14.13.0",
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",