1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.deploy;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.LinkedHashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import org.apache.maven.RepositoryUtils;
30 import org.apache.maven.artifact.ArtifactUtils;
31 import org.apache.maven.model.Plugin;
32 import org.apache.maven.model.PluginExecution;
33 import org.apache.maven.plugin.MojoExecutionException;
34 import org.apache.maven.plugin.MojoFailureException;
35 import org.apache.maven.plugin.descriptor.PluginDescriptor;
36 import org.apache.maven.plugins.annotations.LifecyclePhase;
37 import org.apache.maven.plugins.annotations.Mojo;
38 import org.apache.maven.plugins.annotations.Parameter;
39 import org.apache.maven.project.MavenProject;
40 import org.apache.maven.project.artifact.ProjectArtifact;
41 import org.eclipse.aether.deployment.DeployRequest;
42 import org.eclipse.aether.repository.RemoteRepository;
43
44
45
46
47
48
49
50 @Mojo(name = "deploy", defaultPhase = LifecyclePhase.DEPLOY, threadSafe = true)
51 public class DeployMojo extends AbstractDeployMojo {
52 private static final Pattern ALT_LEGACY_REPO_SYNTAX_PATTERN = Pattern.compile("(.+?)::(.+?)::(.+)");
53
54 private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile("(.+?)::(.+)");
55
56 @Parameter(defaultValue = "${project}", readonly = true, required = true)
57 private MavenProject project;
58
59 @Parameter(defaultValue = "${reactorProjects}", required = true, readonly = true)
60 private List<MavenProject> reactorProjects;
61
62 @Parameter(defaultValue = "${plugin}", required = true, readonly = true)
63 private PluginDescriptor pluginDescriptor;
64
65
66
67
68
69
70
71 @Parameter(defaultValue = "false", property = "deployAtEnd")
72 private boolean deployAtEnd;
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 @Parameter(property = "altDeploymentRepository")
89 private String altDeploymentRepository;
90
91
92
93
94
95
96
97
98
99
100 @Parameter(property = "altSnapshotDeploymentRepository")
101 private String altSnapshotDeploymentRepository;
102
103
104
105
106
107
108
109
110
111
112 @Parameter(property = "altReleaseDeploymentRepository")
113 private String altReleaseDeploymentRepository;
114
115
116
117
118
119
120
121
122
123
124
125
126 @Parameter(property = "maven.deploy.skip", defaultValue = "false")
127 private String skip = Boolean.FALSE.toString();
128
129 private enum State {
130 SKIPPED,
131 DEPLOYED,
132 TO_BE_DEPLOYED
133 }
134
135 private static final String DEPLOY_PROCESSED_MARKER = DeployMojo.class.getName() + ".processed";
136
137 private static final String DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY =
138 DeployMojo.class.getName() + ".altReleaseDeploymentRepository";
139
140 private static final String DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY =
141 DeployMojo.class.getName() + ".altSnapshotDeploymentRepository";
142
143 private static final String DEPLOY_ALT_DEPLOYMENT_REPOSITORY =
144 DeployMojo.class.getName() + ".altDeploymentRepository";
145
146 private void putState(State state) {
147 getPluginContext().put(DEPLOY_PROCESSED_MARKER, state.name());
148 }
149
150 private void putPluginContextValue(String key, String value) {
151 if (value != null) {
152 getPluginContext().put(key, value);
153 }
154 }
155
156 private String getPluginContextValue(Map<String, Object> pluginContext, String key) {
157 return (String) pluginContext.get(key);
158 }
159
160 private State getState(Map<String, Object> pluginContext) {
161 return State.valueOf(getPluginContextValue(pluginContext, DEPLOY_PROCESSED_MARKER));
162 }
163
164 private boolean hasState(MavenProject project) {
165 Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, project);
166 return pluginContext.containsKey(DEPLOY_PROCESSED_MARKER);
167 }
168
169 public void execute() throws MojoExecutionException, MojoFailureException {
170 State state;
171 if (Boolean.parseBoolean(skip)
172 || ("releases".equals(skip) && !ArtifactUtils.isSnapshot(project.getVersion()))
173 || ("snapshots".equals(skip) && ArtifactUtils.isSnapshot(project.getVersion()))) {
174 getLog().info("Skipping artifact deployment");
175 state = State.SKIPPED;
176 } else {
177 failIfOffline();
178 warnIfAffectedPackagingAndMaven(project.getPackaging());
179
180 if (!deployAtEnd) {
181
182 RemoteRepository deploymentRepository = getDeploymentRepository(
183 project,
184 altSnapshotDeploymentRepository,
185 altReleaseDeploymentRepository,
186 altDeploymentRepository);
187
188 DeployRequest request = new DeployRequest();
189 request.setRepository(deploymentRepository);
190 processProject(project, request);
191 deploy(request);
192 state = State.DEPLOYED;
193 } else {
194 putPluginContextValue(DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY, altSnapshotDeploymentRepository);
195 putPluginContextValue(DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY, altReleaseDeploymentRepository);
196 putPluginContextValue(DEPLOY_ALT_DEPLOYMENT_REPOSITORY, altDeploymentRepository);
197 state = State.TO_BE_DEPLOYED;
198 }
199 }
200
201 putState(state);
202
203 List<MavenProject> allProjectsUsingPlugin = getAllProjectsUsingPlugin();
204
205 if (allProjectsMarked(allProjectsUsingPlugin)) {
206 deployAllAtOnce(allProjectsUsingPlugin);
207 } else if (state == State.TO_BE_DEPLOYED) {
208 getLog().info("Deferring deploy for " + project.getGroupId() + ":" + project.getArtifactId() + ":"
209 + project.getVersion() + " at end");
210 }
211 }
212
213 private void deployAllAtOnce(List<MavenProject> allProjectsUsingPlugin) throws MojoExecutionException {
214 Map<RemoteRepository, DeployRequest> requests = new LinkedHashMap<>();
215
216
217
218 for (MavenProject reactorProject : allProjectsUsingPlugin) {
219 Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, reactorProject);
220 State state = getState(pluginContext);
221 if (state == State.TO_BE_DEPLOYED) {
222
223 RemoteRepository deploymentRepository = getDeploymentRepository(
224 reactorProject,
225 getPluginContextValue(pluginContext, DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY),
226 getPluginContextValue(pluginContext, DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY),
227 getPluginContextValue(pluginContext, DEPLOY_ALT_DEPLOYMENT_REPOSITORY));
228
229 DeployRequest request = requests.computeIfAbsent(deploymentRepository, repo -> {
230 DeployRequest newRequest = new DeployRequest();
231 newRequest.setRepository(repo);
232 return newRequest;
233 });
234 processProject(reactorProject, request);
235 }
236 }
237
238 for (DeployRequest request : requests.values()) {
239 deploy(request);
240 }
241 }
242
243 private boolean allProjectsMarked(List<MavenProject> allProjectsUsingPlugin) {
244 for (MavenProject reactorProject : allProjectsUsingPlugin) {
245 if (!hasState(reactorProject)) {
246 return false;
247 }
248 }
249 return true;
250 }
251
252 private List<MavenProject> getAllProjectsUsingPlugin() {
253 ArrayList<MavenProject> result = new ArrayList<>();
254 for (MavenProject reactorProject : reactorProjects) {
255 if (hasExecution(reactorProject.getPlugin("org.apache.maven.plugins:maven-deploy-plugin"))) {
256 result.add(reactorProject);
257 }
258 }
259 return result;
260 }
261
262 private boolean hasExecution(Plugin plugin) {
263 if (plugin == null) {
264 return false;
265 }
266
267 for (PluginExecution execution : plugin.getExecutions()) {
268 if (!execution.getGoals().isEmpty() && !"none".equalsIgnoreCase(execution.getPhase())) {
269 return true;
270 }
271 }
272 return false;
273 }
274
275 private void processProject(final MavenProject project, DeployRequest request) throws MojoExecutionException {
276
277 if (isFile(project.getFile())) {
278 request.addArtifact(RepositoryUtils.toArtifact(new ProjectArtifact(project)));
279 } else {
280 throw new MojoExecutionException("The project POM could not be attached");
281 }
282
283 if (!"pom".equals(project.getPackaging())) {
284 org.apache.maven.artifact.Artifact mavenMainArtifact = project.getArtifact();
285 if (isFile(mavenMainArtifact.getFile())) {
286 request.addArtifact(RepositoryUtils.toArtifact(mavenMainArtifact));
287 } else if (!project.getAttachedArtifacts().isEmpty()) {
288 throw new MojoExecutionException("The packaging plugin for this project did not assign "
289 + "a main file to the project but it has attachments. Change packaging to 'pom'.");
290 } else {
291 throw new MojoExecutionException(
292 "The packaging for this project did not assign a file to the build artifact");
293 }
294 }
295
296 for (org.apache.maven.artifact.Artifact attached : project.getAttachedArtifacts()) {
297 getLog().debug("Attaching for deploy: " + attached.getId());
298 request.addArtifact(RepositoryUtils.toArtifact(attached));
299 }
300 }
301
302 private boolean isFile(File file) {
303 return file != null && file.isFile();
304 }
305
306
307
308
309 RemoteRepository getDeploymentRepository(
310 final MavenProject project,
311 final String altSnapshotDeploymentRepository,
312 final String altReleaseDeploymentRepository,
313 final String altDeploymentRepository)
314 throws MojoExecutionException {
315 RemoteRepository repo = null;
316
317 String altDeploymentRepo;
318 if (ArtifactUtils.isSnapshot(project.getVersion()) && altSnapshotDeploymentRepository != null) {
319 altDeploymentRepo = altSnapshotDeploymentRepository;
320 } else if (!ArtifactUtils.isSnapshot(project.getVersion()) && altReleaseDeploymentRepository != null) {
321 altDeploymentRepo = altReleaseDeploymentRepository;
322 } else {
323 altDeploymentRepo = altDeploymentRepository;
324 }
325
326 if (altDeploymentRepo != null) {
327 getLog().info("Using alternate deployment repository " + altDeploymentRepo);
328
329 Matcher matcher = ALT_LEGACY_REPO_SYNTAX_PATTERN.matcher(altDeploymentRepo);
330
331 if (matcher.matches()) {
332 String id = matcher.group(1).trim();
333 String layout = matcher.group(2).trim();
334 String url = matcher.group(3).trim();
335
336 if ("default".equals(layout)) {
337 getLog().warn("Using legacy syntax for alternative repository. " + "Use \"" + id + "::" + url
338 + "\" instead.");
339 repo = getRemoteRepository(id, url);
340 } else {
341 throw new MojoExecutionException(
342 altDeploymentRepo,
343 "Invalid legacy syntax and layout for repository.",
344 "Invalid legacy syntax and layout for alternative repository. Use \"" + id + "::" + url
345 + "\" instead, and only default layout is supported.");
346 }
347 } else {
348 matcher = ALT_REPO_SYNTAX_PATTERN.matcher(altDeploymentRepo);
349
350 if (!matcher.matches()) {
351 throw new MojoExecutionException(
352 altDeploymentRepo,
353 "Invalid syntax for repository.",
354 "Invalid syntax for alternative repository. Use \"id::url\".");
355 } else {
356 String id = matcher.group(1).trim();
357 String url = matcher.group(2).trim();
358
359 repo = getRemoteRepository(id, url);
360 }
361 }
362 }
363
364 if (repo == null) {
365 repo = RepositoryUtils.toRepo(project.getDistributionManagementArtifactRepository());
366 }
367
368 if (repo == null) {
369 String msg = "Deployment failed: repository element was not specified in the POM inside"
370 + " distributionManagement element or in -DaltDeploymentRepository=id::url parameter";
371
372 throw new MojoExecutionException(msg);
373 }
374
375 return repo;
376 }
377 }