diff --git a/src/main/java/org/springframework/cloud/release/PomParser.java b/src/main/java/org/springframework/cloud/release/PomParser.java index 26072798..6b209c94 100644 --- a/src/main/java/org/springframework/cloud/release/PomParser.java +++ b/src/main/java/org/springframework/cloud/release/PomParser.java @@ -5,6 +5,13 @@ import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.lang.invoke.MethodHandles; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; @@ -22,40 +29,78 @@ class PomParser { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static final String STARTER_POM = "spring-cloud-starter-parent/pom.xml"; - private static final String BOOT_STARTER_ARTIFACTID = "spring-boot-starter-parent"; + private static final String BOOT_STARTER_ARTIFACT_ID = "spring-boot-starter-parent"; private static final String DEPENDENCIES_POM = "spring-cloud-dependencies/pom.xml"; + private static final String CLOUD_DEPENDENCIES_ARTIFACT_ID = "spring-cloud-dependencies-parent"; + private static final Pattern SC_VERSION_PATTERN = Pattern.compile("^(spring-cloud-.*)\\.version$"); private final File projectRootDir; private final String bootPom; + private final String dependenciesPom; private final PomReader pomReader = new PomReader(); PomParser(File projectRootDir) { - this(projectRootDir, STARTER_POM); + this(projectRootDir, STARTER_POM, DEPENDENCIES_POM); } - PomParser(File projectRootDir, String bootPom) { + PomParser(File projectRootDir, String bootPom, String dependenciesPom) { this.projectRootDir = projectRootDir; this.bootPom = bootPom; + this.dependenciesPom = dependenciesPom; } - String bootVersion() { - File bootPom = new File(this.projectRootDir, this.bootPom); - if (!bootPom.exists()) { - throw new IllegalStateException("Pom with boot version is not present"); - } - Model model = this.pomReader.readPom(bootPom); + Versions bootVersion() { + Model model = pom(this.bootPom); String bootArtifactId = model.getParent().getArtifactId(); - if (log.isDebugEnabled()) { - log.debug("Boot artifact id is equal to [{}]", bootArtifactId); - } - if (!BOOT_STARTER_ARTIFACTID.equals(bootArtifactId)) { - throw new IllegalStateException("The pom doesn't have a boot version"); + log.debug("Boot artifact id is equal to [{}]", bootArtifactId); + if (!BOOT_STARTER_ARTIFACT_ID.equals(bootArtifactId)) { + throw new IllegalStateException("The pom doesn't have a [" + BOOT_STARTER_ARTIFACT_ID + "] artifact id"); } String bootVersion = model.getParent().getVersion(); - if (log.isDebugEnabled()) { - log.debug("Boot version is equal to [{}]", bootVersion); + log.debug("Boot version is equal to [{}]", bootVersion); + return new Versions(bootVersion); + } + + private Model pom(String pom) { + if (pom == null) { + throw new IllegalStateException("Pom is not present"); } - return bootVersion; + File pomFile = new File(this.projectRootDir, pom); + if (!pomFile.exists()) { + throw new IllegalStateException("Pom is not present"); + } + return this.pomReader.readPom(pomFile); + } + + Versions springCloudVersions() { + Model model = pom(this.dependenciesPom); + String buildArtifact = model.getParent().getArtifactId(); + log.debug("[{}] artifact id is equal to [{}]", CLOUD_DEPENDENCIES_ARTIFACT_ID, buildArtifact); + if (!CLOUD_DEPENDENCIES_ARTIFACT_ID.equals(buildArtifact)) { + throw new IllegalStateException("The pom doesn't have a [" + CLOUD_DEPENDENCIES_ARTIFACT_ID + "] artifact id"); + } + String buildVersion = model.getParent().getVersion(); + log.debug("Spring Cloud Build version is equal to [{}]", buildVersion); + Set projects = model.getProperties().entrySet() + .stream() + .filter(propertyMatchesSCPattern()) + .map(toProject()) + .collect(Collectors.toSet()); + return new Versions(buildVersion, projects); + } + + private Predicate> propertyMatchesSCPattern() { + return entry -> SC_VERSION_PATTERN.matcher(entry.getKey().toString()).matches(); + } + + private Function, Project> toProject() { + return entry -> { + Matcher matcher = SC_VERSION_PATTERN.matcher(entry.getKey().toString()); + // you have to first match to get info about the group + matcher.matches(); + String name = matcher.group(1); + return new Project(name, entry.getValue().toString()); + }; } } diff --git a/src/main/java/org/springframework/cloud/release/ProjectRepo.java b/src/main/java/org/springframework/cloud/release/ProjectRepo.java index a27d32a8..d6add4aa 100644 --- a/src/main/java/org/springframework/cloud/release/ProjectRepo.java +++ b/src/main/java/org/springframework/cloud/release/ProjectRepo.java @@ -46,17 +46,13 @@ class ProjectRepo { */ File cloneProject(URI projectUri) { try { - if (log.isDebugEnabled()) { - log.debug("Cloning repo from [{}] to [{}]", projectUri, this.basedir); - } + log.debug("Cloning repo from [{}] to [{}]", projectUri, this.basedir); Git git = cloneToBasedir(projectUri, this.basedir); if (git != null) { git.close(); } File clonedRepo = git.getRepository().getDirectory(); - if (log.isDebugEnabled()) { - log.debug("Cloned repo to [{}]", clonedRepo); - } + log.debug("Cloned repo to [{}]", clonedRepo); return clonedRepo; } catch (Exception e) { @@ -71,13 +67,9 @@ class ProjectRepo { */ void checkout(File project, String branch) { try { - if (log.isDebugEnabled()) { - log.debug("Checking out branch [{}] for repo [{}] to [{}]", this.basedir, branch); - } + log.debug("Checking out branch [{}] for repo [{}] to [{}]", this.basedir, branch); checkoutBranch(project, branch); - if (log.isDebugEnabled()) { - log.debug("Successfully checked out the branch [{}]", branch); - } + log.debug("Successfully checked out the branch [{}]", branch); } catch (Exception e) { throw new IllegalStateException(e); diff --git a/src/main/java/org/springframework/cloud/release/Versions.java b/src/main/java/org/springframework/cloud/release/Versions.java index 45ec55b0..2f01683f 100644 --- a/src/main/java/org/springframework/cloud/release/Versions.java +++ b/src/main/java/org/springframework/cloud/release/Versions.java @@ -1,7 +1,7 @@ package org.springframework.cloud.release; -import java.util.HashMap; -import java.util.Map; +import java.util.HashSet; +import java.util.Set; /** * Represents versions taken out from Spring Cloud Release pom @@ -12,5 +12,53 @@ class Versions { String boot; String build; - Map projects = new HashMap<>(); + Set projects = new HashSet<>(); + + Versions(String boot) { + this.boot = boot; + } + + Versions(String build, Set projects) { + this.build = build; + this.projects = projects; + } + + Versions(String boot, String build, Set projects) { + this.boot = boot; + this.build = build; + this.projects = projects; + } +} + +class Project { + final String name; + final String version; + + Project(String name, String version) { + this.name = name; + this.version = version; + } + + @Override public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Project project = (Project) o; + if (this.name != null ? !this.name.equals(project.name) : project.name != null) + return false; + return this.version != null ? + this.version.equals(project.version) : + project.version == null; + } + + @Override public int hashCode() { + int result = this.name != null ? this.name.hashCode() : 0; + result = 31 * result + (this.version != null ? this.version.hashCode() : 0); + return result; + } + + @Override public String toString() { + return "Project{" + "name='" + this.name + '\'' + ", version='" + this.version + '\'' + '}'; + } } \ No newline at end of file diff --git a/src/test/java/org/springframework/cloud/release/AcceptanceTests.java b/src/test/java/org/springframework/cloud/release/AcceptanceTests.java index 0a6d8413..ce09ba97 100644 --- a/src/test/java/org/springframework/cloud/release/AcceptanceTests.java +++ b/src/test/java/org/springframework/cloud/release/AcceptanceTests.java @@ -9,10 +9,11 @@ public class AcceptanceTests { /** - - should clone spring cloud release - - should check out a branch / tag + - should clone spring cloud release (x) + - should check out a branch / tag (x) + - should parse spring-cloud-starter-parent/pom.xml and resolve: + - Boot version (x) - should parse spring-cloud-dependencies/pom.xml and resolve: - - Boot version - Project versions from properties - Spring Cloud Build version from parent - should update the existing poms with the taken versions diff --git a/src/test/java/org/springframework/cloud/release/PomParserTests.java b/src/test/java/org/springframework/cloud/release/PomParserTests.java index cf175c8f..27098b54 100644 --- a/src/test/java/org/springframework/cloud/release/PomParserTests.java +++ b/src/test/java/org/springframework/cloud/release/PomParserTests.java @@ -28,24 +28,90 @@ public class PomParserTests { thenThrownBy(parser::bootVersion) .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Pom with boot version is not present"); + .hasMessageContaining("Pom is not present"); + } + + @Test + public void should_throw_exception_when_null_is_passed_to_boot() { + PomParser parser = new PomParser(this.springCloudReleaseProject, null, null); + + thenThrownBy(parser::bootVersion) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Pom is not present"); } @Test public void should_throw_exception_when_boot_version_is_missing_in_pom() { - PomParser parser = new PomParser(this.springCloudReleaseProject, "pom.xml"); + PomParser parser = new PomParser(this.springCloudReleaseProject, "pom.xml", null); thenThrownBy(parser::bootVersion) .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("The pom doesn't have a boot version"); + .hasMessageContaining("The pom doesn't have a [spring-boot-starter-parent] artifact id"); } @Test public void should_populate_boot_version() { PomParser parser = new PomParser(this.springCloudReleaseProject); - String bootVersion = parser.bootVersion(); + String bootVersion = parser.bootVersion().boot; then(bootVersion).isEqualTo("1.5.1.BUILD-SNAPSHOT"); } + + @Test + public void should_throw_exception_when_cloud_pom_is_missing() { + PomParser parser = new PomParser(new File(".")); + + thenThrownBy(parser::springCloudVersions) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Pom is not present"); + } + + @Test + public void should_throw_exception_when_null_is_passed_to_cloud() { + PomParser parser = new PomParser(this.springCloudReleaseProject, null, null); + + thenThrownBy(parser::springCloudVersions) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Pom is not present"); + } + + @Test + public void should_throw_exception_when_cloud_version_is_missing_in_pom() { + PomParser parser = new PomParser(this.springCloudReleaseProject, null, "pom.xml"); + + thenThrownBy(parser::springCloudVersions) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("The pom doesn't have a [spring-cloud-dependencies-parent] artifact id"); + } + + @Test + public void should_populate_cloud_version() { + PomParser parser = new PomParser(this.springCloudReleaseProject); + + Versions cloudVersions = parser.springCloudVersions(); + + then(cloudVersions.build).isEqualTo("1.3.1.BUILD-SNAPSHOT"); + then(cloudVersions.projects) + .contains( + project("spring-cloud-aws", "1.2.0.BUILD-SNAPSHOT"), + project("spring-cloud-bus", "1.3.0.BUILD-SNAPSHOT"), + project("spring-cloud-contract", "1.1.0.BUILD-SNAPSHOT"), + project("spring-cloud-cloudfoundry", "1.1.0.BUILD-SNAPSHOT"), + project("spring-cloud-commons", "1.2.0.BUILD-SNAPSHOT"), + project("spring-cloud-config", "1.3.0.BUILD-SNAPSHOT"), + project("spring-cloud-netflix", "1.3.0.BUILD-SNAPSHOT"), + project("spring-cloud-security", "1.2.0.BUILD-SNAPSHOT"), + project("spring-cloud-consul", "1.2.0.BUILD-SNAPSHOT"), + project("spring-cloud-sleuth", "1.2.0.BUILD-SNAPSHOT"), + project("spring-cloud-stream", "Chelsea.BUILD-SNAPSHOT"), + project("spring-cloud-task", "1.1.2.BUILD-SNAPSHOT"), + project("spring-cloud-vault", "1.0.0.BUILD-SNAPSHOT"), + project("spring-cloud-zookeeper", "1.1.0.BUILD-SNAPSHOT") + ); + } + + Project project(String name, String value) { + return new Project(name, value); + } } \ No newline at end of file