From 0b937a8331560650583c0c10e34e4832c9e2edea Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 7 May 2019 16:50:10 +0200 Subject: [PATCH] Updates guides as a post action fixes gh-147 --- .../cloud/release/internal/Releaser.java | 38 +++++++- .../release/internal/ReleaserProperties.java | 13 +++ .../cloud/release/internal/git/GitRepo.java | 61 +++++++++++++ .../release/internal/git/GithubIssues.java | 6 ++ .../internal/git/ProjectGitHandler.java | 19 +++- .../internal/pom/ProcessedProject.java | 60 +++++++++++++ .../internal/pom/ProjectPomUpdater.java | 1 + .../release/internal/pom/ProjectVersion.java | 11 +++ .../internal/post/PostReleaseActions.java | 65 ++++++++++++-- .../internal/project/ProjectBuilder.java | 87 +++++++++++++----- .../internal/versions/VersionsFetcher.java | 13 ++- .../internal/pom/ProjectVersionTests.java | 11 +++ .../post/PostReleaseActionsTests.java | 75 +++++++++++++--- .../internal/project/ProjectBuilderTests.java | 35 ++------ .../versions/VersionsFetcherTests.java | 20 +++++ .../cloud/release/internal/spring/Args.java | 20 +++-- .../spring/ReleaserConfiguration.java | 9 +- .../spring/ReleaserPropertiesUpdater.java | 1 + .../internal/spring/SpringReleaser.java | 90 +++++++++++++------ .../cloud/release/internal/spring/Tasks.java | 4 +- .../internal/spring/AcceptanceTests.java | 7 +- .../internal/spring/SpringReleaserTests.java | 23 ++++- 22 files changed, 553 insertions(+), 116 deletions(-) create mode 100644 spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProcessedProject.java diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java index 1d292a87..bc8356aa 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java @@ -17,6 +17,7 @@ package org.springframework.cloud.release.internal; import java.io.File; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,6 +25,7 @@ import org.slf4j.LoggerFactory; import org.springframework.cloud.release.internal.docs.DocumentationUpdater; import org.springframework.cloud.release.internal.git.ProjectGitHandler; import org.springframework.cloud.release.internal.gradle.GradleUpdater; +import org.springframework.cloud.release.internal.pom.ProcessedProject; import org.springframework.cloud.release.internal.pom.ProjectPomUpdater; import org.springframework.cloud.release.internal.pom.ProjectVersion; import org.springframework.cloud.release.internal.pom.Projects; @@ -213,18 +215,48 @@ public class Releaser { } } - public void updateSpringGuides(ProjectVersion releaseVersion, Projects projects) { + public void updateSpringGuides(ProjectVersion releaseVersion, Projects projects, + List processedProjects) { if (!(releaseVersion.isRelease() || releaseVersion.isServiceRelease())) { log.info( "\nWon't update Spring Guides for a non Release / Service Release version"); return; } + Exception springGuidesException = createIssueInSpringGuides(releaseVersion, + projects); + Exception deployGuidesException = deployGuides(processedProjects); + if (springGuidesException != null || deployGuidesException != null) { + throw new MakeBuildUnstableException( + "Failed to update Spring Guides. Spring Guides updated successfully [" + + (springGuidesException != null) + + "] deployed guides successfully [" + + (deployGuidesException != null) + "]"); + } + } + + private Exception createIssueInSpringGuides(ProjectVersion releaseVersion, + Projects projects) { try { this.projectGitHandler.createIssueInSpringGuides(projects, releaseVersion); + log.info("\nSuccessfully created an issue in Spring Guides"); + return null; } catch (Exception ex) { - throw new MakeBuildUnstableException( - "Successfully updated Spring Guides issues", ex); + log.error("Failed to update Spring Guides repo", ex); + return new MakeBuildUnstableException("Failed to update Spring Guides repo", + ex); + } + } + + private Exception deployGuides(List processedProjects) { + try { + this.postReleaseActions.deployGuides(processedProjects); + log.info("\nSuccessfully updated the guides repo"); + return null; + } + catch (Exception ex) { + log.error("Failed to deploy new guides", ex); + return new MakeBuildUnstableException("Failed to deploy new guides", ex); } } diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/ReleaserProperties.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/ReleaserProperties.java index f4430730..c73441f2 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/ReleaserProperties.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/ReleaserProperties.java @@ -725,6 +725,11 @@ public class ReleaserProperties implements Serializable { */ private String deployCommand = "./mvnw deploy -DskipTests -B -Pfast,deploy {{systemProps}}"; + /** + * Command to be executed to build and deploy guides project only. + */ + private String deployGuidesCommand = "./mvnw clean verify deploy -B -Pguides,integration -pl guides {{systemProps}}"; + /** * Command to be executed to publish documentation. If present "{{version}}" will * be replaced by the provided version. @@ -777,6 +782,14 @@ public class ReleaserProperties implements Serializable { this.deployCommand = deployCommand; } + public String getDeployGuidesCommand() { + return this.deployGuidesCommand; + } + + public void setDeployGuidesCommand(String deployGuidesCommand) { + this.deployGuidesCommand = deployGuidesCommand; + } + public String[] getPublishDocsCommands() { return this.publishDocsCommands; } diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/GitRepo.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/GitRepo.java index b498700f..ba0fd7e1 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/GitRepo.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/GitRepo.java @@ -34,15 +34,18 @@ import com.jcraft.jsch.agentproxy.usocket.JNAUSocketFactory; import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.CloneCommand; import org.eclipse.jgit.api.CreateBranchCommand; +import org.eclipse.jgit.api.FetchCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ListBranchCommand; import org.eclipse.jgit.api.PushCommand; +import org.eclipse.jgit.api.ResetCommand; import org.eclipse.jgit.api.TransportConfigCallback; import org.eclipse.jgit.api.errors.EmtpyCommitException; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.JschConfigSessionFactory; import org.eclipse.jgit.transport.OpenSshConfig; import org.eclipse.jgit.transport.RefSpec; @@ -126,6 +129,34 @@ class GitRepo { } } + /** + * Fetch changes. + */ + void fetch() { + try { + log.info("Pull changes for repo [{}]", this.basedir); + fetch(this.basedir); + log.info("Successfully pulled the changes"); + } + catch (Exception e) { + throw new IllegalStateException(e); + } + } + + /** + * Reset changes. + */ + void reset() { + try { + log.info("Resetting changes for repo [{}]", this.basedir); + reset(this.basedir); + log.info("Successfully reset any changes"); + } + catch (Exception e) { + throw new IllegalStateException(e); + } + } + /** * Performs a commit. * @param message - commit message @@ -282,6 +313,36 @@ class GitRepo { return new File(destinationFolder, projectUrl.getHumanishName()); } + private FetchResult fetch(File projectDir) throws GitAPIException { + Git git = this.gitFactory.open(projectDir); + FetchCommand command = git.fetch(); + try { + return command.call(); + } + catch (GitAPIException e) { + deleteBaseDirIfExists(); + throw e; + } + finally { + git.close(); + } + } + + private Ref reset(File projectDir) throws GitAPIException { + Git git = this.gitFactory.open(projectDir); + ResetCommand command = git.reset().setMode(ResetCommand.ResetType.HARD); + try { + return command.call(); + } + catch (GitAPIException e) { + deleteBaseDirIfExists(); + throw e; + } + finally { + git.close(); + } + } + private Ref checkoutBranch(File projectDir, String branch) throws GitAPIException { Git git = this.gitFactory.open(projectDir); CheckoutCommand command = git.checkout().setName(branch); diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/GithubIssues.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/GithubIssues.java index f487db39..cd95bb05 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/GithubIssues.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/GithubIssues.java @@ -75,6 +75,12 @@ class GithubIssues { releaseVersion); return; } + fileAGithubIssue(projects, releaseVersion); + // iterate over projects, checkout the tag, build the guides project + // only with -Pintegration,guides profile + } + + private void fileAGithubIssue(Projects projects, String releaseVersion) { Repo springGuides = this.github.repos() .get(new Coordinates.Simple("spring-guides", "getting-started-guides")); String issueTitle = StringUtils.capitalize(releaseVersion) + " " diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/ProjectGitHandler.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/ProjectGitHandler.java index 864024e4..00a398ae 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/ProjectGitHandler.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/ProjectGitHandler.java @@ -19,6 +19,8 @@ package org.springframework.cloud.release.internal.git; import java.io.File; import java.nio.file.Files; import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jgit.transport.URIish; import org.slf4j.Logger; @@ -37,6 +39,8 @@ import org.springframework.util.StringUtils; */ public class ProjectGitHandler implements ReleaserPropertiesAware { + private static final Map CACHE = new ConcurrentHashMap<>(); + private static final Logger log = LoggerFactory.getLogger(ProjectGitHandler.class); private static final String MSG = "Bumping versions"; @@ -195,11 +199,24 @@ public class ProjectGitHandler implements ReleaserPropertiesAware { File cloneProject(String url) { try { + URIish urIish = new URIish(url); + // retrieve from cache + // reset any changes and fetch the latest data + File clonedProject = CACHE.get(urIish); + if (clonedProject != null) { + log.info( + "Project has already been cloned. Will reset the current branch and fetch the latest changes."); + gitRepo(clonedProject).reset(); + gitRepo(clonedProject).fetch(); + return clonedProject; + } File destinationDir = this.properties.getGit() .getCloneDestinationDir() != null ? new File(this.properties.getGit().getCloneDestinationDir()) : Files.createTempDirectory("releaser").toFile(); - return gitRepo(destinationDir).cloneProject(new URIish(url)); + File clonedLocation = gitRepo(destinationDir).cloneProject(urIish); + CACHE.put(urIish, clonedLocation); + return clonedLocation; } catch (Exception e) { throw new IllegalStateException(e); diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProcessedProject.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProcessedProject.java new file mode 100644 index 00000000..c4072a88 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProcessedProject.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013-2019 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 + * + * https://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.cloud.release.internal.pom; + +import org.springframework.cloud.release.internal.ReleaserProperties; + +/** + * Represents a processed project. + * + * @author Marcin Grzejszczak + */ +public class ProcessedProject { + + /** + * Updated properties for a given project. When doing a meta-release this will + * represent a merge of the global properties with the per-application ones. For + * non-meta-release these will be the application properties. + */ + public final ReleaserProperties propertiesForProject; + + /** + * Version to which the project should be updated. + */ + public final ProjectVersion newProjectVersion; + + public ProcessedProject(ReleaserProperties propertiesForProject, + ProjectVersion newProjectVersion) { + this.propertiesForProject = propertiesForProject; + this.newProjectVersion = newProjectVersion; + } + + @Override + public String toString() { + return "ProcessedProject{" + "name=" + projectName() + ",version=" + + projectVersion() + '}'; + } + + public String projectName() { + return this.newProjectVersion.projectName; + } + + private String projectVersion() { + return this.newProjectVersion.version; + } + +} diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectPomUpdater.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectPomUpdater.java index 21d88c54..83190709 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectPomUpdater.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectPomUpdater.java @@ -89,6 +89,7 @@ public class ProjectPomUpdater implements ReleaserPropertiesAware { * ones * @return projects retrieved from the release train bom */ + // TODO: I don't like this flag but don't have a better idea public Projects retrieveVersionsFromReleaseTrainBom(String branch, boolean updateFixedVersions) { Versions versions = CACHE.computeIfAbsent(branch, s -> { diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java index 62381b99..8fdf8c96 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java @@ -232,6 +232,17 @@ public class ProjectVersion implements Comparable { .compareTo(new TrainVersionNumber(thatValue)); } + /** + * Returns the release tag name. + * @return tag name or empty if non ga or sr. + */ + public String releaseTagName() { + if (isReleaseOrServiceRelease()) { + return "v" + this.version; + } + return ""; + } + @Override public String toString() { return this.version; diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/post/PostReleaseActions.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/post/PostReleaseActions.java index d4c17989..75a533bd 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/post/PostReleaseActions.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/post/PostReleaseActions.java @@ -34,10 +34,12 @@ import org.slf4j.LoggerFactory; import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.git.ProjectGitHandler; import org.springframework.cloud.release.internal.gradle.GradleUpdater; +import org.springframework.cloud.release.internal.pom.ProcessedProject; import org.springframework.cloud.release.internal.pom.ProjectPomUpdater; import org.springframework.cloud.release.internal.pom.ProjectVersion; import org.springframework.cloud.release.internal.pom.Projects; import org.springframework.cloud.release.internal.project.ProjectBuilder; +import org.springframework.cloud.release.internal.versions.VersionsFetcher; import org.springframework.core.NestedExceptionUtils; import org.springframework.util.StringUtils; @@ -60,14 +62,42 @@ public class PostReleaseActions implements Closeable { private final ReleaserProperties properties; + private final VersionsFetcher versionsFetcher; + public PostReleaseActions(ProjectGitHandler projectGitHandler, ProjectPomUpdater projectPomUpdater, GradleUpdater gradleUpdater, - ProjectBuilder projectBuilder, ReleaserProperties properties) { + ProjectBuilder projectBuilder, ReleaserProperties properties, + VersionsFetcher versionsFetcher) { this.projectGitHandler = projectGitHandler; this.projectPomUpdater = projectPomUpdater; this.gradleUpdater = gradleUpdater; this.projectBuilder = projectBuilder; this.properties = properties; + this.versionsFetcher = versionsFetcher; + } + + /** + * Clones the projects, checks out the proper branch and runs guides building and + * deployment. + * @param processedProjects - set of project with versions to assert against + */ + public void deployGuides(List processedProjects) { + if (!this.properties.getGit().isUpdateSpringGuides()) { + log.info( + "Will not build and deploy latest Spring Guides, since the switch to do so " + + "is off. Set [releaser.git.update-spring-guides] to [true] to change that"); + return; + } + List latestGaProcessedProjects = processedProjects.stream() + .filter(processedProject -> this.versionsFetcher + .isLatestGa(processedProject.newProjectVersion)) + .collect(Collectors.toList()); + log.info("Found the following latest ga processed projects " + + latestGaProcessedProjects); + List projectUrlAndExceptions = runDeployGuides( + latestGaProcessedProjects); + log.info("Deployed all guides!"); + assertExceptions(projectUrlAndExceptions); } /** @@ -108,6 +138,10 @@ public class PostReleaseActions implements Closeable { .map(e -> updateAllProjects(projects, e)).map(this::getResult) .flatMap(Collection::stream).collect(Collectors.toList()); log.info("Updated all samples!"); + assertExceptions(projectUrlAndExceptions); + } + + private void assertExceptions(List projectUrlAndExceptions) { String exceptionMessages = projectUrlAndExceptions.stream() .filter(ProjectUrlAndException::hasException) .map(e -> "Project [" + e.key + "] for url [" + e.url + "] " @@ -119,13 +153,34 @@ public class PostReleaseActions implements Closeable { .collect(Collectors.joining("\n")); if (StringUtils.hasText(exceptionMessages)) { throw new IllegalStateException( - "Exceptions were found while updating samples\n" + exceptionMessages); + "Exceptions were found while running post release tasks\n" + + exceptionMessages); } else { - log.info("No exceptions were found while updating the samples"); + log.info("No exceptions were found while running post release tasks"); } } + private List runDeployGuides( + List latestGaProcessedProjects) { + return latestGaProcessedProjects.stream() + .map(processedProject -> run(processedProject.projectName(), "", + () -> SERVICE.submit(() -> { + String tagName = processedProject.newProjectVersion + .releaseTagName(); + File clonedProject = this.projectGitHandler + .cloneProjectFromOrg(processedProject.projectName()); + this.projectGitHandler.checkout(clonedProject, tagName); + projectBuilder(processedProject) + .deployGuides(processedProject.newProjectVersion); + }))) + .map(this::getSingleResult).collect(Collectors.toList()); + } + + ProjectBuilder projectBuilder(ProcessedProject processedProject) { + return new ProjectBuilder(processedProject.propertiesForProject); + } + private Future> updateAllProjects(Projects projects, Map.Entry> e) { return SERVICE.submit(() -> { @@ -142,7 +197,7 @@ public class PostReleaseActions implements Closeable { .map(url -> run(key, url, () -> commitUpdatedProject(projects, key, projectVersionForReleaseTrain, postRelease, url))) - .map(this::getResult).collect(Collectors.toList()); + .map(this::getSingleResult).collect(Collectors.toList()); }); } @@ -201,7 +256,7 @@ public class PostReleaseActions implements Closeable { return new ProjectAndFuture(key, url, SERVICE.submit(runnable)); } - private ProjectUrlAndException getResult(ProjectAndFuture projectAndFuture) { + private ProjectUrlAndException getSingleResult(ProjectAndFuture projectAndFuture) { Exception e = null; try { projectAndFuture.future.get(10, TimeUnit.MINUTES); diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/project/ProjectBuilder.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/project/ProjectBuilder.java index 05b031aa..444aa9e0 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/project/ProjectBuilder.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/project/ProjectBuilder.java @@ -37,7 +37,6 @@ import org.slf4j.LoggerFactory; import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.ReleaserPropertiesAware; import org.springframework.cloud.release.internal.pom.ProjectVersion; -import org.springframework.cloud.release.internal.versions.VersionsFetcher; import org.springframework.util.StringUtils; /** @@ -45,18 +44,49 @@ import org.springframework.util.StringUtils; */ public class ProjectBuilder implements ReleaserPropertiesAware { + /** + * Enumeration over commonly used Maven profiles. + */ + private enum Profile { + + /** + * Profile used for milestone versions. + */ + MILESTONE, + + /** + * Profile used for ga versions. + */ + CENTRAL, + + /** + * Profile used to run integration tests. + */ + INTEGRATION, + + /** + * Profile used to run guides publishing. + */ + GUIDES; + + /** + * Converts the profile to lowercase, maven command line property. + * @return profile with prepended -P + */ + public String asMavenProfile() { + return "-P" + this.name().toLowerCase(); + } + + } + private static final Logger log = LoggerFactory.getLogger(ProjectBuilder.class); private static final String VERSION_MUSTACHE = "{{version}}"; private ReleaserProperties properties; - private final VersionsFetcher versionsFetcher; - - public ProjectBuilder(ReleaserProperties properties, - VersionsFetcher versionsFetcher) { + public ProjectBuilder(ReleaserProperties properties) { this.properties = properties; - this.versionsFetcher = versionsFetcher; } public void build(ProjectVersion versionFromReleaseTrain) { @@ -91,23 +121,27 @@ public class ProjectBuilder implements ReleaserPropertiesAware { } } - private String commandWithSystemProps(String command, ProjectVersion version) { + private String commandWithSystemProps(String command, ProjectVersion version, + Profile... profiles) { if (command.contains(ReleaserProperties.Maven.SYSTEM_PROPS_PLACEHOLDER)) { - return appendProfile(command, version); + return appendProfile(command, version, profiles); } - return appendProfile(command, version) + " " + return appendProfile(command, version, profiles) + " " + ReleaserProperties.Maven.SYSTEM_PROPS_PLACEHOLDER; } - private String appendProfile(String command, ProjectVersion version) { + private String appendProfile(String command, ProjectVersion version, + Profile... profiles) { String trimmedCommand = command.trim(); if (version.isMilestone() || version.isRc()) { log.info("Adding the milestone profile to the Maven build"); - return trimmedCommand + " -Pmilestone"; + return trimmedCommand + " " + Profile.MILESTONE.asMavenProfile() + + profilesToString(profiles); } else if (version.isRelease() || version.isServiceRelease()) { log.info("Adding the central profile to the Maven build"); - return trimmedCommand + " -Pcentral" + profilesForLatestVersion(version); + return trimmedCommand + " " + Profile.CENTRAL.asMavenProfile() + + profilesToString(profiles); } else { log.info("The build is a snapshot one - will not add any profiles"); @@ -115,14 +149,9 @@ public class ProjectBuilder implements ReleaserPropertiesAware { return trimmedCommand; } - private String profilesForLatestVersion(ProjectVersion projectVersion) { - boolean latestGa = this.versionsFetcher.isLatestGa(projectVersion); - if (latestGa) { - log.info("Version [" + projectVersion.version - + "] is the latest GA! Will append additional profiles"); - return " -Pguides"; - } - return ""; + private String profilesToString(Profile... profiles) { + return Arrays.stream(profiles).map(profile -> "-P" + profile) + .collect(Collectors.joining(" ")); } private void assertNoHtmlFilesInDocsContainUnresolvedTags(String workingDir) { @@ -139,9 +168,18 @@ public class ProjectBuilder implements ReleaserPropertiesAware { } public void deploy(ProjectVersion version) { + doDeploy(version, this.properties.getMaven().getDeployCommand()); + } + + public void deployGuides(ProjectVersion version) { + doDeploy(version, this.properties.getMaven().getDeployGuidesCommand(), + Profile.GUIDES, Profile.INTEGRATION); + } + + private void doDeploy(ProjectVersion version, String command, Profile... profiles) { try { - String[] commands = commandWithSystemProps( - this.properties.getMaven().getDeployCommand(), version).split(" "); + String[] commands = commandWithSystemProps(command, version, profiles) + .split(" "); runCommand(commands); log.info("The project has successfully been deployed"); } @@ -204,6 +242,11 @@ public class ProjectBuilder implements ReleaserPropertiesAware { break; } } + return toCommandList(systemPropsWithPrefix, index, commands); + } + + private String[] toCommandList(String[] systemPropsWithPrefix, AtomicInteger index, + String[] commands) { List commandsList = new ArrayList<>(Arrays.asList(commands)); List systemPropsList = Arrays.asList(systemPropsWithPrefix); if (index.get() != -1) { diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/versions/VersionsFetcher.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/versions/VersionsFetcher.java index 8965ffd0..dbc3acb8 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/versions/VersionsFetcher.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/versions/VersionsFetcher.java @@ -97,8 +97,17 @@ public class VersionsFetcher implements ReleaserPropertiesAware { this.properties.getVersions().getBomName()); return false; } - Projects projectVersions = this.projectPomUpdater - .retrieveVersionsFromReleaseTrainBom("v" + bomVersion.toString(), false); + Projects projectVersions = null; + try { + projectVersions = this.projectPomUpdater.retrieveVersionsFromReleaseTrainBom( + "v" + bomVersion.toString(), false); + } + catch (Exception ex) { + log.error( + "Failed to check the project versions. Will return that the proejct is not GA", + ex); + return false; + } boolean containsProject = projectVersions.containsProject(version.projectName); if (containsProject) { return bomVersion.compareTo(projectVersions.forName(version.projectName)) > 0; diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java index 9462f85c..dc57bdd6 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java @@ -463,6 +463,17 @@ public class ProjectVersionTests { unknownTypeOfVersion); } + @Test + public void should_return_v100RELEASE_when_tag_name_is_requested() { + then(projectVersion("1.0.0.RELEASE").releaseTagName()) + .isEqualTo("v1.0.0.RELEASE"); + } + + @Test + public void should_return_empty_when_tag_name_is_non_ga() { + then(projectVersion("1.0.0.BUILD-SNAPSHOT").releaseTagName()).isEmpty(); + } + private void thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent( List unknownTypeOfVersion) { then(unknownTypeOfVersion).isNotEmpty(); diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/post/PostReleaseActionsTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/post/PostReleaseActionsTests.java index cd355d95..059adef4 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/post/PostReleaseActionsTests.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/post/PostReleaseActionsTests.java @@ -39,6 +39,7 @@ import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.git.GitTestUtils; import org.springframework.cloud.release.internal.git.ProjectGitHandler; import org.springframework.cloud.release.internal.gradle.GradleUpdater; +import org.springframework.cloud.release.internal.pom.ProcessedProject; import org.springframework.cloud.release.internal.pom.ProjectPomUpdater; import org.springframework.cloud.release.internal.pom.ProjectVersion; import org.springframework.cloud.release.internal.pom.Projects; @@ -94,7 +95,7 @@ public class PostReleaseActionsTests { VersionsFetcher versionsFetcher = new VersionsFetcher(properties, updater); - ProjectBuilder builder = new ProjectBuilder(this.properties, versionsFetcher); + ProjectBuilder builder = new ProjectBuilder(this.properties); @Before public void setup() throws Exception { @@ -107,7 +108,8 @@ public class PostReleaseActionsTests { public void should_do_nothing_when_is_not_meta_release_and_update_test_is_called() { this.properties.getMetaRelease().setEnabled(false); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties); + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); actions.runUpdatedTests(currentGa()); @@ -119,7 +121,8 @@ public class PostReleaseActionsTests { public void should_do_nothing_when_the_switch_for_sample_check_is_off_and_update_test_is_called() { this.properties.getGit().setRunUpdatedSamples(false); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties); + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); actions.runUpdatedTests(currentGa()); @@ -134,7 +137,8 @@ public class PostReleaseActionsTests { tmpFile("spring-cloud-core-tests/").getAbsolutePath() + "/"); this.properties.getMaven().setBuildCommand("touch build.log"); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties); + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); actions.runUpdatedTests(currentGa()); @@ -156,7 +160,8 @@ public class PostReleaseActionsTests { public void should_do_nothing_when_is_not_meta_release_and_release_train_docs_generation_is_called() { this.properties.getMetaRelease().setEnabled(false); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties); + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); actions.generateReleaseTrainDocumentation(currentGa()); @@ -167,7 +172,8 @@ public class PostReleaseActionsTests { public void should_do_nothing_when_the_switch_for_sample_check_is_off_and_release_train_docs_generation_is_called() { this.properties.getGit().setUpdateReleaseTrainDocs(false); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties); + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); actions.generateReleaseTrainDocumentation(currentGa()); @@ -182,7 +188,8 @@ public class PostReleaseActionsTests { this.properties.getMaven() .setGenerateReleaseTrainDocsCommand("touch generate.log"); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties); + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); actions.generateReleaseTrainDocumentation(currentGa()); @@ -198,7 +205,8 @@ public class PostReleaseActionsTests { public void should_do_nothing_when_is_not_meta_release_and_test_samples_update_is_called() { this.properties.getMetaRelease().setEnabled(false); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties); + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); actions.updateAllTestSamples(currentGa()); @@ -210,7 +218,8 @@ public class PostReleaseActionsTests { public void should_do_nothing_when_the_switch_for_test_samples_update_check_is_off_and_update_is_called() { this.properties.getGit().setUpdateReleaseTrainDocs(false); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties); + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); actions.updateAllTestSamples(currentGa()); @@ -228,7 +237,8 @@ public class PostReleaseActionsTests { tmpFile("spring-cloud-core-tests/").getAbsolutePath() + "/")); AtomicReference postReleaseProjects = new AtomicReference<>(); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties) { + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher) { @Override Projects getPostReleaseProjects(Projects projects) { postReleaseProjects.set(super.getPostReleaseProjects(projects)); @@ -270,7 +280,8 @@ public class PostReleaseActionsTests { tmpFile("spring-cloud-static/").getAbsolutePath() + "/")); AtomicReference postReleaseProjects = new AtomicReference<>(); PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.builder, this.properties) { + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher) { @Override Projects getPostReleaseProjects(Projects projects) { postReleaseProjects.set(super.getPostReleaseProjects(projects)); @@ -285,6 +296,48 @@ public class PostReleaseActionsTests { .orElseThrow(() -> new IllegalStateException("Not found")); } + @Test + public void should_do_nothing_when_guides_are_turned_off() { + this.properties.getGit().setUpdateSpringGuides(false); + VersionsFetcher versionsFetcher = BDDMockito.mock(VersionsFetcher.class); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, + this.updater, this.gradleUpdater, this.builder, this.properties, + versionsFetcher); + + actions.deployGuides(Collections.emptyList()); + + BDDAssertions.then(this.cloned).isNull(); + BDDMockito.then(versionsFetcher).shouldHaveZeroInteractions(); + } + + @Test + public void should_build_and_deploy_guides_when_switch_is_on() throws Exception { + this.properties.getGit().setUpdateSpringGuides(true); + String projects = this.temporaryFolder.getAbsolutePath(); + this.properties.getMetaRelease().setGitOrgUrl(projects); + VersionsFetcher versionsFetcher = BDDMockito.mock(VersionsFetcher.class); + BDDMockito.given(versionsFetcher.isLatestGa(BDDMockito.any())).willReturn(true); + AtomicReference projectBuilderStub = new AtomicReference<>(); + ProjectGitHandler handler = BDDMockito.mock(ProjectGitHandler.class); + ProjectBuilder projectBuilder = BDDMockito.mock(ProjectBuilder.class); + PostReleaseActions actions = new PostReleaseActions(handler, this.updater, + this.gradleUpdater, this.builder, this.properties, versionsFetcher) { + @Override + ProjectBuilder projectBuilder(ProcessedProject processedProject) { + projectBuilderStub.set(projectBuilder); + return projectBuilder; + } + }; + ProjectVersion projectVersion = new ProjectVersion( + new File(projects, "spring-cloud-release")); + + actions.deployGuides(Collections + .singletonList(new ProcessedProject(this.properties, projectVersion))); + + BDDAssertions.then(projectBuilderStub.get()).isNotNull(); + BDDMockito.then(projectBuilderStub.get()).should().deployGuides(projectVersion); + } + private String sleuthParentPomVersion() { return this.testPomReader.readPom(new File(this.cloned, "sleuth/pom.xml")) .getParent().getVersion(); diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/project/ProjectBuilderTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/project/ProjectBuilderTests.java index 29c9d8f0..5e5ac059 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/project/ProjectBuilderTests.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/project/ProjectBuilderTests.java @@ -32,10 +32,8 @@ import org.junit.rules.TemporaryFolder; import org.springframework.boot.test.rule.OutputCapture; import org.springframework.cloud.release.internal.PomUpdateAcceptanceTests; import org.springframework.cloud.release.internal.ReleaserProperties; -import org.springframework.cloud.release.internal.pom.ProjectPomUpdater; import org.springframework.cloud.release.internal.pom.ProjectVersion; import org.springframework.cloud.release.internal.pom.TestUtils; -import org.springframework.cloud.release.internal.versions.VersionsFetcher; import org.springframework.util.FileSystemUtils; import static org.assertj.core.api.BDDAssertions.then; @@ -63,7 +61,7 @@ public class ProjectBuilderTests { } ProjectBuilder projectBuilder(ReleaserProperties properties) { - return new ProjectBuilder(properties, versionsFetcher(properties)) { + return new ProjectBuilder(properties) { @Override ProcessExecutor executor(String workingDir) { return testExecutor(workingDir); @@ -139,7 +137,7 @@ public class ProjectBuilderTests { builder.build(new ProjectVersion("foo", "1.0.0.RELEASE")); then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("foo -Pcentral -Pguides"); + .contains("foo -Pcentral"); } @Test @@ -308,7 +306,7 @@ public class ProjectBuilderTests { builder.deploy(new ProjectVersion("foo", "1.0.0.RELEASE")); then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("foo -Pcentral -Pguides"); + .contains("foo -Pcentral"); } @Test @@ -322,7 +320,7 @@ public class ProjectBuilderTests { builder.deploy(new ProjectVersion("foo", "1.0.0.SR1")); then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("foo -Pcentral -Pguides"); + .contains("foo -Pcentral"); } @Test @@ -375,8 +373,7 @@ public class ProjectBuilderTests { properties.getMaven().setPublishDocsCommands(new String[] { "ls -al", "ls -al" }); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); TestProcessExecutor executor = testExecutor(properties.getWorkingDir()); - ProjectBuilder builder = new ProjectBuilder(properties, - versionsFetcher(properties)) { + ProjectBuilder builder = new ProjectBuilder(properties) { @Override ProcessExecutor executor(String workingDir) { return executor; @@ -390,16 +387,6 @@ public class ProjectBuilderTests { then(executor.counter).isEqualTo(2); } - private VersionsFetcher versionsFetcher(ReleaserProperties properties) { - ProjectPomUpdater pomUpdater = new ProjectPomUpdater(properties); - return new VersionsFetcher(properties, pomUpdater) { - @Override - public boolean isLatestGa(ProjectVersion version) { - return true; - } - }; - } - @Test public void should_successfully_execute_a_publish_docs_command_with_sys_props_placeholder() throws Exception { @@ -409,8 +396,7 @@ public class ProjectBuilderTests { properties.getMaven().setSystemProperties("-Dhello=world -Dfoo=bar"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); TestProcessExecutor executor = testExecutor(properties.getWorkingDir()); - ProjectBuilder builder = new ProjectBuilder(properties, - versionsFetcher(properties)) { + ProjectBuilder builder = new ProjectBuilder(properties) { @Override ProcessExecutor executor(String workingDir) { return executor; @@ -432,8 +418,7 @@ public class ProjectBuilderTests { .setPublishDocsCommands(new String[] { "echo '{{version}}'" }); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); TestProcessExecutor executor = testExecutor(properties.getWorkingDir()); - ProjectBuilder builder = new ProjectBuilder(properties, - versionsFetcher(properties)) { + ProjectBuilder builder = new ProjectBuilder(properties) { @Override ProcessExecutor executor(String workingDir) { return executor; @@ -454,8 +439,7 @@ public class ProjectBuilderTests { File resolved = tmpFile("/builder/resolved"); properties.setWorkingDir(resolved.getPath()); TestProcessExecutor executor = testExecutor(properties.getWorkingDir()); - ProjectBuilder builder = new ProjectBuilder(properties, - versionsFetcher(properties)) { + ProjectBuilder builder = new ProjectBuilder(properties) { @Override ProcessExecutor executor(String workingDir) { return executor; @@ -486,8 +470,7 @@ public class ProjectBuilderTests { ReleaserProperties properties = new ReleaserProperties(); properties.getMaven().setBuildCommand("exit 1"); properties.setWorkingDir(tmpFile("/builder/unresolved").getPath()); - ProjectBuilder builder = new ProjectBuilder(properties, - versionsFetcher(properties)) { + ProjectBuilder builder = new ProjectBuilder(properties) { @Override ProcessExecutor executor(String workingDir) { return new ProcessExecutor(properties.getWorkingDir()) { diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/versions/VersionsFetcherTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/versions/VersionsFetcherTests.java index 290d17e7..3fe632f9 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/versions/VersionsFetcherTests.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/versions/VersionsFetcherTests.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.pom.ProjectPomUpdater; import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; class VersionsFetcherTests { @@ -99,6 +100,25 @@ class VersionsFetcherTests { BDDAssertions.then(latestGa).isFalse(); } + @Test + void should_return_false_when_exception_occurs_while_fetching_version_info() { + ProjectVersion projectVersion = new ProjectVersion("spring-cloud-contract", + "1.0.0.BUILD-SNAPSHOT"); + ReleaserProperties properties = new ReleaserProperties(); + VersionsFetcher versionsFetcher = new VersionsFetcher(properties, + new ProjectPomUpdater(properties) { + @Override + public Projects retrieveVersionsFromReleaseTrainBom(String branch, + boolean updateFixedVersions) { + throw new IllegalStateException("BOOM!"); + } + }); + + boolean latestGa = versionsFetcher.isLatestGa(projectVersion); + + BDDAssertions.then(latestGa).isFalse(); + } + private File file(String relativePath) throws URISyntaxException { return new File(VersionsFetcherTests.class.getResource(relativePath).toURI()); } diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Args.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Args.java index 222f8e9d..2dfe8f49 100644 --- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Args.java +++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Args.java @@ -17,12 +17,15 @@ package org.springframework.cloud.release.internal.spring; import java.io.File; +import java.util.Collections; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.release.internal.Releaser; import org.springframework.cloud.release.internal.ReleaserProperties; +import org.springframework.cloud.release.internal.pom.ProcessedProject; import org.springframework.cloud.release.internal.pom.ProjectVersion; import org.springframework.cloud.release.internal.pom.Projects; import org.springframework.context.ApplicationEvent; @@ -47,6 +50,8 @@ class Args { final ReleaserProperties properties; + final List processedProjects; + final boolean interactive; final TaskType taskType; @@ -63,6 +68,8 @@ class Args { this.originalVersion = originalVersion; this.versionFromScRelease = versionFromScRelease; this.properties = properties; + this.processedProjects = Collections + .singletonList(new ProcessedProject(properties, versionFromScRelease)); this.interactive = interactive; this.taskType = taskType; this.applicationEventPublisher = applicationEventPublisher; @@ -70,14 +77,15 @@ class Args { // Used by meta-release task Args(Releaser releaser, Projects projects, ProjectVersion versionFromScRelease, - ReleaserProperties properties, boolean interactive, - ApplicationEventPublisher applicationEventPublisher) { + ReleaserProperties properties, List processedProjects, + boolean interactive, ApplicationEventPublisher applicationEventPublisher) { this.releaser = releaser; this.project = null; this.projects = projects; this.originalVersion = null; this.versionFromScRelease = versionFromScRelease; this.properties = properties; + this.processedProjects = processedProjects; this.interactive = interactive; this.taskType = TaskType.POST_RELEASE; this.applicationEventPublisher = applicationEventPublisher; @@ -91,6 +99,7 @@ class Args { this.originalVersion = null; this.versionFromScRelease = null; this.properties = null; + this.processedProjects = Collections.emptyList(); this.interactive = false; this.taskType = taskType; this.applicationEventPublisher = null; @@ -112,10 +121,9 @@ class Args { public String toString() { return "Args{" + "releaser=" + this.releaser + ", project=" + this.project + ", projects=" + this.projects + ", originalVersion=" - + this.originalVersion + ", versionFromScRelease=" - + this.versionFromScRelease + ", properties=" + this.properties - + ", interactive=" + this.interactive + ", taskType=" + this.taskType - + '}'; + + this.originalVersion + ", versionFromBom=" + this.versionFromScRelease + + ", properties=" + this.properties + ", interactive=" + this.interactive + + ", taskType=" + this.taskType + '}'; } } diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java index 464c7d6c..4936386b 100644 --- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java +++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java @@ -56,8 +56,8 @@ class ReleaserConfiguration { } @Bean - ProjectBuilder projectBuilder(VersionsFetcher versionsFetcher) { - return new ProjectBuilder(this.properties, versionsFetcher); + ProjectBuilder projectBuilder() { + return new ProjectBuilder(this.properties); } @Bean @@ -94,9 +94,10 @@ class ReleaserConfiguration { @Bean PostReleaseActions postReleaseActions(ProjectGitHandler handler, ProjectPomUpdater pomUpdater, GradleUpdater gradleUpdater, - ProjectBuilder projectBuilder, ReleaserProperties releaserProperties) { + ProjectBuilder projectBuilder, ReleaserProperties releaserProperties, + VersionsFetcher versionsFetcher) { return new PostReleaseActions(handler, pomUpdater, gradleUpdater, projectBuilder, - releaserProperties); + releaserProperties, versionsFetcher); } @Bean diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserPropertiesUpdater.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserPropertiesUpdater.java index f458532e..c0dcdc17 100644 --- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserPropertiesUpdater.java +++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserPropertiesUpdater.java @@ -50,6 +50,7 @@ class ReleaserPropertiesUpdater { File clonedProjectFromOrg) { ReleaserProperties props = updatePropertiesFromFile(properties, clonedProjectFromOrg); + props.setWorkingDir(clonedProjectFromOrg.getAbsolutePath()); log.info("Updated properties [\n\n{}\n\n]", props); updateProperties(props); return props; diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/SpringReleaser.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/SpringReleaser.java index aa16c725..2251cb92 100644 --- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/SpringReleaser.java +++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/SpringReleaser.java @@ -19,6 +19,8 @@ package org.springframework.cloud.release.internal.spring; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import org.slf4j.Logger; @@ -28,6 +30,7 @@ import org.springframework.cloud.release.internal.Releaser; import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.options.Options; import org.springframework.cloud.release.internal.options.OptionsBuilder; +import org.springframework.cloud.release.internal.pom.ProcessedProject; import org.springframework.cloud.release.internal.pom.ProjectVersion; import org.springframework.cloud.release.internal.pom.Projects; import org.springframework.context.ApplicationEventPublisher; @@ -40,6 +43,8 @@ import org.springframework.util.StringUtils; */ public class SpringReleaser { + private static final Map CACHE = new ConcurrentHashMap<>(); + private static final Logger log = LoggerFactory.getLogger(SpringReleaser.class); private final Releaser releaser; @@ -81,33 +86,46 @@ public class SpringReleaser { } public void release(Options options) { - ProjectsAndVersion projectsAndVersion = null; if (options.metaRelease) { prepareForMetaRelease(options); } if (this.properties.isPostReleaseTasksOnly()) { log.info("Skipping release process and moving only to post release"); - this.optionsProcessor.postReleaseOptions(options, - postReleaseOptionsAgs(options, projectsAndVersion)); + this.optionsProcessor.postReleaseOptions(options, postReleaseOptionsAgs( + options, null, postReleaseTaskOnlyProcessedProjects(options))); buildCompleted(); return; } - performReleaseAndPostRelease(options, projectsAndVersion); + performReleaseAndPostRelease(options, null); buildCompleted(); } + private List postReleaseTaskOnlyProcessedProjects(Options options) { + return metaReleaseProjects(options).stream().map(project -> { + File clonedProjectFromOrg = this.releaser.clonedProjectFromOrg(project); + ReleaserProperties properties = updatePropertiesIfCustomConfigPresent( + this.properties.copy(), clonedProjectFromOrg); + log.info("Successfully cloned the project [{}] to [{}]", project, + clonedProjectFromOrg); + ProjectsAndVersion projects = projects(clonedProjectFromOrg); + return new ProcessedProject(properties, projects.versionFromBom); + }).collect(Collectors.toList()); + } + private void buildCompleted() { this.applicationEventPublisher.publishEvent(new BuildCompleted(this)); } private void performReleaseAndPostRelease(Options options, ProjectsAndVersion projectsAndVersion) { + List processedProjects = new ArrayList<>(); if (options.metaRelease) { ReleaserProperties original = this.properties.copy(); log.debug("The following properties were found [{}]", original); - metaReleaseProjects(options) - .forEach(project -> processProjectForMetaRelease(original.copy(), - options, project)); + processedProjects = metaReleaseProjects(options).stream() + .map(project -> processProjectForMetaRelease(original.copy(), options, + project)) + .collect(Collectors.toList()); } else { log.info( @@ -116,7 +134,7 @@ public class SpringReleaser { projectsAndVersion = processProject(options, projectFolder, TaskType.RELEASE); } this.optionsProcessor.postReleaseOptions(options, - postReleaseOptionsAgs(options, projectsAndVersion)); + postReleaseOptionsAgs(options, projectsAndVersion, processedProjects)); } private void prepareForMetaRelease(Options options) { @@ -126,15 +144,18 @@ public class SpringReleaser { this.properties.getMetaRelease().setEnabled(options.metaRelease); } - void processProjectForMetaRelease(ReleaserProperties copy, Options options, - String project) { + ProcessedProject processProjectForMetaRelease(ReleaserProperties copy, + Options options, String project) { log.info("Original properties [\n\n{}\n\n]", copy); File clonedProjectFromOrg = this.releaser.clonedProjectFromOrg(project); - updatePropertiesIfCustomConfigPresent(copy, clonedProjectFromOrg); + copy = updatePropertiesIfCustomConfigPresent(copy, clonedProjectFromOrg); log.info("Successfully cloned the project [{}] to [{}]", project, clonedProjectFromOrg); + ProjectsAndVersion projectsAndVersion; try { - processProject(options, clonedProjectFromOrg, TaskType.RELEASE); + projectsAndVersion = processProject(options, clonedProjectFromOrg, + TaskType.RELEASE); + return new ProcessedProject(copy, projectsAndVersion.versionFromBom); } catch (Exception e) { log.error("\n\n\nBUILD FAILED!!!\n\nException occurred for project <" @@ -196,7 +217,8 @@ public class SpringReleaser { return new File(workingDir); } - Args postReleaseOptionsAgs(Options options, ProjectsAndVersion projectsAndVersion) { + Args postReleaseOptionsAgs(Options options, ProjectsAndVersion projectsAndVersion, + List processedProjects) { Projects projects = projectsAndVersion == null ? projectsToUpdateForFixedVersions() : projectsAndVersion.projectVersions; ProjectVersion version = projects.containsProject( @@ -206,7 +228,7 @@ public class SpringReleaser { this.properties.getPom().setBranch(version.version); } return new Args(this.releaser, projects, version, this.properties, - options.interactive, this.applicationEventPublisher); + processedProjects, options.interactive, this.applicationEventPublisher); } private ProjectVersion versionFromBranch() { @@ -216,7 +238,13 @@ public class SpringReleaser { } private ProjectsAndVersion projects(File project) { - ProjectVersion versionFromScRelease; + ProjectsAndVersion projectsAndVersion = CACHE.get(project); + if (projectsAndVersion != null) { + log.info("Found cached version of projects and version [{}]", + projectsAndVersion); + return projectsAndVersion; + } + ProjectVersion versionFromBom; Projects projectsToUpdate; log.info("Fetch from git [{}], meta release [{}]", this.properties.getGit().isFetchVersionsFromGit(), @@ -225,25 +253,34 @@ public class SpringReleaser { && !this.properties.getMetaRelease().isEnabled()) { printVersionRetrieval(); projectsToUpdate = this.releaser.retrieveVersionsFromSCRelease(); - versionFromScRelease = projectsToUpdate.forFile(project); - assertNoSnapshotsForANonSnapshotProject(projectsToUpdate, - versionFromScRelease); + versionFromBom = assertNoSnapshotsForANonSnapshotProject(project, + projectsToUpdate); } else { ProjectVersion originalVersion = new ProjectVersion(project); String fixedVersionForProject = this.properties.getFixedVersions() .get(project.getName()); - versionFromScRelease = StringUtils.hasText(fixedVersionForProject) + versionFromBom = StringUtils.hasText(fixedVersionForProject) ? new ProjectVersion(originalVersion.projectName, fixedVersionForProject) : new ProjectVersion(project); projectsToUpdate = this.properties.getFixedVersions().entrySet().stream() .map(entry -> new ProjectVersion(entry.getKey(), entry.getValue())) .collect(Collectors.toCollection(Projects::new)); - projectsToUpdate.add(versionFromScRelease); + projectsToUpdate.add(versionFromBom); printSettingVersionFromFixedVersions(projectsToUpdate); } - return new ProjectsAndVersion(projectsToUpdate, versionFromScRelease); + projectsAndVersion = new ProjectsAndVersion(projectsToUpdate, versionFromBom); + CACHE.put(project, projectsAndVersion); + return projectsAndVersion; + } + + ProjectVersion assertNoSnapshotsForANonSnapshotProject(File project, + Projects projectsToUpdate) { + ProjectVersion versionFromBom; + versionFromBom = projectsToUpdate.forFile(project); + assertNoSnapshotsForANonSnapshotProject(projectsToUpdate, versionFromBom); + return versionFromBom; } ProjectsAndVersion processProject(Options options, File project, TaskType taskType) { @@ -251,8 +288,8 @@ public class SpringReleaser { ProjectVersion originalVersion = new ProjectVersion(project); final Args defaultArgs = new Args(this.releaser, project, projectsAndVersion.projectVersions, originalVersion, - projectsAndVersion.versionFromScRelease, this.properties, - options.interactive, taskType, this.applicationEventPublisher); + projectsAndVersion.versionFromBom, this.properties, options.interactive, + taskType, this.applicationEventPublisher); log.debug("Processing project [{}] with args [{}]", project, defaultArgs); this.optionsProcessor.processOptions(options, defaultArgs); return projectsAndVersion; @@ -293,12 +330,11 @@ public class SpringReleaser { final Projects projectVersions; - final ProjectVersion versionFromScRelease; + final ProjectVersion versionFromBom; - ProjectsAndVersion(Projects projectVersions, - ProjectVersion versionFromScRelease) { + ProjectsAndVersion(Projects projectVersions, ProjectVersion versionFromBom) { this.projectVersions = projectVersions; - this.versionFromScRelease = versionFromScRelease; + this.versionFromBom = versionFromBom; } } diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Tasks.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Tasks.java index 85f90835..dfc3915d 100644 --- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Tasks.java +++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Tasks.java @@ -68,8 +68,8 @@ final class Tasks { }, TaskType.POST_RELEASE); static Task UPDATE_GUIDES = task("updateGuides", "ug", "UPDATE GUIDES", "Updating Spring Guides", args -> { - args.releaser.updateSpringGuides(args.versionFromScRelease, - args.projects); + args.releaser.updateSpringGuides(args.versionFromScRelease, args.projects, + args.processedProjects); }, TaskType.POST_RELEASE); static Task UPDATE_SAGAN = task("updateSagan", "g", "UPDATE SAGAN", "Updating Sagan with release info", args -> { diff --git a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java index 3215eb3a..22fd4cb8 100644 --- a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java +++ b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java @@ -65,7 +65,6 @@ import org.springframework.cloud.release.internal.sagan.Release; import org.springframework.cloud.release.internal.sagan.SaganClient; import org.springframework.cloud.release.internal.sagan.SaganUpdater; import org.springframework.cloud.release.internal.template.TemplateGenerator; -import org.springframework.cloud.release.internal.versions.VersionsFetcher; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEventPublisher; import org.springframework.util.FileSystemUtils; @@ -696,8 +695,7 @@ public class AcceptanceTests { private Releaser defaultReleaser(String expectedVersion, String projectName, ReleaserProperties properties) { ProjectPomUpdater pomUpdater = new ProjectPomUpdater(properties); - VersionsFetcher versionsFetcher = new VersionsFetcher(properties, pomUpdater); - ProjectBuilder projectBuilder = new ProjectBuilder(properties, versionsFetcher); + ProjectBuilder projectBuilder = new ProjectBuilder(properties); TestProjectGitHandler handler = new TestProjectGitHandler(properties, expectedVersion, projectName); TemplateGenerator templateGenerator = new TemplateGenerator(properties, handler); @@ -727,8 +725,7 @@ public class AcceptanceTests { private Releaser defaultMetaReleaser(ReleaserProperties properties) { ProjectPomUpdater pomUpdater = new ProjectPomUpdater(properties); - VersionsFetcher versionsFetcher = new VersionsFetcher(properties, pomUpdater); - ProjectBuilder projectBuilder = new ProjectBuilder(properties, versionsFetcher); + ProjectBuilder projectBuilder = new ProjectBuilder(properties); NonAssertingTestProjectGitHandler handler = new NonAssertingTestProjectGitHandler( properties); TemplateGenerator templateGenerator = Mockito diff --git a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/SpringReleaserTests.java b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/SpringReleaserTests.java index 416d8203..b1f04a38 100644 --- a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/SpringReleaserTests.java +++ b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/SpringReleaserTests.java @@ -40,6 +40,9 @@ import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.ReleaserPropertiesAware; import org.springframework.cloud.release.internal.options.Options; import org.springframework.cloud.release.internal.options.OptionsBuilder; +import org.springframework.cloud.release.internal.pom.ProcessedProject; +import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEventPublisher; @@ -147,7 +150,8 @@ public class SpringReleaserTests { @Override Args postReleaseOptionsAgs(Options options, - ProjectsAndVersion projectsAndVersion) { + ProjectsAndVersion projectsAndVersion, + List processedProjects) { return new Args(TaskType.RELEASE); } @@ -159,11 +163,26 @@ public class SpringReleaserTests { @Override ProjectsAndVersion processProject(Options options, File project, TaskType taskType) { - return null; + return new ProjectsAndVersion(sampleProjects(), + new ProjectVersion("spring-cloud-foo", "1.0.0.BUILD-SNAPSHOT")); + } + + @Override + ProjectVersion assertNoSnapshotsForANonSnapshotProject(File project, + Projects projectsToUpdate) { + return sampleVersion(); } }; } + private Projects sampleProjects() { + return new Projects(sampleVersion()); + } + + private ProjectVersion sampleVersion() { + return new ProjectVersion("spring-cloud-foo", "1.0.0.RELEASE"); + } + private ReleaserProperties properties() { ReleaserProperties properties = new ReleaserProperties(); properties.getMaven().setBuildCommand("build");