package e2e; import org.apache.maven.shared.invoker.MavenInvocationException; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.ObjectId; import org.junit.BeforeClass; import org.junit.Test; import scaffolding.MvnRunner; import scaffolding.TestProject; import java.io.IOException; import java.util.List; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static scaffolding.ExactCountMatcher.noneOf; import static scaffolding.ExactCountMatcher.oneOf; import static scaffolding.GitMatchers.hasCleanWorkingDirectory; import static scaffolding.GitMatchers.hasTag; import static scaffolding.MvnRunner.assertArtifactInLocalRepo; public class PartialReleaseTest { final String buildNumber = String.valueOf(System.currentTimeMillis()); final String expectedAggregatorVersion = "1.0." + buildNumber; final String expectedParentVersion = "1.2.3." + buildNumber; final String expectedCoreVersion = "2.0." + buildNumber; final String expectedAppVersion = "3.2." + buildNumber; final TestProject testProject = TestProject.parentAsSibilngProject(); @BeforeClass public static void installPluginToLocalRepo() throws MavenInvocationException { MvnRunner.installReleasePluginToLocalRepo(); } @Test public void buildsAndInstallsAndTagsAllModules() throws Exception { List<String> commandOutput = testProject.mvnRelease(buildNumber, "-DmodulesToRelease=core-utils"); buildsEachProjectOnceAndOnlyOnce(commandOutput); installsAllModulesIntoTheRepoWithTheBuildNumber(); theLocalAndRemoteGitReposAreTaggedWithTheModuleNameAndVersion(); } @Test public void whenNoChangesHaveBeenDetectedTheRequestedModuleIsBuiltAnyway() throws IOException, InterruptedException { testProject.mvnRelease("1", "-DmodulesToRelease=core-utils"); testProject.mvnRelease(buildNumber, "-DmodulesToRelease=core-utils"); } private void buildsEachProjectOnceAndOnlyOnce(List<String> commandOutput) throws Exception { assertThat( commandOutput, allOf( oneOf(containsString("Going to release core-utils " + expectedCoreVersion)), oneOf(containsString("Building parent-as-sibling")), // once for initial build only oneOf(containsString("Building parent-module")), oneOf(containsString("Building core-utils")), noneOf(containsString("Building console-app")), oneOf(containsString("The Calculator Test has run")) ) ); } private void installsAllModulesIntoTheRepoWithTheBuildNumber() throws Exception { assertArtifactInLocalRepo("com.github.danielflower.mavenplugins.testprojects.parentassibling", "parent-module", expectedParentVersion); assertArtifactInLocalRepo("com.github.danielflower.mavenplugins.testprojects.parentassibling", "core-utils", expectedCoreVersion); } private void theLocalAndRemoteGitReposAreTaggedWithTheModuleNameAndVersion() throws IOException, InterruptedException { assertThat(testProject.local, not(hasTag("parent-as-sibling-" + expectedAggregatorVersion))); assertThat(testProject.origin, not(hasTag("parent-as-sibling-" + expectedAggregatorVersion))); // The parent module should have a tag but this is non-trivial to implement in a maintainable manner. // The problem is that the plugin executes Maven but does not know which builds Maven will actually // run. I have considered 3 strategies: // 1. Parse the console output from Maven. I worry this will result in future breakages if Maven output changes. // 2. Figure out which modules Maven will build. There are Maven libraries that make this possible however it again // feels like something that could break depending on the maven version. // 3. Get the plugin to work with --projects flag. This is probably the best way and almost works, however the Pom // updater only updates the modules that are being built, which sounds okay but it turns out that it results // in modules referencing a snapshot parent that doesn't exist, and maven checks this even though the project // with the bad reference isn't being checked. // Although there are solutions to the problem, they all felt too brittle. // assertThat(testProject.local, hasTag("parent-module-" + expectedParentVersion)); // assertThat(testProject.origin, hasTag("parent-module-" + expectedParentVersion)); assertThat(testProject.local, hasTag("core-utils-" + expectedCoreVersion)); assertThat(testProject.origin, hasTag("core-utils-" + expectedCoreVersion)); assertThat(testProject.local, not(hasTag("console-app-" + expectedAppVersion))); assertThat(testProject.origin, not(hasTag("console-app-" + expectedAppVersion))); } @Test public void thePomChangesAreRevertedAfterTheRelease() throws IOException, InterruptedException { ObjectId originHeadAtStart = head(testProject.origin); ObjectId localHeadAtStart = head(testProject.local); assertThat(originHeadAtStart, equalTo(localHeadAtStart)); testProject.mvnRelease(buildNumber); assertThat(head(testProject.origin), equalTo(originHeadAtStart)); assertThat(head(testProject.local), equalTo(localHeadAtStart)); assertThat(testProject.local, hasCleanWorkingDirectory()); } private ObjectId head(Git git) throws IOException { return git.getRepository().getRef("HEAD").getObjectId(); } }