1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.release.phase;
20
21 import java.nio.file.FileSystems;
22 import java.nio.file.Paths;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27
28 import org.apache.maven.artifact.ArtifactUtils;
29 import org.apache.maven.project.MavenProject;
30 import org.apache.maven.scm.manager.NoSuchScmProviderException;
31 import org.apache.maven.scm.provider.ScmProvider;
32 import org.apache.maven.scm.repository.ScmRepository;
33 import org.apache.maven.scm.repository.ScmRepositoryException;
34 import org.apache.maven.shared.release.ReleaseExecutionException;
35 import org.apache.maven.shared.release.ReleaseResult;
36 import org.apache.maven.shared.release.config.ReleaseDescriptor;
37 import org.apache.maven.shared.release.env.ReleaseEnvironment;
38 import org.apache.maven.shared.release.policy.PolicyException;
39 import org.apache.maven.shared.release.policy.version.VersionPolicy;
40 import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
41 import org.apache.maven.shared.release.scm.ScmRepositoryConfigurator;
42 import org.apache.maven.shared.release.util.CiFriendlyVersion;
43 import org.apache.maven.shared.release.util.ReleaseUtil;
44 import org.apache.maven.shared.release.versions.VersionParseException;
45 import org.codehaus.plexus.components.interactivity.Prompter;
46 import org.codehaus.plexus.components.interactivity.PrompterException;
47 import org.slf4j.Logger;
48
49 import static java.util.Objects.requireNonNull;
50 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public abstract class AbstractMapVersionsPhase extends AbstractReleasePhase {
80
81
82
83 private final ScmRepositoryConfigurator scmRepositoryConfigurator;
84
85
86
87
88 private final Prompter prompter;
89
90
91
92
93 private final Map<String, VersionPolicy> versionPolicies;
94
95
96
97
98 private final boolean convertToSnapshot;
99
100
101
102
103 private final boolean convertToBranch;
104
105 private final Set<String> exclusionPatterns = new HashSet<>();
106
107 public AbstractMapVersionsPhase(
108 ScmRepositoryConfigurator scmRepositoryConfigurator,
109 Prompter prompter,
110 Map<String, VersionPolicy> versionPolicies,
111 boolean convertToSnapshot,
112 boolean convertToBranch) {
113 this.scmRepositoryConfigurator = requireNonNull(scmRepositoryConfigurator);
114 this.prompter = requireNonNull(prompter);
115 this.versionPolicies = requireNonNull(versionPolicies);
116 this.convertToSnapshot = convertToSnapshot;
117 this.convertToBranch = convertToBranch;
118 }
119
120 @Override
121 public ReleaseResult execute(
122 ReleaseDescriptor releaseDescriptor,
123 ReleaseEnvironment releaseEnvironment,
124 List<MavenProject> reactorProjects)
125 throws ReleaseExecutionException {
126 ReleaseResult result = new ReleaseResult();
127
128 List<String> additionalExcludes = releaseDescriptor.getCheckModificationExcludes();
129
130 if (additionalExcludes != null) {
131 exclusionPatterns.addAll(additionalExcludes);
132 }
133
134 MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
135
136 if (releaseDescriptor.isAutoVersionSubmodules() && ArtifactUtils.isSnapshot(rootProject.getVersion())) {
137
138 MavenProject project = rootProject;
139
140 String projectId = ArtifactUtils.versionlessKey(project.getGroupId(), project.getArtifactId());
141
142 String nextVersion = resolveNextVersion(project, projectId, releaseDescriptor, releaseEnvironment);
143
144 if (!convertToSnapshot) {
145 releaseDescriptor.addReleaseVersion(projectId, nextVersion);
146 } else if (releaseDescriptor.isBranchCreation() && convertToBranch) {
147 releaseDescriptor.addReleaseVersion(projectId, nextVersion);
148 } else {
149 releaseDescriptor.addDevelopmentVersion(projectId, nextVersion);
150 }
151
152 for (MavenProject subProject : reactorProjects) {
153 String subProjectId = ArtifactUtils.versionlessKey(subProject.getGroupId(), subProject.getArtifactId());
154
155 if (convertToSnapshot) {
156 String subProjectNextVersion = releaseDescriptor.getProjectDevelopmentVersion(subProjectId);
157 String v;
158 if (subProjectNextVersion != null) {
159 v = subProjectNextVersion;
160 } else if (ArtifactUtils.isSnapshot(subProject.getVersion())) {
161 v = nextVersion;
162 } else {
163 v = subProject.getVersion();
164 }
165
166 if (releaseDescriptor.isBranchCreation() && convertToBranch) {
167 releaseDescriptor.addReleaseVersion(subProjectId, v);
168 } else {
169 releaseDescriptor.addDevelopmentVersion(subProjectId, v);
170 }
171 } else {
172 String subProjectNextVersion = releaseDescriptor.getProjectReleaseVersion(subProjectId);
173 if (subProjectNextVersion != null) {
174 releaseDescriptor.addReleaseVersion(subProjectId, subProjectNextVersion);
175 } else {
176 releaseDescriptor.addReleaseVersion(subProjectId, nextVersion);
177 }
178 }
179 }
180 } else {
181
182 for (MavenProject project : reactorProjects) {
183 String projectId = ArtifactUtils.versionlessKey(project.getGroupId(), project.getArtifactId());
184
185 boolean isExcludedPathFound = false;
186 if (project.getFile() != null) {
187 isExcludedPathFound = exclusionPatterns.stream()
188 .anyMatch(exclusionPattern -> FileSystems.getDefault()
189 .getPathMatcher("glob:" + exclusionPattern)
190 .matches(Paths.get(project.getFile().getPath())));
191 }
192 if (!isExcludedPathFound) {
193 String nextVersion = resolveNextVersion(project, projectId, releaseDescriptor, releaseEnvironment);
194 if (!convertToSnapshot) {
195 releaseDescriptor.addReleaseVersion(projectId, nextVersion);
196 } else if (releaseDescriptor.isBranchCreation() && convertToBranch) {
197 releaseDescriptor.addReleaseVersion(projectId, nextVersion);
198 } else {
199 releaseDescriptor.addDevelopmentVersion(projectId, nextVersion);
200 }
201 }
202 }
203 }
204
205 result.setResultCode(ReleaseResult.SUCCESS);
206
207 return result;
208 }
209
210 private String resolveNextVersion(
211 MavenProject project,
212 String projectId,
213 ReleaseDescriptor releaseDescriptor,
214 ReleaseEnvironment releaseEnvironment)
215 throws ReleaseExecutionException {
216 String defaultVersion;
217 if (convertToBranch) {
218
219 if (!(releaseDescriptor.isUpdateBranchVersions()
220 && (ArtifactUtils.isSnapshot(project.getVersion())
221 || releaseDescriptor.isUpdateVersionsToSnapshot()))) {
222 return project.getVersion();
223 }
224
225 defaultVersion = getReleaseVersion(projectId, releaseDescriptor);
226 } else if (!convertToSnapshot)
227 {
228 defaultVersion = getReleaseVersion(projectId, releaseDescriptor);
229 } else if (releaseDescriptor.isBranchCreation()) {
230
231 if (!(ArtifactUtils.isSnapshot(project.getVersion()) && releaseDescriptor.isUpdateWorkingCopyVersions())) {
232 return project.getVersion();
233 }
234
235 defaultVersion = getDevelopmentVersion(projectId, releaseDescriptor);
236 } else {
237
238 if (!(releaseDescriptor.isUpdateWorkingCopyVersions())) {
239 return project.getVersion();
240 }
241
242 defaultVersion = getDevelopmentVersion(projectId, releaseDescriptor);
243 }
244
245
246 String suggestedVersion = null;
247 String nextVersion = defaultVersion;
248 String messageFormat = null;
249 try {
250 while (nextVersion == null || ArtifactUtils.isSnapshot(nextVersion) != convertToSnapshot) {
251 if (suggestedVersion == null) {
252 String baseVersion = null;
253 if (convertToSnapshot) {
254 baseVersion = getReleaseVersion(projectId, releaseDescriptor);
255 }
256
257 if (baseVersion == null) {
258 baseVersion = project.getVersion();
259 }
260
261 try {
262 try {
263 suggestedVersion = resolveSuggestedVersion(
264 project, baseVersion, releaseDescriptor, releaseEnvironment);
265 } catch (VersionParseException e) {
266 if (releaseDescriptor.isInteractive()) {
267 suggestedVersion =
268 resolveSuggestedVersion(project, "1.0", releaseDescriptor, releaseEnvironment);
269 } else {
270 throw new ReleaseExecutionException(
271 "Error parsing version, cannot determine next " + "version: " + e.getMessage(),
272 e);
273 }
274 }
275 } catch (PolicyException | VersionParseException e) {
276 throw new ReleaseExecutionException(e.getMessage(), e);
277 }
278 }
279
280 if (releaseDescriptor.isInteractive()) {
281 if (messageFormat == null) {
282 messageFormat = "What is the " + getContextString(releaseDescriptor) + " version for \"%s\"? ("
283 + buffer().project("%s") + ")";
284 }
285 String message = String.format(messageFormat, project.getName(), project.getArtifactId());
286 nextVersion = prompter.prompt(message, suggestedVersion);
287
288
289 } else if (defaultVersion == null) {
290 nextVersion = suggestedVersion;
291 } else if (convertToSnapshot) {
292 throw new ReleaseExecutionException(defaultVersion + " is invalid, expected a snapshot");
293 } else {
294 throw new ReleaseExecutionException(defaultVersion + " is invalid, expected a non-snapshot");
295 }
296 }
297 } catch (PrompterException e) {
298 throw new ReleaseExecutionException("Error reading version from input handler: " + e.getMessage(), e);
299 }
300 return nextVersion;
301 }
302
303 private String getContextString(ReleaseDescriptor releaseDescriptor) {
304 if (convertToBranch) {
305 return "branch";
306 }
307 if (!convertToSnapshot) {
308 return "release";
309 }
310 if (releaseDescriptor.isBranchCreation()) {
311 return "new working copy";
312 }
313 return "new development";
314 }
315
316 private String resolveSuggestedVersion(
317 MavenProject project,
318 String baseVersion,
319 ReleaseDescriptor releaseDescriptor,
320 ReleaseEnvironment releaseEnvironment)
321 throws PolicyException, VersionParseException {
322 String policyId = releaseDescriptor.getProjectVersionPolicyId();
323 VersionPolicy policy = versionPolicies.get(policyId);
324 if (policy == null) {
325 throw new PolicyException("Policy '" + policyId + "' is unknown, available: " + versionPolicies.keySet());
326 }
327
328 VersionPolicyRequest request = new VersionPolicyRequest().setVersion(baseVersion);
329
330 if (releaseDescriptor.getProjectVersionPolicyConfig() != null) {
331 request.setConfig(releaseDescriptor.getProjectVersionPolicyConfig().toString());
332 }
333 request.setWorkingDirectory(releaseDescriptor.getWorkingDirectory());
334
335 if (CiFriendlyVersion.isCiFriendlyVersion(getOriginalVersion(project))) {
336 String sha1 = CiFriendlyVersion.resolveSha1Property(project.getProperties(), releaseDescriptor);
337 request.setVersion(baseVersion.replace(sha1, ""));
338 }
339
340 if (scmRepositoryConfigurator != null && releaseDescriptor.getScmSourceUrl() != null) {
341 try {
342 ScmRepository repository = scmRepositoryConfigurator.getConfiguredRepository(
343 releaseDescriptor, releaseEnvironment.getSettings());
344
345 ScmProvider provider = scmRepositoryConfigurator.getRepositoryProvider(repository);
346
347 request.setScmRepository(repository);
348 request.setScmProvider(provider);
349 } catch (ScmRepositoryException | NoSuchScmProviderException e) {
350 Logger logger = getLogger();
351 if (logger.isWarnEnabled()) {
352 logger.warn("Next Version will NOT be based on the version control: {}", e.getMessage());
353 } else {
354 if (logger.isDebugEnabled()) {
355 logger.warn("Next Version will NOT be based on the version control", e);
356 }
357 }
358 }
359 }
360 return convertToSnapshot
361 ? policy.getDevelopmentVersion(request).getVersion()
362 : policy.getReleaseVersion(request).getVersion();
363 }
364
365 private static String getOriginalVersion(MavenProject project) {
366 String version = null;
367 while (version == null && project != null) {
368 if (project.getOriginalModel() != null) {
369 version = project.getOriginalModel().getVersion();
370 } else {
371 version = project.getVersion();
372 }
373 project = project.getParent();
374 }
375 return version;
376 }
377
378 private String getDevelopmentVersion(String projectId, ReleaseDescriptor releaseDescriptor) {
379 String projectVersion = releaseDescriptor.getProjectDevelopmentVersion(projectId);
380
381 if (projectVersion == null || projectVersion.isEmpty()) {
382 projectVersion = releaseDescriptor.getDefaultDevelopmentVersion();
383 }
384
385 if (projectVersion == null || projectVersion.isEmpty()) {
386 return null;
387 }
388
389 return projectVersion;
390 }
391
392 private String getReleaseVersion(String projectId, ReleaseDescriptor releaseDescriptor) {
393 String projectVersion = releaseDescriptor.getProjectReleaseVersion(projectId);
394
395 if (projectVersion == null || projectVersion.isEmpty()) {
396 projectVersion = releaseDescriptor.getDefaultReleaseVersion();
397 }
398
399 if (projectVersion == null || projectVersion.isEmpty()) {
400 return null;
401 }
402
403 return projectVersion;
404 }
405
406 @Override
407 public ReleaseResult simulate(
408 ReleaseDescriptor releaseDescriptor,
409 ReleaseEnvironment releaseEnvironment,
410 List<MavenProject> reactorProjects)
411 throws ReleaseExecutionException {
412 ReleaseResult result = new ReleaseResult();
413
414
415 execute(releaseDescriptor, releaseEnvironment, reactorProjects);
416
417 result.setResultCode(ReleaseResult.SUCCESS);
418
419 return result;
420 }
421 }