diff --git a/infrastructure.properties b/infrastructure.properties deleted file mode 100644 index 9f5bb8a..0000000 --- a/infrastructure.properties +++ /dev/null @@ -1,5 +0,0 @@ -io.workDir=~/temp/spring-data-shell - -git.username=olivergierke -git.author=Oliver Gierke -git.email=ogierke@pivotal.io \ No newline at end of file diff --git a/pom.xml b/pom.xml index a36135b..bc65060 100644 --- a/pom.xml +++ b/pom.xml @@ -8,16 +8,21 @@ org.springframework.boot spring-boot-starter-parent - 1.2.4.RELEASE + 1.3.0.RELEASE 1.8 - org.springframework.shell.Bootstrap + org.springframework.data.release.Application + + org.springframework.boot + spring-boot-starter + + org.springframework.boot spring-boot-starter-logging @@ -72,13 +77,18 @@ org.springframework.boot spring-boot-starter-test - + org.eclipse.jgit org.eclipse.jgit 4.0.1.201506240215-r + + org.springframework.boot + spring-boot-configuration-processor + true + @@ -93,8 +103,13 @@ - org.springframework.shell.Bootstrap + ${jar.mainclass} spring-data-release-shell + + + git.password=${git.password} + + diff --git a/readme.md b/readme.md index 3e12c42..8d34a9a 100644 --- a/readme.md +++ b/readme.md @@ -1 +1,8 @@ -`mvn package appassembler:assemble && sh target/appassembler/bin/spring-data-release-shell` \ No newline at end of file +1. Add an `application-local.properties` to the project root and add the following properties: + +- `git.username` - Your GitHub username. +- `git.password` - Your GitHub password. +- `git.author` - Your full name (used for preparing commits). +- `git.email` - Your email (used for preparing commits). + +2. Run `mvn package appassembler:assemble && sh target/appassembler/bin/spring-data-release-shell` diff --git a/src/main/java/org/springframework/data/release/Application.java b/src/main/java/org/springframework/data/release/Application.java new file mode 100644 index 0000000..a9e921c --- /dev/null +++ b/src/main/java/org/springframework/data/release/Application.java @@ -0,0 +1,44 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release; + +import java.util.logging.Logger; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.shell.support.logging.HandlerUtils; + +/** + * @author Oliver Gierke + */ +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + + SpringApplication application = new SpringApplication(Application.class); + application.setAdditionalProfiles("local"); + + try { + BootShim bs = new BootShim(args, application.run(args)); + bs.run(); + } catch (RuntimeException e) { + throw e; + } finally { + HandlerUtils.flushAllHandlers(Logger.getLogger("")); + } + } +} diff --git a/src/main/java/org/springframework/data/release/BootShim.java b/src/main/java/org/springframework/data/release/BootShim.java new file mode 100644 index 0000000..91b0b60 --- /dev/null +++ b/src/main/java/org/springframework/data/release/BootShim.java @@ -0,0 +1,126 @@ +package org.springframework.data.release; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.shell.CommandLine; +import org.springframework.shell.ShellException; +import org.springframework.shell.SimpleShellCommandLineOptions; +import org.springframework.shell.core.ExitShellRequest; +import org.springframework.shell.core.JLineShellComponent; +import org.springframework.shell.support.logging.HandlerUtils; +import org.springframework.util.StopWatch; + +public class BootShim { + private static BootShim bootstrap; + private static StopWatch sw = new StopWatch("Spring Shell"); + private static CommandLine commandLine; + private ConfigurableApplicationContext ctx; + + public BootShim(String[] args, ConfigurableApplicationContext context) { + this.ctx = context; + + try { + commandLine = SimpleShellCommandLineOptions.parseCommandLine(args); + } catch (IOException var5) { + throw new ShellException(var5.getMessage(), var5); + } + + this.configureApplicationContext(this.ctx); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner((BeanDefinitionRegistry) this.ctx); + if (commandLine.getDisableInternalCommands()) { + scanner.scan(new String[] { "org.springframework.shell.converters", "org.springframework.shell.plugin.support" }); + } else { + scanner.scan(new String[] { "org.springframework.shell.commands", "org.springframework.shell.converters", + "org.springframework.shell.plugin.support" }); + } + + } + + public ApplicationContext getApplicationContext() { + return this.ctx; + } + + private void configureApplicationContext(ConfigurableApplicationContext annctx) { + this.createAndRegisterBeanDefinition(annctx, JLineShellComponent.class, "shell"); + annctx.getBeanFactory().registerSingleton("commandLine", commandLine); + } + + protected void createAndRegisterBeanDefinition(GenericApplicationContext annctx, Class clazz) { + this.createAndRegisterBeanDefinition(annctx, clazz, (String) null); + } + + protected void createAndRegisterBeanDefinition(ConfigurableApplicationContext annctx, Class clazz, String name) { + RootBeanDefinition rbd = new RootBeanDefinition(); + rbd.setBeanClass(clazz); + DefaultListableBeanFactory bf = (DefaultListableBeanFactory) annctx.getBeanFactory(); + if (name != null) { + bf.registerBeanDefinition(name, rbd); + } else { + bf.registerBeanDefinition(clazz.getSimpleName(), rbd); + } + + } + + private void setupLogging() { + Logger rootLogger = Logger.getLogger(""); + HandlerUtils.wrapWithDeferredLogHandler(rootLogger, Level.SEVERE); + Logger sfwLogger = Logger.getLogger("org.springframework"); + sfwLogger.setLevel(Level.WARNING); + Logger rooLogger = Logger.getLogger("org.springframework.shell"); + rooLogger.setLevel(Level.FINE); + } + + public ExitShellRequest run() { + sw.start(); + String[] commandsToExecuteAndThenQuit = commandLine.getShellCommandsToExecute(); + JLineShellComponent shell = (JLineShellComponent) this.ctx.getBean("shell", JLineShellComponent.class); + ExitShellRequest exitShellRequest; + if (null != commandsToExecuteAndThenQuit) { + boolean successful = false; + exitShellRequest = ExitShellRequest.FATAL_EXIT; + String[] arr$ = commandsToExecuteAndThenQuit; + int len$ = commandsToExecuteAndThenQuit.length; + + for (int i$ = 0; i$ < len$; ++i$) { + String cmd = arr$[i$]; + successful = shell.executeCommand(cmd).isSuccess(); + if (!successful) { + break; + } + } + + if (successful) { + exitShellRequest = ExitShellRequest.NORMAL_EXIT; + } + } else { + shell.start(); + shell.promptLoop(); + exitShellRequest = shell.getExitShellRequest(); + if (exitShellRequest == null) { + exitShellRequest = ExitShellRequest.NORMAL_EXIT; + } + + shell.waitForComplete(); + } + + sw.stop(); + if (shell.isDevelopmentMode()) { + System.out.println("Total execution time: " + sw.getLastTaskTimeMillis() + " ms"); + } + + return exitShellRequest; + } + + public JLineShellComponent getJLineShellComponent() { + return (JLineShellComponent) this.ctx.getBean("shell", JLineShellComponent.class); + } +} diff --git a/src/main/java/org/springframework/data/release/io/OsConfiguration.java b/src/main/java/org/springframework/data/release/CliComponent.java similarity index 59% rename from src/main/java/org/springframework/data/release/io/OsConfiguration.java rename to src/main/java/org/springframework/data/release/CliComponent.java index 77d5416..8e2fa2c 100644 --- a/src/main/java/org/springframework/data/release/io/OsConfiguration.java +++ b/src/main/java/org/springframework/data/release/CliComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,16 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.release.io; +package org.springframework.data.release; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.stereotype.Component; /** * @author Oliver Gierke */ -@Configuration -@PropertySource("file:infrastructure.properties") -class OsConfiguration { +@Component +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface CliComponent { } diff --git a/src/main/java/org/springframework/data/release/announcement/AnnouncementOperations.java b/src/main/java/org/springframework/data/release/announcement/AnnouncementOperations.java index e504ae5..41c6b47 100644 --- a/src/main/java/org/springframework/data/release/announcement/AnnouncementOperations.java +++ b/src/main/java/org/springframework/data/release/announcement/AnnouncementOperations.java @@ -79,6 +79,6 @@ public class AnnouncementOperations { public static void main(String[] args) { AnnouncementOperations operations = new AnnouncementOperations(); - System.out.println(operations.getProjectBulletpoints(new TrainIteration(ReleaseTrains.FOWLER, Iteration.SR1))); + System.out.println(operations.getProjectBulletpoints(new TrainIteration(ReleaseTrains.GOSLING, Iteration.SR1))); } } diff --git a/src/main/java/org/springframework/data/release/cli/IssueTracerCommands.java b/src/main/java/org/springframework/data/release/cli/IssueTrackerCommands.java similarity index 76% rename from src/main/java/org/springframework/data/release/cli/IssueTracerCommands.java rename to src/main/java/org/springframework/data/release/cli/IssueTrackerCommands.java index 15268dc..f2c0ebd 100644 --- a/src/main/java/org/springframework/data/release/cli/IssueTracerCommands.java +++ b/src/main/java/org/springframework/data/release/cli/IssueTrackerCommands.java @@ -15,26 +15,30 @@ */ package org.springframework.data.release.cli; +import java.util.stream.Collectors; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; +import org.springframework.data.release.CliComponent; +import org.springframework.data.release.jira.Changelog; import org.springframework.data.release.jira.Credentials; import org.springframework.data.release.jira.IssueTracker; import org.springframework.data.release.jira.JiraConnector; import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.Project; import org.springframework.data.release.model.TrainIteration; +import org.springframework.data.release.utils.ExecutionUtils; import org.springframework.plugin.core.PluginRegistry; import org.springframework.shell.core.CommandMarker; import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliOption; -import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; /** * @author Oliver Gierke */ -@Component -public class IssueTracerCommands implements CommandMarker { +@CliComponent +public class IssueTrackerCommands implements CommandMarker { private final PluginRegistry tracker; private final JiraConnector jira; @@ -45,7 +49,8 @@ public class IssueTracerCommands implements CommandMarker { * @param environment */ @Autowired - public IssueTracerCommands(PluginRegistry tracker, JiraConnector jira, Environment environment) { + public IssueTrackerCommands(PluginRegistry tracker, JiraConnector jira, + Environment environment) { String username = environment.getProperty("jira.username", (String) null); String password = environment.getProperty("jira.password", (String) null); @@ -61,9 +66,9 @@ public class IssueTracerCommands implements CommandMarker { } @CliCommand(value = "jira tickets") - public String jira( - @CliOption(key = "", mandatory = true) TrainIteration iteration, // - @CliOption(key = "for-current-user", specifiedDefaultValue = "true", unspecifiedDefaultValue = "false") boolean forCurrentUser) { + public String jira(@CliOption(key = "", mandatory = true) TrainIteration iteration, // + @CliOption(key = "for-current-user", specifiedDefaultValue = "true", + unspecifiedDefaultValue = "false") boolean forCurrentUser) { if (forCurrentUser && credentials == null) { return "No authentication specified! Use 'jira authenticate' first!"; @@ -82,14 +87,11 @@ public class IssueTracerCommands implements CommandMarker { return tracker.getPluginFor(module.getProject()).getChangelogFor(module).toString(); } - StringBuilder builder = new StringBuilder(); + return ExecutionUtils.runAndReturn(iteration, this::getChangelog).// + stream().map(it -> it.toString()).collect(Collectors.joining("\n")); + } - for (ModuleIteration module : iteration) { - - IssueTracker issues = tracker.getPluginFor(module.getProject()); - builder.append(issues.getChangelogFor(module)).append("\n"); - } - - return builder.toString(); + private Changelog getChangelog(ModuleIteration module) { + return tracker.getPluginFor(module.getProject()).getChangelogFor(module); } } diff --git a/src/main/java/org/springframework/data/release/cli/ModelCommands.java b/src/main/java/org/springframework/data/release/cli/ModelCommands.java index 522e3b1..ebad2ad 100644 --- a/src/main/java/org/springframework/data/release/cli/ModelCommands.java +++ b/src/main/java/org/springframework/data/release/cli/ModelCommands.java @@ -15,36 +15,25 @@ */ package org.springframework.data.release.cli; -import java.util.ArrayList; -import java.util.List; +import java.util.stream.Collectors; +import org.springframework.data.release.CliComponent; import org.springframework.data.release.model.ReleaseTrains; import org.springframework.data.release.model.Train; import org.springframework.shell.core.CommandMarker; import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliOption; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; /** * @author Oliver Gierke */ -@Component +@CliComponent public class ModelCommands implements CommandMarker { @CliCommand("trains") public String train(@CliOption(key = { "", "train" }) Train train) { - if (train != null) { - return train.toString(); - } - - List names = new ArrayList<>(); - - for (Train releaseTrain : ReleaseTrains.TRAINS) { - names.add(releaseTrain.getName()); - } - - return StringUtils.collectionToDelimitedString(names, ", "); + return train != null ? train.toString() + : ReleaseTrains.TRAINS.stream().map(Train::getName).collect(Collectors.joining(", ")); } } diff --git a/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java b/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java index ac4b94b..a8b4268 100644 --- a/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java +++ b/src/main/java/org/springframework/data/release/cli/ReleaseCommands.java @@ -16,18 +16,17 @@ package org.springframework.data.release.cli; import static org.springframework.data.release.model.Projects.*; + import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.release.docs.DocumentationOperations; import org.springframework.data.release.git.GitOperations; -import org.springframework.data.release.git.Tags; +import org.springframework.data.release.git.VersionTags; import org.springframework.data.release.gradle.GradleOperations; import org.springframework.data.release.maven.MavenOperations; -import org.springframework.data.release.maven.Pom; import org.springframework.data.release.misc.ReleaseOperations; import org.springframework.data.release.model.ArtifactVersion; -import org.springframework.data.release.model.Module; import org.springframework.data.release.model.Phase; import org.springframework.data.release.model.ReleaseTrains; import org.springframework.data.release.model.Train; @@ -41,7 +40,7 @@ import org.springframework.stereotype.Component; * @author Oliver Gierke */ @Component -@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@RequiredArgsConstructor(onConstructor = @__(@Autowired) ) public class ReleaseCommands implements CommandMarker { private final MavenOperations maven; @@ -53,25 +52,16 @@ public class ReleaseCommands implements CommandMarker { @CliCommand("release predict") public String predictTrainAndIteration() throws Exception { - Pom pom = maven.getMavenProject(COMMONS); + return git.getTags(COMMONS).getLatest().toArtifactVersion().// + map(this::getTrainNameForCommonsVersion).// + orElse(null); + } - Tags tags = git.getTags(COMMONS); + public String getTrainNameForCommonsVersion(ArtifactVersion version) { - ArtifactVersion version = tags.getLatest().toArtifactVersion(); - System.out.println(version); - - for (Train train : ReleaseTrains.TRAINS) { - - Module module = train.getModule(COMMONS); - - if (!pom.getVersion().toString().startsWith(module.getVersion().toMajorMinorBugfix())) { - continue; - } - - return train.getName(); - } - - return null; + return ReleaseTrains.TRAINS.stream().// + filter(train -> version.toString().startsWith(train.getModule(COMMONS).getVersion().toString())).// + findFirst().map(Train::getName).orElse(null); } /** diff --git a/src/main/java/org/springframework/data/release/cli/StaticResources.java b/src/main/java/org/springframework/data/release/cli/StaticResources.java index a2bb509..863136f 100644 --- a/src/main/java/org/springframework/data/release/cli/StaticResources.java +++ b/src/main/java/org/springframework/data/release/cli/StaticResources.java @@ -34,7 +34,7 @@ public class StaticResources { public StaticResources(ModuleIteration module) { Project project = module.getProject(); - ArtifactVersion version = ArtifactVersion.from(module); + ArtifactVersion version = ArtifactVersion.of(module); this.baseUrl = String.format(URL_TEMPLATE, project.getName().toLowerCase(), version); } diff --git a/src/main/java/org/springframework/data/release/cli/TrainConverter.java b/src/main/java/org/springframework/data/release/cli/TrainConverter.java index 5ab2deb..b33b3bd 100644 --- a/src/main/java/org/springframework/data/release/cli/TrainConverter.java +++ b/src/main/java/org/springframework/data/release/cli/TrainConverter.java @@ -56,7 +56,6 @@ public class TrainConverter implements Converter { @Override public boolean getAllPossibleValues(List completions, Class targetType, String existingData, String optionContext, MethodTarget target) { - return false; } } diff --git a/src/main/java/org/springframework/data/release/docs/DocumentationOperations.java b/src/main/java/org/springframework/data/release/docs/DocumentationOperations.java index 584cf89..2ac390d 100644 --- a/src/main/java/org/springframework/data/release/docs/DocumentationOperations.java +++ b/src/main/java/org/springframework/data/release/docs/DocumentationOperations.java @@ -22,7 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.release.git.GitOperations; import org.springframework.data.release.git.GitProject; import org.springframework.data.release.git.Tag; -import org.springframework.data.release.git.Tags; +import org.springframework.data.release.git.VersionTags; import org.springframework.data.release.io.Workspace; import org.springframework.data.release.io.Workspace.LineCallback; import org.springframework.data.release.model.ModuleIteration; @@ -44,7 +44,7 @@ public class DocumentationOperations { public void updateDockbookIncludes(TrainIteration iteration) throws Exception { - Tags tags = git.getTags(COMMONS); + VersionTags tags = git.getTags(COMMONS); ModuleIteration commons = iteration.getModule(COMMONS); ModuleIteration previousIteration = iteration.getPreviousIteration(commons); diff --git a/src/main/java/org/springframework/data/release/git/GitCommands.java b/src/main/java/org/springframework/data/release/git/GitCommands.java index db07d85..62f4cfb 100644 --- a/src/main/java/org/springframework/data/release/git/GitCommands.java +++ b/src/main/java/org/springframework/data/release/git/GitCommands.java @@ -18,6 +18,7 @@ package org.springframework.data.release.git; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.release.CliComponent; import org.springframework.data.release.model.Project; import org.springframework.data.release.model.ReleaseTrains; import org.springframework.data.release.model.Train; @@ -25,14 +26,13 @@ import org.springframework.data.release.model.TrainIteration; import org.springframework.shell.core.CommandMarker; import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliOption; -import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; /** * @author Oliver Gierke */ -@Component -@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@CliComponent +@RequiredArgsConstructor(onConstructor = @__(@Autowired) ) public class GitCommands implements CommandMarker { private final GitOperations git; @@ -43,8 +43,8 @@ public class GitCommands implements CommandMarker { } @CliCommand("git update") - public void checkout(@CliOption(key = { "", "train" }, mandatory = true) String trainName) throws Exception, - InterruptedException { + public void checkout(@CliOption(key = { "", "train" }, mandatory = true) String trainName) + throws Exception, InterruptedException { git.update(ReleaseTrains.getTrainByName(trainName)); } @@ -84,7 +84,7 @@ public class GitCommands implements CommandMarker { public void push(// @CliOption(key = "", mandatory = true) TrainIteration iteration, // @CliOption(key = "tags", specifiedDefaultValue = "true", unspecifiedDefaultValue = "false") String tags) - throws Exception { + throws Exception { boolean pushTags = Boolean.parseBoolean(tags); diff --git a/src/main/java/org/springframework/data/release/git/GitOperations.java b/src/main/java/org/springframework/data/release/git/GitOperations.java index b49ad9f..9db5f6b 100644 --- a/src/main/java/org/springframework/data/release/git/GitOperations.java +++ b/src/main/java/org/springframework/data/release/git/GitOperations.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,12 +19,8 @@ import lombok.RequiredArgsConstructor; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Future; import java.util.stream.Collectors; - -import javax.annotation.PostConstruct; +import java.util.stream.StreamSupport; import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; @@ -36,31 +32,25 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; -import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.TagOpt; -import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.data.release.io.CommandResult; import org.springframework.data.release.io.Workspace; import org.springframework.data.release.jira.IssueTracker; import org.springframework.data.release.jira.Ticket; import org.springframework.data.release.model.ArtifactVersion; -import org.springframework.data.release.model.Iteration; -import org.springframework.data.release.model.Module; import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.Project; import org.springframework.data.release.model.Train; import org.springframework.data.release.model.TrainIteration; -import org.springframework.data.release.utils.CommandUtils; +import org.springframework.data.release.utils.ExecutionUtils; import org.springframework.data.release.utils.Logger; import org.springframework.plugin.core.PluginRegistry; import org.springframework.stereotype.Component; import org.springframework.util.Assert; /** - * Component to execut Git related operations. + * Component to execute Git related operations. * * @author Oliver Gierke */ @@ -72,15 +62,7 @@ public class GitOperations { private final Workspace workspace; private final Logger logger; private final PluginRegistry issueTracker; - private final Environment environment; - - private CredentialsProvider credentials; - - @PostConstruct - public void init() { - this.credentials = new UsernamePasswordCredentialsProvider(environment.getProperty("git.username"), - environment.getProperty("git.password")); - } + private final GitProperties gitProperties; public GitProject getGitProject(Project project) { return new GitProject(project, server); @@ -96,7 +78,7 @@ public class GitOperations { Assert.notNull(train, "Train must not be null!"); - for (ModuleIteration module : train) { + ExecutionUtils.run(train, module -> { Branch branch = Branch.from(module); @@ -109,24 +91,23 @@ public class GitOperations { setRef("origin/".concat(branch.toString())).// call(); } - } + }); } /** - * Checks out all projects of the given {@link Train} at the tags for the given {@link Iteration}. + * Checks out all projects of the given {@link TrainIteration}. * - * @param train * @param iteration * @throws Exception */ - public void checkout(TrainIteration iteration) throws Exception { + public void checkout(TrainIteration iteration) { update(iteration.getTrain()); - for (ModuleIteration module : iteration) { + ExecutionUtils.run(iteration, module -> { Project project = module.getProject(); - ArtifactVersion artifactVersion = ArtifactVersion.from(module); + ArtifactVersion artifactVersion = ArtifactVersion.of(module); Tag tag = findTagFor(project, artifactVersion); @@ -138,16 +119,17 @@ public class GitOperations { try (Git git = new Git(getRepository(module.getProject()))) { logger.log(module, "git checkout %s", tag); + git.checkout().setStartPoint(tag.toString()); } - } + }); logger.log(iteration, "Successfully checked out projects."); } public void prepare(TrainIteration iteration) throws Exception { - for (ModuleIteration module : iteration) { + ExecutionUtils.run(iteration, module -> { Branch branch = Branch.from(module); @@ -161,28 +143,18 @@ public class GitOperations { setRebase(true).// call(); } - } + }); } - public void update(Train train) throws Exception { - - List> executions = new ArrayList<>(); - - for (Module module : train) { - update(module.getProject()); - } - - for (Future execution : executions) { - CommandUtils.getCommandResult(execution); - } + public void update(Train train) { + ExecutionUtils.run(train, module -> update(module.getProject())); } - public void push(TrainIteration iteration) throws Exception { + public void push(TrainIteration iteration) { - for (ModuleIteration module : iteration) { + ExecutionUtils.run(iteration, module -> { Branch branch = Branch.from(module); - logger.log(module, "git push origin %s", branch); try (Git git = new Git(getRepository(module.getProject()))) { @@ -192,15 +164,15 @@ public class GitOperations { git.push().// setRemote("origin").// setRefSpecs(new RefSpec(ref.getName())).// - setCredentialsProvider(credentials).// + setCredentialsProvider(gitProperties.getCredentials()).// call(); } - } + }); } - public void pushTags(Train train) throws Exception { + public void pushTags(Train train) { - for (Module module : train) { + ExecutionUtils.run(train.getModules(), module -> { logger.log(module.getProject(), "git push --tags"); @@ -209,10 +181,10 @@ public class GitOperations { git.push().// setRemote("origin").// setPushTags().// - setCredentialsProvider(this.credentials).// + setCredentialsProvider(gitProperties.getCredentials()).// call(); } - } + }); } public void update(Project project) throws Exception { @@ -220,9 +192,7 @@ public class GitOperations { GitProject gitProject = new GitProject(project, server); String repositoryName = gitProject.getRepositoryName(); - Repository repository = getRepository(project); - - try (Git git = new Git(repository)) { + try (Git git = new Git(getRepository(project))) { if (workspace.hasProjectDirectory(project)) { @@ -232,35 +202,34 @@ public class GitOperations { checkout(project, Branch.MASTER); git.reset().setMode(ResetType.HARD).call(); - git.fetch().setTagOpt(TagOpt.FETCH_TAGS); - git.pull().call(); - // return os.executeCommand("git checkout master && git reset --hard && git fetch --tags && git pull origin - // master", - // project); - } else { logger.log(project, "No repository found! Cloning from %s…", gitProject.getProjectUri()); - clone(project); - // return os.executeCommand(command); + clone(project); } } } - public Tags getTags(Project project) throws Exception { + public VersionTags getTags(Project project) { try (Git git = new Git(getRepository(project))) { - return new Tags(git.tagList().call().stream().map(ref -> new Tag(ref.getName())).collect(Collectors.toList())); + + return new VersionTags(git.tagList().call().stream().// + map(ref -> Tag.of(ref.getName())).// + collect(Collectors.toList())); + + } catch (Exception o_O) { + throw new RuntimeException(o_O); } } - public void tagRelease(TrainIteration iteration) throws Exception { + public void tagRelease(TrainIteration iteration) { - for (ModuleIteration module : iteration) { + ExecutionUtils.run(iteration, module -> { Branch branch = Branch.from(module); Project project = module.getProject(); @@ -284,7 +253,7 @@ public class GitOperations { git.tag().setName(tag.toString()).setObjectId(commit).call(); } } - } + }); } /** @@ -301,19 +270,17 @@ public class GitOperations { Assert.notNull(iteration, "Train iteration must not be null!"); Assert.hasText(summary, "Summary must not be null or empty!"); - for (ModuleIteration module : iteration) { - commit(module, expandSummary(summary, module, iteration), details); - } + ExecutionUtils.run(iteration, module -> commit(module, expandSummary(summary, module, iteration), details)); } - private String expandSummary(String summary, ModuleIteration module, TrainIteration iteration) { + private static String expandSummary(String summary, ModuleIteration module, TrainIteration iteration) { if (!summary.contains("%s")) { return summary; } return String.format(summary, - ArtifactVersion.from(module).toString().concat(String.format(" (%s)", iteration.toString()))); + ArtifactVersion.of(module).toString().concat(String.format(" (%s)", iteration.toString()))); } /** @@ -336,8 +303,8 @@ public class GitOperations { Ticket ticket = tracker.getReleaseTicketFor(module); Commit commit = new Commit(ticket, summary, details); - String author = environment.getProperty("git.author"); - String email = environment.getProperty("git.email"); + String author = gitProperties.getAuthor(); + String email = gitProperties.getEmail(); logger.log(module, "git commit -m \"%s\" --author=\"%s <%s>\"", commit, author, email); @@ -382,16 +349,12 @@ public class GitOperations { * @return * @throws IOException */ - private Tag findTagFor(Project project, ArtifactVersion version) throws Exception { + private Tag findTagFor(Project project, ArtifactVersion version) { - for (Tag tag : getTags(project)) { - - if (tag.toArtifactVersion().equals(version)) { - return tag; - } - } - - return null; + return StreamSupport.stream(getTags(project).spliterator(), false).// + filter(tag -> tag.toArtifactVersion().map(it -> it.equals(version)).orElse(false)).// + findFirst().orElseThrow(() -> new IllegalArgumentException( + String.format("No tag found for version %s of project %s!", version, project))); } public void checkout(Project project, Branch branch) throws Exception { @@ -409,10 +372,11 @@ public class GitOperations { } checkout.call(); + } } - private Repository getRepository(Project project) throws Exception { + private Repository getRepository(Project project) throws IOException { return FileRepositoryBuilder.create(workspace.getFile(".git", project)); } diff --git a/src/main/java/org/springframework/data/release/git/GitProperties.java b/src/main/java/org/springframework/data/release/git/GitProperties.java new file mode 100644 index 0000000..fa73c59 --- /dev/null +++ b/src/main/java/org/springframework/data/release/git/GitProperties.java @@ -0,0 +1,60 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.git; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.Getter; + +import javax.annotation.PostConstruct; + +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +/** + * Configurable properties for Git. + * + * @author Oliver Gierke + */ +@Data +@Component +@ConfigurationProperties(prefix = "git") +public class GitProperties { + + private @Getter(AccessLevel.PRIVATE) String username, password; + private String author, email; + + @PostConstruct + public void init() { + + Assert.hasText(username, "No GitHub username (git.username) configured!"); + Assert.hasText(username, "No GitHub password (git.password) configured!"); + Assert.hasText(username, "No Git author (git.author) configured!"); + Assert.hasText(username, "No Git email (git.email) configured!"); + } + + /** + * Returns the jGit {@link CredentialsProvider} to be used. + * + * @return + */ + public CredentialsProvider getCredentials() { + return new UsernamePasswordCredentialsProvider(username, password); + } +} diff --git a/src/main/java/org/springframework/data/release/git/Tag.java b/src/main/java/org/springframework/data/release/git/Tag.java index c09210f..c0459b6 100644 --- a/src/main/java/org/springframework/data/release/git/Tag.java +++ b/src/main/java/org/springframework/data/release/git/Tag.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,12 @@ */ package org.springframework.data.release.git; +import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; +import java.util.Optional; + import org.springframework.data.release.model.ArtifactVersion; /** @@ -25,12 +28,19 @@ import org.springframework.data.release.model.ArtifactVersion; * * @author Oliver Gierke */ -@RequiredArgsConstructor @EqualsAndHashCode +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class Tag implements Comparable { private final String name; + public static Tag of(String source) { + + int slashIndex = source.lastIndexOf('/'); + + return new Tag(source.substring(slashIndex == -1 ? 0 : slashIndex + 1)); + } + /** * Returns the part of the name of the tag that is suitable to derive a version from the tag. Will transparently strip * a {@code v} prefix from the name. @@ -41,8 +51,17 @@ public class Tag implements Comparable { return name.startsWith("v") ? name.substring(1) : name; } - public ArtifactVersion toArtifactVersion() { - return ArtifactVersion.parse(getVersionSource()); + public boolean isVersionTag() { + return toArtifactVersion().isPresent(); + } + + public Optional toArtifactVersion() { + + try { + return Optional.of(ArtifactVersion.of(getVersionSource())); + } catch (IllegalArgumentException o_O) { + return Optional.empty(); + } } /** @@ -70,6 +89,10 @@ public class Tag implements Comparable { */ @Override public int compareTo(Tag that) { - return that.name.compareTo(this.name); + + // Prefer artifact versions but fall back to name comparison + + return toArtifactVersion().map(left -> that.toArtifactVersion().map(right -> left.compareTo(right)).// + orElse(name.compareTo(that.name))).orElse(name.compareTo(that.name)); } } diff --git a/src/main/java/org/springframework/data/release/git/Tags.java b/src/main/java/org/springframework/data/release/git/VersionTags.java similarity index 79% rename from src/main/java/org/springframework/data/release/git/Tags.java rename to src/main/java/org/springframework/data/release/git/VersionTags.java index ec2fde6..635e3a0 100644 --- a/src/main/java/org/springframework/data/release/git/Tags.java +++ b/src/main/java/org/springframework/data/release/git/VersionTags.java @@ -15,12 +15,11 @@ */ package org.springframework.data.release.git; -import java.util.ArrayList; -import java.util.Collections; +import lombok.EqualsAndHashCode; + import java.util.Iterator; import java.util.List; - -import lombok.EqualsAndHashCode; +import java.util.stream.Collectors; import org.springframework.data.release.model.ArtifactVersion; import org.springframework.data.release.model.ModuleIteration; @@ -32,23 +31,22 @@ import org.springframework.util.Assert; * @author Oliver Gierke */ @EqualsAndHashCode -public class Tags implements Iterable { +public class VersionTags implements Iterable { private final List tags; /** - * Creates a new {@link Tags} instance for the given {@link List} of {@link Tag}s. + * Creates a new {@link VersionTags} instance for the given {@link List} of {@link Tag}s. * * @param source must not be {@literal null}. */ - Tags(List source) { + VersionTags(List source) { Assert.notNull(source, "Tags must not be null!"); - List tags = new ArrayList<>(source); - Collections.sort(tags); - - this.tags = Collections.unmodifiableList(tags); + this.tags = source.stream().// + filter(Tag::isVersionTag).// + sorted().collect(Collectors.toList()); } /** @@ -57,11 +55,11 @@ public class Tags implements Iterable { * @return */ public Tag getLatest() { - return tags.get(0); + return tags.get(tags.size() - 1); } public Tag createTag(ModuleIteration iteration) { - return getLatest().createNew(ArtifactVersion.from(iteration)); + return getLatest().createNew(ArtifactVersion.of(iteration)); } /** diff --git a/src/main/java/org/springframework/data/release/io/CommonsExecOsCommandOperations.java b/src/main/java/org/springframework/data/release/io/CommonsExecOsCommandOperations.java index 0f7cb2f..4eed8fa 100644 --- a/src/main/java/org/springframework/data/release/io/CommonsExecOsCommandOperations.java +++ b/src/main/java/org/springframework/data/release/io/CommonsExecOsCommandOperations.java @@ -24,8 +24,6 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.Future; -import javax.annotation.PostConstruct; - import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecuteResultHandler; import org.apache.commons.exec.DefaultExecutor; @@ -140,7 +138,7 @@ class CommonsExecOsCommandOperations implements OsCommandOperations { * * @throws Exception */ - @PostConstruct + // @PostConstruct public void initialize() throws Exception { String javaHome = executeCommand("/usr/libexec/java_home -F -v 1.8 -a x86_64 -d64").get().getOutput(); diff --git a/src/main/java/org/springframework/data/release/io/IoProperties.java b/src/main/java/org/springframework/data/release/io/IoProperties.java new file mode 100644 index 0000000..aca10cd --- /dev/null +++ b/src/main/java/org/springframework/data/release/io/IoProperties.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.io; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author Oliver Gierke + */ +@Slf4j +@Data +@Component +@ConfigurationProperties(prefix = "io") +public class IoProperties { + + private String workDir; + + public void setWorkDir(String workDir) { + + this.workDir = workDir.replace("~", System.getProperty("user.home")); + log.info(String.format("Using %s as working directory!", workDir)); + } + + public File getWorkDir() { + return new File(workDir); + } +} diff --git a/src/main/java/org/springframework/data/release/io/Workspace.java b/src/main/java/org/springframework/data/release/io/Workspace.java index 34366bc..dfdeed3 100644 --- a/src/main/java/org/springframework/data/release/io/Workspace.java +++ b/src/main/java/org/springframework/data/release/io/Workspace.java @@ -15,6 +15,8 @@ */ package org.springframework.data.release.io; +import lombok.RequiredArgsConstructor; + import java.io.File; import java.io.IOException; import java.nio.charset.Charset; @@ -23,10 +25,7 @@ import java.util.Scanner; import javax.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; - import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; import org.springframework.data.release.model.Project; import org.springframework.stereotype.Component; import org.springframework.util.Assert; @@ -39,14 +38,12 @@ import com.google.common.io.Files; * @author Oliver Gierke */ @Component -@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@RequiredArgsConstructor(onConstructor = @__(@Autowired) ) public class Workspace { private static final Charset UTF_8 = Charset.forName("UTF-8"); - public static final String WORK_DIR_PROPERTY = "io.workDir"; - - private final Environment environment; + private final IoProperties ioProperties; /** * Returns the current working directory. @@ -54,9 +51,7 @@ public class Workspace { * @return */ public File getWorkingDirectory() { - - String workDir = environment.getProperty("io.workDir"); - return new File(workDir.replace("~", System.getProperty("user.home"))); + return ioProperties.getWorkDir(); } /** diff --git a/src/main/java/org/springframework/data/release/jira/Changelog.java b/src/main/java/org/springframework/data/release/jira/Changelog.java index facb97b..5c28990 100644 --- a/src/main/java/org/springframework/data/release/jira/Changelog.java +++ b/src/main/java/org/springframework/data/release/jira/Changelog.java @@ -44,7 +44,7 @@ public class Changelog { @Override public String toString() { - ArtifactVersion version = ArtifactVersion.from(module); + ArtifactVersion version = ArtifactVersion.of(module); String headline = String.format("Changes in version %s (%s)", version, new DateFormatter("YYYY-MM-dd").print(new Date(), Locale.US)); diff --git a/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java b/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java index 552ede0..540b1bb 100644 --- a/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java +++ b/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java @@ -15,14 +15,14 @@ */ package org.springframework.data.release.jira; +import lombok.RequiredArgsConstructor; + import java.net.URI; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; - -import lombok.RequiredArgsConstructor; +import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; @@ -48,7 +48,7 @@ import org.springframework.web.util.UriTemplate; * @author Oliver Gierke */ @Component -@RequiredArgsConstructor(onConstructor = @_(@Autowired)) +@RequiredArgsConstructor(onConstructor = @__(@Autowired) ) class GitHubIssueTracker implements IssueTracker { private static final String MILESTONE_URI = "https://api.github.com/repos/spring-projects/{repoName}/milestones?state={state}"; @@ -68,13 +68,12 @@ class GitHubIssueTracker implements IssueTracker { @Cacheable("release-tickets") public Ticket getReleaseTicketFor(ModuleIteration module) { - for (GitHubIssue issue : getIssuesFor(module)) { - if (issue.isReleaseTicket(module)) { - return new Ticket(issue.getId(), issue.getTitle()); - } - } - - throw new IllegalArgumentException(String.format("Could not find a release ticket for %s!", module)); + return getIssuesFor(module).stream().// + filter(issue -> issue.isReleaseTicket(module)).// + findFirst().// + map(issue -> new Ticket(issue.getId(), issue.getTitle())).// + orElseThrow( + () -> new IllegalArgumentException(String.format("Could not find a release ticket for %s!", module))); } /* @@ -85,12 +84,9 @@ class GitHubIssueTracker implements IssueTracker { @Cacheable("changelogs") public Changelog getChangelogFor(ModuleIteration module) { - List issues = getIssuesFor(module); - List tickets = new ArrayList<>(issues.size()); - - for (GitHubIssue issue : issues) { - tickets.add(new Ticket(issue.getId(), issue.getTitle())); - } + List tickets = getIssuesFor(module).stream().// + map(issue -> new Ticket(issue.getId(), issue.getTitle())).// + collect(Collectors.toList()); logger.log(module, "Created changelog with %s entries.", tickets.size()); @@ -131,8 +127,8 @@ class GitHubIssueTracker implements IssueTracker { logger.log(module, "Looking up milestone from %s…", milestoneUri); - List exchange = operations.exchange(MILESTONE_URI, HttpMethod.GET, null, MILESTONES_TYPE, - parameters).getBody(); + List exchange = operations + .exchange(MILESTONE_URI, HttpMethod.GET, null, MILESTONES_TYPE, parameters).getBody(); GitHubMilestone milestone = null; diff --git a/src/main/java/org/springframework/data/release/jira/Jira.java b/src/main/java/org/springframework/data/release/jira/Jira.java index 6ac1e81..ca50090 100644 --- a/src/main/java/org/springframework/data/release/jira/Jira.java +++ b/src/main/java/org/springframework/data/release/jira/Jira.java @@ -15,6 +15,8 @@ */ package org.springframework.data.release.jira; +import lombok.RequiredArgsConstructor; + import java.net.URI; import java.util.ArrayList; import java.util.Collections; @@ -22,13 +24,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import lombok.RequiredArgsConstructor; - import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.data.release.Application; import org.springframework.data.release.model.Iteration; import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.Project; @@ -47,7 +48,7 @@ import org.springframework.web.util.UriTemplate; * @author Oliver Gierke */ @Component -@RequiredArgsConstructor(onConstructor = @_(@Autowired)) +@RequiredArgsConstructor(onConstructor = @__(@Autowired) ) class Jira implements JiraConnector { private static final String JIRA_HOST = "https://jira.spring.io"; @@ -64,9 +65,7 @@ class Jira implements JiraConnector { */ @Override @CacheEvict(value = "tickets", allEntries = true) - public void reset() { - - } + public void reset() {} @Cacheable("release-tickets") public Ticket getReleaseTicketFor(ModuleIteration iteration) { @@ -81,6 +80,10 @@ class Jira implements JiraConnector { JiraIssues issues = operations.exchange(SEARCH_TEMPLATE, HttpMethod.GET, null, JiraIssues.class, parameters) .getBody(); + if (issues.getIssues().isEmpty()) { + throw new IllegalStateException(String.format("Did not find a release ticket for %s!", iteration)); + } + JiraIssue issue = issues.getIssues().get(0); return new Ticket(issue.getKey(), issue.getFields().getSummary()); @@ -121,8 +124,8 @@ class Jira implements JiraConnector { parameters.put("fields", "summary,fixVersions"); parameters.put("startAt", startAt); - issues = operations.exchange(SEARCH_TEMPLATE, HttpMethod.GET, new HttpEntity<>(headers), JiraIssues.class, - parameters).getBody(); + issues = operations + .exchange(SEARCH_TEMPLATE, HttpMethod.GET, new HttpEntity<>(headers), JiraIssues.class, parameters).getBody(); logger.log(iteration, "Got tickets %s to %s of %s.", startAt, issues.getNextStartAt(), issues.getTotal()); @@ -210,11 +213,10 @@ class Jira implements JiraConnector { public static void main(String[] args) { - try (ConfigurableApplicationContext context = new ClassPathXmlApplicationContext( - "META-INF/spring/spring-shell-plugin.xml")) { + try (ConfigurableApplicationContext context = SpringApplication.run(Application.class, args)) { JiraConnector tracker = context.getBean(JiraConnector.class); - TrainIteration iteration = new TrainIteration(ReleaseTrains.CODD, Iteration.SR2); + TrainIteration iteration = new TrainIteration(ReleaseTrains.GOSLING, Iteration.SR1); ModuleIteration module = iteration.getModule("JPA"); // Changelog changelog = tracker.getChangelogFor(module); diff --git a/src/main/java/org/springframework/data/release/maven/Artifact.java b/src/main/java/org/springframework/data/release/maven/Artifact.java index cd99321..e033592 100644 --- a/src/main/java/org/springframework/data/release/maven/Artifact.java +++ b/src/main/java/org/springframework/data/release/maven/Artifact.java @@ -48,7 +48,7 @@ public class Artifact { this.module = module; this.repository = new Repository(module.getIteration()); - this.version = ArtifactVersion.from(module); + this.version = ArtifactVersion.of(module); } /** diff --git a/src/main/java/org/springframework/data/release/maven/MavenOperations.java b/src/main/java/org/springframework/data/release/maven/MavenOperations.java index eacff6b..7de4df7 100644 --- a/src/main/java/org/springframework/data/release/maven/MavenOperations.java +++ b/src/main/java/org/springframework/data/release/maven/MavenOperations.java @@ -34,6 +34,7 @@ import org.springframework.data.release.model.Phase; import org.springframework.data.release.model.Project; import org.springframework.data.release.model.Train; import org.springframework.data.release.model.TrainIteration; +import org.springframework.data.release.utils.ExecutionUtils; import org.springframework.data.release.utils.Logger; import org.springframework.stereotype.Component; import org.springframework.util.Assert; @@ -47,7 +48,6 @@ import org.xmlbeam.io.XBFileIO; @RequiredArgsConstructor(onConstructor = @__(@Autowired) ) public class MavenOperations { - private static final String COMMONS_VERSION_PROPERTY = "springdata.commons"; private static final String POM_XML = "pom.xml"; private final Workspace workspace; @@ -90,9 +90,8 @@ public class MavenOperations { execute(workspace.getFile("parent/pom.xml", BUILD), new PomCallback() { @Override - public ParentPom doWith(ParentPom pom) { + public void doWith(ParentPom pom) { pom.setSharedResourcesVersion(phase.equals(PREPARE) ? buildVersion : nextBuildVersion); - return pom; } }); @@ -108,7 +107,7 @@ public class MavenOperations { execute(workspace.getFile(POM_XML, project), new PomCallback() { @Override - public Pom doWith(Pom pom) { + public void doWith(Pom pom) { for (Project dependency : project.getDependencies()) { @@ -132,8 +131,6 @@ public class MavenOperations { pom.setParentVersion(version); updateRepository(project, pom, repository, phase); - - return pom; } }); } @@ -149,22 +146,22 @@ public class MavenOperations { */ public void triggerDistributionBuild(TrainIteration iteration) throws Exception { - for (ModuleIteration moduleIteration : iteration) { + ExecutionUtils.run(iteration, module -> { - Project project = moduleIteration.getProject(); + Project project = module.getProject(); if (BUILD.equals(project)) { - continue; + return; } if (!isMavenProject(project)) { logger.log(project, "Skipping project as no pom.xml could be found in the working directory!"); - continue; + return; } logger.log(project, "Triggering distribution build…"); - ArtifactVersion version = ArtifactVersion.from(moduleIteration); + ArtifactVersion version = ArtifactVersion.of(module); String command = "mvn clean deploy -DskipTests -Pdistribute"; @@ -174,14 +171,14 @@ public class MavenOperations { command = command.concat(",release"); } - CommandResult result = os.executeWithOutput(command, moduleIteration.getProject()).get(); + CommandResult result = os.executeWithOutput(command, module.getProject()).get(); if (result.hasError()) { throw result.getException(); } logger.log(project, "Successfully finished distribution build!"); - } + }); } private boolean isMavenProject(Project project) { @@ -197,7 +194,7 @@ public class MavenOperations { execute(bomPomFile, new PomCallback() { @Override - public Pom doWith(Pom pom) { + public void doWith(Pom pom) { for (ModuleIteration module : iteration.getModulesExcept(BUILD)) { @@ -213,8 +210,6 @@ public class MavenOperations { pom.setDependencyManagementVersion(additionalArtifact, version); } } - - return pom; } }); } @@ -246,13 +241,11 @@ public class MavenOperations { Class typeArgument = GenericTypeResolver.resolveTypeArgument(callback.getClass(), PomCallback.class); T pom = (T) io.read(typeArgument); - pom = callback.doWith(pom); - + callback.doWith(pom); io.write(pom); } private interface PomCallback { - - public T doWith(T pom); + public void doWith(T pom); } } diff --git a/src/main/java/org/springframework/data/release/maven/MavenProject.java b/src/main/java/org/springframework/data/release/maven/MavenProject.java index 6d1d7eb..c010c31 100644 --- a/src/main/java/org/springframework/data/release/maven/MavenProject.java +++ b/src/main/java/org/springframework/data/release/maven/MavenProject.java @@ -37,6 +37,6 @@ class MavenProject { } public ArtifactVersion getReleaseVersion() { - return new ArtifactVersion(module.getVersion()); + return ArtifactVersion.of(module.getVersion()); } } diff --git a/src/main/java/org/springframework/data/release/maven/Repository.java b/src/main/java/org/springframework/data/release/maven/Repository.java index 1359a7a..d8a8e93 100644 --- a/src/main/java/org/springframework/data/release/maven/Repository.java +++ b/src/main/java/org/springframework/data/release/maven/Repository.java @@ -28,8 +28,8 @@ public class Repository { private final String url; public Repository(Iteration iteration) { - this.id = iteration.isPublicVersion() ? "spring-libs-release" : "spring-libs-milestone"; - this.url = iteration.isPublicVersion() ? BASE.concat("release") : BASE.concat("milestone"); + this.id = iteration.isPublic() ? "spring-libs-release" : "spring-libs-milestone"; + this.url = iteration.isPublic() ? BASE.concat("release") : BASE.concat("milestone"); } public String getId() { diff --git a/src/main/java/org/springframework/data/release/model/ArtifactVersion.java b/src/main/java/org/springframework/data/release/model/ArtifactVersion.java index 2c0ff68..57a507c 100644 --- a/src/main/java/org/springframework/data/release/model/ArtifactVersion.java +++ b/src/main/java/org/springframework/data/release/model/ArtifactVersion.java @@ -16,7 +16,6 @@ package org.springframework.data.release.model; import lombok.EqualsAndHashCode; -import lombok.RequiredArgsConstructor; import org.springframework.util.Assert; @@ -25,7 +24,6 @@ import org.springframework.util.Assert; * * @author Oliver Gierke */ -@RequiredArgsConstructor @EqualsAndHashCode public class ArtifactVersion implements Comparable { @@ -43,13 +41,20 @@ public class ArtifactVersion implements Comparable { * Creates a new {@link ArtifactVersion} from the given logical {@link Version}. * * @param version must not be {@literal null}. + * @param suffix must not be {@literal null} or empty. */ - public ArtifactVersion(Version version) { + private ArtifactVersion(Version version, String suffix) { Assert.notNull(version, "Version must not be null!"); + Assert.hasText(suffix, "Suffix must not be null or empty!"); + ; this.version = version; - this.suffix = RELEASE_SUFFIX; + this.suffix = suffix; + } + + public static ArtifactVersion of(Version version) { + return new ArtifactVersion(version, RELEASE_SUFFIX); } /** @@ -58,7 +63,7 @@ public class ArtifactVersion implements Comparable { * @param source must not be {@literal null} or empty. * @return */ - public static ArtifactVersion parse(String source) { + public static ArtifactVersion of(String source) { Assert.hasText(source, "Version source must not be null or empty!"); @@ -67,7 +72,7 @@ public class ArtifactVersion implements Comparable { Version version = Version.parse(source.substring(0, suffixStart)); String suffix = source.substring(suffixStart + 1); - Assert.isTrue(suffix.matches(VALID_SUFFIX), "Invalid version suffix!"); + Assert.isTrue(suffix.matches(VALID_SUFFIX), String.format("Invalid version suffix: %s!", source)); return new ArtifactVersion(version, suffix); } @@ -78,14 +83,14 @@ public class ArtifactVersion implements Comparable { * @param iterationVersion must not be {@literal null}. * @return */ - public static ArtifactVersion from(IterationVersion iterationVersion) { + public static ArtifactVersion of(IterationVersion iterationVersion) { Assert.notNull(iterationVersion, "IterationVersion must not be null!"); Version version = iterationVersion.getVersion(); Iteration iteration = iterationVersion.getIteration(); - if (iteration.isGAVersion()) { + if (iteration.isGAIteration()) { return new ArtifactVersion(version, RELEASE_SUFFIX); } @@ -133,17 +138,38 @@ public class ArtifactVersion implements Comparable { return suffix.matches(MILESTONE_SUFFIX); } + /** + * Returns the next development version to be used for the current release version, which means next minor for GA + * versions and next bug fix for service releases. Will return the current version as snapshot otherwise. + * + * @return + */ public ArtifactVersion getNextDevelopmentVersion() { - if (suffix.equals(SNAPSHOT_SUFFIX)) { - return this; + if (suffix.equals(RELEASE_SUFFIX)) { + + boolean isGaVersion = version.withBugfix(0).equals(version); + Version nextVersion = isGaVersion ? version.nextMinor() : version.nextBugfix(); + + return new ArtifactVersion(nextVersion, SNAPSHOT_SUFFIX); } + return suffix.equals(SNAPSHOT_SUFFIX) ? this : new ArtifactVersion(version, SNAPSHOT_SUFFIX); + } + + /** + * Returns the next bug fix version for the current version if it's a release version or the snapshot version of the + * current one otherwise. + * + * @return + */ + public ArtifactVersion getNextBugfixVersion() { + if (suffix.equals(RELEASE_SUFFIX)) { return new ArtifactVersion(version.nextBugfix(), SNAPSHOT_SUFFIX); } - return new ArtifactVersion(version, SNAPSHOT_SUFFIX); + return suffix.equals(SNAPSHOT_SUFFIX) ? this : new ArtifactVersion(version, SNAPSHOT_SUFFIX); } /* @@ -152,7 +178,9 @@ public class ArtifactVersion implements Comparable { */ @Override public int compareTo(ArtifactVersion that) { - return this.toString().compareTo(that.toString()); + + int versionsEqual = this.version.compareTo(that.version); + return versionsEqual != 0 ? versionsEqual : this.suffix.compareTo(that.suffix); } /* @@ -165,7 +193,7 @@ public class ArtifactVersion implements Comparable { } /** - * Returns the {@link String} of the plain version (read: x.y.z, ommitting trailing bugfix zeros). + * Returns the {@link String} of the plain version (read: x.y.z, omitting trailing bug fix zeros). * * @return */ diff --git a/src/main/java/org/springframework/data/release/model/Iteration.java b/src/main/java/org/springframework/data/release/model/Iteration.java index 236fdfa..e7fe64a 100644 --- a/src/main/java/org/springframework/data/release/model/Iteration.java +++ b/src/main/java/org/springframework/data/release/model/Iteration.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,11 +52,17 @@ public class Iteration { this.next = next; } - public boolean isGAVersion() { + public boolean isGAIteration() { return this.equals(GA); } - public boolean isPublicVersion() { + /** + * Returns whether the {@link Iteration} is considered public, i.e. the artifacts produced by the iteration are + * supposed to be published to Maven Central. + * + * @return + */ + public boolean isPublic() { return isServiceIteration() || this.equals(GA); } diff --git a/src/main/java/org/springframework/data/release/model/Module.java b/src/main/java/org/springframework/data/release/model/Module.java index 35d320b..73bc537 100644 --- a/src/main/java/org/springframework/data/release/model/Module.java +++ b/src/main/java/org/springframework/data/release/model/Module.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,6 +57,16 @@ public class Module { return new Module(project, nextVersion.toString()); } + /** + * Returns whether the current {@link Module} refers to the same project as the given one. + * + * @param module must not be {@literal null}. + * @return + */ + public boolean hasSameProjectAs(Module module) { + return this.project.equals(module.project); + } + @Override public String toString() { return String.format("Spring Data %s %s - %s", project.getName(), version, project.getKey()); diff --git a/src/main/java/org/springframework/data/release/model/ModuleIteration.java b/src/main/java/org/springframework/data/release/model/ModuleIteration.java index 91d605a..815be00 100644 --- a/src/main/java/org/springframework/data/release/model/ModuleIteration.java +++ b/src/main/java/org/springframework/data/release/model/ModuleIteration.java @@ -64,7 +64,7 @@ public class ModuleIteration implements IterationVersion { public String getVersionString() { StringBuilder builder = new StringBuilder(); - builder.append(ArtifactVersion.from(this).toShortString()); + builder.append(ArtifactVersion.of(this).toShortString()); if (!iteration.isServiceIteration()) { builder.append(" ").append(iteration.getName()); diff --git a/src/main/java/org/springframework/data/release/model/Projects.java b/src/main/java/org/springframework/data/release/model/Projects.java index 264fe3d..351cfcd 100644 --- a/src/main/java/org/springframework/data/release/model/Projects.java +++ b/src/main/java/org/springframework/data/release/model/Projects.java @@ -25,7 +25,7 @@ import java.util.List; public class Projects { public static final Project COMMONS, BUILD, REST, JPA, MONGO_DB, NEO4J, SOLR, COUCHBASE, CASSANDRA, ELASTICSEARCH, - REDIS, GEMFIRE; + REDIS, GEMFIRE, KEY_VALUE, ENVERS; public static final List PROJECTS; static { @@ -44,9 +44,12 @@ public class Projects { GEMFIRE = new Project("SGF", "Gemfire", Arrays.asList(COMMONS)); REST = new Project("DATAREST", "REST", Arrays.asList(COMMONS, JPA, MONGO_DB, NEO4J, GEMFIRE, SOLR, CASSANDRA), - Arrays.asList("spring-data-rest-core", "spring-data-rest-core")); + Arrays.asList("spring-data-rest-core", "spring-data-rest-core", "spring-data-rest-hal-browser")); + + KEY_VALUE = new Project("DATAKV", "KeyValue", Arrays.asList(COMMONS)); + ENVERS = new Project("DATAENV", "Envers", Arrays.asList(JPA, COMMONS)); PROJECTS = Arrays.asList(BUILD, COMMONS, JPA, MONGO_DB, NEO4J, SOLR, COUCHBASE, CASSANDRA, ELASTICSEARCH, REDIS, - GEMFIRE, REST); + GEMFIRE, REST, KEY_VALUE, ENVERS); } } diff --git a/src/main/java/org/springframework/data/release/model/ReleaseTrains.java b/src/main/java/org/springframework/data/release/model/ReleaseTrains.java index 49611ef..21489f7 100644 --- a/src/main/java/org/springframework/data/release/model/ReleaseTrains.java +++ b/src/main/java/org/springframework/data/release/model/ReleaseTrains.java @@ -27,7 +27,7 @@ import java.util.List; public class ReleaseTrains { public static final List TRAINS; - public static final Train CODD, DIJKSTRA, EVANS, FOWLER; + public static final Train CODD, DIJKSTRA, EVANS, FOWLER, GOSLING, HOPPER; static { @@ -35,10 +35,13 @@ public class ReleaseTrains { DIJKSTRA = dijkstra(); EVANS = DIJKSTRA.next("Evans", Transition.MINOR); FOWLER = EVANS.next("Fowler", Transition.MINOR); + GOSLING = FOWLER.next("Gosling", Transition.MINOR, new Module(KEY_VALUE, "1.0")); + HOPPER = GOSLING.next("Hopper", Transition.MINOR, new Module(NEO4J, "4.1"), new Module(COUCHBASE, "2.1"), + new Module(ENVERS, "1.0")); // Trains - TRAINS = Arrays.asList(CODD, DIJKSTRA, EVANS, FOWLER); + TRAINS = Arrays.asList(CODD, DIJKSTRA, EVANS, FOWLER, GOSLING, HOPPER); // Train names diff --git a/src/main/java/org/springframework/data/release/model/Train.java b/src/main/java/org/springframework/data/release/model/Train.java index ab42e45..788a724 100644 --- a/src/main/java/org/springframework/data/release/model/Train.java +++ b/src/main/java/org/springframework/data/release/model/Train.java @@ -21,15 +21,17 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.Value; -import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.springframework.shell.support.util.OsUtils; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; /** * @author Oliver Gierke @@ -38,7 +40,7 @@ import org.springframework.util.StringUtils; public class Train implements Iterable { private final String name;; - private final List modules; + private final Collection modules; private final Iterations iterations; public Train(String name, Module... modules) { @@ -48,10 +50,10 @@ public class Train implements Iterable { this.iterations = Iterations.DEFAULT; } - public Train(String name, List modules) { + public Train(String name, Collection modules) { this.name = name; - this.modules = Collections.unmodifiableList(modules); + this.modules = Collections.unmodifiableCollection(modules); this.iterations = Iterations.DEFAULT; } @@ -66,46 +68,39 @@ public class Train implements Iterable { public Module getModule(String name) { - for (Module module : this) { - if (module.getProject().getName().equals(name)) { - return module; - } - } - - return null; + return modules.stream().// + filter(module -> module.getProject().getName().equals(name)).// + findFirst().// + orElseThrow(() -> new IllegalArgumentException(String.format("No Module found with name %s!", name))); } public Module getModule(Project project) { - for (Module module : this) { - if (module.getProject().equals(project)) { - return module; - } - } - - return null; + return modules.stream().// + filter(module -> module.getProject().equals(project)).// + findFirst().orElseThrow( + () -> new IllegalArgumentException(String.format("No module found for project %s!", project.getName()))); } - public Train next(String name, Transition transition) { + public Train next(String name, Transition transition, Module... additionalModules) { - List nextModules = new ArrayList<>(); + Set collect = Stream.concat(modules.stream(), Stream.of(additionalModules)).// + map(module -> Arrays.stream(additionalModules).// + reduce(module.next(transition), + (it, additionalModule) -> it.hasSameProjectAs(additionalModule) ? additionalModule : it)) + .collect(Collectors.toSet()); - for (Module module : modules) { - nextModules.add(module.next(transition)); - } - - return new Train(name, nextModules); + return new Train(name, collect); } public ModuleIteration getModuleIteration(Iteration iteration, String moduleName) { - for (Module module : this) { - if (module.hasName(moduleName)) { - return new ModuleIteration(module, iteration, this); - } - } - - return null; + return modules.stream().// + filter(module -> module.hasName(moduleName)).// + findFirst().// + map(module -> new ModuleIteration(module, iteration, this)).// + orElseThrow( + () -> new IllegalArgumentException(String.format("No module found with module name %s!", moduleName))); } public Iterable getModuleIterations(Iteration iteration) { @@ -114,19 +109,12 @@ public class Train implements Iterable { List getModuleIterations(Iteration iteration, Project... exclusions) { - List iterations = new ArrayList<>(modules.size()); List exclusionList = Arrays.asList(exclusions); - for (Module module : this) { - - if (exclusionList.contains(module.getProject())) { - continue; - } - - iterations.add(new ModuleIteration(module, iteration, this)); - } - - return iterations; + return modules.stream().// + filter(module -> !exclusionList.contains(module.getProject())).// + map(module -> new ModuleIteration(module, iteration, this)).// + collect(Collectors.toList()); } public Iteration getIteration(String name) { @@ -136,7 +124,8 @@ public class Train implements Iterable { public ArtifactVersion getModuleVersion(Project project, Iteration iteration) { Module module = getModule(project); - return ArtifactVersion.from(new ModuleIteration(module, iteration, this)); + + return ArtifactVersion.of(new ModuleIteration(module, iteration, this)); } /* @@ -148,8 +137,14 @@ public class Train implements Iterable { StringBuilder builder = new StringBuilder(); - builder.append(name).append(OsUtils.LINE_SEPARATOR).append(OsUtils.LINE_SEPARATOR); - builder.append(StringUtils.collectionToDelimitedString(modules, OsUtils.LINE_SEPARATOR)); + builder.append(name).// + append(OsUtils.LINE_SEPARATOR).// + append(OsUtils.LINE_SEPARATOR); + + builder.append(modules.stream().// + map(Module::toString).// + sorted().// + collect(Collectors.joining(OsUtils.LINE_SEPARATOR))); return builder.toString(); } @@ -186,24 +181,18 @@ public class Train implements Iterable { Assert.hasText(name, "Name must not be null or empty!"); - for (Iteration iteration : this) { - if (iteration.getName().equalsIgnoreCase(name)) { - return iteration; - } - } - - return null; + return iterations.stream().// + filter(iteration -> iteration.getName().equalsIgnoreCase(name)).// + findFirst() + .orElseThrow(() -> new IllegalArgumentException(String.format("No iteration found with name %s!", name))); } Iteration getPreviousIteration(Iteration iteration) { - for (Iteration candidate : iterations) { - if (candidate.isNext(iteration)) { - return candidate; - } - } - - throw new IllegalArgumentException(String.format("Could not find previous iteration for %s!", iteration)); + return iterations.stream().// + filter(candidate -> candidate.isNext(iteration)).// + findFirst().orElseThrow(() -> new IllegalArgumentException( + String.format("Could not find previous iteration for %s!", iteration))); } /* diff --git a/src/main/java/org/springframework/data/release/model/Version.java b/src/main/java/org/springframework/data/release/model/Version.java index f62d073..f1ff92b 100644 --- a/src/main/java/org/springframework/data/release/model/Version.java +++ b/src/main/java/org/springframework/data/release/model/Version.java @@ -23,7 +23,7 @@ public class Version implements Comparable { * * @param parts must not be {@literal null} or empty. */ - public Version(int... parts) { + private Version(int... parts) { Assert.notNull(parts); Assert.isTrue(parts.length > 0 && parts.length < 5); @@ -39,6 +39,10 @@ public class Version implements Comparable { Assert.isTrue(build >= 0, "Build version must be greater or equal zero!"); } + public static Version of(int... parts) { + return new Version(parts); + } + /** * Parses the given string representation of a version into a {@link Version} object. * diff --git a/src/main/java/org/springframework/data/release/utils/CommandUtils.java b/src/main/java/org/springframework/data/release/utils/CommandUtils.java deleted file mode 100644 index 2aae3b0..0000000 --- a/src/main/java/org/springframework/data/release/utils/CommandUtils.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2015 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.release.utils; - -import java.util.concurrent.Future; - -import org.springframework.data.release.io.CommandResult; - -/** - * @author Oliver Gierke - */ -public class CommandUtils { - - public static CommandResult getCommandResult(Future future) throws Exception { - - CommandResult result = future.get(); - - if (result.hasError()) { - throw new CommandException(result); - } - - return result; - } - - public static class CommandException extends RuntimeException { - - private final CommandResult result; - - public CommandException(CommandResult result) { - - super(result.getException()); - this.result = result; - } - - /* - * (non-Javadoc) - * @see java.lang.Throwable#getMessage() - */ - @Override - public String getMessage() { - return String.format("Command execution failed: %s.", result); - } - } -} diff --git a/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java b/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java new file mode 100644 index 0000000..840e182 --- /dev/null +++ b/src/main/java/org/springframework/data/release/utils/ExecutionUtils.java @@ -0,0 +1,82 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.utils; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.springframework.util.Assert; + +/** + * Utility method to easily execute functionality in parallel. + * + * @author Oliver Gierke + */ +public class ExecutionUtils { + + /** + * Runs the given {@link ConsumerWithException} for each element in the given {@link Iterable} in parallel waiting for + * all executions to complete before returning. Exceptions being thrown in the {@link ConsumerWithException} will be + * converted into {@link RuntimeException}s. + * + * @param iterable must not be {@literal null}. + * @param consumer must not be {@literal null}. + */ + public static void run(Iterable iterable, ConsumerWithException consumer) { + + Assert.notNull(iterable, "Iterable must not be null!"); + Assert.notNull(consumer, "Consumer must not be null!"); + + StreamSupport.stream(iterable.spliterator(), false).// + map(it -> CompletableFuture.runAsync(() -> { + try { + consumer.accept(it); + } catch (Exception o_O) { + throw new RuntimeException(o_O); + } + })).collect(Collectors.toList()).forEach(future -> future.join()); + + } + + /** + * Runs the given {@link Function} for each element in the given {@link Iterable} in parallel waiting for all + * executions to complete before returning the results. + * + * @param iterable must not be {@literal null}. + * @param function must not be {@literal null}. + * @return + */ + public static Collection runAndReturn(Iterable iterable, Function function) { + + Assert.notNull(iterable, "Iterable must not be null!"); + Assert.notNull(function, "Consumer must not be null!"); + + return StreamSupport.stream(iterable.spliterator(), false).// + map(it -> CompletableFuture.supplyAsync(() -> function.apply(it))).// + collect(Collectors.toList()).// + stream().// + map(future -> future.join()).// + collect(Collectors.toList()); + } + + public static interface ConsumerWithException { + + void accept(T t) throws Exception; + } +} diff --git a/src/main/java/org/springframework/data/release/utils/Logger.java b/src/main/java/org/springframework/data/release/utils/Logger.java index 94c854c..cd357b3 100644 --- a/src/main/java/org/springframework/data/release/utils/Logger.java +++ b/src/main/java/org/springframework/data/release/utils/Logger.java @@ -17,6 +17,7 @@ package org.springframework.data.release.utils; import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.Project; +import org.springframework.data.release.model.Train; import org.springframework.data.release.model.TrainIteration; import org.springframework.shell.support.logging.HandlerUtils; import org.springframework.stereotype.Component; @@ -43,6 +44,10 @@ public class Logger { log(iteration.toString(), template, args); } + public void log(Train train, String template, Object... args) { + log(train.getName(), template, args); + } + private void log(String context, String template, Object... args) { LOGGER.info(String.format(PREFIX_TEMPLATE, context, String.format(template, args))); } diff --git a/src/main/resources/META-INF/spring/spring-shell-plugin.xml b/src/main/resources/META-INF/spring/spring-shell-plugin.xml deleted file mode 100644 index c61e0b2..0000000 --- a/src/main/resources/META-INF/spring/spring-shell-plugin.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..f759759 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +io.work-dir=~/temp/spring-data-shell diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml deleted file mode 100644 index f1b93eb..0000000 --- a/src/main/resources/logback.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - %d %5p %40.40c:%4L - %m%n - - - - - - - - - - \ No newline at end of file diff --git a/src/test/java/org/springframework/data/release/AbstractIntegrationTests.java b/src/test/java/org/springframework/data/release/AbstractIntegrationTests.java index 0268b99..9faa6c4 100644 --- a/src/test/java/org/springframework/data/release/AbstractIntegrationTests.java +++ b/src/test/java/org/springframework/data/release/AbstractIntegrationTests.java @@ -16,14 +16,14 @@ package org.springframework.data.release; import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Oliver Gierke */ +@ActiveProfiles({ "test", "local" }) @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = TestConfig.class) -public abstract class AbstractIntegrationTests { - -} +@SpringApplicationConfiguration(classes = Application.class) +public abstract class AbstractIntegrationTests {} diff --git a/src/test/java/org/springframework/data/release/ArtifactUnitTests.java b/src/test/java/org/springframework/data/release/ArtifactUnitTests.java index 32af713..13dda41 100644 --- a/src/test/java/org/springframework/data/release/ArtifactUnitTests.java +++ b/src/test/java/org/springframework/data/release/ArtifactUnitTests.java @@ -35,7 +35,7 @@ public class ArtifactUnitTests { Artifact artifact = new Artifact(ReleaseTrains.DIJKSTRA.getModuleIteration(Iteration.M1, "JPA")); assertThat(artifact.getArtifactId(), is("spring-data-jpa")); - assertThat(artifact.getVersion(), is(ArtifactVersion.parse("1.6.0.M1"))); - assertThat(artifact.getNextDevelopmentVersion(), is(ArtifactVersion.parse("1.6.0.BUILD-SNAPSHOT"))); + assertThat(artifact.getVersion(), is(ArtifactVersion.of("1.6.0.M1"))); + assertThat(artifact.getNextDevelopmentVersion(), is(ArtifactVersion.of("1.6.0.BUILD-SNAPSHOT"))); } } diff --git a/src/test/java/org/springframework/data/release/cli/ReleaseCommandsIntegrationTests.java b/src/test/java/org/springframework/data/release/cli/ReleaseCommandsIntegrationTests.java index dc41076..875ca9b 100644 --- a/src/test/java/org/springframework/data/release/cli/ReleaseCommandsIntegrationTests.java +++ b/src/test/java/org/springframework/data/release/cli/ReleaseCommandsIntegrationTests.java @@ -35,8 +35,8 @@ public class ReleaseCommandsIntegrationTests extends AbstractIntegrationTests { @Test public void predictsReleaseTrainCorrectly() throws Exception { - git.update(ReleaseTrains.DIJKSTRA); + git.update(ReleaseTrains.GOSLING); - assertThat(releaseCommands.predictTrainAndIteration(), is("Dijkstra")); + assertThat(releaseCommands.predictTrainAndIteration(), is("Gosling")); } } diff --git a/src/test/java/org/springframework/data/release/git/BranchUnitTests.java b/src/test/java/org/springframework/data/release/git/BranchUnitTests.java index 9b6e9dd..fe92646 100644 --- a/src/test/java/org/springframework/data/release/git/BranchUnitTests.java +++ b/src/test/java/org/springframework/data/release/git/BranchUnitTests.java @@ -32,14 +32,14 @@ public class BranchUnitTests { @Test public void testname() { - IterationVersion iterationVersion = new SimpleIterationVersion(new Version(1, 4), Iteration.RC1); + IterationVersion iterationVersion = new SimpleIterationVersion(Version.of(1, 4), Iteration.RC1); assertThat(Branch.from(iterationVersion).toString(), is("master")); } @Test public void createsBugfixBranchForServiceRelease() { - IterationVersion iterationVersion = new SimpleIterationVersion(new Version(1, 4), Iteration.SR1); + IterationVersion iterationVersion = new SimpleIterationVersion(Version.of(1, 4), Iteration.SR1); assertThat(Branch.from(iterationVersion).toString(), is("1.4.x")); } } diff --git a/src/test/java/org/springframework/data/release/git/GitOperationsIntegrationTests.java b/src/test/java/org/springframework/data/release/git/GitOperationsIntegrationTests.java index e87726b..320c127 100644 --- a/src/test/java/org/springframework/data/release/git/GitOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/release/git/GitOperationsIntegrationTests.java @@ -15,14 +15,15 @@ */ package org.springframework.data.release.git; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import static org.springframework.data.release.model.Projects.*; -import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.release.AbstractIntegrationTests; import org.springframework.data.release.model.ReleaseTrains; -import org.springframework.util.StringUtils; +import org.springframework.data.release.model.TestReleaseTrains; /** * @author Oliver Gierke @@ -32,22 +33,25 @@ public class GitOperationsIntegrationTests extends AbstractIntegrationTests { @Autowired GitOperations gitOperations; @Test - @Ignore - public void testname() throws Exception { - gitOperations.update(ReleaseTrains.CODD); + public void updatesGitRepositories() throws Exception { + gitOperations.update(ReleaseTrains.GOSLING); } @Test - @Ignore public void showTags() throws Exception { - Tags tags = gitOperations.getTags(COMMONS); - System.out.println(StringUtils.collectionToDelimitedString(tags.asList(), "\n")); + gitOperations.update(TestReleaseTrains.SAMPLE); + + assertThat(gitOperations.getTags(BUILD).asList(), is(not(emptyIterable()))); } @Test public void foo() throws Exception { + gitOperations.update(TestReleaseTrains.SAMPLE); + } - gitOperations.update(ReleaseTrains.EVANS); + @Test + public void obtainsVersionTagsForRepoThatAlsoHasOtherTags() { + gitOperations.getTags(MONGO_DB); } } diff --git a/src/test/java/org/springframework/data/release/git/GitProjectUnitTests.java b/src/test/java/org/springframework/data/release/git/GitProjectUnitTests.java index d9abd50..d7b7786 100644 --- a/src/test/java/org/springframework/data/release/git/GitProjectUnitTests.java +++ b/src/test/java/org/springframework/data/release/git/GitProjectUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,20 +19,31 @@ import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.Test; +import org.springframework.data.release.model.Module; +import org.springframework.data.release.model.Project; import org.springframework.data.release.model.ReleaseTrains; import org.springframework.data.release.model.Train; /** + * Unit tests for {@link GitProject}. + * * @author Oliver Gierke */ public class GitProjectUnitTests { @Test - public void testname() { + public void buildsGitHubRepositoryUriCorrectly() { Train codd = ReleaseTrains.CODD; - GitProject project = new GitProject(codd.getModule("Commons").getProject(), new GitServer()); + GitServer server = new GitServer(); + Module module = codd.getModule("Commons"); + Project project = module.getProject(); - assertThat(project.getProjectUri(), is("https://www.github.com/spring-projects/spring-data-commons")); + GitProject gitProject = new GitProject(project, server); + + String projectUri = gitProject.getProjectUri(); + + assertThat(projectUri, startsWith(server.getUri())); + assertThat(projectUri, endsWith("spring-data-commons")); } } diff --git a/src/test/java/org/springframework/data/release/git/GitPropertiesIntegrationTests.java b/src/test/java/org/springframework/data/release/git/GitPropertiesIntegrationTests.java new file mode 100644 index 0000000..b7d8503 --- /dev/null +++ b/src/test/java/org/springframework/data/release/git/GitPropertiesIntegrationTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.git; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.release.AbstractIntegrationTests; + +/** + * @author Oliver Gierke + */ +public class GitPropertiesIntegrationTests extends AbstractIntegrationTests { + + @Autowired GitProperties gitProperties; + + @Test + public void hasBasicPropertiesConfigured() { + assertThat(gitProperties.getAuthor(), is(notNullValue())); + assertThat(gitProperties.getEmail(), is(notNullValue())); + } +} diff --git a/src/test/java/org/springframework/data/release/io/CommonsExecOsCommandOperationsIntegegrationTests.java b/src/test/java/org/springframework/data/release/io/IoPropertiesIntegrationTests.java similarity index 51% rename from src/test/java/org/springframework/data/release/io/CommonsExecOsCommandOperationsIntegegrationTests.java rename to src/test/java/org/springframework/data/release/io/IoPropertiesIntegrationTests.java index 94e2b40..7b4b2ee 100644 --- a/src/test/java/org/springframework/data/release/io/CommonsExecOsCommandOperationsIntegegrationTests.java +++ b/src/test/java/org/springframework/data/release/io/IoPropertiesIntegrationTests.java @@ -21,38 +21,16 @@ import static org.junit.Assert.*; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.release.AbstractIntegrationTests; -import org.springframework.data.release.model.Projects; /** * @author Oliver Gierke */ -public class CommonsExecOsCommandOperationsIntegegrationTests extends AbstractIntegrationTests { +public class IoPropertiesIntegrationTests extends AbstractIntegrationTests { - @Autowired OsCommandOperations operations; + @Autowired IoProperties ioProperties; @Test - public void testname() throws Exception { - - // CommandResult result = operations - // .executeCommand("export GIT_TRACE=1 && git clone https://github.com/spring-projects/spring-data-build").get(); - - // CommandResult result = operations.executeCommand("git pull", Projects.BUILD).get(); - - CommandResult result = operations.executeCommand("git remote -v", Projects.BUILD).get(); - // .get(); - - if (result.hasError()) { - - System.out.println(result.getStatus()); - System.out.println(result.getOutput()); - System.out.println(result.getException().getMessage()); - - throw result.getException(); - } else { - System.out.println(result.getOutput()); - } - - assertThat(result.hasError(), is(false)); - + public void configuresWorkingDirectoryFromApplicationProperties() { + assertThat(ioProperties.getWorkDir(), is(notNullValue())); } } diff --git a/src/test/java/org/springframework/data/release/maven/MavenIntegrationTests.java b/src/test/java/org/springframework/data/release/maven/MavenIntegrationTests.java index 98df45e..d85930d 100644 --- a/src/test/java/org/springframework/data/release/maven/MavenIntegrationTests.java +++ b/src/test/java/org/springframework/data/release/maven/MavenIntegrationTests.java @@ -17,9 +17,7 @@ package org.springframework.data.release.maven; import java.io.IOException; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TemporaryFolder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.data.release.AbstractIntegrationTests; @@ -36,15 +34,13 @@ public class MavenIntegrationTests extends AbstractIntegrationTests { @Autowired Workspace workspace; @Autowired ProjectionFactory projection; - public @Rule TemporaryFolder folder = new TemporaryFolder(); - @Test public void modifiesParentPomCorrectly() throws IOException { XBFileIO io = projection.io().file(new ClassPathResource("parent-pom.xml").getFile()); ParentPom pom = io.read(ParentPom.class); - pom.setSharedResourcesVersion(ArtifactVersion.parse("1.2.0.RELEASE")); + pom.setSharedResourcesVersion(ArtifactVersion.of("1.2.0.RELEASE")); // System.out.println(projection.asString(pom)); } diff --git a/src/test/java/org/springframework/data/release/model/ArtifactVersionUnitTests.java b/src/test/java/org/springframework/data/release/model/ArtifactVersionUnitTests.java index f910cea..b606a2a 100644 --- a/src/test/java/org/springframework/data/release/model/ArtifactVersionUnitTests.java +++ b/src/test/java/org/springframework/data/release/model/ArtifactVersionUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,14 +15,10 @@ */ package org.springframework.data.release.model; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.junit.Test; -import org.springframework.data.release.model.ArtifactVersion; -import org.springframework.data.release.model.Iteration; -import org.springframework.data.release.model.IterationVersion; -import org.springframework.data.release.model.Version; /** * @author Oliver Gierke @@ -31,22 +27,22 @@ public class ArtifactVersionUnitTests { @Test(expected = IllegalArgumentException.class) public void rejectsInvalidVersionSuffix() { - ArtifactVersion.parse("1.4.5.GA"); + ArtifactVersion.of("1.4.5.GA"); } @Test public void parsesReleaseVersionCorrectly() { - ArtifactVersion version = ArtifactVersion.parse("1.4.5.RELEASE"); + ArtifactVersion version = ArtifactVersion.of("1.4.5.RELEASE"); assertThat(version.isReleaseVersion(), is(true)); - assertThat(version.getNextDevelopmentVersion(), is(ArtifactVersion.parse("1.4.6.BUILD-SNAPSHOT"))); + assertThat(version.getNextDevelopmentVersion(), is(ArtifactVersion.of("1.4.6.BUILD-SNAPSHOT"))); } @Test public void createsMilestoneVersionCorrectly() { - ArtifactVersion version = ArtifactVersion.parse("1.4.5.M1"); + ArtifactVersion version = ArtifactVersion.of("1.4.5.M1"); assertThat(version.isReleaseVersion(), is(false)); assertThat(version.isMilestoneVersion(), is(true)); @@ -55,7 +51,7 @@ public class ArtifactVersionUnitTests { @Test public void createsReleaseVersionByDefault() { - ArtifactVersion version = new ArtifactVersion(new Version(1, 4, 5)); + ArtifactVersion version = ArtifactVersion.of(Version.of(1, 4, 5)); assertThat(version.isReleaseVersion(), is(true)); assertThat(version.toString(), is("1.4.5.RELEASE")); @@ -64,8 +60,8 @@ public class ArtifactVersionUnitTests { @Test public void createsMilestoneVersionFromIteration() { - IterationVersion oneFourMilestoneOne = new SimpleIterationVersion(new Version(1, 4), Iteration.M1); - ArtifactVersion version = ArtifactVersion.from(oneFourMilestoneOne); + IterationVersion oneFourMilestoneOne = new SimpleIterationVersion(Version.of(1, 4), Iteration.M1); + ArtifactVersion version = ArtifactVersion.of(oneFourMilestoneOne); assertThat(version.isMilestoneVersion(), is(true)); assertThat(version.toString(), is("1.4.0.M1")); @@ -74,8 +70,8 @@ public class ArtifactVersionUnitTests { @Test public void createsReleaseVersionFromIteration() { - IterationVersion oneFourGA = new SimpleIterationVersion(new Version(1, 4), Iteration.GA); - ArtifactVersion version = ArtifactVersion.from(oneFourGA); + IterationVersion oneFourGA = new SimpleIterationVersion(Version.of(1, 4), Iteration.GA); + ArtifactVersion version = ArtifactVersion.of(oneFourGA); assertThat(version.isReleaseVersion(), is(true)); assertThat(version.toString(), is("1.4.0.RELEASE")); @@ -84,10 +80,48 @@ public class ArtifactVersionUnitTests { @Test public void createsServiceReleaseVersionFromIteration() { - IterationVersion oneFourServiceReleaseTwo = new SimpleIterationVersion(new Version(1, 4), Iteration.SR2); - ArtifactVersion version = ArtifactVersion.from(oneFourServiceReleaseTwo); + IterationVersion oneFourServiceReleaseTwo = new SimpleIterationVersion(Version.of(1, 4), Iteration.SR2); + ArtifactVersion version = ArtifactVersion.of(oneFourServiceReleaseTwo); assertThat(version.isReleaseVersion(), is(true)); assertThat(version.toString(), is("1.4.2.RELEASE")); } + + @Test + public void returnsNextMinorSnapshotVersionForGARelease() { + + ArtifactVersion version = ArtifactVersion.of("1.5.0.RELEASE").getNextDevelopmentVersion(); + + assertThat(version.isMilestoneVersion(), is(false)); + assertThat(version.isReleaseVersion(), is(false)); + assertThat(version, is(ArtifactVersion.of("1.6.0.BUILD-SNAPSHOT"))); + } + + @Test + public void ordersCorrectly() { + + ArtifactVersion oneNine = ArtifactVersion.of("1.9.0.RELEASE"); + ArtifactVersion oneTen = ArtifactVersion.of("1.10.0.RELEASE"); + + assertThat(oneNine.compareTo(oneTen), is(lessThan(0))); + } + + @Test + public void ordersSnapshotsOfSameVersionSmaller() { + + ArtifactVersion oneTenRelease = ArtifactVersion.of("1.10.0.RELEASE"); + ArtifactVersion oneTenSnapshot = ArtifactVersion.of("1.10.0.BUILD-SNAPSHOT"); + + assertThat(oneTenRelease.compareTo(oneTenSnapshot), is(greaterThan(0))); + } + + @Test + public void returnsCorrectBugfixVersions() { + + assertThat(ArtifactVersion.of("1.0.0.RELEASE").getNextBugfixVersion(), + is(ArtifactVersion.of("1.0.1.BUILD-SNAPSHOT"))); + assertThat(ArtifactVersion.of("1.0.0.M1").getNextBugfixVersion(), is(ArtifactVersion.of("1.0.0.BUILD-SNAPSHOT"))); + assertThat(ArtifactVersion.of("1.0.1.RELEASE").getNextBugfixVersion(), + is(ArtifactVersion.of("1.0.2.BUILD-SNAPSHOT"))); + } } diff --git a/src/test/java/org/springframework/data/release/TestConfig.java b/src/test/java/org/springframework/data/release/model/TestReleaseTrains.java similarity index 66% rename from src/test/java/org/springframework/data/release/TestConfig.java rename to src/test/java/org/springframework/data/release/model/TestReleaseTrains.java index 4ad5fa5..93d09a9 100644 --- a/src/test/java/org/springframework/data/release/TestConfig.java +++ b/src/test/java/org/springframework/data/release/model/TestReleaseTrains.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.release; +package org.springframework.data.release.model; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; +import java.util.Arrays; /** + * Sample release {@link Train} definitions. + * * @author Oliver Gierke */ -@Configuration -@ComponentScan -public class TestConfig { +public class TestReleaseTrains { + public static Train SAMPLE = new Train("SAMPLE", Arrays.asList(new Module(Projects.BUILD, "1.0"))); } diff --git a/src/test/java/org/springframework/data/release/model/TrainsUnitTest.java b/src/test/java/org/springframework/data/release/model/TrainsUnitTest.java new file mode 100644 index 0000000..f52650e --- /dev/null +++ b/src/test/java/org/springframework/data/release/model/TrainsUnitTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.model; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Unit tests for release {@link Train}s. + * + * @author Oliver Gierke + */ +public class TrainsUnitTest { + + @Test + public void prefersNewVersionOfAdditionalModule() { + + Module module = ReleaseTrains.HOPPER.getModule(Projects.NEO4J); + + assertThat(module.getVersion(), is(Version.parse("4.1"))); + } + + @Test + public void addsNewlyAddedModule() { + assertThat(ReleaseTrains.HOPPER.getModule(Projects.ENVERS), is(notNullValue())); + } +} diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties new file mode 100644 index 0000000..4982dd4 --- /dev/null +++ b/src/test/resources/application-test.properties @@ -0,0 +1,3 @@ +io.work-dir=~/temp/shell-test +logging.level.org.springframework=WARN +logging.level.org.springframework.data.release=INFO