diff --git a/release-tools/src/main/java/org/springframework/data/release/build/MavenBuildSystem.java b/release-tools/src/main/java/org/springframework/data/release/build/MavenBuildSystem.java index e6406d4..9a5a965 100644 --- a/release-tools/src/main/java/org/springframework/data/release/build/MavenBuildSystem.java +++ b/release-tools/src/main/java/org/springframework/data/release/build/MavenBuildSystem.java @@ -41,12 +41,11 @@ import org.springframework.data.release.model.Module; import org.springframework.data.release.model.ModuleIteration; 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; + import org.xmlbeam.ProjectionFactory; import org.xmlbeam.io.XBFileIO; @@ -116,7 +115,18 @@ class MavenBuildSystem implements BuildSystem { logger.log(project, "Triggering distribution build…"); mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, // - SKIP_TESTS, profile("distribute"), Argument.of("-B"))); + SKIP_TESTS, profile("distribute"), Argument.of("-B"), + arg("artifactory.server").withValue(properties.getServer().getUri()), + arg("distribution-repository").withValue(properties.getDistributionRepository()), + arg("artifactory.username").withValue(properties.getUsername()), + arg("artifactory.password").withValue(properties.getPassword()))); + + mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, // + SKIP_TESTS, profile("distribute-schema"), Argument.of("-B"), + arg("artifactory.server").withValue(properties.getServer().getUri()), + arg("distribution-repository").withValue(properties.getDistributionRepository()), + arg("artifactory.username").withValue(properties.getUsername()), + arg("artifactory.password").withValue(properties.getPassword()))); logger.log(project, "Successfully finished distribution build!"); @@ -192,36 +202,6 @@ class MavenBuildSystem implements BuildSystem { return true; } - /** - * Triggers building the distribution artifacts for all Maven projects of the given {@link Train}. - * - * @param iteration - * @throws Exception - */ - public void triggerDistributionBuild(TrainIteration iteration) throws Exception { - - ExecutionUtils.run(iteration, module -> { - - Project project = module.getProject(); - - if (BUILD.equals(project)) { - return; - } - - if (!isMavenProject(project)) { - logger.log(project, "Skipping project as no pom.xml could be found in the working directory!"); - return; - } - - logger.log(project, "Triggering distribution build…"); - - mvn.execute(project, - CommandLine.of(Goal.CLEAN, Goal.DEPLOY, ReleaseVersion.of(module).getDistributionProfiles(), SKIP_TESTS)); - - logger.log(project, "Successfully finished distribution build!"); - }); - } - /* * (non-Javadoc) * @see org.springframework.data.release.build.BuildSystem#prepareVersion(org.springframework.data.release.model.ModuleIteration, org.springframework.data.release.model.Phase) @@ -388,42 +368,4 @@ class MavenBuildSystem implements BuildSystem { throw new RuntimeException(o_O); } } - - @RequiredArgsConstructor(access = AccessLevel.PRIVATE) - private static class ReleaseVersion { - - private final ArtifactVersion version; - - /** - * Creates a new {@link ReleaseVersion} for the given {@link ModuleIteration}. - * - * @param module must not be {@literal null}. - * @return - */ - public static ReleaseVersion of(ModuleIteration module) { - - ArtifactVersion artifactVersion = ArtifactVersion.of(module); - - Assert.isTrue(artifactVersion.isMilestoneVersion() || artifactVersion.isReleaseVersion(), - String.format("Given module is not in a fixed version, detected %s!", artifactVersion)); - - return new ReleaseVersion(ArtifactVersion.of(module)); - } - - /** - * Returns the Maven profiles to be used during the distribution build. - * - * @return - */ - public Argument getDistributionProfiles() { - - if (version.isMilestoneVersion()) { - return profile("distribute", "milestone"); - } else if (version.isReleaseVersion()) { - return profile("distribute", "release"); - } - - throw new IllegalStateException("Should not occur!"); - } - } } diff --git a/release-tools/src/main/java/org/springframework/data/release/build/MavenProperties.java b/release-tools/src/main/java/org/springframework/data/release/build/MavenProperties.java index f1a3672..95edbc4 100644 --- a/release-tools/src/main/java/org/springframework/data/release/build/MavenProperties.java +++ b/release-tools/src/main/java/org/springframework/data/release/build/MavenProperties.java @@ -27,8 +27,9 @@ import org.springframework.util.Assert; /** * Maven configuration properties. - * + * * @author Oliver Gierke + * @author Mark Paluch */ @Slf4j @Data @@ -39,11 +40,12 @@ class MavenProperties { private File mavenHome; private File localRepository; private Map plugins; + private boolean consoleLogger = true; /** * Configures the local Maven repository location to use. In case the given folder does not already exists it's * created. - * + * * @param localRepository must not be {@literal null} or empty. */ public void setLocalRepository(String localRepository) { @@ -61,7 +63,7 @@ class MavenProperties { /** * Returns the fully-qualified plugin goal for the given local one. - * + * * @param goal must not be {@literal null} or empty. * @return */ diff --git a/release-tools/src/main/java/org/springframework/data/release/build/MavenRuntime.java b/release-tools/src/main/java/org/springframework/data/release/build/MavenRuntime.java index 1cbcbfc..2a63249 100644 --- a/release-tools/src/main/java/org/springframework/data/release/build/MavenRuntime.java +++ b/release-tools/src/main/java/org/springframework/data/release/build/MavenRuntime.java @@ -15,15 +15,22 @@ */ package org.springframework.data.release.build; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import java.io.Closeable; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import java.util.stream.Collectors; import org.apache.maven.shared.invoker.DefaultInvocationRequest; import org.apache.maven.shared.invoker.DefaultInvoker; import org.apache.maven.shared.invoker.InvocationResult; import org.apache.maven.shared.invoker.Invoker; -import org.apache.maven.shared.invoker.MavenInvocationException; + import org.springframework.data.release.io.OsOperations; import org.springframework.data.release.io.Workspace; import org.springframework.data.release.model.Project; @@ -62,37 +69,126 @@ class MavenRuntime { public void execute(Project project, CommandLine arguments) { - String logPrefix = StringUtils.padRight(project.getName(), 10); - Invoker invoker = new DefaultInvoker(); - invoker.setMavenHome(properties.getMavenHome()); - invoker.setOutputHandler(line -> log.info(logPrefix + ": " + line)); - invoker.setErrorHandler(line -> log.warn(logPrefix + ": " + line)); - - File localRepository = properties.getLocalRepository(); - - if (localRepository != null) { - invoker.setLocalRepositoryDirectory(localRepository); - } - - DefaultInvocationRequest request = new DefaultInvocationRequest(); - request.setJavaHome(os.getJavaHome()); - request.setShellEnvironmentInherited(true); - request.setBaseDirectory(workspace.getProjectDirectory(project)); - logger.log(project, "Executing mvn %s", arguments.toString()); - request.setGoals(arguments.toCommandLine(it -> properties.getFullyQualifiedPlugin(it.getGoal()))); + try (MavenLogger mavenLogger = getLogger(project, arguments.getGoals())) { - try { + Invoker invoker = new DefaultInvoker(); + invoker.setMavenHome(properties.getMavenHome()); + invoker.setOutputHandler(mavenLogger::info); + invoker.setErrorHandler(mavenLogger::warn); + + File localRepository = properties.getLocalRepository(); + + if (localRepository != null) { + invoker.setLocalRepositoryDirectory(localRepository); + } + + DefaultInvocationRequest request = new DefaultInvocationRequest(); + request.setJavaHome(os.getJavaHome()); + request.setShellEnvironmentInherited(true); + request.setBaseDirectory(workspace.getProjectDirectory(project)); + + request.setGoals(arguments.toCommandLine(it -> properties.getFullyQualifiedPlugin(it.getGoal()))); InvocationResult result = invoker.execute(request); if (result.getExitCode() != 0) { throw new RuntimeException(result.getExecutionException()); } - - } catch (MavenInvocationException o_O) { - throw new RuntimeException(o_O); + } catch (Exception e) { + throw new RuntimeException(e); } } + + private MavenLogger getLogger(Project project, List goals) { + + if (this.properties.isConsoleLogger()) { + return new SlfLogger(log, project); + } + + return new FileLogger(log, project, this.workspace.getLogsDirectory(), goals); + } + + /** + * Maven Logging Forwarder. + */ + interface MavenLogger extends Closeable { + + void info(String message); + + void warn(String message); + } + + @RequiredArgsConstructor + static class SlfLogger implements MavenLogger { + + private final org.slf4j.Logger logger; + private final String logPrefix; + + SlfLogger(org.slf4j.Logger logger, Project project) { + this.logger = logger; + this.logPrefix = StringUtils.padRight(project.getName(), 10); + } + + @Override + public void info(String message) { + logger.info(logPrefix + ": " + message); + } + + @Override + public void warn(String message) { + logger.warn(logPrefix + ": " + message); + } + + @Override + public void close() throws IOException { + // no-op + } + } + + static class FileLogger implements MavenLogger { + + private final PrintWriter printWriter; + private final FileOutputStream outputStream; + + FileLogger(org.slf4j.Logger logger, Project project, File logsDirectory, List goals) { + + if (!logsDirectory.exists()) { + logsDirectory.mkdirs(); + } + + String goalNames = goals.stream().map(CommandLine.Goal::getGoal).collect(Collectors.joining("-")); + + String filename = String.format("mvn-%s-%s.log", project.getName(), goalNames); + + try { + File file = new File(logsDirectory, filename); + logger.info("Routing Maven output to " + file.getCanonicalPath()); + outputStream = new FileOutputStream(file, true); + } catch (IOException e) { + throw new RuntimeException(e); + } + + printWriter = new PrintWriter(outputStream, true); + } + + @Override + public void info(String message) { + printWriter.println(message); + + } + + @Override + public void warn(String message) { + printWriter.println(message); + } + + @Override + public void close() throws IOException { + printWriter.close(); + outputStream.close(); + } + } + } diff --git a/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java index f63945c..a446c30 100644 --- a/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java +++ b/release-tools/src/main/java/org/springframework/data/release/deployment/DeploymentProperties.java @@ -28,6 +28,7 @@ import org.springframework.web.util.UriTemplate; /** * @author Oliver Gierke + * @author Mark Paluch */ @Data @Component @@ -56,6 +57,11 @@ public class DeploymentProperties { */ private String stagingRepository; + /** + * The repository to deploy docs/schemas to. + */ + private String distributionRepository; + private String repositoryPrefix = ""; private Gpg gpg; @@ -64,9 +70,13 @@ public class DeploymentProperties { return repositoryPrefix.concat(stagingRepository); } + public String getDistributionRepository() { + return repositoryPrefix.concat(distributionRepository); + } + /** * Returns the URI of the staging repository. - * + * * @return */ public String getStagingRepositoryUrl() { @@ -88,7 +98,7 @@ public class DeploymentProperties { /** * Returns the URI to the resource that a promotion can be triggered at. - * + * * @param information must not be {@literal null}. * @return */ diff --git a/release-tools/src/main/java/org/springframework/data/release/io/IoProperties.java b/release-tools/src/main/java/org/springframework/data/release/io/IoProperties.java index 3df5948..01001d3 100644 --- a/release-tools/src/main/java/org/springframework/data/release/io/IoProperties.java +++ b/release-tools/src/main/java/org/springframework/data/release/io/IoProperties.java @@ -25,6 +25,7 @@ import org.springframework.stereotype.Component; /** * @author Oliver Gierke + * @author Mark Paluch */ @Slf4j @Data @@ -32,7 +33,7 @@ import org.springframework.stereotype.Component; @ConfigurationProperties(prefix = "io") class IoProperties { - private File workDir, javaHome; + private File workDir, javaHome, logs; public void setWorkDir(String workDir) { diff --git a/release-tools/src/main/java/org/springframework/data/release/io/Workspace.java b/release-tools/src/main/java/org/springframework/data/release/io/Workspace.java index a55475e..d4a35ea 100644 --- a/release-tools/src/main/java/org/springframework/data/release/io/Workspace.java +++ b/release-tools/src/main/java/org/springframework/data/release/io/Workspace.java @@ -48,7 +48,7 @@ import org.springframework.util.Assert; /** * Abstraction of the workspace that is used to work with the {@link Project}'s repositories, execute builds, etc. - * + * * @author Oliver Gierke */ @Component @@ -64,25 +64,38 @@ public class Workspace { /** * Returns the current working directory. - * + * * @return */ public File getWorkingDirectory() { return ioProperties.getWorkDir(); } + /** + * Returns the current logs directory. + * + * @return + */ + public File getLogsDirectory() { + return ioProperties.getLogs(); + } + /** * Cleans up the working directory by removing all files and folders in it. - * + * * @throws IOException */ public void cleanup() throws IOException { - logger.log("Workspace", "Cleaning up workspace directory at %s.", getWorkingDirectory().getAbsolutePath()); + delete(getWorkingDirectory().toPath(), "workspace"); + delete(getLogsDirectory().toPath(), "logs"); + } - Path workingDirPath = getWorkingDirectory().toPath(); + private void delete(Path path, String type) throws IOException { - Files.walkFileTree(workingDirPath, new SimpleFileVisitor() { + logger.log("Workspace", "Cleaning up %s directory at %s.", type, path.toAbsolutePath()); + + Files.walkFileTree(path, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { @@ -93,7 +106,7 @@ public class Workspace { @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - if (!workingDirPath.equals(dir)) { + if (!path.equals(dir)) { Files.delete(dir); } @@ -130,7 +143,7 @@ public class Workspace { /** * Returns the directory for the given {@link Project}. - * + * * @param project must not be {@literal null}. * @return */ @@ -142,7 +155,7 @@ public class Workspace { /** * Returns whether the project directory for the given project already exists. - * + * * @param project must not be {@literal null}. * @return */ @@ -154,7 +167,7 @@ public class Workspace { /** * Returns a file with the given name relative to the working directory for the given {@link Project}. - * + * * @param name must not be {@literal null} or empty. * @param project must not be {@literal null}. * @return @@ -218,7 +231,7 @@ public class Workspace { /** * Initializes the working directory and creates the folders if necessary. - * + * * @throws IOException */ @PostConstruct diff --git a/release-tools/src/main/resources/application.properties b/release-tools/src/main/resources/application.properties index 288bf15..aab5b88 100644 --- a/release-tools/src/main/resources/application.properties +++ b/release-tools/src/main/resources/application.properties @@ -1,11 +1,14 @@ io.work-dir=~/temp/spring-data-shell/workspace +io.logs=logs # Maven setup maven.local-repository=~/temp/spring-data-shell/repository maven.plugins.versions=org.codehaus.mojo:versions-maven-plugin:2.2 +maven.console-logger=true deployment.server.uri=https://repo.spring.io deployment.staging-repository=libs-staging-local +deployment.distribution-repository=temp-private-local deployment.username=buildmaster #deployment.password <- local