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 }