release-please 14.10.2 → 14.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/build/src/factories/plugin-factory.d.ts +3 -0
- package/build/src/factories/plugin-factory.js +12 -3
- package/build/src/manifest.d.ts +1 -0
- package/build/src/plugins/maven-workspace.d.ts +48 -2
- package/build/src/plugins/maven-workspace.js +213 -55
- package/build/src/plugins/workspace.d.ts +39 -0
- package/build/src/plugins/workspace.js +94 -27
- package/build/src/util/logger.js +1 -1
- package/package.json +1 -1
- package/schemas/config.json +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
[1]: https://www.npmjs.com/package/release-please?activeTab=versions
|
|
6
6
|
|
|
7
|
+
## [14.11.0](https://github.com/googleapis/release-please/compare/v14.10.2...v14.11.0) (2022-10-05)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **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))
|
|
13
|
+
|
|
7
14
|
## [14.10.2](https://github.com/googleapis/release-please/compare/v14.10.1...v14.10.2) (2022-10-04)
|
|
8
15
|
|
|
9
16
|
|
|
@@ -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,
|
|
27
|
-
|
|
28
|
-
|
|
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
|
};
|
package/build/src/manifest.d.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
99
|
-
|
|
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
|
|
141
|
-
return
|
|
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.
|
|
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 =
|
|
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
|
|
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
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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;
|
package/build/src/util/logger.js
CHANGED
|
@@ -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
package/schemas/config.json
CHANGED
|
@@ -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
|
},
|