release-please 12.5.0 → 13.0.0-candidate.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +4 -0
  3. package/build/src/bin/release-please.d.ts +55 -11
  4. package/build/src/bin/release-please.js +419 -152
  5. package/build/src/bootstrapper.d.ts +12 -0
  6. package/build/src/bootstrapper.js +60 -0
  7. package/build/src/changelog-notes/default.d.ts +17 -0
  8. package/build/src/changelog-notes/default.js +72 -0
  9. package/build/src/changelog-notes.d.ts +17 -0
  10. package/build/src/{updaters/java/readme.js → changelog-notes.js} +2 -7
  11. package/build/src/commit.d.ts +26 -0
  12. package/build/src/{util/to-conventional-changelog-format.js → commit.js} +97 -2
  13. package/build/src/errors/index.d.ts +0 -5
  14. package/build/src/errors/index.js +1 -10
  15. package/build/src/factory.d.ts +25 -37
  16. package/build/src/factory.js +160 -150
  17. package/build/src/github.d.ts +154 -884
  18. package/build/src/github.js +608 -1036
  19. package/build/src/manifest.d.ts +191 -47
  20. package/build/src/manifest.js +599 -487
  21. package/build/src/plugin.d.ts +20 -0
  22. package/build/src/{plugins/plugin.js → plugin.js} +10 -9
  23. package/build/src/plugins/cargo-workspace.d.ts +48 -18
  24. package/build/src/plugins/cargo-workspace.js +247 -328
  25. package/build/src/plugins/merge.d.ts +11 -0
  26. package/build/src/plugins/merge.js +83 -0
  27. package/build/src/plugins/node-workspace.d.ts +35 -17
  28. package/build/src/plugins/node-workspace.js +234 -271
  29. package/build/src/plugins/workspace.d.ts +102 -0
  30. package/build/src/plugins/workspace.js +170 -0
  31. package/build/src/pull-request.d.ts +10 -0
  32. package/build/src/{updaters/java/pom-xml.js → pull-request.js} +2 -7
  33. package/build/src/release-notes.d.ts +29 -0
  34. package/build/src/release-notes.js +71 -0
  35. package/build/src/release-pull-request.d.ts +13 -0
  36. package/build/src/release-pull-request.js +16 -0
  37. package/build/src/release.d.ts +6 -0
  38. package/build/src/release.js +16 -0
  39. package/build/src/repository.d.ts +5 -0
  40. package/build/src/repository.js +16 -0
  41. package/build/src/strategies/dart.d.ts +8 -0
  42. package/build/src/strategies/dart.js +63 -0
  43. package/build/src/strategies/elixir.d.ts +5 -0
  44. package/build/src/{releasers → strategies}/elixir.js +18 -14
  45. package/build/src/strategies/go-yoshi.d.ts +13 -0
  46. package/build/src/strategies/go-yoshi.js +106 -0
  47. package/build/src/strategies/go.d.ts +5 -0
  48. package/build/src/{releasers → strategies}/go.js +11 -12
  49. package/build/src/strategies/helm.d.ts +8 -0
  50. package/build/src/strategies/helm.js +63 -0
  51. package/build/src/strategies/java-yoshi.d.ts +24 -0
  52. package/build/src/strategies/java-yoshi.js +203 -0
  53. package/build/src/strategies/krm-blueprint.d.ts +7 -0
  54. package/build/src/{releasers → strategies}/krm-blueprint.js +26 -22
  55. package/build/src/strategies/node.d.ts +9 -0
  56. package/build/src/strategies/node.js +82 -0
  57. package/build/src/strategies/ocaml.d.ts +5 -0
  58. package/build/src/{releasers → strategies}/ocaml.js +34 -28
  59. package/build/src/strategies/php-yoshi.d.ts +10 -0
  60. package/build/src/strategies/php-yoshi.js +213 -0
  61. package/build/src/strategies/php.d.ts +6 -0
  62. package/build/src/{releasers → strategies}/php.js +24 -23
  63. package/build/src/strategies/python.d.ts +8 -0
  64. package/build/src/strategies/python.js +117 -0
  65. package/build/src/strategies/ruby-yoshi.d.ts +17 -0
  66. package/build/src/strategies/ruby-yoshi.js +116 -0
  67. package/build/src/strategies/ruby.d.ts +13 -0
  68. package/build/src/{releasers → strategies}/ruby.js +26 -27
  69. package/build/src/strategies/rust.d.ts +20 -0
  70. package/build/src/strategies/rust.js +120 -0
  71. package/build/src/strategies/simple.d.ts +5 -0
  72. package/build/src/{releasers → strategies}/simple.js +18 -14
  73. package/build/src/strategies/terraform-module.d.ts +7 -0
  74. package/build/src/{releasers → strategies}/terraform-module.js +29 -23
  75. package/build/src/strategy.d.ts +100 -0
  76. package/build/src/strategy.js +233 -0
  77. package/build/src/update.d.ts +23 -0
  78. package/build/src/{updaters/update.js → update.js} +1 -1
  79. package/build/src/updaters/changelog.d.ts +7 -10
  80. package/build/src/updaters/changelog.js +3 -9
  81. package/build/src/updaters/changelog.js.map +1 -1
  82. package/build/src/updaters/composite.d.ts +19 -0
  83. package/build/src/updaters/composite.js +42 -0
  84. package/build/src/updaters/dart/pubspec-yaml.d.ts +12 -0
  85. package/build/src/updaters/{pubspec-yaml.js → dart/pubspec-yaml.js} +13 -12
  86. package/build/src/updaters/default.d.ts +21 -0
  87. package/build/src/updaters/{version-txt.js → default.js} +16 -10
  88. package/build/src/updaters/dotnet/csproj.d.ts +12 -0
  89. package/build/src/updaters/{java/google-utils.js → dotnet/csproj.js} +16 -13
  90. package/build/src/updaters/elixir/elixir-mix-exs.d.ts +12 -0
  91. package/build/src/updaters/{elixir-mix-exs.js → elixir/elixir-mix-exs.js} +12 -10
  92. package/build/src/updaters/helm/chart-yaml.d.ts +10 -11
  93. package/build/src/updaters/helm/chart-yaml.js +12 -10
  94. package/build/src/updaters/java/java-update.d.ts +14 -0
  95. package/build/src/updaters/java/{java_update.js → java-update.js} +22 -22
  96. package/build/src/updaters/java/versions-manifest.d.ts +12 -2
  97. package/build/src/updaters/java/versions-manifest.js +20 -4
  98. package/build/src/updaters/krm/krm-blueprint-version.d.ts +10 -11
  99. package/build/src/updaters/krm/krm-blueprint-version.js +13 -12
  100. package/build/src/updaters/node/package-json.d.ts +12 -0
  101. package/build/src/updaters/{package-json.js → node/package-json.js} +14 -16
  102. package/build/src/updaters/node/package-lock-json.d.ts +8 -0
  103. package/build/src/updaters/node/package-lock-json.js +36 -0
  104. package/build/src/updaters/node/samples-package-json.d.ts +23 -0
  105. package/build/src/updaters/{samples-package-json.js → node/samples-package-json.js} +19 -8
  106. package/build/src/updaters/ocaml/dune-project.d.ts +10 -11
  107. package/build/src/updaters/ocaml/dune-project.js +11 -9
  108. package/build/src/updaters/ocaml/esy-json.d.ts +10 -11
  109. package/build/src/updaters/ocaml/esy-json.js +12 -10
  110. package/build/src/updaters/ocaml/opam.d.ts +10 -11
  111. package/build/src/updaters/ocaml/opam.js +11 -9
  112. package/build/src/updaters/php/php-client-version.d.ts +12 -0
  113. package/build/src/updaters/{php-client-version.js → php/php-client-version.js} +10 -9
  114. package/build/src/updaters/php/php-manifest.d.ts +13 -0
  115. package/build/src/updaters/{php-manifest.js → php/php-manifest.js} +17 -15
  116. package/build/src/updaters/php/root-composer-update-packages.d.ts +12 -0
  117. package/build/src/updaters/{root-composer-update-packages.js → php/root-composer-update-packages.js} +17 -16
  118. package/build/src/updaters/python/pyproject-toml.d.ts +10 -11
  119. package/build/src/updaters/python/pyproject-toml.js +13 -11
  120. package/build/src/updaters/python/python-file-with-version.d.ts +7 -11
  121. package/build/src/updaters/python/python-file-with-version.js +7 -8
  122. package/build/src/updaters/python/setup-cfg.d.ts +10 -11
  123. package/build/src/updaters/python/setup-cfg.js +10 -8
  124. package/build/src/updaters/python/setup-py.d.ts +10 -11
  125. package/build/src/updaters/python/setup-py.js +10 -8
  126. package/build/src/updaters/raw-content.d.ts +19 -0
  127. package/build/src/{plugins/index.js → updaters/raw-content.js} +23 -12
  128. package/build/src/updaters/release-please-config.d.ts +8 -0
  129. package/build/src/updaters/release-please-config.js +41 -0
  130. package/build/src/updaters/release-please-manifest.d.ts +2 -11
  131. package/build/src/updaters/release-please-manifest.js +11 -14
  132. package/build/src/updaters/ruby/version-rb.d.ts +12 -0
  133. package/build/src/updaters/{version-rb.js → ruby/version-rb.js} +10 -8
  134. package/build/src/updaters/rust/cargo-lock.d.ts +7 -11
  135. package/build/src/updaters/rust/cargo-lock.js +14 -16
  136. package/build/src/updaters/rust/cargo-toml.d.ts +7 -11
  137. package/build/src/updaters/rust/cargo-toml.js +19 -21
  138. package/build/src/updaters/terraform/module-version.d.ts +10 -11
  139. package/build/src/updaters/terraform/module-version.js +11 -9
  140. package/build/src/updaters/terraform/readme.d.ts +10 -11
  141. package/build/src/updaters/terraform/readme.js +11 -10
  142. package/build/src/updaters/terraform/readme.js.map +1 -1
  143. package/build/src/util/branch-name.d.ts +5 -4
  144. package/build/src/util/branch-name.js +13 -10
  145. package/build/src/{commit-split.d.ts → util/commit-split.d.ts} +2 -4
  146. package/build/src/{commit-split.js → util/commit-split.js} +4 -2
  147. package/build/src/util/indent-commit.d.ts +1 -1
  148. package/build/src/util/logger.d.ts +5 -2
  149. package/build/src/util/logger.js +9 -4
  150. package/build/src/util/pull-request-body.d.ts +20 -0
  151. package/build/src/util/pull-request-body.js +129 -0
  152. package/build/src/util/pull-request-title.d.ts +8 -6
  153. package/build/src/util/pull-request-title.js +20 -6
  154. package/build/src/util/tag-name.d.ts +9 -0
  155. package/build/src/util/tag-name.js +41 -0
  156. package/build/src/{updaters → util}/toml-edit.d.ts +0 -0
  157. package/build/src/{updaters → util}/toml-edit.js +0 -0
  158. package/build/src/version.d.ts +11 -0
  159. package/build/src/version.js +45 -0
  160. package/build/src/versioning-strategies/always-bump-patch.d.ts +7 -0
  161. package/build/src/{updaters/package-lock-json.js → versioning-strategies/always-bump-patch.js} +8 -11
  162. package/build/src/versioning-strategies/default.d.ts +15 -0
  163. package/build/src/versioning-strategies/default.js +67 -0
  164. package/build/src/versioning-strategies/dependency-manifest.d.ts +7 -0
  165. package/build/src/versioning-strategies/dependency-manifest.js +90 -0
  166. package/build/src/versioning-strategies/java-add-snapshot.d.ts +9 -0
  167. package/build/src/versioning-strategies/java-add-snapshot.js +53 -0
  168. package/build/src/versioning-strategies/java-snapshot.d.ts +9 -0
  169. package/build/src/versioning-strategies/java-snapshot.js +67 -0
  170. package/build/src/versioning-strategies/service-pack.d.ts +7 -0
  171. package/build/src/versioning-strategies/service-pack.js +40 -0
  172. package/build/src/versioning-strategy.d.ts +28 -0
  173. package/build/src/versioning-strategy.js +55 -0
  174. package/package.json +9 -8
  175. package/build/src/constants.d.ts +0 -6
  176. package/build/src/constants.js +0 -23
  177. package/build/src/conventional-commits.d.ts +0 -53
  178. package/build/src/conventional-commits.js +0 -167
  179. package/build/src/github-release.d.ts +0 -34
  180. package/build/src/github-release.js +0 -92
  181. package/build/src/graphql-to-commits.d.ts +0 -60
  182. package/build/src/graphql-to-commits.js +0 -112
  183. package/build/src/index.d.ts +0 -94
  184. package/build/src/index.js +0 -32
  185. package/build/src/plugins/index.d.ts +0 -5
  186. package/build/src/plugins/plugin.d.ts +0 -21
  187. package/build/src/release-pr.d.ts +0 -101
  188. package/build/src/release-pr.js +0 -461
  189. package/build/src/releasers/dart.d.ts +0 -9
  190. package/build/src/releasers/dart.js +0 -65
  191. package/build/src/releasers/elixir.d.ts +0 -5
  192. package/build/src/releasers/go-yoshi.d.ts +0 -10
  193. package/build/src/releasers/go-yoshi.js +0 -162
  194. package/build/src/releasers/go.d.ts +0 -6
  195. package/build/src/releasers/helm.d.ts +0 -9
  196. package/build/src/releasers/helm.js +0 -66
  197. package/build/src/releasers/index.d.ts +0 -7
  198. package/build/src/releasers/index.js +0 -76
  199. package/build/src/releasers/java/bump_type.d.ts +0 -4
  200. package/build/src/releasers/java/bump_type.js +0 -38
  201. package/build/src/releasers/java/stability.d.ts +0 -5
  202. package/build/src/releasers/java/stability.js +0 -37
  203. package/build/src/releasers/java/version.d.ts +0 -13
  204. package/build/src/releasers/java/version.js +0 -112
  205. package/build/src/releasers/java-backport.d.ts +0 -9
  206. package/build/src/releasers/java-backport.js +0 -43
  207. package/build/src/releasers/java-bom.d.ts +0 -16
  208. package/build/src/releasers/java-bom.js +0 -83
  209. package/build/src/releasers/java-lts.d.ts +0 -9
  210. package/build/src/releasers/java-lts.js +0 -47
  211. package/build/src/releasers/java-yoshi.d.ts +0 -28
  212. package/build/src/releasers/java-yoshi.js +0 -304
  213. package/build/src/releasers/krm-blueprint.d.ts +0 -6
  214. package/build/src/releasers/node.d.ts +0 -10
  215. package/build/src/releasers/node.js +0 -84
  216. package/build/src/releasers/ocaml.d.ts +0 -5
  217. package/build/src/releasers/php-yoshi.d.ts +0 -5
  218. package/build/src/releasers/php-yoshi.js +0 -191
  219. package/build/src/releasers/php.d.ts +0 -7
  220. package/build/src/releasers/python.d.ts +0 -11
  221. package/build/src/releasers/python.js +0 -127
  222. package/build/src/releasers/ruby-yoshi.d.ts +0 -5
  223. package/build/src/releasers/ruby-yoshi.js +0 -142
  224. package/build/src/releasers/ruby.d.ts +0 -11
  225. package/build/src/releasers/rust.d.ts +0 -30
  226. package/build/src/releasers/rust.js +0 -163
  227. package/build/src/releasers/simple.d.ts +0 -5
  228. package/build/src/releasers/terraform-module.d.ts +0 -6
  229. package/build/src/updaters/elixir-mix-exs.d.ts +0 -13
  230. package/build/src/updaters/java/google-utils.d.ts +0 -13
  231. package/build/src/updaters/java/java_update.d.ts +0 -13
  232. package/build/src/updaters/java/pom-xml.d.ts +0 -3
  233. package/build/src/updaters/java/readme.d.ts +0 -3
  234. package/build/src/updaters/java/readme.js.map +0 -1
  235. package/build/src/updaters/package-json.d.ts +0 -16
  236. package/build/src/updaters/package-lock-json.d.ts +0 -7
  237. package/build/src/updaters/php-client-version.d.ts +0 -13
  238. package/build/src/updaters/php-manifest.d.ts +0 -13
  239. package/build/src/updaters/pubspec-yaml.d.ts +0 -13
  240. package/build/src/updaters/root-composer-update-package.d.ts +0 -13
  241. package/build/src/updaters/root-composer-update-package.js +0 -45
  242. package/build/src/updaters/root-composer-update-packages.d.ts +0 -13
  243. package/build/src/updaters/samples-package-json.d.ts +0 -13
  244. package/build/src/updaters/update.d.ts +0 -20
  245. package/build/src/updaters/version-rb.d.ts +0 -13
  246. package/build/src/updaters/version-txt.d.ts +0 -12
  247. package/build/src/updaters/version.d.ts +0 -13
  248. package/build/src/updaters/version.js +0 -31
  249. package/build/src/util/checkpoint.d.ts +0 -6
  250. package/build/src/util/checkpoint.js +0 -33
  251. package/build/src/util/release-notes.d.ts +0 -7
  252. package/build/src/util/release-notes.js +0 -34
  253. package/build/src/util/to-conventional-changelog-format.d.ts +0 -2
@@ -13,545 +13,657 @@
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.Manifest = void 0;
17
- const commit_split_1 = require("./commit-split");
18
- const constants_1 = require("./constants");
16
+ exports.Manifest = exports.MANIFEST_PULL_REQUEST_TITLE_PATTERN = exports.ROOT_PROJECT_PATH = exports.DEFAULT_RELEASE_PLEASE_MANIFEST = exports.DEFAULT_RELEASE_PLEASE_CONFIG = void 0;
17
+ const version_1 = require("./version");
18
+ const logger_1 = require("./util/logger");
19
+ const commit_split_1 = require("./util/commit-split");
20
+ const tag_name_1 = require("./util/tag-name");
19
21
  const branch_name_1 = require("./util/branch-name");
20
- const _1 = require(".");
22
+ const pull_request_title_1 = require("./util/pull-request-title");
23
+ const factory_1 = require("./factory");
24
+ const pull_request_body_1 = require("./util/pull-request-body");
25
+ const merge_1 = require("./plugins/merge");
21
26
  const release_please_manifest_1 = require("./updaters/release-please-manifest");
22
- const checkpoint_1 = require("./util/checkpoint");
23
- const github_release_1 = require("./github-release");
24
- const plugins_1 = require("./plugins");
25
- const signoff_commit_message_1 = require("./util/signoff-commit-message");
27
+ exports.DEFAULT_RELEASE_PLEASE_CONFIG = 'release-please-config.json';
28
+ exports.DEFAULT_RELEASE_PLEASE_MANIFEST = '.release-please-manifest.json';
29
+ exports.ROOT_PROJECT_PATH = '.';
30
+ const DEFAULT_COMPONENT_NAME = '';
31
+ const DEFAULT_LABELS = ['autorelease: pending'];
32
+ const DEFAULT_RELEASE_LABELS = ['autorelease: tagged'];
33
+ exports.MANIFEST_PULL_REQUEST_TITLE_PATTERN = 'chore: release ${branch}';
26
34
  class Manifest {
27
- constructor(options) {
28
- this.gh = options.github;
29
- this.configFileName = options.configFile || constants_1.RELEASE_PLEASE_CONFIG;
30
- this.manifestFileName = options.manifestFile || constants_1.RELEASE_PLEASE_MANIFEST;
31
- this.checkpoint = options.checkpoint || checkpoint_1.checkpoint;
32
- this.signoff = options.signoff;
35
+ /**
36
+ * Create a Manifest from explicit config in code. This assumes that the
37
+ * repository has a single component at the root path.
38
+ *
39
+ * @param {GitHub} github GitHub client
40
+ * @param {string} targetBranch The releaseable base branch
41
+ * @param {RepositoryConfig} repositoryConfig Parsed configuration of path => release configuration
42
+ * @param {ReleasedVersions} releasedVersions Parsed versions of path => latest release version
43
+ * @param {ManifestOptions} manifestOptions Optional. Manifest options
44
+ * @param {string} manifestOptions.bootstrapSha If provided, use this SHA
45
+ * as the point to consider commits after
46
+ * @param {boolean} manifestOptions.alwaysLinkLocal Option for the node-workspace
47
+ * plugin
48
+ * @param {boolean} manifestOptions.separatePullRequests If true, create separate pull
49
+ * requests instead of a single manifest release pull request
50
+ * @param {PluginType[]} manifestOptions.plugins Any plugins to use for this repository
51
+ * @param {boolean} manifestOptions.fork If true, create pull requests from a fork. Defaults
52
+ * to `false`
53
+ * @param {string} manifestOptions.signoff Add a Signed-off-by annotation to the commit
54
+ * @param {string} manifestOptions.manifestPath Path to the versions manifest
55
+ * @param {string[]} manifestOptions.labels Labels that denote a pending, untagged release
56
+ * pull request. Defaults to `[autorelease: pending]`
57
+ * @param {string[]} manifestOptions.releaseLabels Labels to apply to a tagged release
58
+ * pull request. Defaults to `[autorelease: tagged]`
59
+ */
60
+ constructor(github, targetBranch, repositoryConfig, releasedVersions, manifestOptions) {
61
+ this.repository = github.repository;
62
+ this.github = github;
63
+ this.targetBranch = targetBranch;
64
+ this.repositoryConfig = repositoryConfig;
65
+ this.releasedVersions = releasedVersions;
66
+ this.manifestPath =
67
+ (manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.manifestPath) || exports.DEFAULT_RELEASE_PLEASE_MANIFEST;
68
+ this.separatePullRequests = (manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.separatePullRequests) || false;
69
+ this.plugins = (manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.plugins) || [];
70
+ this.fork = (manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.fork) || false;
71
+ this.signoffUser = manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.signoff;
72
+ this.releaseLabels =
73
+ (manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.releaseLabels) || DEFAULT_RELEASE_LABELS;
74
+ this.labels = (manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.labels) || DEFAULT_LABELS;
75
+ this.bootstrapSha = manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.bootstrapSha;
76
+ this.lastReleaseSha = manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.lastReleaseSha;
77
+ this.draft = manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.draft;
78
+ this.draftPullRequest = manifestOptions === null || manifestOptions === void 0 ? void 0 : manifestOptions.draftPullRequest;
33
79
  }
34
- async getBranchName() {
35
- return branch_name_1.BranchName.ofTargetBranch(await this.gh.getDefaultBranch());
80
+ /**
81
+ * Create a Manifest from config files in the repository.
82
+ *
83
+ * @param {GitHub} github GitHub client
84
+ * @param {string} targetBranch The releaseable base branch
85
+ * @param {string} configFile Optional. The path to the manifest config file
86
+ * @param {string} manifestFile Optional. The path to the manifest versions file
87
+ * @returns {Manifest}
88
+ */
89
+ static async fromManifest(github, targetBranch, configFile = exports.DEFAULT_RELEASE_PLEASE_CONFIG, manifestFile = exports.DEFAULT_RELEASE_PLEASE_MANIFEST, manifestOptionOverrides = {}) {
90
+ const [{ config: repositoryConfig, options: manifestOptions }, releasedVersions,] = await Promise.all([
91
+ parseConfig(github, configFile, targetBranch),
92
+ parseReleasedVersions(github, manifestFile, targetBranch),
93
+ ]);
94
+ return new Manifest(github, targetBranch, repositoryConfig, releasedVersions, { ...manifestOptions, ...manifestOptionOverrides });
36
95
  }
37
- async getFileJson(fileName, sha) {
38
- let content;
39
- try {
40
- if (sha) {
41
- content = await this.gh.getFileContentsWithSimpleAPI(fileName, sha, false);
42
- }
43
- else {
44
- content = await this.gh.getFileContents(fileName);
45
- }
46
- }
47
- catch (e) {
48
- this.checkpoint(`Failed to get ${fileName} at ${sha !== null && sha !== void 0 ? sha : 'HEAD'}: ${e.status}`, checkpoint_1.CheckpointType.Failure);
49
- // If a sha is provided this is a request for the manifest file at the
50
- // last merged Release PR. The only reason it would not exist is if a user
51
- // checkedout that branch and deleted the manifest file right before
52
- // merging. There is no recovery from that so we'll fall back to using
53
- // the manifest at the tip of the defaultBranch.
54
- if (sha === undefined) {
55
- // !sha means this is a request against the tip of the defaultBranch and
56
- // we require that the manifest and config exist there. If they don't,
57
- // they can be added and this exception will not be thrown.
58
- throw e;
59
- }
60
- return;
96
+ /**
97
+ * Create a Manifest from explicit config in code. This assumes that the
98
+ * repository has a single component at the root path.
99
+ *
100
+ * @param {GitHub} github GitHub client
101
+ * @param {string} targetBranch The releaseable base branch
102
+ * @param {ReleaserConfig} config Release strategy options
103
+ * @param {ManifestOptions} manifestOptions Optional. Manifest options
104
+ * @param {string} manifestOptions.bootstrapSha If provided, use this SHA
105
+ * as the point to consider commits after
106
+ * @param {boolean} manifestOptions.alwaysLinkLocal Option for the node-workspace
107
+ * plugin
108
+ * @param {boolean} manifestOptions.separatePullRequests If true, create separate pull
109
+ * requests instead of a single manifest release pull request
110
+ * @param {PluginType[]} manifestOptions.plugins Any plugins to use for this repository
111
+ * @param {boolean} manifestOptions.fork If true, create pull requests from a fork. Defaults
112
+ * to `false`
113
+ * @param {string} manifestOptions.signoff Add a Signed-off-by annotation to the commit
114
+ * @param {string} manifestOptions.manifestPath Path to the versions manifest
115
+ * @param {string[]} manifestOptions.labels Labels that denote a pending, untagged release
116
+ * pull request. Defaults to `[autorelease: pending]`
117
+ * @param {string[]} manifestOptions.releaseLabels Labels to apply to a tagged release
118
+ * pull request. Defaults to `[autorelease: tagged]`
119
+ * @returns {Manifest}
120
+ */
121
+ static async fromConfig(github, targetBranch, config, manifestOptions, path = exports.ROOT_PROJECT_PATH) {
122
+ const repositoryConfig = {};
123
+ repositoryConfig[path] = config;
124
+ const strategy = await factory_1.buildStrategy({
125
+ github,
126
+ ...config,
127
+ });
128
+ const component = await strategy.getComponent();
129
+ const releasedVersions = {};
130
+ const latestVersion = await latestReleaseVersion(github, targetBranch, component);
131
+ if (latestVersion) {
132
+ releasedVersions[path] = latestVersion;
61
133
  }
62
- return JSON.parse(content.parsedContent);
134
+ return new Manifest(github, targetBranch, repositoryConfig, releasedVersions, manifestOptions);
63
135
  }
64
- async getManifestJson(sha) {
65
- // cache headManifest since it's loaded in validate() as well as later on
66
- // and we never write to it.
67
- let manifest;
68
- if (sha === undefined) {
69
- if (!this.headManifest) {
70
- this.headManifest = await this.getFileJson(this.manifestFileName);
136
+ /**
137
+ * Build all candidate pull requests for this repository.
138
+ *
139
+ * Iterates through each path and builds a candidate pull request for component.
140
+ * Applies any configured plugins.
141
+ *
142
+ * @returns {ReleasePullRequest[]} The candidate pull requests to open or update.
143
+ */
144
+ async buildPullRequests() {
145
+ var _a;
146
+ logger_1.logger.info('Building pull requests');
147
+ const pathsByComponent = await this.getPathsByComponent();
148
+ const strategiesByPath = await this.getStrategiesByPath();
149
+ // Collect all the SHAs of the latest release packages
150
+ logger_1.logger.info('Collecting release commit SHAs');
151
+ let releasesFound = 0;
152
+ const expectedReleases = Object.keys(strategiesByPath).length;
153
+ // SHAs by path
154
+ const releaseShasByPath = {};
155
+ // Releases by path
156
+ const releasesByPath = {};
157
+ for await (const release of this.github.releaseIterator(400)) {
158
+ // logger.debug(release);
159
+ const tagName = tag_name_1.TagName.parse(release.tagName);
160
+ if (!tagName) {
161
+ logger_1.logger.warn(`Unable to parse release name: ${release.name}`);
162
+ continue;
71
163
  }
72
- manifest = this.headManifest;
73
- }
74
- else {
75
- manifest = await this.getFileJson(this.manifestFileName, sha);
76
- }
77
- return manifest;
78
- }
79
- async getManifestVersions(sha, newPaths) {
80
- let manifestJson;
81
- const defaultBranch = await this.gh.getDefaultBranch();
82
- const bootstrapMsg = `Bootstrapping from ${this.manifestFileName} ` +
83
- `at tip of ${defaultBranch}`;
84
- if (sha === undefined) {
85
- this.checkpoint(bootstrapMsg, checkpoint_1.CheckpointType.Failure);
86
- }
87
- if (sha === false) {
88
- this.checkpoint(`${bootstrapMsg} for missing paths [${newPaths.join(', ')}]`, checkpoint_1.CheckpointType.Failure);
89
- }
90
- let atSha = 'tip';
91
- if (!sha) {
92
- manifestJson = await this.getManifestJson();
93
- }
94
- else {
95
- // try to retrieve manifest from last release sha.
96
- const maybeManifestJson = await this.getManifestJson(sha);
97
- atSha = sha;
98
- if (maybeManifestJson === undefined) {
99
- // user deleted manifest from last release PR before merging.
100
- this.checkpoint(bootstrapMsg, checkpoint_1.CheckpointType.Failure);
101
- manifestJson = await this.getManifestJson();
102
- atSha = 'tip';
164
+ const component = tagName.component || DEFAULT_COMPONENT_NAME;
165
+ const path = pathsByComponent[component];
166
+ if (!path) {
167
+ logger_1.logger.warn(`Found release tag with component '${component}', but not configured in manifest`);
168
+ continue;
103
169
  }
104
- else {
105
- manifestJson = maybeManifestJson;
170
+ const expectedVersion = this.releasedVersions[path];
171
+ if (!expectedVersion) {
172
+ logger_1.logger.warn(`Unable to find expected version for path '${path}' in manifest`);
173
+ continue;
106
174
  }
107
- }
108
- const parsed = new Map(Object.entries(manifestJson));
109
- if (sha === false) {
110
- return parsed;
111
- }
112
- else {
113
- return [parsed, atSha];
114
- }
115
- }
116
- async getConfigJson() {
117
- var _a, _b, _c, _d, _e, _f, _g, _h;
118
- // cache config since it's loaded in validate() as well as later on and we
119
- // never write to it.
120
- if (!this.configFile) {
121
- const config = await this.getFileJson(this.configFileName);
122
- const packages = [];
123
- for (const pkgPath in config.packages) {
124
- const pkgCfg = config.packages[pkgPath];
125
- const pkg = {
126
- path: pkgPath,
127
- releaseType: (_b = (_a = pkgCfg['release-type']) !== null && _a !== void 0 ? _a : config['release-type']) !== null && _b !== void 0 ? _b : 'node',
128
- packageName: pkgCfg['package-name'],
129
- bumpMinorPreMajor: (_c = pkgCfg['bump-minor-pre-major']) !== null && _c !== void 0 ? _c : config['bump-minor-pre-major'],
130
- bumpPatchForMinorPreMajor: (_d = pkgCfg['bump-patch-for-minor-pre-major']) !== null && _d !== void 0 ? _d : config['bump-patch-for-minor-pre-major'],
131
- changelogSections: (_e = pkgCfg['changelog-sections']) !== null && _e !== void 0 ? _e : config['changelog-sections'],
132
- changelogPath: pkgCfg['changelog-path'],
133
- releaseAs: this.resolveReleaseAs(pkgCfg['release-as'], config['release-as']),
134
- draft: (_f = pkgCfg['draft']) !== null && _f !== void 0 ? _f : config['draft'],
135
- skipGithubRelease: (_h = (_g = pkgCfg['skip-github-release']) !== null && _g !== void 0 ? _g : config['skip-github-release']) !== null && _h !== void 0 ? _h : false,
175
+ if (expectedVersion.toString() === tagName.version.toString()) {
176
+ logger_1.logger.debug(`Found release for path ${path}, ${release.tagName}`);
177
+ releaseShasByPath[path] = release.sha;
178
+ releasesByPath[path] = {
179
+ tag: tagName,
180
+ sha: release.sha,
181
+ notes: release.notes || '',
136
182
  };
137
- packages.push(pkg);
183
+ releasesFound += 1;
184
+ }
185
+ if (releasesFound >= expectedReleases) {
186
+ break;
138
187
  }
139
- this.configFile = { parsedPackages: packages, ...config };
140
- }
141
- return this.configFile;
142
- }
143
- // Default release-as only considered if non-empty string.
144
- // Per-pkg release-as may be:
145
- // 1. undefined: use default release-as if present, otherwise normal version
146
- // resolution (auto-increment from CC, fallback to defaultInitialVersion)
147
- // 1. non-empty string: use this version
148
- // 2. empty string: override default release-as if present, otherwise normal
149
- // version resolution.
150
- resolveReleaseAs(pkgRA, defaultRA) {
151
- let releaseAs;
152
- if (defaultRA) {
153
- releaseAs = defaultRA;
154
188
  }
155
- if (pkgRA !== undefined) {
156
- releaseAs = pkgRA;
189
+ const needsBootstrap = releasesFound < expectedReleases;
190
+ if (releasesFound < expectedReleases) {
191
+ logger_1.logger.warn(`Expected ${expectedReleases} releases, only found ${releasesFound}`);
192
+ }
193
+ for (const path in releasesByPath) {
194
+ const release = releasesByPath[path];
195
+ logger_1.logger.debug(`release for path: ${path}, version: ${release.tag.version.toString()}, sha: ${release.sha}`);
196
+ }
197
+ // iterate through commits and collect commits until we have
198
+ // seen all release commits
199
+ logger_1.logger.info('Collecting commits since all latest releases');
200
+ const commits = [];
201
+ const commitGenerator = this.github.mergeCommitIterator(this.targetBranch, 500);
202
+ const releaseShas = new Set(Object.values(releaseShasByPath));
203
+ logger_1.logger.debug(releaseShas);
204
+ const expectedShas = releaseShas.size;
205
+ // sha => release pull request
206
+ const releasePullRequestsBySha = {};
207
+ let releaseCommitsFound = 0;
208
+ for await (const commit of commitGenerator) {
209
+ if (releaseShas.has(commit.sha)) {
210
+ if (commit.pullRequest) {
211
+ releasePullRequestsBySha[commit.sha] = commit.pullRequest;
212
+ }
213
+ else {
214
+ logger_1.logger.warn(`Release SHA ${commit.sha} did not have an associated pull request`);
215
+ }
216
+ releaseCommitsFound += 1;
217
+ }
218
+ if (this.lastReleaseSha && this.lastReleaseSha === commit.sha) {
219
+ logger_1.logger.info(`Using configured lastReleaseSha ${this.lastReleaseSha} as last commit.`);
220
+ break;
221
+ }
222
+ else if (needsBootstrap && commit.sha === this.bootstrapSha) {
223
+ logger_1.logger.info(`Needed bootstrapping, found configured bootstrapSha ${this.bootstrapSha}`);
224
+ break;
225
+ }
226
+ else if (!needsBootstrap && releaseCommitsFound >= expectedShas) {
227
+ // found enough commits
228
+ break;
229
+ }
230
+ commits.push({
231
+ sha: commit.sha,
232
+ message: commit.message,
233
+ files: commit.files,
234
+ });
157
235
  }
158
- if (!releaseAs) {
159
- releaseAs = undefined;
236
+ if (releaseCommitsFound < expectedShas) {
237
+ logger_1.logger.warn(`Expected ${expectedShas} commits, only found ${releaseCommitsFound}`);
160
238
  }
161
- return releaseAs;
162
- }
163
- async getPackagesToRelease(allCommits, sha) {
164
- const packages = (await this.getConfigJson()).parsedPackages;
165
- const [manifestVersions, atSha] = await this.getManifestVersions(sha);
239
+ // split commits by path
240
+ logger_1.logger.info(`Splitting ${commits.length} commits by path`);
166
241
  const cs = new commit_split_1.CommitSplit({
167
242
  includeEmpty: true,
168
- packagePaths: packages.map(p => p.path),
243
+ packagePaths: Object.keys(this.repositoryConfig),
169
244
  });
170
- const commitsPerPath = cs.split(allCommits);
171
- const packagesToRelease = {};
172
- const missingVersionPaths = [];
173
- const defaultBranch = await this.gh.getDefaultBranch();
174
- for (const pkg of packages) {
175
- // The special path of '.' indicates the root module is being released
176
- // in this case, use the entire list of commits:
177
- const commits = pkg.path === '.' ? allCommits : commitsPerPath[pkg.path];
178
- if (!commits || commits.length === 0) {
245
+ const commitsPerPath = cs.split(commits);
246
+ let newReleasePullRequests = [];
247
+ for (const path in this.repositoryConfig) {
248
+ const config = this.repositoryConfig[path];
249
+ logger_1.logger.info(`Building candidate release pull request for path: ${path}`);
250
+ logger_1.logger.debug(`type: ${config.releaseType}`);
251
+ logger_1.logger.debug(`targetBranch: ${this.targetBranch}`);
252
+ const pathCommits = commitsAfterSha(path === exports.ROOT_PROJECT_PATH ? commits : commitsPerPath[path], releaseShasByPath[path]);
253
+ if (!pathCommits || pathCommits.length === 0) {
254
+ logger_1.logger.info(`No commits for path: ${path}, skipping`);
179
255
  continue;
180
256
  }
181
- const lastVersion = manifestVersions.get(pkg.path);
182
- if (!lastVersion) {
183
- this.checkpoint(`Failed to find version for ${pkg.path} in ` +
184
- `${this.manifestFileName} at ${atSha} of ${defaultBranch}`, checkpoint_1.CheckpointType.Failure);
185
- missingVersionPaths.push(pkg.path);
186
- }
187
- else {
188
- this.checkpoint(`Found version ${lastVersion} for ${pkg.path} in ` +
189
- `${this.manifestFileName} at ${atSha} of ${defaultBranch}`, checkpoint_1.CheckpointType.Success);
257
+ logger_1.logger.debug(`commits: ${pathCommits.length}`);
258
+ const latestReleasePullRequest = releasePullRequestsBySha[releaseShasByPath[path]];
259
+ if (!latestReleasePullRequest) {
260
+ logger_1.logger.warn('No latest release pull request found.');
190
261
  }
191
- packagesToRelease[pkg.path] = {
192
- commits,
193
- lastVersion,
194
- config: pkg,
195
- };
196
- }
197
- if (missingVersionPaths.length > 0) {
198
- const headManifestVersions = await this.getManifestVersions(false, missingVersionPaths);
199
- for (const missingVersionPath of missingVersionPaths) {
200
- const headVersion = headManifestVersions.get(missingVersionPath);
201
- if (headVersion === undefined) {
202
- this.checkpoint(`Failed to find version for ${missingVersionPath} in ` +
203
- `${this.manifestFileName} at tip of ${defaultBranch}`, checkpoint_1.CheckpointType.Failure);
262
+ const strategy = strategiesByPath[path];
263
+ const latestRelease = releasesByPath[path];
264
+ const releasePullRequest = await strategy.buildReleasePullRequest(pathCommits, latestRelease, (_a = config.draftPullRequest) !== null && _a !== void 0 ? _a : this.draftPullRequest, this.labels);
265
+ if (releasePullRequest) {
266
+ if (releasePullRequest.version) {
267
+ const versionsMap = new Map();
268
+ versionsMap.set(path, releasePullRequest.version);
269
+ releasePullRequest.updates.push({
270
+ path: this.manifestPath,
271
+ createIfMissing: false,
272
+ updater: new release_please_manifest_1.ReleasePleaseManifest({
273
+ version: releasePullRequest.version,
274
+ versionsMap,
275
+ }),
276
+ });
204
277
  }
205
- packagesToRelease[missingVersionPath].lastVersion = headVersion;
278
+ newReleasePullRequests.push({
279
+ path,
280
+ config,
281
+ pullRequest: releasePullRequest,
282
+ });
206
283
  }
207
284
  }
208
- return Object.values(packagesToRelease);
285
+ // Build plugins
286
+ const plugins = this.plugins.map(pluginType => factory_1.buildPlugin({
287
+ type: pluginType,
288
+ github: this.github,
289
+ targetBranch: this.targetBranch,
290
+ repositoryConfig: this.repositoryConfig,
291
+ }));
292
+ // Combine pull requests into 1 unless configured for separate
293
+ // pull requests
294
+ if (!this.separatePullRequests) {
295
+ plugins.push(new merge_1.Merge(this.github, this.targetBranch, this.repositoryConfig));
296
+ }
297
+ for (const plugin of plugins) {
298
+ newReleasePullRequests = await plugin.run(newReleasePullRequests);
299
+ }
300
+ return newReleasePullRequests.map(pullRequestWithConfig => pullRequestWithConfig.pullRequest);
209
301
  }
210
- async validateJsonFile(getFileMethod, fileName) {
211
- let response = {
212
- valid: false,
213
- obj: undefined,
214
- };
215
- try {
216
- const obj = await this[getFileMethod]();
217
- if (obj.constructor.name === 'Object') {
218
- response = { valid: true, obj: obj };
302
+ /**
303
+ * Opens/updates all candidate release pull requests for this repository.
304
+ *
305
+ * @returns {number[]} Pull request numbers of release pull requests
306
+ */
307
+ async createPullRequests() {
308
+ const candidatePullRequests = await this.buildPullRequests();
309
+ if (candidatePullRequests.length === 0) {
310
+ return [];
311
+ }
312
+ // if there are any merged, pending release pull requests, don't open
313
+ // any new release PRs
314
+ const mergedPullRequestsGenerator = this.findMergedReleasePullRequests();
315
+ for await (const _ of mergedPullRequestsGenerator) {
316
+ logger_1.logger.warn('There are untagged, merged release PRs outstanding - aborting');
317
+ return [];
318
+ }
319
+ // collect open release pull requests
320
+ logger_1.logger.info('Looking for open release pull requests');
321
+ const openPullRequests = [];
322
+ const generator = this.github.pullRequestIterator(this.targetBranch, 'OPEN');
323
+ for await (const openPullRequest of generator) {
324
+ if (hasAllLabels(this.labels, openPullRequest.labels) &&
325
+ branch_name_1.BranchName.parse(openPullRequest.headBranchName) &&
326
+ pull_request_body_1.PullRequestBody.parse(openPullRequest.body)) {
327
+ openPullRequests.push(openPullRequest);
219
328
  }
220
329
  }
221
- catch (e) {
222
- let errMsg;
223
- if (e instanceof SyntaxError) {
224
- errMsg = `Invalid JSON in ${fileName}`;
225
- }
226
- else {
227
- errMsg = `Unable to ${getFileMethod}(${fileName}): ${e.message}`;
228
- }
229
- this.checkpoint(errMsg, checkpoint_1.CheckpointType.Failure);
330
+ logger_1.logger.info(`found ${openPullRequests.length} open release pull requests.`);
331
+ const promises = [];
332
+ for (const pullRequest of candidatePullRequests) {
333
+ promises.push(this.createOrUpdatePullRequest(pullRequest, openPullRequests));
230
334
  }
231
- return response;
335
+ return await Promise.all(promises);
232
336
  }
233
- async validate() {
234
- var _a;
235
- const configValidation = await this.validateJsonFile('getConfigJson', this.configFileName);
236
- let validConfig = false;
237
- if (configValidation.valid) {
238
- const obj = configValidation.obj;
239
- validConfig = !!Object.keys((_a = obj.packages) !== null && _a !== void 0 ? _a : {}).length;
240
- if (!validConfig) {
241
- this.checkpoint(`No packages found: ${this.configFileName}`, checkpoint_1.CheckpointType.Failure);
337
+ async createOrUpdatePullRequest(pullRequest, openPullRequests) {
338
+ // look for existing, open pull rquest
339
+ const existing = openPullRequests.find(openPullRequest => openPullRequest.headBranchName === pullRequest.headRefName);
340
+ if (existing) {
341
+ // If unchanged, no need to push updates
342
+ if (existing.body === pullRequest.body.toString()) {
343
+ logger_1.logger.info(`PR https://github.com/${this.repository.owner}/${this.repository.repo}/pull/${existing.number} remained the same`);
344
+ return undefined;
242
345
  }
346
+ const updatedPullRequest = await this.github.updatePullRequest(existing.number, pullRequest, this.targetBranch, {
347
+ fork: this.fork,
348
+ signoffUser: this.signoffUser,
349
+ });
350
+ return updatedPullRequest;
243
351
  }
244
- const manifestValidation = await this.validateJsonFile('getManifestJson', this.manifestFileName);
245
- let validManifest = false;
246
- if (manifestValidation.valid) {
247
- validManifest = true;
248
- const versions = new Map(Object.entries(manifestValidation.obj));
249
- for (const [_, version] of versions) {
250
- if (typeof version !== 'string') {
251
- validManifest = false;
252
- this.checkpoint(`${this.manifestFileName} must only contain string values`, checkpoint_1.CheckpointType.Failure);
253
- break;
254
- }
255
- }
352
+ else {
353
+ const newPullRequest = await this.github.createReleasePullRequest(pullRequest, this.targetBranch, {
354
+ fork: this.fork,
355
+ signoffUser: this.signoffUser,
356
+ });
357
+ return newPullRequest;
256
358
  }
257
- return validConfig && validManifest;
258
- }
259
- async getReleasePR(pkg) {
260
- const { releaseType, draft, ...options } = pkg;
261
- const releaserOptions = {
262
- monorepoTags: true,
263
- ...options,
264
- };
265
- const releaserClass = _1.factory.releasePRClass(releaseType);
266
- const releasePR = new releaserClass({
267
- github: this.gh,
268
- skipDependencyUpdates: true,
269
- ...releaserOptions,
270
- });
271
- return [releasePR, draft];
272
359
  }
273
- async runReleasers(packagesForReleasers, sha) {
274
- const newManifestVersions = new Map();
275
- const pkgsWithChanges = [];
276
- for (const pkg of packagesForReleasers) {
277
- const [releasePR] = await this.getReleasePR(pkg.config);
278
- const pkgName = await releasePR.getPackageName();
279
- const displayTag = `${releasePR.constructor.name}(${pkgName.name})`;
280
- this.checkpoint(`Processing package: ${displayTag}`, checkpoint_1.CheckpointType.Success);
281
- if (pkg.lastVersion === undefined) {
282
- this.checkpoint(`Falling back to default version for ${displayTag}: ` +
283
- releasePR.defaultInitialVersion(), checkpoint_1.CheckpointType.Failure);
360
+ async *findMergedReleasePullRequests() {
361
+ // Find merged release pull requests
362
+ const pullRequestGenerator = this.github.pullRequestIterator(this.targetBranch, 'MERGED', 200);
363
+ for await (const pullRequest of pullRequestGenerator) {
364
+ if (!hasAllLabels(this.labels, pullRequest.labels)) {
365
+ continue;
284
366
  }
285
- const openPROptions = await releasePR.getOpenPROptions(pkg.commits, pkg.lastVersion
286
- ? {
287
- name: pkgName.getComponent() +
288
- releasePR.tagSeparator() +
289
- 'v' +
290
- pkg.lastVersion,
291
- sha: sha !== null && sha !== void 0 ? sha : 'beginning of time',
292
- version: pkg.lastVersion,
293
- }
294
- : undefined);
295
- if (openPROptions) {
296
- pkg.config.packageName = (await releasePR.getPackageName()).name;
297
- const changes = await this.gh.getChangeSet(openPROptions.updates, await this.gh.getDefaultBranch());
298
- pkgsWithChanges.push({
299
- config: pkg.config,
300
- prData: { version: openPROptions.version, changes },
301
- });
302
- newManifestVersions.set(pkg.config.path, openPROptions.version);
367
+ logger_1.logger.debug(`Found pull request #${pullRequest.number}: '${pullRequest.title}'`);
368
+ const pullRequestBody = pull_request_body_1.PullRequestBody.parse(pullRequest.body);
369
+ if (!pullRequestBody) {
370
+ logger_1.logger.debug('could not parse pull request body as a release PR');
371
+ continue;
303
372
  }
373
+ yield pullRequest;
304
374
  }
305
- return [newManifestVersions, pkgsWithChanges];
306
375
  }
307
- async getManifestChanges(newManifestVersions) {
308
- // TODO: simplify `Update.contents?` to just be a string - no need to
309
- // roundtrip through a GitHubFileContents
310
- const manifestContents = {
311
- sha: '',
312
- parsedContent: '',
313
- content: Buffer.from(JSON.stringify(await this.getManifestJson())).toString('base64'),
314
- };
315
- const manifestUpdate = new release_please_manifest_1.ReleasePleaseManifest({
316
- changelogEntry: '',
317
- packageName: '',
318
- path: this.manifestFileName,
319
- version: '',
320
- versions: newManifestVersions,
321
- contents: manifestContents,
322
- });
323
- return await this.gh.getChangeSet([manifestUpdate], await this.gh.getDefaultBranch());
324
- }
325
- buildPRBody(pkg) {
326
- var _a, _b;
327
- const version = pkg.prData.version;
328
- let body = '<details><summary>' +
329
- `${pkg.config.packageName}: ${version}` +
330
- '</summary>';
331
- let changelogPath = (_a = pkg.config.changelogPath) !== null && _a !== void 0 ? _a : 'CHANGELOG.md';
332
- if (pkg.config.path !== '.') {
333
- changelogPath = `${pkg.config.path}/${changelogPath}`;
334
- }
335
- const changelog = (_b = pkg.prData.changes.get(changelogPath)) === null || _b === void 0 ? void 0 : _b.content;
336
- if (!changelog) {
337
- this.checkpoint(`Failed to find ${changelogPath}`, checkpoint_1.CheckpointType.Failure);
376
+ /**
377
+ * Find merged, untagged releases and build candidate releases to tag.
378
+ *
379
+ * @returns {CandidateRelease[]} List of release candidates
380
+ */
381
+ async buildReleases() {
382
+ var _a;
383
+ logger_1.logger.info('Building releases');
384
+ const strategiesByPath = await this.getStrategiesByPath();
385
+ // Find merged release pull requests
386
+ const generator = await this.findMergedReleasePullRequests();
387
+ const releases = [];
388
+ for await (const pullRequest of generator) {
389
+ logger_1.logger.info('Looking at files touched by path');
390
+ const cs = new commit_split_1.CommitSplit({
391
+ includeEmpty: true,
392
+ packagePaths: Object.keys(this.repositoryConfig),
393
+ });
394
+ const commits = [
395
+ {
396
+ sha: pullRequest.sha,
397
+ message: pullRequest.title,
398
+ files: pullRequest.files,
399
+ },
400
+ ];
401
+ const commitsPerPath = cs.split(commits);
402
+ for (const path in this.repositoryConfig) {
403
+ const config = this.repositoryConfig[path];
404
+ logger_1.logger.info(`Building release for path: ${path}`);
405
+ logger_1.logger.debug(`type: ${config.releaseType}`);
406
+ logger_1.logger.debug(`targetBranch: ${this.targetBranch}`);
407
+ const pathCommits = path === exports.ROOT_PROJECT_PATH ? commits : commitsPerPath[path];
408
+ if (!pathCommits || pathCommits.length === 0) {
409
+ logger_1.logger.info(`No commits for path: ${path}, skipping`);
410
+ continue;
411
+ }
412
+ const strategy = strategiesByPath[path];
413
+ const release = await strategy.buildRelease(pullRequest);
414
+ if (release) {
415
+ releases.push({
416
+ ...release,
417
+ path,
418
+ pullRequest,
419
+ draft: (_a = config.draft) !== null && _a !== void 0 ? _a : this.draft,
420
+ });
421
+ }
422
+ }
338
423
  }
339
- else {
340
- const match = changelog.match(
341
- // changelog entries start like
342
- // ## 1.0.0 (1983...
343
- // ## [4.0.0](https...
344
- // ### [1.2.4](https...
345
- RegExp(`.*###? \\[?${version}\\]?.*?\n(?<currentEntry>.*?)` +
346
- // either the next changelog or new lines / spaces to the end if
347
- // this is the first entry in the changelog
348
- '(\n###? [0-9[].*|[\n ]*$)', 's'));
349
- if (!match) {
350
- this.checkpoint(`Failed to find entry in changelog for ${version}`, checkpoint_1.CheckpointType.Failure);
424
+ return releases;
425
+ }
426
+ /**
427
+ * Find merged, untagged releases. For each release, create a GitHub release,
428
+ * comment on the pull request used to generated it and update the pull request
429
+ * labels.
430
+ *
431
+ * @returns {GitHubRelease[]} List of created GitHub releases
432
+ */
433
+ async createReleases() {
434
+ const releasesByPullRequest = {};
435
+ const pullRequestsByNumber = {};
436
+ for (const release of await this.buildReleases()) {
437
+ pullRequestsByNumber[release.pullRequest.number] = release.pullRequest;
438
+ if (releasesByPullRequest[release.pullRequest.number]) {
439
+ releasesByPullRequest[release.pullRequest.number].push(release);
351
440
  }
352
441
  else {
353
- const { currentEntry } = match.groups;
354
- body += '\n\n\n' + currentEntry.trim() + '\n';
442
+ releasesByPullRequest[release.pullRequest.number] = [release];
355
443
  }
356
444
  }
357
- body += '</details>\n';
358
- return body;
359
- }
360
- async buildManifestPR(newManifestVersions,
361
- // using version, changes
362
- packages) {
363
- let body = ':robot: I have created a release \\*beep\\* \\*boop\\*\n---\n';
364
- let changes = new Map();
365
- for (const pkg of packages) {
366
- body += this.buildPRBody(pkg);
367
- changes = new Map([...changes, ...pkg.prData.changes]);
445
+ const promises = [];
446
+ for (const pullNumber in releasesByPullRequest) {
447
+ promises.push(this.createReleasesForPullRequest(releasesByPullRequest[pullNumber], pullRequestsByNumber[pullNumber]));
368
448
  }
369
- const manifestChanges = await this.getManifestChanges(newManifestVersions);
370
- changes = new Map([...changes, ...manifestChanges]);
371
- body +=
372
- '\n\nThis PR was generated with [Release Please]' +
373
- `(https://github.com/googleapis/${constants_1.RELEASE_PLEASE}). See [documentation]` +
374
- `(https://github.com/googleapis/${constants_1.RELEASE_PLEASE}#${constants_1.RELEASE_PLEASE}).`;
375
- return [body, changes];
449
+ const releases = await Promise.all(promises);
450
+ return releases.reduce((collection, r) => collection.concat(r), []);
376
451
  }
377
- async getPlugins() {
378
- var _a;
379
- const plugins = [];
380
- const config = await this.getConfigJson();
381
- for (const p of (_a = config.plugins) !== null && _a !== void 0 ? _a : []) {
382
- plugins.push(plugins_1.getPlugin(p, this.gh, config));
383
- }
384
- return plugins;
452
+ async createReleasesForPullRequest(releases, pullRequest) {
453
+ // create the release
454
+ const promises = [];
455
+ for (const release of releases) {
456
+ promises.push(this.createRelease(release));
457
+ }
458
+ const githubReleases = await Promise.all(promises);
459
+ // adjust tags on pullRequest
460
+ await Promise.all([
461
+ this.github.removeIssueLabels(this.labels, pullRequest.number),
462
+ this.github.addIssueLabels(this.releaseLabels, pullRequest.number),
463
+ ]);
464
+ return githubReleases;
385
465
  }
386
- async resolveLastReleaseSha(branchName) {
387
- const config = await this.getConfigJson();
388
- let lastReleaseSha;
389
- let source = 'no last release sha found';
390
- if (config['last-release-sha']) {
391
- lastReleaseSha = config['last-release-sha'];
392
- source = 'last-release-sha';
393
- }
394
- else {
395
- const lastMergedPR = await this.gh.lastMergedPRByHeadBranch(branchName);
396
- if (lastMergedPR) {
397
- lastReleaseSha = lastMergedPR.sha;
398
- source = 'last-release-pr';
399
- }
400
- else if (config['bootstrap-sha']) {
401
- lastReleaseSha = config['bootstrap-sha'];
402
- source = 'bootstrap-sha';
403
- }
404
- }
405
- this.checkpoint(`Found last release sha "${lastReleaseSha}" using "${source}"`, checkpoint_1.CheckpointType.Success);
406
- return lastReleaseSha;
407
- }
408
- async pullRequest() {
409
- const valid = await this.validate();
410
- if (!valid) {
411
- return;
412
- }
413
- const branchName = (await this.getBranchName()).toString();
414
- const lastReleaseSha = await this.resolveLastReleaseSha(branchName);
415
- const commits = await this.gh.commitsSinceShaRest(lastReleaseSha);
416
- const packagesForReleasers = await this.getPackagesToRelease(commits, lastReleaseSha);
417
- let [newManifestVersions, pkgsWithChanges] = await this.runReleasers(packagesForReleasers, lastReleaseSha);
418
- if (pkgsWithChanges.length === 0) {
419
- this.checkpoint('No user facing changes to release', checkpoint_1.CheckpointType.Success);
420
- return;
421
- }
422
- for (const plugin of await this.getPlugins()) {
423
- [newManifestVersions, pkgsWithChanges] = await plugin.run(newManifestVersions, pkgsWithChanges);
424
- }
425
- const [body, changes] = await this.buildManifestPR(newManifestVersions, pkgsWithChanges);
426
- const title = `chore: release ${await this.gh.getDefaultBranch()}`;
427
- // Sign-off message if signoff option is enabled
428
- const message = this.signoff
429
- ? signoff_commit_message_1.signoffCommitMessage(title, this.signoff)
430
- : title;
431
- const pr = await this.gh.openPR({
432
- branch: branchName,
433
- title,
434
- message,
435
- body: body,
436
- updates: [],
437
- labels: constants_1.DEFAULT_LABELS,
438
- changes,
466
+ async createRelease(release) {
467
+ const githubRelease = await this.github.createRelease(release, {
468
+ draft: release.draft,
439
469
  });
440
- if (pr) {
441
- await this.gh.addLabels(constants_1.DEFAULT_LABELS, pr);
442
- }
443
- return pr;
470
+ // comment on pull request
471
+ const comment = `:robot: Release is at ${githubRelease.url} :sunflower:`;
472
+ await this.github.commentOnIssue(comment, release.pullRequest.number);
473
+ return {
474
+ ...githubRelease,
475
+ path: release.path,
476
+ version: release.tag.version.toString(),
477
+ major: release.tag.version.major,
478
+ minor: release.tag.version.minor,
479
+ patch: release.tag.version.patch,
480
+ };
444
481
  }
445
- async githubRelease() {
446
- var _a;
447
- const valid = await this.validate();
448
- if (!valid) {
449
- return;
450
- }
451
- const branchName = (await this.getBranchName()).toString();
452
- const lastMergedPR = await this.gh.lastMergedPRByHeadBranch(branchName);
453
- if (lastMergedPR === undefined) {
454
- this.checkpoint('Unable to find last merged Manifest PR for tagging', checkpoint_1.CheckpointType.Failure);
455
- return;
456
- }
457
- if (lastMergedPR.labels.includes(github_release_1.GITHUB_RELEASE_LABEL)) {
458
- this.checkpoint('Releases already created for last merged release PR', checkpoint_1.CheckpointType.Success);
459
- return;
460
- }
461
- if (!lastMergedPR.labels.includes(constants_1.DEFAULT_LABELS[0])) {
462
- this.checkpoint(`Warning: last merged PR(#${lastMergedPR.number}) is missing ` +
463
- `label "${constants_1.DEFAULT_LABELS[0]}" but has not yet been ` +
464
- `labeled "${github_release_1.GITHUB_RELEASE_LABEL}". If PR(#${lastMergedPR.number}) ` +
465
- 'is meant to be a release PR, please apply the ' +
466
- `label "${constants_1.DEFAULT_LABELS[0]}".`, checkpoint_1.CheckpointType.Failure);
467
- return;
468
- }
469
- const packagesForReleasers = await this.getPackagesToRelease(
470
- // use the lastMergedPR.sha as a Commit: lastMergedPR.files will inform
471
- // getPackagesToRelease() what packages had changes (i.e. at least one
472
- // file under their path changed in the lastMergedPR such as
473
- // "packages/mypkg/package.json"). These are exactly the packages we want
474
- // to create releases/tags for.
475
- [{ sha: lastMergedPR.sha, message: '', files: lastMergedPR.files }], lastMergedPR.sha);
476
- const releases = {};
477
- let allReleasesCreated = !!packagesForReleasers.length;
478
- for (const pkg of packagesForReleasers) {
479
- const [releasePR, draft] = await this.getReleasePR(pkg.config);
480
- const pkgName = (await releasePR.getPackageName()).name;
481
- const pkgLogDisp = `${releasePR.constructor.name}(${pkgName})`;
482
- if (!pkg.lastVersion) {
483
- // a user manually modified the manifest file on the release branch
484
- // right before merging it and deleted the entry for this pkg.
485
- this.checkpoint(`Unable to find last version for ${pkgLogDisp}.`, checkpoint_1.CheckpointType.Failure);
486
- releases[pkg.config.path] = undefined;
487
- continue;
488
- }
489
- if (pkg.config.skipGithubRelease) {
490
- this.gh.commentOnIssue(`:robot: ${pkgName} not configured for release :no_entry_sign:`, lastMergedPR.number);
491
- releases[pkg.config.path] = undefined;
492
- continue;
493
- }
494
- this.checkpoint('Creating release for ' + `${pkgLogDisp}@${pkg.lastVersion}`, checkpoint_1.CheckpointType.Success);
495
- const releaser = new github_release_1.GitHubRelease({
496
- github: this.gh,
497
- releasePR,
498
- draft,
499
- });
500
- let release;
501
- try {
502
- release = await releaser.createRelease(pkg.lastVersion, lastMergedPR);
503
- }
504
- catch (err) {
505
- // There is no transactional bulk create releases API. Previous runs
506
- // may have failed due to transient infrastructure problems part way
507
- // through creating releases. Here we skip any releases that were
508
- // already successfully created.
509
- //
510
- // Note about `draft` releases: The GitHub API Release unique key is
511
- // `tag_name`. However, if `draft` is true, no git tag is created. Thus
512
- // multiple `draft` releases can be created with the exact same inputs.
513
- // (It's a tad confusing because `tag_name` still comes back populated
514
- // in these calls but the tag doesn't actually exist).
515
- // A draft release can even be created with a `tag_name` referring to an
516
- // existing tag referenced by another release.
517
- // However, GitHub will prevent "publishing" any draft release that
518
- // would cause a duplicate tag to be created. release-please manifest
519
- // users specifying the "release-draft" option could run into this
520
- // duplicate releases scenario. It's easy enough to just delete the
521
- // duplicate draft entries in the UI (or API).
522
- if (err.status === 422 && ((_a = err.errors) === null || _a === void 0 ? void 0 : _a.length)) {
523
- if (err.errors[0].code === 'already_exists' &&
524
- err.errors[0].field === 'tag_name') {
525
- this.checkpoint(`Release for ${pkgLogDisp}@${pkg.lastVersion} already exists`, checkpoint_1.CheckpointType.Success);
526
- }
527
- }
528
- else {
529
- // PR will not be tagged with GITHUB_RELEASE_LABEL so another run
530
- // can try again.
531
- allReleasesCreated = false;
532
- await this.gh.commentOnIssue(`:robot: Failed to create release for ${pkgName} :cloud:`, lastMergedPR.number);
533
- this.checkpoint('Failed to create release for ' +
534
- `${pkgLogDisp}@${pkg.lastVersion}: ${err.message}`, checkpoint_1.CheckpointType.Failure);
535
- }
536
- releases[pkg.config.path] = undefined;
537
- continue;
538
- }
539
- if (release) {
540
- await this.gh.commentOnIssue(`:robot: Release for ${pkgName} is at ${release.html_url} :sunflower:`, lastMergedPR.number);
541
- releases[pkg.config.path] = releaser.releaseResponse({
542
- release,
543
- version: pkg.lastVersion,
544
- sha: lastMergedPR.sha,
545
- number: lastMergedPR.number,
482
+ async getStrategiesByPath() {
483
+ if (!this._strategiesByPath) {
484
+ logger_1.logger.info('Building strategies by path');
485
+ this._strategiesByPath = {};
486
+ for (const path in this.repositoryConfig) {
487
+ const config = this.repositoryConfig[path];
488
+ logger_1.logger.debug(`${path}: ${config.releaseType}`);
489
+ const strategy = await factory_1.buildStrategy({
490
+ ...config,
491
+ github: this.github,
492
+ path,
493
+ targetBranch: this.targetBranch,
546
494
  });
495
+ this._strategiesByPath[path] = strategy;
547
496
  }
548
497
  }
549
- if (allReleasesCreated) {
550
- await this.gh.addLabels([github_release_1.GITHUB_RELEASE_LABEL], lastMergedPR.number);
551
- await this.gh.removeLabels(constants_1.DEFAULT_LABELS, lastMergedPR.number);
498
+ return this._strategiesByPath;
499
+ }
500
+ async getPathsByComponent() {
501
+ if (!this._pathsByComponent) {
502
+ this._pathsByComponent = {};
503
+ const strategiesByPath = await this.getStrategiesByPath();
504
+ for (const path in this.repositoryConfig) {
505
+ const strategy = strategiesByPath[path];
506
+ const component = strategy.component || (await strategy.getDefaultComponent()) || '';
507
+ if (this._pathsByComponent[component]) {
508
+ logger_1.logger.warn(`Multiple paths for ${component}: ${this._pathsByComponent[component]}, ${path}`);
509
+ }
510
+ this._pathsByComponent[component] = path;
511
+ }
552
512
  }
553
- return releases;
513
+ return this._pathsByComponent;
554
514
  }
555
515
  }
556
516
  exports.Manifest = Manifest;
517
+ /**
518
+ * Helper to convert parsed JSON releaser config into ReleaserConfig for
519
+ * the Manifest.
520
+ *
521
+ * @param {ReleaserPackageConfig} config Parsed configuration from JSON file.
522
+ * @returns {ReleaserConfig}
523
+ */
524
+ function extractReleaserConfig(config) {
525
+ return {
526
+ releaseType: config['release-type'] || 'node',
527
+ bumpMinorPreMajor: config['bump-minor-pre-major'],
528
+ bumpPatchForMinorPreMajor: config['bump-patch-for-minor-pre-major'],
529
+ changelogSections: config['changelog-sections'],
530
+ changelogPath: config['changelog-path'],
531
+ releaseAs: config['release-as'],
532
+ skipGithubRelease: config['skip-github-release'],
533
+ draft: config.draft,
534
+ draftPullRequest: config['draft-pull-request'],
535
+ component: config['component'],
536
+ packageName: config['package-name'],
537
+ versionFile: config['version-file'],
538
+ extraFiles: config['extra-files'],
539
+ includeComponentInTag: config['include-component-in-tag'],
540
+ };
541
+ }
542
+ /**
543
+ * Helper to convert fetch the manifest config from the repository and
544
+ * parse into configuration for the Manifest.
545
+ *
546
+ * @param {GitHub} github GitHub client
547
+ * @param {string} configFile Path in the repository to the manifest config
548
+ * @param {string} branch Branch to fetch the config file from
549
+ */
550
+ async function parseConfig(github, configFile, branch) {
551
+ const config = await github.getFileJson(configFile, branch);
552
+ const defaultConfig = extractReleaserConfig(config);
553
+ const repositoryConfig = {};
554
+ for (const path in config.packages) {
555
+ repositoryConfig[path] = mergeReleaserConfig(defaultConfig, extractReleaserConfig(config.packages[path]));
556
+ }
557
+ const manifestOptions = {
558
+ bootstrapSha: config['bootstrap-sha'],
559
+ lastReleaseSha: config['last-release-sha'],
560
+ alwaysLinkLocal: config['always-link-local'],
561
+ separatePullRequests: config['separate-pull-requests'],
562
+ plugins: config['plugins'],
563
+ };
564
+ return { config: repositoryConfig, options: manifestOptions };
565
+ }
566
+ /**
567
+ * Helper to parse the manifest versions file.
568
+ *
569
+ * @param {GitHub} github GitHub client
570
+ * @param {string} manifestFile Path in the repository to the versions file
571
+ * @param {string} branch Branch to fetch the versions file from
572
+ */
573
+ async function parseReleasedVersions(github, manifestFile, branch) {
574
+ const manifestJson = await github.getFileJson(manifestFile, branch);
575
+ const releasedVersions = {};
576
+ for (const path in manifestJson) {
577
+ releasedVersions[path] = version_1.Version.parse(manifestJson[path]);
578
+ }
579
+ return releasedVersions;
580
+ }
581
+ /**
582
+ * Find the most recent matching release tag on the branch we're
583
+ * configured for.
584
+ *
585
+ * @param {string} prefix - Limit the release to a specific component.
586
+ * @param {boolean} preRelease - Whether or not to return pre-release
587
+ * versions. Defaults to false.
588
+ */
589
+ async function latestReleaseVersion(github, targetBranch, prefix) {
590
+ var _a;
591
+ const branchPrefix = prefix
592
+ ? prefix.endsWith('-')
593
+ ? prefix.replace(/-$/, '')
594
+ : prefix
595
+ : undefined;
596
+ logger_1.logger.info(`Looking for latest release on branch: ${targetBranch} with prefix: ${prefix}`);
597
+ // only look at the last 250 or so commits to find the latest tag - we
598
+ // don't want to scan the entire repository history if this repo has never
599
+ // been released
600
+ const generator = github.mergeCommitIterator(targetBranch, 250);
601
+ for await (const commitWithPullRequest of generator) {
602
+ const mergedPullRequest = commitWithPullRequest.pullRequest;
603
+ if (!mergedPullRequest) {
604
+ continue;
605
+ }
606
+ const branchName = branch_name_1.BranchName.parse(mergedPullRequest.headBranchName);
607
+ if (!branchName) {
608
+ continue;
609
+ }
610
+ // If branchPrefix is specified, ensure it is found in the branch name.
611
+ // If branchPrefix is not specified, component should also be undefined.
612
+ if (branchName.getComponent() !== branchPrefix) {
613
+ continue;
614
+ }
615
+ const pullRequestTitle = pull_request_title_1.PullRequestTitle.parse(mergedPullRequest.title);
616
+ if (!pullRequestTitle) {
617
+ continue;
618
+ }
619
+ const version = pullRequestTitle.getVersion();
620
+ if ((_a = version === null || version === void 0 ? void 0 : version.preRelease) === null || _a === void 0 ? void 0 : _a.includes('SNAPSHOT')) {
621
+ // FIXME, don't hardcode this
622
+ continue;
623
+ }
624
+ return version;
625
+ }
626
+ return;
627
+ }
628
+ function mergeReleaserConfig(defaultConfig, pathConfig) {
629
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
630
+ return {
631
+ releaseType: (_a = pathConfig.releaseType) !== null && _a !== void 0 ? _a : defaultConfig.releaseType,
632
+ bumpMinorPreMajor: (_b = pathConfig.bumpMinorPreMajor) !== null && _b !== void 0 ? _b : defaultConfig.bumpMinorPreMajor,
633
+ bumpPatchForMinorPreMajor: (_c = pathConfig.bumpPatchForMinorPreMajor) !== null && _c !== void 0 ? _c : defaultConfig.bumpPatchForMinorPreMajor,
634
+ changelogSections: (_d = pathConfig.changelogSections) !== null && _d !== void 0 ? _d : defaultConfig.changelogSections,
635
+ changelogPath: (_e = pathConfig.changelogPath) !== null && _e !== void 0 ? _e : defaultConfig.changelogPath,
636
+ releaseAs: (_f = pathConfig.releaseAs) !== null && _f !== void 0 ? _f : defaultConfig.releaseAs,
637
+ skipGithubRelease: (_g = pathConfig.skipGithubRelease) !== null && _g !== void 0 ? _g : defaultConfig.skipGithubRelease,
638
+ draft: (_h = pathConfig.draft) !== null && _h !== void 0 ? _h : defaultConfig.draft,
639
+ component: (_j = pathConfig.component) !== null && _j !== void 0 ? _j : defaultConfig.component,
640
+ packageName: (_k = pathConfig.packageName) !== null && _k !== void 0 ? _k : defaultConfig.packageName,
641
+ versionFile: (_l = pathConfig.versionFile) !== null && _l !== void 0 ? _l : defaultConfig.versionFile,
642
+ extraFiles: (_m = pathConfig.extraFiles) !== null && _m !== void 0 ? _m : defaultConfig.extraFiles,
643
+ };
644
+ }
645
+ /**
646
+ * Helper to compare if a list of labels fully contains another list of labels
647
+ * @param {string[]} expected List of labels expected to be contained
648
+ * @param {string[]} existing List of existing labels to consider
649
+ */
650
+ function hasAllLabels(expected, existing) {
651
+ const existingSet = new Set(existing);
652
+ for (const label of expected) {
653
+ if (!existingSet.has(label)) {
654
+ return false;
655
+ }
656
+ }
657
+ return true;
658
+ }
659
+ function commitsAfterSha(commits, lastReleaseSha) {
660
+ if (!commits) {
661
+ return [];
662
+ }
663
+ const index = commits.findIndex(commit => commit.sha === lastReleaseSha);
664
+ if (index === -1) {
665
+ return commits;
666
+ }
667
+ return commits.slice(0, index);
668
+ }
557
669
  //# sourceMappingURL=manifest.js.map