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.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import org.apache.maven.project.MavenProject;
28  import org.apache.maven.scm.ScmException;
29  import org.apache.maven.scm.ScmFile;
30  import org.apache.maven.scm.ScmFileSet;
31  import org.apache.maven.scm.ScmFileStatus;
32  import org.apache.maven.scm.ScmVersion;
33  import org.apache.maven.scm.command.checkin.CheckInScmResult;
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.repository.ScmRepository;
39  import org.apache.maven.scm.repository.ScmRepositoryException;
40  import org.apache.maven.shared.release.ReleaseExecutionException;
41  import org.apache.maven.shared.release.ReleaseFailureException;
42  import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
43  import org.apache.maven.shared.release.config.ReleaseUtils;
44  import org.apache.maven.shared.release.env.DefaultReleaseEnvironment;
45  import org.apache.maven.shared.release.scm.ReleaseScmCommandException;
46  import org.apache.maven.shared.release.scm.ReleaseScmRepositoryException;
47  import org.apache.maven.shared.release.stubs.ScmManagerStub;
48  import org.apache.maven.shared.release.util.ReleaseUtil;
49  import org.junit.Test;
50  
51  import static org.junit.Assert.assertEquals;
52  import static org.junit.Assert.assertNull;
53  import static org.junit.Assert.assertTrue;
54  import static org.junit.Assert.fail;
55  import static org.mockito.ArgumentMatchers.argThat;
56  import static org.mockito.ArgumentMatchers.eq;
57  import static org.mockito.ArgumentMatchers.isA;
58  import static org.mockito.ArgumentMatchers.isNull;
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 release or branch preparation SCM commit phase.
66   *
67   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
68   */
69  public class ScmCommitPreparationPhaseTest extends AbstractReleaseTestCase {
70      private static final String PREFIX = "[maven-release-manager] prepare release ";
71  
72      @Override
73      public void setUp() throws Exception {
74          super.setUp();
75  
76          phase = lookup(ReleasePhase.class, "scm-commit-release");
77      }
78  
79      @Test
80      public void testIsCorrectImplementation() {
81          assertEquals(ScmCommitReleasePhase.class, phase.getClass());
82      }
83  
84      @Test
85      public void testResolvesCorrectBranchImplementation() throws Exception {
86          assertTrue(lookup(ReleasePhase.class, "scm-commit-branch") instanceof ScmCommitBranchPhase);
87      }
88  
89      @Test
90      public void testCommit() throws Exception {
91          // prepare
92          List<MavenProject> reactorProjects = createReactorProjects();
93          ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
94          builder.setScmSourceUrl("scm-url");
95          MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
96          builder.setWorkingDirectory(rootProject.getFile().getParentFile().getAbsolutePath());
97          builder.setScmReleaseLabel("release-label");
98  
99          ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile(), rootProject.getFile());
100 
101         ScmProvider scmProviderMock = mock(ScmProvider.class);
102         when(scmProviderMock.checkIn(
103                         isA(ScmRepository.class),
104                         argThat(new IsScmFileSetEquals(fileSet)),
105                         isNull(ScmVersion.class),
106                         eq(PREFIX + "release-label")))
107                 .thenReturn(new CheckInScmResult(
108                         "...",
109                         Collections.singletonList(
110                                 new ScmFile(rootProject.getFile().getPath(), ScmFileStatus.CHECKED_IN))));
111 
112         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
113         stub.setScmProvider(scmProviderMock);
114 
115         // execute
116         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
117 
118         // verify
119         verify(scmProviderMock)
120                 .checkIn(
121                         isA(ScmRepository.class), argThat(new IsScmFileSetEquals(fileSet)),
122                         isNull(ScmVersion.class), eq(PREFIX + "release-label"));
123         verifyNoMoreInteractions(scmProviderMock);
124     }
125 
126     @Test
127     public void testCommitAlternateMessage() throws Exception {
128         // prepare
129         List<MavenProject> reactorProjects = createReactorProjects();
130         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
131         builder.setScmSourceUrl("scm-url");
132         builder.setScmCommentPrefix("[release]");
133         builder.setScmReleaseCommitComment("@{prefix} Release of @{groupId}:@{artifactId} @{releaseLabel}");
134         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
135         builder.setWorkingDirectory(rootProject.getFile().getParentFile().getAbsolutePath());
136         builder.setScmReleaseLabel("release-label");
137 
138         ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile(), rootProject.getFile());
139 
140         ScmProvider scmProviderMock = mock(ScmProvider.class);
141         when(scmProviderMock.checkIn(
142                         isA(ScmRepository.class),
143                         argThat(new IsScmFileSetEquals(fileSet)),
144                         isNull(ScmVersion.class),
145                         eq("[release] Release of groupId:artifactId release-label")))
146                 .thenReturn(new CheckInScmResult(
147                         "...",
148                         Collections.singletonList(
149                                 new ScmFile(rootProject.getFile().getPath(), ScmFileStatus.CHECKED_IN))));
150 
151         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
152         stub.setScmProvider(scmProviderMock);
153 
154         // execute
155         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
156 
157         // verify
158         verify(scmProviderMock)
159                 .checkIn(
160                         isA(ScmRepository.class), argThat(new IsScmFileSetEquals(fileSet)),
161                         isNull(ScmVersion.class), eq("[release] Release of groupId:artifactId release-label"));
162         verifyNoMoreInteractions(scmProviderMock);
163     }
164 
165     @Test
166     public void testCommitMultiModule() throws Exception {
167         // prepare
168         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
169         String dir = "scm-commit/multiple-poms";
170         List<MavenProject> reactorProjects = createReactorProjects(dir, dir, null);
171         builder.setScmSourceUrl("scm-url");
172         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
173         builder.setWorkingDirectory(rootProject.getFile().getParentFile().getAbsolutePath());
174         builder.setScmReleaseLabel("release-label");
175 
176         List<File> poms = new ArrayList<>();
177         for (Iterator<MavenProject> i = reactorProjects.iterator(); i.hasNext(); ) {
178             MavenProject project = i.next();
179             poms.add(project.getFile());
180         }
181         ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile(), poms);
182 
183         ScmProvider scmProviderMock = mock(ScmProvider.class);
184         when(scmProviderMock.checkIn(
185                         isA(ScmRepository.class),
186                         argThat(new IsScmFileSetEquals(fileSet)),
187                         isNull(ScmVersion.class),
188                         eq(PREFIX + "release-label")))
189                 .thenReturn(new CheckInScmResult(
190                         "...",
191                         Collections.singletonList(
192                                 new ScmFile(rootProject.getFile().getPath(), ScmFileStatus.CHECKED_IN))));
193         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
194         stub.setScmProvider(scmProviderMock);
195 
196         // execute
197         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
198 
199         // verify
200         verify(scmProviderMock)
201                 .checkIn(
202                         isA(ScmRepository.class), argThat(new IsScmFileSetEquals(fileSet)),
203                         isNull(ScmVersion.class), eq(PREFIX + "release-label"));
204         verifyNoMoreInteractions(scmProviderMock);
205     }
206 
207     @Test
208     public void testCommitDevelopment() throws Exception {
209         // prepare
210         phase = (ReleasePhase) lookup(ReleasePhase.class, "scm-commit-development");
211 
212         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
213         List<MavenProject> reactorProjects = createReactorProjects();
214         builder.setScmSourceUrl("scm-url");
215         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
216         builder.setWorkingDirectory(rootProject.getFile().getParentFile().getAbsolutePath());
217         builder.setScmReleaseLabel("release-label");
218 
219         ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile(), rootProject.getFile());
220 
221         ScmProvider scmProviderMock = mock(ScmProvider.class);
222         when(scmProviderMock.checkIn(
223                         isA(ScmRepository.class),
224                         argThat(new IsScmFileSetEquals(fileSet)),
225                         isNull(ScmVersion.class),
226                         eq("[maven-release-manager] prepare for next development iteration")))
227                 .thenReturn(new CheckInScmResult(
228                         "...",
229                         Collections.singletonList(
230                                 new ScmFile(rootProject.getFile().getPath(), ScmFileStatus.CHECKED_IN))));
231 
232         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
233         stub.setScmProvider(scmProviderMock);
234 
235         // execute
236         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
237 
238         // verify
239         verify(scmProviderMock)
240                 .checkIn(
241                         isA(ScmRepository.class),
242                         argThat(new IsScmFileSetEquals(fileSet)),
243                         isNull(ScmVersion.class),
244                         eq("[maven-release-manager] prepare for next development iteration"));
245         verifyNoMoreInteractions(scmProviderMock);
246     }
247 
248     @Test
249     public void testCommitDevelopmentAlternateMessage() throws Exception {
250         // prepare
251         phase = (ReleasePhase) lookup(ReleasePhase.class, "scm-commit-development");
252 
253         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
254         List<MavenProject> reactorProjects = createReactorProjects();
255         builder.setScmSourceUrl("scm-url");
256         builder.setScmCommentPrefix("[release]");
257         builder.setScmDevelopmentCommitComment(
258                 "@{prefix} Bump version of @{groupId}:@{artifactId} after @{releaseLabel}");
259         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
260         builder.setWorkingDirectory(rootProject.getFile().getParentFile().getAbsolutePath());
261         builder.setScmReleaseLabel("release-label");
262 
263         ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile(), rootProject.getFile());
264 
265         ScmProvider scmProviderMock = mock(ScmProvider.class);
266         when(scmProviderMock.checkIn(
267                         isA(ScmRepository.class),
268                         argThat(new IsScmFileSetEquals(fileSet)),
269                         isNull(ScmVersion.class),
270                         eq("[release] Bump version of groupId:artifactId after release-label")))
271                 .thenReturn(new CheckInScmResult(
272                         "...",
273                         Collections.singletonList(
274                                 new ScmFile(rootProject.getFile().getPath(), ScmFileStatus.CHECKED_IN))));
275 
276         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
277         stub.setScmProvider(scmProviderMock);
278 
279         // execute
280         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
281 
282         // verify
283         verify(scmProviderMock)
284                 .checkIn(
285                         isA(ScmRepository.class),
286                         argThat(new IsScmFileSetEquals(fileSet)),
287                         isNull(ScmVersion.class),
288                         eq("[release] Bump version of groupId:artifactId after release-label"));
289         verifyNoMoreInteractions(scmProviderMock);
290     }
291 
292     @Test
293     public void testCommitNoReleaseLabel() throws Exception {
294         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
295         List<MavenProject> reactorProjects = createReactorProjects();
296 
297         try {
298             phase.execute(
299                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
300             fail("Should have thrown an exception");
301         } catch (ReleaseFailureException e) {
302             assertTrue(true);
303         }
304     }
305 
306     @Test
307     public void testCommitGenerateReleasePoms() throws Exception {
308         // prepare
309         List<MavenProject> reactorProjects = createReactorProjects();
310         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
311         builder.setScmSourceUrl("scm-url");
312         builder.setGenerateReleasePoms(true);
313         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
314         builder.setWorkingDirectory(rootProject.getFile().getParentFile().getAbsolutePath());
315         builder.setScmReleaseLabel("release-label");
316 
317         List<File> files = new ArrayList<>();
318         files.add(rootProject.getFile());
319         files.add(ReleaseUtil.getReleasePom(rootProject));
320         ScmFileSet fileSet = new ScmFileSet(rootProject.getFile().getParentFile(), files);
321 
322         ScmProvider scmProviderMock = mock(ScmProvider.class);
323         when(scmProviderMock.checkIn(
324                         isA(ScmRepository.class),
325                         argThat(new IsScmFileSetEquals(fileSet)),
326                         isNull(ScmVersion.class),
327                         eq(PREFIX + "release-label")))
328                 .thenReturn(new CheckInScmResult(
329                         "...",
330                         Collections.singletonList(
331                                 new ScmFile(rootProject.getFile().getPath(), ScmFileStatus.CHECKED_IN))));
332 
333         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
334         stub.setScmProvider(scmProviderMock);
335 
336         // execute
337         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
338 
339         // verify
340         verify(scmProviderMock)
341                 .checkIn(
342                         isA(ScmRepository.class), argThat(new IsScmFileSetEquals(fileSet)),
343                         isNull(ScmVersion.class), eq(PREFIX + "release-label"));
344         verifyNoMoreInteractions(scmProviderMock);
345     }
346 
347     @Test
348     public void testSimulateCommit() throws Exception {
349         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
350         List<MavenProject> reactorProjects = createReactorProjects();
351         builder.setScmSourceUrl("scm-url");
352         MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
353         builder.setWorkingDirectory(rootProject.getFile().getParentFile().getAbsolutePath());
354         builder.setScmReleaseLabel("release-label");
355 
356         ScmProvider scmProviderMock = mock(ScmProvider.class);
357 
358         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
359         stub.setScmProvider(scmProviderMock);
360 
361         phase.simulate(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
362 
363         // never invoke scmProviderMock
364         verifyNoMoreInteractions(scmProviderMock);
365     }
366 
367     @Test
368     public void testSimulateCommitNoReleaseLabel() throws Exception {
369         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
370         List<MavenProject> reactorProjects = createReactorProjects();
371 
372         try {
373             phase.simulate(
374                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
375             fail("Should have thrown an exception");
376         } catch (ReleaseFailureException e) {
377             assertTrue(true);
378         }
379     }
380 
381     @Test
382     public void testNoSuchScmProviderExceptionThrown() throws Exception {
383         // prepare
384         List<MavenProject> reactorProjects = createReactorProjects();
385         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
386 
387         ScmManagerStub scmManagerStub = (ScmManagerStub) lookup(ScmManager.class);
388         scmManagerStub.setException(new NoSuchScmProviderException("..."));
389         // execute
390         try {
391             phase.execute(
392                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
393 
394             fail("Status check should have failed");
395         } catch (ReleaseExecutionException e) {
396             // verify
397             assertEquals(
398                     "check cause",
399                     NoSuchScmProviderException.class,
400                     e.getCause().getClass());
401         }
402     }
403 
404     @Test
405     public void testScmRepositoryExceptionThrown() throws Exception {
406         // prepare
407         List<MavenProject> reactorProjects = createReactorProjects();
408         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
409 
410         ScmManagerStub scmManagerStub = (ScmManagerStub) lookup(ScmManager.class);
411         scmManagerStub.setException(new ScmRepositoryException("..."));
412 
413         // execute
414         try {
415             phase.execute(
416                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
417 
418             fail("Status check should have failed");
419         } catch (ReleaseScmRepositoryException e) {
420             // verify
421             assertNull("Check no additional cause", e.getCause());
422         }
423     }
424 
425     @Test
426     public void testScmExceptionThrown() throws Exception {
427         // prepare
428         List<MavenProject> reactorProjects = createReactorProjects();
429         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
430 
431         ScmProvider scmProviderMock = mock(ScmProvider.class);
432         when(scmProviderMock.checkIn(
433                         isA(ScmRepository.class), isA(ScmFileSet.class), isNull(ScmVersion.class), isA(String.class)))
434                 .thenThrow(new ScmException("..."));
435 
436         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
437         stub.setScmProvider(scmProviderMock);
438 
439         // execute
440         try {
441             phase.execute(
442                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
443 
444             fail("Status check should have failed");
445         } catch (ReleaseExecutionException e) {
446             assertEquals("check cause", ScmException.class, e.getCause().getClass());
447         }
448 
449         // verify
450         verify(scmProviderMock)
451                 .checkIn(
452                         isA(ScmRepository.class), isA(ScmFileSet.class),
453                         isNull(ScmVersion.class), isA(String.class));
454         verifyNoMoreInteractions(scmProviderMock);
455     }
456 
457     @Test
458     public void testScmResultFailure() throws Exception {
459         List<MavenProject> reactorProjects = createReactorProjects();
460         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
461 
462         ScmManager scmManager = (ScmManager) lookup(ScmManager.class);
463         ScmProviderStub providerStub = (ScmProviderStub) scmManager.getProviderByUrl("scm-url");
464 
465         providerStub.setCheckInScmResult(new CheckInScmResult("", "", "", false));
466 
467         try {
468             phase.execute(
469                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
470 
471             fail("Commit should have failed");
472         } catch (ReleaseScmCommandException e) {
473             assertNull("check no other cause", e.getCause());
474         }
475     }
476 
477     @Test
478     public void testSuppressCommitWithRemoteTaggingFails() throws Exception {
479         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
480         List<MavenProject> reactorProjects = createReactorProjects();
481 
482         builder.setRemoteTagging(true);
483         builder.setPinExternals(false);
484         builder.setSuppressCommitBeforeTagOrBranch(true);
485 
486         ScmProvider scmProviderMock = mock(ScmProvider.class);
487 
488         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
489         stub.setScmProvider(scmProviderMock);
490 
491         try {
492             phase.execute(
493                     ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
494 
495             fail("Commit should have failed with ReleaseFailureException");
496         } catch (ReleaseFailureException e) {
497             assertNull("check no other cause", e.getCause());
498         }
499 
500         // never invoke scmProviderMock
501         verifyNoMoreInteractions(scmProviderMock);
502     }
503 
504     @Test
505     public void testSuppressCommitAfterBranch() throws Exception {
506         ReleaseDescriptorBuilder builder = createReleaseDescriptorBuilder();
507         List<MavenProject> reactorProjects = createReactorProjects();
508 
509         builder.setBranchCreation(true);
510         builder.setRemoteTagging(false);
511         builder.setSuppressCommitBeforeTagOrBranch(true);
512 
513         ScmProvider scmProviderMock = mock(ScmProvider.class);
514 
515         ScmManagerStub stub = (ScmManagerStub) lookup(ScmManager.class);
516         stub.setScmProvider(scmProviderMock);
517 
518         phase.execute(ReleaseUtils.buildReleaseDescriptor(builder), new DefaultReleaseEnvironment(), reactorProjects);
519 
520         // never invoke scmProviderMock
521         verifyNoMoreInteractions(scmProviderMock);
522     }
523 
524     private List<MavenProject> createReactorProjects() throws Exception {
525         String dir = "scm-commit/single-pom";
526         return createReactorProjects(dir, dir, null);
527     }
528 
529     private static ReleaseDescriptorBuilder createReleaseDescriptorBuilder() {
530         ReleaseDescriptorBuilder builder = new ReleaseDescriptorBuilder();
531         builder.setScmSourceUrl("scm-url");
532         builder.setScmReleaseLabel("release-label");
533         builder.setWorkingDirectory(getTestFile("target/test/checkout").getAbsolutePath());
534         return builder;
535     }
536 }