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 javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.io.IOException;
27 import java.nio.file.LinkOption;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.util.List;
31
32 import org.apache.maven.project.MavenProject;
33 import org.apache.maven.scm.CommandParameter;
34 import org.apache.maven.scm.CommandParameters;
35 import org.apache.maven.scm.ScmException;
36 import org.apache.maven.scm.ScmFileSet;
37 import org.apache.maven.scm.ScmTag;
38 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
39 import org.apache.maven.scm.manager.NoSuchScmProviderException;
40 import org.apache.maven.scm.provider.ScmProvider;
41 import org.apache.maven.scm.repository.ScmRepository;
42 import org.apache.maven.scm.repository.ScmRepositoryException;
43 import org.apache.maven.shared.release.ReleaseExecutionException;
44 import org.apache.maven.shared.release.ReleaseFailureException;
45 import org.apache.maven.shared.release.ReleaseResult;
46 import org.apache.maven.shared.release.config.ReleaseDescriptor;
47 import org.apache.maven.shared.release.env.ReleaseEnvironment;
48 import org.apache.maven.shared.release.scm.ReleaseScmCommandException;
49 import org.apache.maven.shared.release.scm.ReleaseScmRepositoryException;
50 import org.apache.maven.shared.release.scm.ScmRepositoryConfigurator;
51 import org.apache.maven.shared.release.util.ReleaseUtil;
52 import org.codehaus.plexus.util.FileUtils;
53
54 import static java.util.Objects.requireNonNull;
55 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
56
57
58
59
60 @Singleton
61 @Named("checkout-project-from-scm")
62 public class CheckoutProjectFromScm extends AbstractReleasePhase {
63
64
65
66 private final ScmRepositoryConfigurator scmRepositoryConfigurator;
67
68 @Inject
69 public CheckoutProjectFromScm(ScmRepositoryConfigurator scmRepositoryConfigurator) {
70 this.scmRepositoryConfigurator = requireNonNull(scmRepositoryConfigurator);
71 }
72
73 @Override
74 public ReleaseResult execute(
75 ReleaseDescriptor releaseDescriptor,
76 ReleaseEnvironment releaseEnvironment,
77 List<MavenProject> reactorProjects)
78 throws ReleaseExecutionException, ReleaseFailureException {
79 ReleaseResult releaseResult;
80
81 if (releaseDescriptor.isLocalCheckout()) {
82
83
84
85
86
87 String providerPart = releaseDescriptor
88 .getScmSourceUrl()
89 .substring(0, releaseDescriptor.getScmSourceUrl().indexOf(':', 4));
90
91 String scmPath = releaseDescriptor.getWorkingDirectory();
92
93
94
95
96 do {
97 try {
98 if (scmPath.startsWith("/")) {
99
100 scmPath = scmPath.substring(1);
101 }
102
103 String scmUrl = providerPart + ":file:///" + scmPath;
104 releaseDescriptor.setScmSourceUrl(scmUrl);
105 getLogger().info("Performing a LOCAL checkout from " + releaseDescriptor.getScmSourceUrl());
106
107 releaseResult = performCheckout(releaseDescriptor, releaseEnvironment, reactorProjects);
108 } catch (ScmException scmEx) {
109
110 releaseResult = null;
111 }
112
113 if (releaseResult == null || releaseResult.getResultCode() == ReleaseResult.ERROR) {
114
115
116 releaseResult = null;
117
118
119 int lastSlashPos = scmPath.lastIndexOf(File.separator);
120 if (lastSlashPos > 0) {
121 scmPath = scmPath.substring(0, lastSlashPos);
122 } else {
123 throw new ReleaseExecutionException("could not perform a local checkout");
124 }
125 }
126 } while (releaseResult == null);
127 } else {
128
129 try {
130 releaseResult = performCheckout(releaseDescriptor, releaseEnvironment, reactorProjects);
131 } catch (ScmException e) {
132 releaseResult = new ReleaseResult();
133 releaseResult.setResultCode(ReleaseResult.ERROR);
134 logError(releaseResult, e.getMessage());
135
136 throw new ReleaseExecutionException(
137 "An error is occurred in the checkout process: " + e.getMessage(), e);
138 }
139 }
140
141 return releaseResult;
142 }
143
144 private ReleaseResult performCheckout(
145 ReleaseDescriptor releaseDescriptor,
146 ReleaseEnvironment releaseEnvironment,
147 List<MavenProject> reactorProjects)
148 throws ReleaseExecutionException, ReleaseFailureException, ScmException {
149 ReleaseResult result = new ReleaseResult();
150
151 logInfo(result, "Checking out the project to perform the release ...");
152
153 ScmRepository repository;
154 ScmProvider provider;
155
156 try {
157 repository = scmRepositoryConfigurator.getConfiguredRepository(
158 releaseDescriptor, releaseEnvironment.getSettings());
159
160 provider = scmRepositoryConfigurator.getRepositoryProvider(repository);
161 } catch (ScmRepositoryException e) {
162 result.setResultCode(ReleaseResult.ERROR);
163 logError(result, e.getMessage());
164
165 throw new ReleaseScmRepositoryException(e.getMessage(), e.getValidationMessages());
166 } catch (NoSuchScmProviderException e) {
167 result.setResultCode(ReleaseResult.ERROR);
168 logError(result, e.getMessage());
169
170 throw new ReleaseExecutionException("Unable to configure SCM repository: " + e.getMessage(), e);
171 }
172
173 MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
174
175
176 File checkoutDirectory =
177 FileUtils.resolveFile(rootProject.getBasedir(), releaseDescriptor.getCheckoutDirectory());
178
179 if (checkoutDirectory.exists()) {
180 try {
181 FileUtils.deleteDirectory(checkoutDirectory);
182 } catch (IOException e) {
183 result.setResultCode(ReleaseResult.ERROR);
184 logError(result, e.getMessage());
185
186 throw new ReleaseExecutionException("Unable to remove old checkout directory: " + e.getMessage(), e);
187 }
188 }
189
190 checkoutDirectory.mkdirs();
191
192 CommandParameters commandParameters = new CommandParameters();
193 commandParameters.setString(
194 CommandParameter.SHALLOW,
195 Boolean.valueOf(releaseDescriptor.isScmShallowClone()).toString());
196
197 CheckOutScmResult scmResult = provider.checkOut(
198 repository,
199 new ScmFileSet(checkoutDirectory),
200 new ScmTag(releaseDescriptor.getScmReleaseLabel()),
201 commandParameters);
202
203 if (releaseDescriptor.isLocalCheckout() && !scmResult.isSuccess()) {
204
205
206 return null;
207 }
208
209 String scmRelativePathProjectDirectory = scmResult.getRelativePathProjectDirectory();
210 if (scmRelativePathProjectDirectory == null || scmRelativePathProjectDirectory.isEmpty()) {
211 Path workingDirectory = Paths.get(releaseDescriptor.getWorkingDirectory());
212
213 Path rootProjectBasedir;
214 try {
215 rootProjectBasedir = rootProject.getBasedir().toPath().toRealPath(LinkOption.NOFOLLOW_LINKS);
216 } catch (IOException e) {
217 throw new ReleaseExecutionException(e.getMessage(), e);
218 }
219
220 scmRelativePathProjectDirectory =
221 workingDirectory.relativize(rootProjectBasedir).toString();
222 }
223 releaseDescriptor.setScmRelativePathProjectDirectory(scmRelativePathProjectDirectory);
224
225 if (!scmResult.isSuccess()) {
226 result.setResultCode(ReleaseResult.ERROR);
227 logError(result, scmResult.getProviderMessage());
228
229 throw new ReleaseScmCommandException("Unable to checkout from SCM", scmResult);
230 }
231
232 result.setResultCode(ReleaseResult.SUCCESS);
233
234 return result;
235 }
236
237 @Override
238 public ReleaseResult simulate(
239 ReleaseDescriptor releaseDescriptor,
240 ReleaseEnvironment releaseEnvironment,
241 List<MavenProject> reactorProjects)
242 throws ReleaseExecutionException, ReleaseFailureException {
243 ReleaseResult result = new ReleaseResult();
244
245 MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
246 File checkoutDirectory =
247 FileUtils.resolveFile(rootProject.getBasedir(), releaseDescriptor.getCheckoutDirectory());
248
249 if (releaseDescriptor.isLocalCheckout()) {
250 logInfo(
251 result,
252 "The project would have a " + buffer().strong("local") + " check out to perform the release from "
253 + checkoutDirectory + "...");
254 } else {
255 logInfo(
256 result,
257 "The project would be checked out to perform the release from " + checkoutDirectory + "...");
258 }
259
260 result.setResultCode(ReleaseResult.SUCCESS);
261 return result;
262 }
263 }