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