View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.shared.release.phase;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.nio.file.LinkOption;
24  import java.util.Collections;
25  import java.util.List;
26  
27  import org.apache.maven.project.MavenProject;
28  import org.apache.maven.scm.ScmBranchParameters;
29  import org.apache.maven.scm.ScmException;
30  import org.apache.maven.scm.ScmFile;
31  import org.apache.maven.scm.ScmFileSet;
32  import org.apache.maven.scm.ScmFileStatus;
33  import org.apache.maven.scm.command.branch.BranchScmResult;
34  import org.apache.maven.scm.manager.NoSuchScmProviderException;
35  import org.apache.maven.scm.manager.ScmManager;
36  import org.apache.maven.scm.provider.ScmProvider;
37  import org.apache.maven.scm.provider.ScmProviderStub;
38  import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
39  import org.apache.maven.scm.repository.ScmRepository;
40  import org.apache.maven.scm.repository.ScmRepositoryException;
41  import org.apache.maven.shared.release.ReleaseExecutionException;
42  import org.apache.maven.shared.release.ReleaseFailureException;
43  import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
44  import org.apache.maven.shared.release.config.ReleaseUtils;
45  import org.apache.maven.shared.release.env.DefaultReleaseEnvironment;
46  import org.apache.maven.shared.release.scm.ReleaseScmCommandException;
47  import org.apache.maven.shared.release.scm.ReleaseScmRepositoryException;
48  import org.apache.maven.shared.release.stubs.ScmManagerStub;
49  import org.apache.maven.shared.release.util.ReleaseUtil;
50  import org.junit.Test;
51  
52  import static org.junit.Assert.assertEquals;
53  import static org.junit.Assert.assertNull;
54  import static org.junit.Assert.assertTrue;
55  import static org.junit.Assert.fail;
56  import static org.mockito.ArgumentMatchers.argThat;
57  import static org.mockito.ArgumentMatchers.eq;
58  import static org.mockito.ArgumentMatchers.isA;
59  import static org.mockito.Mockito.mock;
60  import static org.mockito.Mockito.verify;
61  import static org.mockito.Mockito.verifyNoMoreInteractions;
62  import static org.mockito.Mockito.when;
63  
64  /**
65   * Test the SCM branch phase.
66   *
67   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
68   */
69  public class ScmBranchPhaseTest extends AbstractReleaseTestCase {
70      @Override
71      public void setUp() throws Exception {
72          super.setUp();
73  
74          phase = lookup(ReleasePhase.class, "scm-branch");
75      }
76  
77      public static String getPath(File file) throws IOException {
78          return file.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS).toString();
79      }
80  
81      @Test
82      public void testBranch() throws Exception {
83          // prepare
84          ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
85          List<MavenProject> reactorProjects = createReactorProjects();
86          builder.setScmSourceUrl("scm-url");
87          MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
88          builder.setWorkingDirectory(getPath(rootProject.getFile().getParentFile()));
89          builder.setPomFileName("pom.xml");
90          builder.setScmReleaseLabel("release-label");
91          builder.setScmCommentPrefix("[my prefix] ");
92  
93          ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile());
94  
95          ScmProvider scmProviderMock = mock(ScmProvider.class);
96          when(scmProviderMock.branch(
97                          isA(ScmRepository.class),
98                          argThat(new IsScmFileSetEquals(fileSet)),
99                          eq("release-label"),
100                         argThat(new IsScmBranchParametersEquals(
101                                 new ScmBranchParameters("[my prefix] copy for branch release-label")))))
102                 .thenReturn(new BranchScmResult(
103                         "...",
104                         Collections.singletonList(new ScmFile(getPath(rootProject.getFile()), ScmFileStatus.TAGGED))));
105         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
106         stub.setScmProvider(scmProviderMock);
107 
108         // execute
109         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
110 
111         // verify
112         verify(scmProviderMock)
113                 .branch(
114                         isA(ScmRepository.class),
115                         argThat(new IsScmFileSetEquals(fileSet)),
116                         eq("release-label"),
117                         argThat(new IsScmBranchParametersEquals(
118                                 new ScmBranchParameters("[my prefix] copy for branch release-label"))));
119         verifyNoMoreInteractions(scmProviderMock);
120     }
121 
122     @Test
123     public void testCommitMultiModuleDeepFolders() throws Exception {
124         // prepare
125         String dir = "scm-commit/multimodule-with-deep-subprojects";
126         List<MavenProject> reactorProjects = createReactorProjects(dir, dir, null);
127         String sourceUrl = "http://svn.example.com/repos/project/trunk/";
128         String scmUrl = "scm:svn:" + sourceUrl;
129         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
130         builder.setScmSourceUrl(scmUrl);
131         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
132         builder.setWorkingDirectory(getPath(rootProject.getFile().getParentFile()));
133         builder.setPomFileName("pom.xml");
134         builder.setScmReleaseLabel("release-label");
135         builder.setScmCommentPrefix("[my prefix] ");
136         builder.setScmBranchBase("http://svn.example.com/repos/project/branches/");
137 
138         ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile());
139 
140         SvnScmProviderRepository scmProviderRepository = new SvnScmProviderRepository(sourceUrl);
141         scmProviderRepository.setBranchBase("http://svn.example.com/repos/project/branches/");
142         ScmRepository repository = new ScmRepository("svn", scmProviderRepository);
143         ScmProvider scmProviderMock = mock(ScmProvider.class);
144         when(scmProviderMock.branch(
145                         eq(repository),
146                         argThat(new IsScmFileSetEquals(fileSet)),
147                         eq("release-label"),
148                         argThat(new IsScmBranchParametersEquals(
149                                 new ScmBranchParameters("[my prefix] copy for branch release-label")))))
150                 .thenReturn(new BranchScmResult(
151                         "...",
152                         Collections.singletonList(new ScmFile(getPath(rootProject.getFile()), ScmFileStatus.TAGGED))));
153 
154         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
155         stub.setScmProvider(scmProviderMock);
156         stub.addScmRepositoryForUrl(scmUrl, repository);
157 
158         // execute
159         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
160 
161         // verify
162         verify(scmProviderMock)
163                 .branch(
164                         eq(repository),
165                         argThat(new IsScmFileSetEquals(fileSet)),
166                         eq("release-label"),
167                         argThat(new IsScmBranchParametersEquals(
168                                 new ScmBranchParameters("[my prefix] copy for branch release-label"))));
169         verifyNoMoreInteractions(scmProviderMock);
170     }
171 
172     @Test
173     public void testCommitForFlatMultiModule() throws Exception {
174         // prepare
175         List<MavenProject> reactorProjects =
176                 createReactorProjects("rewrite-for-release/pom-with-parent-flat", "root-project");
177         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
178         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
179         builder.setScmSourceUrl(rootProject.getScm().getConnection());
180         builder.setWorkingDirectory(getWorkingDirectory("rewrite-for-release/pom-with-parent-flat")
181                 .toRealPath(LinkOption.NOFOLLOW_LINKS)
182                 .toString());
183         builder.setPomFileName("root-project/pom.xml");
184         builder.setScmReleaseLabel("release-label");
185         builder.setScmCommentPrefix("[my prefix] ");
186 
187         // one directory up from root project
188         ScmFileSet fileSet =
189                 new ScmFileSet(rootProject.getFile().getParentFile().getParentFile());
190 
191         String scmUrl = "file://localhost/tmp/scm-repo/trunk";
192         SvnScmProviderRepository scmProviderRepository = new SvnScmProviderRepository(scmUrl);
193         ScmRepository repository = new ScmRepository("svn", scmProviderRepository);
194         ScmProvider scmProviderMock = mock(ScmProvider.class);
195         when(scmProviderMock.branch(
196                         eq(repository),
197                         argThat(new IsScmFileSetEquals(fileSet)),
198                         eq("release-label"),
199                         argThat(new IsScmBranchParametersEquals(
200                                 new ScmBranchParameters("[my prefix] copy for branch release-label")))))
201                 .thenReturn(new BranchScmResult(
202                         "...",
203                         Collections.singletonList(new ScmFile(getPath(rootProject.getFile()), ScmFileStatus.TAGGED))));
204 
205         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
206         stub.setScmProvider(scmProviderMock);
207         stub.addScmRepositoryForUrl("scm:svn:" + scmUrl, repository);
208 
209         // execute
210         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
211 
212         // verify
213         verify(scmProviderMock)
214                 .branch(
215                         eq(repository),
216                         argThat(new IsScmFileSetEquals(fileSet)),
217                         eq("release-label"),
218                         argThat(new IsScmBranchParametersEquals(
219                                 new ScmBranchParameters("[my prefix] copy for branch release-label"))));
220         verifyNoMoreInteractions(scmProviderMock);
221     }
222 
223     @Test
224     public void testCommitMultiModule() throws Exception {
225         // prepare
226         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
227         String dir = "scm-commit/multiple-poms";
228         List<MavenProject> reactorProjects = createReactorProjects(dir, dir, null);
229         builder.setScmSourceUrl("scm-url");
230         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
231         builder.setWorkingDirectory(getPath(rootProject.getFile().getParentFile()));
232         builder.setPomFileName("pom.xml");
233         builder.setScmReleaseLabel("release-label");
234         builder.setScmCommentPrefix("[my prefix] ");
235 
236         ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile());
237 
238         ScmProvider scmProviderMock = mock(ScmProvider.class);
239         when(scmProviderMock.branch(
240                         isA(ScmRepository.class),
241                         argThat(new IsScmFileSetEquals(fileSet)),
242                         eq("release-label"),
243                         argThat(new IsScmBranchParametersEquals(
244                                 new ScmBranchParameters("[my prefix] copy for branch release-label")))))
245                 .thenReturn(new BranchScmResult(
246                         "...",
247                         Collections.singletonList(new ScmFile(getPath(rootProject.getFile()), ScmFileStatus.TAGGED))));
248 
249         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
250         stub.setScmProvider(scmProviderMock);
251 
252         // exeucte
253         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
254 
255         // verify
256         verify(scmProviderMock)
257                 .branch(
258                         isA(ScmRepository.class),
259                         argThat(new IsScmFileSetEquals(fileSet)),
260                         eq("release-label"),
261                         argThat(new IsScmBranchParametersEquals(
262                                 new ScmBranchParameters("[my prefix] copy for branch release-label"))));
263         verifyNoMoreInteractions(scmProviderMock);
264     }
265 
266     @Test
267     public void testBranchNoReleaseLabel() throws Exception {
268         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
269         List<MavenProject> reactorProjects = createReactorProjects();
270 
271         try {
272             phase.execute(
273                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
274             fail("Should have thrown an exception");
275         } catch (ReleaseFailureException e) {
276             assertTrue(true);
277         }
278     }
279 
280     @Test
281     public void testSimulateBranch() throws Exception {
282         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
283         List<MavenProject> reactorProjects = createReactorProjects();
284         builder.setScmSourceUrl("scm-url");
285         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
286         builder.setWorkingDirectory(getPath(rootProject.getFile().getParentFile()));
287         builder.setPomFileName("pom.xml");
288         builder.setScmReleaseLabel("release-label");
289 
290         ScmProvider scmProviderMock = mock(ScmProvider.class);
291 
292         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
293         stub.setScmProvider(scmProviderMock);
294 
295         // execute
296         phase.simulate(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
297 
298         // verify
299         // no scmProvider invocation
300         verifyNoMoreInteractions(scmProviderMock);
301     }
302 
303     @Test
304     public void testSimulateBranchNoReleaseLabel() throws Exception {
305         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
306         List<MavenProject> reactorProjects = createReactorProjects();
307 
308         try {
309             phase.simulate(
310                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
311             fail("Should have thrown an exception");
312         } catch (ReleaseFailureException e) {
313             assertTrue(true);
314         }
315     }
316 
317     @Test
318     public void testNoSuchScmProviderExceptionThrown() throws Exception {
319         // prepare
320         List<MavenProject> reactorProjects = createReactorProjects();
321         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
322 
323         ScmManagerStub scmManagerStub = (ScmManagerStub) lookup(ScmManager.class);
324         scmManagerStub.setException(new NoSuchScmProviderException("..."));
325 
326         // execute
327         try {
328             phase.execute(
329                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
330 
331             fail("Status check should have failed");
332         } catch (ReleaseExecutionException e) {
333             // verify
334             assertEquals(
335                     "check cause",
336                     NoSuchScmProviderException.class,
337                     e.getCause().getClass());
338         }
339     }
340 
341     @Test
342     public void testScmRepositoryExceptionThrown() throws Exception {
343         // prepare
344         List<MavenProject> reactorProjects = createReactorProjects();
345         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
346 
347         ScmManagerStub scmManagerStub = (ScmManagerStub) lookup(ScmManager.class);
348         scmManagerStub.setException(new ScmRepositoryException("..."));
349 
350         // execute
351         try {
352             phase.execute(
353                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
354 
355             fail("Status check should have failed");
356         } catch (ReleaseScmRepositoryException e) {
357             // verify
358             assertNull("Check no additional cause", e.getCause());
359         }
360     }
361 
362     @Test
363     public void testScmExceptionThrown() throws Exception {
364         // prepare
365         List<MavenProject> reactorProjects = createReactorProjects();
366         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
367 
368         ScmProvider scmProviderMock = mock(ScmProvider.class);
369         when(scmProviderMock.branch(
370                         isA(ScmRepository.class),
371                         isA(ScmFileSet.class),
372                         isA(String.class),
373                         isA(ScmBranchParameters.class)))
374                 .thenThrow(new ScmException("..."));
375 
376         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
377         stub.setScmProvider(scmProviderMock);
378 
379         // execute
380         try {
381             phase.execute(
382                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
383 
384             fail("Status check should have failed");
385         } catch (ReleaseExecutionException e) {
386             assertEquals("check cause", ScmException.class, e.getCause().getClass());
387         }
388 
389         // verify
390         verify(scmProviderMock)
391                 .branch(
392                         isA(ScmRepository.class),
393                         isA(ScmFileSet.class),
394                         isA(String.class),
395                         isA(ScmBranchParameters.class));
396         verifyNoMoreInteractions(scmProviderMock);
397     }
398 
399     @Test
400     public void testScmResultFailure() throws Exception {
401         List<MavenProject> reactorProjects = createReactorProjects();
402         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
403 
404         ScmManager scmManager = lookup(ScmManager.class);
405         ScmProviderStub providerStub = (ScmProviderStub) scmManager.getProviderByUrl("scm-url");
406 
407         providerStub.setBranchScmResult(new BranchScmResult("", "", "", false));
408 
409         try {
410             phase.execute(
411                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
412 
413             fail("Commit should have failed");
414         } catch (ReleaseScmCommandException e) {
415             assertNull("check no other cause", e.getCause());
416         }
417     }
418 
419     private List<MavenProject> createReactorProjects() throws Exception {
420         String dir = "scm-commit/single-pom";
421         return createReactorProjects(dir, dir, null);
422     }
423 
424     private static ReleaseDescriptorBuilder createReleaseDescriptorBuilder() throws IOException {
425         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
426         builder.setScmSourceUrl("scm-url");
427         builder.setScmReleaseLabel("release-label");
428 
429         File workingDir = getTestFile("target/test/checkout");
430         if (!workingDir.exists()) {
431             assertTrue(
432                     "Failed to create the directory, along with all necessary parent directories", workingDir.mkdirs());
433         }
434 
435         builder.setWorkingDirectory(getPath(workingDir));
436         builder.setPomFileName("pom.xml");
437         return builder;
438     }
439 }