release-please 14.10.2 → 14.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@
4
4
 
5
5
  [1]: https://www.npmjs.com/package/release-please?activeTab=versions
6
6
 
7
+ ## [14.11.1](https://github.com/googleapis/release-please/compare/v14.11.0...v14.11.1) (2022-10-10)
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * Explicitly sort PRs by updated desc ([#1685](https://github.com/googleapis/release-please/issues/1685)) ([807bda0](https://github.com/googleapis/release-please/commit/807bda0ab3e09e6116b43cd670bab1115bfdbff2))
13
+
14
+ ## [14.11.0](https://github.com/googleapis/release-please/compare/v14.10.2...v14.11.0) (2022-10-05)
15
+
16
+
17
+ ### Features
18
+
19
+ * **maven-workspace:** Update all discovered pom.xml within the components ([#1667](https://github.com/googleapis/release-please/issues/1667)) ([ace68d3](https://github.com/googleapis/release-please/commit/ace68d346291db6b591b9b3e1735d12f0a2b2bbc))
20
+
7
21
  ## [14.10.2](https://github.com/googleapis/release-please/compare/v14.10.1...v14.10.2) (2022-10-04)
8
22
 
9
23
 
@@ -2,6 +2,7 @@ import { PluginType, RepositoryConfig } from '../manifest';
2
2
  import { GitHub } from '../github';
3
3
  import { ManifestPlugin } from '../plugin';
4
4
  import { VersioningStrategyType } from './versioning-strategy-factory';
5
+ import { Logger } from '../util/logger';
5
6
  export interface PluginFactoryOptions {
6
7
  type: PluginType;
7
8
  github: GitHub;
@@ -10,6 +11,8 @@ export interface PluginFactoryOptions {
10
11
  manifestPath: string;
11
12
  alwaysLinkLocal?: boolean;
12
13
  updateAllPackages?: boolean;
14
+ considerAllArtifacts?: boolean;
15
+ logger?: Logger;
13
16
  }
14
17
  export declare type PluginBuilder = (options: PluginFactoryOptions) => ManifestPlugin;
15
18
  export declare function buildPlugin(options: PluginFactoryOptions): ManifestPlugin;
@@ -23,9 +23,18 @@ const sentence_case_1 = require("../plugins/sentence-case");
23
23
  const group_priority_1 = require("../plugins/group-priority");
24
24
  const pluginFactories = {
25
25
  'linked-versions': options => new linked_versions_1.LinkedVersions(options.github, options.targetBranch, options.repositoryConfig, options.type.groupName, options.type.components),
26
- 'cargo-workspace': options => new cargo_workspace_1.CargoWorkspace(options.github, options.targetBranch, options.repositoryConfig, options),
27
- 'node-workspace': options => new node_workspace_1.NodeWorkspace(options.github, options.targetBranch, options.repositoryConfig, options),
28
- 'maven-workspace': options => new maven_workspace_1.MavenWorkspace(options.github, options.targetBranch, options.repositoryConfig, options),
26
+ 'cargo-workspace': options => new cargo_workspace_1.CargoWorkspace(options.github, options.targetBranch, options.repositoryConfig, {
27
+ ...options,
28
+ ...options.type,
29
+ }),
30
+ 'node-workspace': options => new node_workspace_1.NodeWorkspace(options.github, options.targetBranch, options.repositoryConfig, {
31
+ ...options,
32
+ ...options.type,
33
+ }),
34
+ 'maven-workspace': options => new maven_workspace_1.MavenWorkspace(options.github, options.targetBranch, options.repositoryConfig, {
35
+ ...options,
36
+ ...options.type,
37
+ }),
29
38
  'sentence-case': options => new sentence_case_1.SentenceCase(options.github, options.targetBranch, options.repositoryConfig, options.type.specialWords),
30
39
  'group-priority': options => new group_priority_1.GroupPriority(options.github, options.targetBranch, options.repositoryConfig, options.type.groups),
31
40
  };
@@ -676,6 +676,8 @@ class GitHub {
676
676
  owner: this.repository.owner,
677
677
  repo: this.repository.repo,
678
678
  base: targetBranch,
679
+ sort: 'updated',
680
+ direction: 'desc',
679
681
  })) {
680
682
  for (const pull of pulls) {
681
683
  // The REST API does not have an option for "merged"
@@ -146,6 +146,7 @@ export interface SentenceCasePluginConfig extends ConfigurablePluginType {
146
146
  }
147
147
  export interface WorkspacePluginConfig extends ConfigurablePluginType {
148
148
  merge?: boolean;
149
+ considerAllArtifacts?: boolean;
149
150
  }
150
151
  export interface GroupPriorityPluginConfig extends ConfigurablePluginType {
151
152
  groups: string[];
@@ -1,6 +1,7 @@
1
- import { WorkspacePlugin, AllPackages, DependencyGraph } from './workspace';
1
+ import { WorkspacePlugin, AllPackages, DependencyGraph, WorkspacePluginOptions } from './workspace';
2
2
  import { Version, VersionsMap } from '../version';
3
- import { CandidateReleasePullRequest } from '../manifest';
3
+ import { CandidateReleasePullRequest, RepositoryConfig } from '../manifest';
4
+ import { GitHub } from '../github';
4
5
  interface Gav {
5
6
  groupId: string;
6
7
  artifactId: string;
@@ -11,11 +12,56 @@ interface MavenArtifact extends Gav {
11
12
  name: string;
12
13
  dependencies: Gav[];
13
14
  testDependencies: Gav[];
15
+ managedDependencies: Gav[];
14
16
  pomContent: string;
15
17
  }
18
+ interface MavenWorkspacePluginOptions extends WorkspacePluginOptions {
19
+ considerAllArtifacts?: boolean;
20
+ }
16
21
  export declare class MavenWorkspace extends WorkspacePlugin<MavenArtifact> {
22
+ readonly considerAllArtifacts: boolean;
23
+ constructor(github: GitHub, targetBranch: string, repositoryConfig: RepositoryConfig, options?: MavenWorkspacePluginOptions);
17
24
  private fetchPom;
18
25
  protected buildAllPackages(candidates: CandidateReleasePullRequest[]): Promise<AllPackages<MavenArtifact>>;
26
+ /**
27
+ * Our maven components can have multiple artifacts if using
28
+ * `considerAllArtifacts`. Find the candidate release for the component
29
+ * that contains that maven artifact.
30
+ * @param {MavenArtifact} pkg The artifact to search for
31
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
32
+ * The candidate pull requests indexed by the package name.
33
+ * @returns {CandidateReleasePullRequest | undefined} The associated
34
+ * candidate release or undefined if there is no existing release yet
35
+ */
36
+ protected findCandidateForPackage(pkg: MavenArtifact, candidatesByPackage: Record<string, CandidateReleasePullRequest>): CandidateReleasePullRequest | undefined;
37
+ /**
38
+ * Helper to determine which packages we will use to base our search
39
+ * for touched packages upon. These are usually the packages that
40
+ * have candidate pull requests open.
41
+ *
42
+ * If you configure `updateAllPackages`, we fill force update all
43
+ * packages as if they had a release.
44
+ * @param {DependencyGraph<T>} graph All the packages in the repository
45
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
46
+ * The candidate pull requests indexed by the package name.
47
+ * @returns {string[]} Package names to
48
+ */
49
+ protected packageNamesToUpdate(graph: DependencyGraph<MavenArtifact>, candidatesByPackage: Record<string, CandidateReleasePullRequest>): string[];
50
+ /**
51
+ * Helper to build up all the versions we are modifying in this
52
+ * repository.
53
+ * @param {DependencyGraph<T>} graph All the packages in the repository
54
+ * @param {T[]} orderedPackages A list of packages that are currently
55
+ * updated by the existing candidate pull requests
56
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
57
+ * The candidate pull requests indexed by the package name.
58
+ * @returns A map of all updated versions (package name => Version) and a
59
+ * map of all updated versions (component path => Version).
60
+ */
61
+ protected buildUpdatedVersions(_graph: DependencyGraph<MavenArtifact>, orderedPackages: MavenArtifact[], candidatesByPackage: Record<string, CandidateReleasePullRequest>): Promise<{
62
+ updatedVersions: VersionsMap;
63
+ updatedPathVersions: VersionsMap;
64
+ }>;
19
65
  protected buildGraph(allPackages: MavenArtifact[]): Promise<DependencyGraph<MavenArtifact>>;
20
66
  protected bumpVersion(artifact: MavenArtifact): Version;
21
67
  protected updateCandidate(existingCandidate: CandidateReleasePullRequest, artifact: MavenArtifact, updatedVersions: VersionsMap): CandidateReleasePullRequest;
@@ -16,7 +16,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.MavenWorkspace = void 0;
17
17
  const workspace_1 = require("./workspace");
18
18
  const version_1 = require("../version");
19
- const versioning_strategy_1 = require("../versioning-strategy");
20
19
  const dom = require("@xmldom/xmldom");
21
20
  const xpath = require("xpath");
22
21
  const path_1 = require("path");
@@ -26,65 +25,24 @@ const pull_request_title_1 = require("../util/pull-request-title");
26
25
  const pull_request_body_1 = require("../util/pull-request-body");
27
26
  const branch_name_1 = require("../util/branch-name");
28
27
  const logger_1 = require("../util/logger");
28
+ const java_snapshot_1 = require("../versioning-strategies/java-snapshot");
29
+ const always_bump_patch_1 = require("../versioning-strategies/always-bump-patch");
29
30
  const composite_1 = require("../updaters/composite");
30
31
  const JAVA_RELEASE_TYPES = new Set(['java', 'java-bom', 'java-yoshi', 'maven']);
31
32
  const XPATH_PROJECT_GROUP = '/*[local-name()="project"]/*[local-name()="groupId"]';
32
33
  const XPATH_PROJECT_ARTIFACT = '/*[local-name()="project"]/*[local-name()="artifactId"]';
33
34
  const XPATH_PROJECT_VERSION = '/*[local-name()="project"]/*[local-name()="version"]';
34
35
  const XPATH_PROJECT_DEPENDENCIES = '/*[local-name()="project"]/*[local-name()="dependencies"]/*[local-name()="dependency"]';
36
+ const XPATH_PROJECT_DEPENDENCY_MANAGEMENT_DEPENDENCIES = '/*[local-name()="project"]/*[local-name()="dependencyManagement"]/*[local-name()="dependencies"]/*[local-name()="dependency"]';
35
37
  class MavenWorkspace extends workspace_1.WorkspacePlugin {
38
+ constructor(github, targetBranch, repositoryConfig, options = {}) {
39
+ var _a;
40
+ super(github, targetBranch, repositoryConfig, options);
41
+ this.considerAllArtifacts = (_a = options.considerAllArtifacts) !== null && _a !== void 0 ? _a : true;
42
+ }
36
43
  async fetchPom(path) {
37
44
  const content = await this.github.getFileContentsOnBranch(path, this.targetBranch);
38
- const document = new dom.DOMParser().parseFromString(content.parsedContent);
39
- const groupNodes = xpath.select(XPATH_PROJECT_GROUP, document);
40
- if (groupNodes.length === 0) {
41
- this.logger.warn(`Missing project.groupId in ${path}`);
42
- return;
43
- }
44
- const artifactNodes = xpath.select(XPATH_PROJECT_ARTIFACT, document);
45
- if (artifactNodes.length === 0) {
46
- this.logger.warn(`Missing project.artifactId in ${path}`);
47
- return;
48
- }
49
- const versionNodes = xpath.select(XPATH_PROJECT_VERSION, document);
50
- if (versionNodes.length === 0) {
51
- this.logger.warn(`Missing project.version in ${path}`);
52
- return;
53
- }
54
- const dependencies = [];
55
- const testDependencies = [];
56
- for (const dependencyNode of xpath.select(XPATH_PROJECT_DEPENDENCIES, document)) {
57
- const parsedNode = (0, pom_xml_1.parseDependencyNode)(dependencyNode);
58
- if (!parsedNode.version) {
59
- continue;
60
- }
61
- if (parsedNode.scope === 'test') {
62
- testDependencies.push({
63
- groupId: parsedNode.groupId,
64
- artifactId: parsedNode.artifactId,
65
- version: parsedNode.version,
66
- });
67
- }
68
- else {
69
- dependencies.push({
70
- groupId: parsedNode.groupId,
71
- artifactId: parsedNode.artifactId,
72
- version: parsedNode.version,
73
- });
74
- }
75
- }
76
- const groupId = groupNodes[0].firstChild.textContent;
77
- const artifactId = artifactNodes[0].firstChild.textContent;
78
- return {
79
- path,
80
- groupId,
81
- artifactId,
82
- name: `${groupId}:${artifactId}`,
83
- version: versionNodes[0].firstChild.textContent,
84
- dependencies,
85
- testDependencies,
86
- pomContent: content.parsedContent,
87
- };
45
+ return parseMavenArtifact(content.parsedContent, path, this.logger);
88
46
  }
89
47
  async buildAllPackages(candidates) {
90
48
  const allPackages = [];
@@ -95,8 +53,11 @@ class MavenWorkspace extends workspace_1.WorkspacePlugin {
95
53
  const path = (0, path_1.dirname)(pomFile);
96
54
  const config = this.repositoryConfig[path];
97
55
  if (!config) {
98
- this.logger.info(`path '${path}' not configured, ignoring '${pomFile}'`);
99
- continue;
56
+ if (!this.considerAllArtifacts) {
57
+ this.logger.info(`path '${path}' not configured, ignoring '${pomFile}'`);
58
+ continue;
59
+ }
60
+ this.logger.info(`path '${path}' not configured, but 'considerAllArtifacts' option enabled`);
100
61
  }
101
62
  const mavenArtifact = await this.fetchPom(pomFile);
102
63
  if (!mavenArtifact) {
@@ -117,16 +78,126 @@ class MavenWorkspace extends workspace_1.WorkspacePlugin {
117
78
  candidatesByPackage,
118
79
  };
119
80
  }
81
+ /**
82
+ * Our maven components can have multiple artifacts if using
83
+ * `considerAllArtifacts`. Find the candidate release for the component
84
+ * that contains that maven artifact.
85
+ * @param {MavenArtifact} pkg The artifact to search for
86
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
87
+ * The candidate pull requests indexed by the package name.
88
+ * @returns {CandidateReleasePullRequest | undefined} The associated
89
+ * candidate release or undefined if there is no existing release yet
90
+ */
91
+ findCandidateForPackage(pkg, candidatesByPackage) {
92
+ this.logger.debug(`Looking for existing candidate for ${pkg.name}`);
93
+ const packageName = this.packageNameFromPackage(pkg);
94
+ const existingCandidate = candidatesByPackage[packageName];
95
+ if (existingCandidate) {
96
+ return existingCandidate;
97
+ }
98
+ // fall back to finding the nearest candidate for that artifact
99
+ return Object.values(candidatesByPackage).find(candidate => pkg.path.startsWith(`${candidate.path}/`));
100
+ }
101
+ /**
102
+ * Helper to determine which packages we will use to base our search
103
+ * for touched packages upon. These are usually the packages that
104
+ * have candidate pull requests open.
105
+ *
106
+ * If you configure `updateAllPackages`, we fill force update all
107
+ * packages as if they had a release.
108
+ * @param {DependencyGraph<T>} graph All the packages in the repository
109
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
110
+ * The candidate pull requests indexed by the package name.
111
+ * @returns {string[]} Package names to
112
+ */
113
+ packageNamesToUpdate(graph, candidatesByPackage) {
114
+ if (this.considerAllArtifacts) {
115
+ const candidatePaths = Object.values(candidatesByPackage).map(candidate => candidate.path);
116
+ // Find artifacts that are in an existing candidate release
117
+ return Array.from(graph.values())
118
+ .filter(({ value }) => candidatePaths.find(path => value.path === path || value.path.startsWith(`${path}/`)))
119
+ .map(({ value }) => this.packageNameFromPackage(value));
120
+ }
121
+ return super.packageNamesToUpdate(graph, candidatesByPackage);
122
+ }
123
+ /**
124
+ * Helper to build up all the versions we are modifying in this
125
+ * repository.
126
+ * @param {DependencyGraph<T>} graph All the packages in the repository
127
+ * @param {T[]} orderedPackages A list of packages that are currently
128
+ * updated by the existing candidate pull requests
129
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
130
+ * The candidate pull requests indexed by the package name.
131
+ * @returns A map of all updated versions (package name => Version) and a
132
+ * map of all updated versions (component path => Version).
133
+ */
134
+ async buildUpdatedVersions(_graph, orderedPackages, candidatesByPackage) {
135
+ const updatedVersions = new Map();
136
+ const updatedPathVersions = new Map();
137
+ // Look for updated pom.xml files
138
+ for (const [_, candidate] of Object.entries(candidatesByPackage)) {
139
+ const pomUpdates = candidate.pullRequest.updates.filter(update => update.path.endsWith('pom.xml'));
140
+ for (const pomUpdate of pomUpdates) {
141
+ if (!pomUpdate.cachedFileContents) {
142
+ pomUpdate.cachedFileContents =
143
+ await this.github.getFileContentsOnBranch(pomUpdate.path, this.targetBranch);
144
+ }
145
+ if (pomUpdate.cachedFileContents) {
146
+ // pre-run the version updater on this artifact and extract the
147
+ // new version
148
+ const updatedArtifact = parseMavenArtifact(pomUpdate.updater.updateContent(pomUpdate.cachedFileContents.parsedContent), pomUpdate.path, this.logger);
149
+ if (updatedArtifact) {
150
+ this.logger.debug(`updating ${updatedArtifact.name} to ${updatedArtifact.version}`);
151
+ updatedVersions.set(updatedArtifact.name, version_1.Version.parse(updatedArtifact.version));
152
+ }
153
+ }
154
+ else {
155
+ this.logger.warn(`${pomUpdate.path} does not have cached contents`);
156
+ }
157
+ }
158
+ if (candidate.pullRequest.version) {
159
+ updatedPathVersions.set(candidate.path, candidate.pullRequest.version);
160
+ }
161
+ }
162
+ for (const pkg of orderedPackages) {
163
+ const packageName = this.packageNameFromPackage(pkg);
164
+ this.logger.debug(`Looking for next version for: ${packageName}`);
165
+ const existingCandidate = candidatesByPackage[packageName];
166
+ if (existingCandidate) {
167
+ const version = existingCandidate.pullRequest.version;
168
+ this.logger.debug(`version: ${version} from release-please`);
169
+ updatedVersions.set(packageName, version);
170
+ }
171
+ else {
172
+ const version = this.bumpVersion(pkg);
173
+ if (updatedVersions.get(packageName)) {
174
+ this.logger.debug('version already set');
175
+ }
176
+ else {
177
+ this.logger.debug(`version: ${version} forced bump`);
178
+ updatedVersions.set(packageName, version);
179
+ updatedPathVersions.set(this.pathFromPackage(pkg), version);
180
+ }
181
+ }
182
+ }
183
+ return {
184
+ updatedVersions,
185
+ updatedPathVersions,
186
+ };
187
+ }
120
188
  async buildGraph(allPackages) {
189
+ this.logger.trace('building graph', allPackages);
121
190
  const artifactsByName = allPackages.reduce((collection, mavenArtifact) => {
122
191
  collection[mavenArtifact.name] = mavenArtifact;
123
192
  return collection;
124
193
  }, {});
194
+ this.logger.trace('artifacts by name', artifactsByName);
125
195
  const graph = new Map();
126
196
  for (const mavenArtifact of allPackages) {
127
197
  const allDeps = [
128
198
  ...mavenArtifact.dependencies,
129
199
  ...mavenArtifact.testDependencies,
200
+ ...mavenArtifact.managedDependencies,
130
201
  ];
131
202
  const workspaceDeps = allDeps.filter(dep => artifactsByName[packageNameFromGav(dep)]);
132
203
  graph.set(mavenArtifact.name, {
@@ -137,8 +208,8 @@ class MavenWorkspace extends workspace_1.WorkspacePlugin {
137
208
  return graph;
138
209
  }
139
210
  bumpVersion(artifact) {
140
- const version = version_1.Version.parse(artifact.version);
141
- return new versioning_strategy_1.PatchVersionUpdate().bump(version);
211
+ const strategy = new java_snapshot_1.JavaSnapshot(new always_bump_patch_1.AlwaysBumpPatch());
212
+ return strategy.bump(version_1.Version.parse(artifact.version), [FAKE_COMMIT]);
142
213
  }
143
214
  updateCandidate(existingCandidate, artifact, updatedVersions) {
144
215
  const version = updatedVersions.get(artifact.name);
@@ -251,4 +322,91 @@ function getChangelogDepsNotes(artifact, updater, updatedVersions, logger = logg
251
322
  }
252
323
  return '';
253
324
  }
325
+ /**
326
+ * Helper to parse a pom.xml file and extract important fields
327
+ * @param {string} pomContent The XML contents as a string
328
+ * @param {string} path The path to the file in the repository including the filename.
329
+ * @param {Logger} logger Context logger
330
+ * @returns {MavenArtifact | undefined} Returns undefined if we are missing key
331
+ * attributes. We log a warning in these cases.
332
+ */
333
+ function parseMavenArtifact(pomContent, path, logger) {
334
+ const document = new dom.DOMParser().parseFromString(pomContent);
335
+ const groupNodes = xpath.select(XPATH_PROJECT_GROUP, document);
336
+ if (groupNodes.length === 0) {
337
+ logger.warn(`Missing project.groupId in ${path}`);
338
+ return;
339
+ }
340
+ const artifactNodes = xpath.select(XPATH_PROJECT_ARTIFACT, document);
341
+ if (artifactNodes.length === 0) {
342
+ logger.warn(`Missing project.artifactId in ${path}`);
343
+ return;
344
+ }
345
+ const versionNodes = xpath.select(XPATH_PROJECT_VERSION, document);
346
+ if (versionNodes.length === 0) {
347
+ logger.warn(`Missing project.version in ${path}`);
348
+ return;
349
+ }
350
+ const dependencies = [];
351
+ const testDependencies = [];
352
+ for (const dependencyNode of xpath.select(XPATH_PROJECT_DEPENDENCIES, document)) {
353
+ const parsedNode = (0, pom_xml_1.parseDependencyNode)(dependencyNode);
354
+ if (!parsedNode.version) {
355
+ continue;
356
+ }
357
+ if (parsedNode.scope === 'test') {
358
+ testDependencies.push({
359
+ groupId: parsedNode.groupId,
360
+ artifactId: parsedNode.artifactId,
361
+ version: parsedNode.version,
362
+ });
363
+ }
364
+ else {
365
+ dependencies.push({
366
+ groupId: parsedNode.groupId,
367
+ artifactId: parsedNode.artifactId,
368
+ version: parsedNode.version,
369
+ });
370
+ }
371
+ }
372
+ const managedDependencies = [];
373
+ for (const dependencyNode of xpath.select(XPATH_PROJECT_DEPENDENCY_MANAGEMENT_DEPENDENCIES, document)) {
374
+ const parsedNode = (0, pom_xml_1.parseDependencyNode)(dependencyNode);
375
+ if (!parsedNode.version) {
376
+ continue;
377
+ }
378
+ managedDependencies.push({
379
+ groupId: parsedNode.groupId,
380
+ artifactId: parsedNode.artifactId,
381
+ version: parsedNode.version,
382
+ });
383
+ }
384
+ const groupId = groupNodes[0].firstChild.textContent;
385
+ const artifactId = artifactNodes[0].firstChild.textContent;
386
+ return {
387
+ path: (0, path_1.dirname)(path),
388
+ groupId,
389
+ artifactId,
390
+ name: `${groupId}:${artifactId}`,
391
+ version: versionNodes[0].firstChild.textContent,
392
+ dependencies,
393
+ testDependencies,
394
+ managedDependencies,
395
+ pomContent,
396
+ };
397
+ }
398
+ // We use a fake commit to leverage the Java versioning strategy
399
+ // (it should be a patch version bump and potentially remove the
400
+ // -SNAPSHOT portion of the version)
401
+ const FAKE_COMMIT = {
402
+ message: 'fix: fake fix',
403
+ type: 'fix',
404
+ scope: null,
405
+ notes: [],
406
+ references: [],
407
+ bareMessage: 'fake fix',
408
+ breaking: false,
409
+ sha: 'abc123',
410
+ files: [],
411
+ };
254
412
  //# sourceMappingURL=maven-workspace.js.map
@@ -35,6 +35,45 @@ export declare abstract class WorkspacePlugin<T> extends ManifestPlugin {
35
35
  private merge;
36
36
  constructor(github: GitHub, targetBranch: string, repositoryConfig: RepositoryConfig, options?: WorkspacePluginOptions);
37
37
  run(candidates: CandidateReleasePullRequest[]): Promise<CandidateReleasePullRequest[]>;
38
+ /**
39
+ * Helper for finding a candidate release based on the package name.
40
+ * By default, we assume that the package name matches the release
41
+ * component.
42
+ * @param {T} pkg The package being released
43
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
44
+ * The candidate pull requests indexed by the package name.
45
+ * @returns {CandidateReleasePullRequest | undefined} The associated
46
+ * candidate release or undefined if there is no existing release yet
47
+ */
48
+ protected findCandidateForPackage(pkg: T, candidatesByPackage: Record<string, CandidateReleasePullRequest>): CandidateReleasePullRequest | undefined;
49
+ /**
50
+ * Helper to determine which packages we will use to base our search
51
+ * for touched packages upon. These are usually the packages that
52
+ * have candidate pull requests open.
53
+ *
54
+ * If you configure `updateAllPackages`, we fill force update all
55
+ * packages as if they had a release.
56
+ * @param {DependencyGraph<T>} graph All the packages in the repository
57
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
58
+ * The candidate pull requests indexed by the package name.
59
+ * @returns {string[]} Package names to
60
+ */
61
+ protected packageNamesToUpdate(graph: DependencyGraph<T>, candidatesByPackage: Record<string, CandidateReleasePullRequest>): string[];
62
+ /**
63
+ * Helper to build up all the versions we are modifying in this
64
+ * repository.
65
+ * @param {DependencyGraph<T>} _graph All the packages in the repository
66
+ * @param {T[]} orderedPackages A list of packages that are currently
67
+ * updated by the existing candidate pull requests
68
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
69
+ * The candidate pull requests indexed by the package name.
70
+ * @returns A map of all updated versions (package name => Version) and a
71
+ * map of all updated versions (component path => Version).
72
+ */
73
+ protected buildUpdatedVersions(_graph: DependencyGraph<T>, orderedPackages: T[], candidatesByPackage: Record<string, CandidateReleasePullRequest>): Promise<{
74
+ updatedVersions: VersionsMap;
75
+ updatedPathVersions: VersionsMap;
76
+ }>;
38
77
  /**
39
78
  * Given a package, return the new bumped version after updating
40
79
  * the dependency.
@@ -61,44 +61,39 @@ class WorkspacePlugin extends plugin_1.ManifestPlugin {
61
61
  const { allPackages, candidatesByPackage } = await this.buildAllPackages(inScopeCandidates);
62
62
  this.logger.info(`Building dependency graph for ${allPackages.length} packages`);
63
63
  const graph = await this.buildGraph(allPackages);
64
- const packageNamesToUpdate = this.updateAllPackages
65
- ? allPackages.map(this.packageNameFromPackage)
66
- : Object.keys(candidatesByPackage);
64
+ const packageNamesToUpdate = this.packageNamesToUpdate(graph, candidatesByPackage);
67
65
  const orderedPackages = this.buildGraphOrder(graph, packageNamesToUpdate);
68
66
  this.logger.info(`Updating ${orderedPackages.length} packages`);
69
- const updatedVersions = new Map();
70
- const updatedPathVersions = new Map();
71
- for (const pkg of orderedPackages) {
72
- const packageName = this.packageNameFromPackage(pkg);
73
- this.logger.debug(`package: ${packageName}`);
74
- const existingCandidate = candidatesByPackage[packageName];
75
- if (existingCandidate) {
76
- const version = existingCandidate.pullRequest.version;
77
- this.logger.debug(`version: ${version} from release-please`);
78
- updatedVersions.set(packageName, version);
79
- }
80
- else {
81
- const version = this.bumpVersion(pkg);
82
- this.logger.debug(`version: ${version} forced bump`);
83
- updatedVersions.set(packageName, version);
84
- updatedPathVersions.set(this.pathFromPackage(pkg), version);
85
- }
86
- }
67
+ const { updatedVersions, updatedPathVersions } = await this.buildUpdatedVersions(graph, orderedPackages, candidatesByPackage);
87
68
  let newCandidates = [];
69
+ // In some cases, there are multiple packages within a single candidate. We
70
+ // only want to process each candidate package once.
71
+ const newCandidatePaths = new Set();
88
72
  for (const pkg of orderedPackages) {
89
- const packageName = this.packageNameFromPackage(pkg);
90
- const existingCandidate = candidatesByPackage[packageName];
73
+ const existingCandidate = this.findCandidateForPackage(pkg, candidatesByPackage);
91
74
  if (existingCandidate) {
92
75
  // if already has an pull request, update the changelog and update
93
- this.logger.info(`Updating exising candidate pull request for ${this.packageNameFromPackage(pkg)}`);
94
- const newCandidate = this.updateCandidate(existingCandidate, pkg, updatedVersions);
95
- newCandidates.push(newCandidate);
76
+ this.logger.info(`Updating exising candidate pull request for ${this.packageNameFromPackage(pkg)}, path: ${existingCandidate.path}`);
77
+ if (newCandidatePaths.has(existingCandidate.path)) {
78
+ this.logger.info(`Already updated candidate for path: ${existingCandidate.path}`);
79
+ }
80
+ else {
81
+ const newCandidate = this.updateCandidate(existingCandidate, pkg, updatedVersions);
82
+ newCandidatePaths.add(newCandidate.path);
83
+ newCandidates.push(newCandidate);
84
+ }
96
85
  }
97
86
  else {
98
87
  // otherwise, build a new pull request with changelog and entry update
99
88
  this.logger.info(`Creating new candidate pull request for ${this.packageNameFromPackage(pkg)}`);
100
89
  const newCandidate = this.newCandidate(pkg, updatedVersions);
101
- newCandidates.push(newCandidate);
90
+ if (newCandidatePaths.has(newCandidate.path)) {
91
+ this.logger.info(`Already created new candidate for path: ${newCandidate.path}`);
92
+ }
93
+ else {
94
+ newCandidatePaths.add(newCandidate.path);
95
+ newCandidates.push(newCandidate);
96
+ }
102
97
  }
103
98
  }
104
99
  if (this.merge) {
@@ -119,6 +114,73 @@ class WorkspacePlugin extends plugin_1.ManifestPlugin {
119
114
  newCandidates = this.postProcessCandidates(newCandidates, updatedVersions);
120
115
  return [...outOfScopeCandidates, ...newCandidates];
121
116
  }
117
+ /**
118
+ * Helper for finding a candidate release based on the package name.
119
+ * By default, we assume that the package name matches the release
120
+ * component.
121
+ * @param {T} pkg The package being released
122
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
123
+ * The candidate pull requests indexed by the package name.
124
+ * @returns {CandidateReleasePullRequest | undefined} The associated
125
+ * candidate release or undefined if there is no existing release yet
126
+ */
127
+ findCandidateForPackage(pkg, candidatesByPackage) {
128
+ const packageName = this.packageNameFromPackage(pkg);
129
+ return candidatesByPackage[packageName];
130
+ }
131
+ /**
132
+ * Helper to determine which packages we will use to base our search
133
+ * for touched packages upon. These are usually the packages that
134
+ * have candidate pull requests open.
135
+ *
136
+ * If you configure `updateAllPackages`, we fill force update all
137
+ * packages as if they had a release.
138
+ * @param {DependencyGraph<T>} graph All the packages in the repository
139
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
140
+ * The candidate pull requests indexed by the package name.
141
+ * @returns {string[]} Package names to
142
+ */
143
+ packageNamesToUpdate(graph, candidatesByPackage) {
144
+ if (this.updateAllPackages) {
145
+ return Array.from(graph.values()).map(({ value }) => this.packageNameFromPackage(value));
146
+ }
147
+ return Object.keys(candidatesByPackage);
148
+ }
149
+ /**
150
+ * Helper to build up all the versions we are modifying in this
151
+ * repository.
152
+ * @param {DependencyGraph<T>} _graph All the packages in the repository
153
+ * @param {T[]} orderedPackages A list of packages that are currently
154
+ * updated by the existing candidate pull requests
155
+ * @param {Record<string, CandidateReleasePullRequest} candidatesByPackage
156
+ * The candidate pull requests indexed by the package name.
157
+ * @returns A map of all updated versions (package name => Version) and a
158
+ * map of all updated versions (component path => Version).
159
+ */
160
+ async buildUpdatedVersions(_graph, orderedPackages, candidatesByPackage) {
161
+ const updatedVersions = new Map();
162
+ const updatedPathVersions = new Map();
163
+ for (const pkg of orderedPackages) {
164
+ const packageName = this.packageNameFromPackage(pkg);
165
+ this.logger.debug(`package: ${packageName}`);
166
+ const existingCandidate = candidatesByPackage[packageName];
167
+ if (existingCandidate) {
168
+ const version = existingCandidate.pullRequest.version;
169
+ this.logger.debug(`version: ${version} from release-please`);
170
+ updatedVersions.set(packageName, version);
171
+ }
172
+ else {
173
+ const version = this.bumpVersion(pkg);
174
+ this.logger.debug(`version: ${version} forced bump`);
175
+ updatedVersions.set(packageName, version);
176
+ updatedPathVersions.set(this.pathFromPackage(pkg), version);
177
+ }
178
+ }
179
+ return {
180
+ updatedVersions,
181
+ updatedPathVersions,
182
+ };
183
+ }
122
184
  /**
123
185
  * Helper to invert the graph from package => packages that it depends on
124
186
  * to package => packages that depend on it.
@@ -163,6 +225,7 @@ class WorkspacePlugin extends plugin_1.ManifestPlugin {
163
225
  return Array.from(visited).sort((a, b) => this.packageNameFromPackage(a).localeCompare(this.packageNameFromPackage(b)));
164
226
  }
165
227
  visitPostOrder(graph, name, visited, path) {
228
+ this.logger.debug(`visiting ${name}, path: ${path}`);
166
229
  if (path.indexOf(name) !== -1) {
167
230
  throw new Error(`found cycle in dependency graph: ${path.join(' -> ')} -> ${name}`);
168
231
  }
@@ -178,12 +241,16 @@ class WorkspacePlugin extends plugin_1.ManifestPlugin {
178
241
  this.logger.warn(`dependency not found in graph: ${depName}`);
179
242
  return;
180
243
  }
244
+ this.logger.info(`visiting ${depName} next`);
181
245
  this.visitPostOrder(graph, depName, visited, nextPath);
182
246
  }
183
247
  if (!visited.has(node.value)) {
184
248
  this.logger.debug(`marking ${name} as visited and adding ${this.packageNameFromPackage(node.value)} to order`);
185
249
  visited.add(node.value);
186
250
  }
251
+ else {
252
+ this.logger.debug(`${node.value} already visited`);
253
+ }
187
254
  }
188
255
  }
189
256
  exports.WorkspacePlugin = WorkspacePlugin;
@@ -46,7 +46,7 @@ class CheckpointLogger {
46
46
  }
47
47
  exports.CheckpointLogger = CheckpointLogger;
48
48
  /* eslint-enable @typescript-eslint/no-explicit-any */
49
- exports.logger = new CheckpointLogger();
49
+ exports.logger = new CheckpointLogger(true);
50
50
  function setLogger(userLogger) {
51
51
  exports.logger = userLogger;
52
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-please",
3
- "version": "14.10.2",
3
+ "version": "14.11.1",
4
4
  "description": "generate release PRs based on the conventionalcommits.org spec",
5
5
  "main": "./build/src/index.js",
6
6
  "bin": "./build/src/bin/release-please.js",
@@ -292,6 +292,10 @@
292
292
  "merge": {
293
293
  "description": "Whether to merge in-scope pull requests into a combined release pull request. Defaults to `true`.",
294
294
  "type": "boolean"
295
+ },
296
+ "considerAllArtifacts": {
297
+ "description": "Whether to analyze all packages in the workspace for cross-component version bumping. This currently only works for the maven-workspace plugin. Defaults to `true`.",
298
+ "type": "boolean"
295
299
  }
296
300
  }
297
301
  },