Added boot version retrieval
This commit is contained in:
9
pom.xml
9
pom.xml
@@ -31,6 +31,11 @@
|
||||
<artifactId>org.eclipse.jgit</artifactId>
|
||||
<version>4.6.0.201612231935-r</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-model</artifactId>
|
||||
<version>3.3.9</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -43,6 +48,10 @@
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-model</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.springframework.cloud.release;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Parses the poms for a given project and populates versions.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
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 DEPENDENCIES_POM = "spring-cloud-dependencies/pom.xml";
|
||||
|
||||
private final File projectRootDir;
|
||||
private final String bootPom;
|
||||
private final PomReader pomReader = new PomReader();
|
||||
|
||||
PomParser(File projectRootDir) {
|
||||
this(projectRootDir, STARTER_POM);
|
||||
}
|
||||
|
||||
PomParser(File projectRootDir, String bootPom) {
|
||||
this.projectRootDir = projectRootDir;
|
||||
this.bootPom = bootPom;
|
||||
}
|
||||
|
||||
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);
|
||||
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");
|
||||
}
|
||||
String bootVersion = model.getParent().getVersion();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Boot version is equal to [{}]", bootVersion);
|
||||
}
|
||||
return bootVersion;
|
||||
}
|
||||
}
|
||||
|
||||
class PomReader {
|
||||
|
||||
Model readPom(File pom) {
|
||||
try(Reader reader = new FileReader(pom)) {
|
||||
MavenXpp3Reader xpp3Reader = new MavenXpp3Reader();
|
||||
return xpp3Reader.read(reader);
|
||||
}
|
||||
catch (XmlPullParserException | IOException e) {
|
||||
throw new IllegalStateException("Failed to read file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package org.springframework.cloud.release;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class ProjectCloner {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final ProjectCloner.JGitFactory gitFactory;
|
||||
|
||||
private final File basedir;
|
||||
|
||||
ProjectCloner(File basedir) {
|
||||
this.basedir = basedir;
|
||||
this.gitFactory = new ProjectCloner.JGitFactory();
|
||||
}
|
||||
|
||||
ProjectCloner(File basedir, ProjectCloner.JGitFactory factory) {
|
||||
this.basedir = basedir;
|
||||
this.gitFactory = factory;
|
||||
}
|
||||
|
||||
File cloneProject(URI projectUrl) {
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Cloning repo from [{}] to [{}]", projectUrl, this.basedir);
|
||||
}
|
||||
Git git = cloneToBasedir(projectUrl, this.basedir);
|
||||
if (git != null) {
|
||||
git.close();
|
||||
}
|
||||
File clonedRepo = git.getRepository().getDirectory();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Cloned repo to [{}]", clonedRepo);
|
||||
}
|
||||
return clonedRepo;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Git cloneToBasedir(URI projectUrl, File destinationFolder)
|
||||
throws GitAPIException {
|
||||
CloneCommand clone = this.gitFactory.getCloneCommandByCloneRepository()
|
||||
.setURI(projectUrl.toString() + ".git").setDirectory(destinationFolder);
|
||||
try {
|
||||
return clone.call();
|
||||
}
|
||||
catch (GitAPIException e) {
|
||||
deleteBaseDirIfExists();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteBaseDirIfExists() {
|
||||
if (this.basedir.exists()) {
|
||||
try {
|
||||
FileUtils.delete(this.basedir, FileUtils.RECURSIVE);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException("Failed to initialize base directory", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the static method calls to {@link org.eclipse.jgit.api.Git} and
|
||||
* {@link org.eclipse.jgit.api.CloneCommand} allowing for easier unit testing.
|
||||
*/
|
||||
static class JGitFactory {
|
||||
CloneCommand getCloneCommandByCloneRepository() {
|
||||
return Git.cloneRepository();
|
||||
}
|
||||
}
|
||||
}
|
||||
144
src/main/java/org/springframework/cloud/release/ProjectRepo.java
Normal file
144
src/main/java/org/springframework/cloud/release/ProjectRepo.java
Normal file
@@ -0,0 +1,144 @@
|
||||
package org.springframework.cloud.release;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jgit.api.CheckoutCommand;
|
||||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstraction over a Git repo. Can clonea repo from a given location
|
||||
* and check its branch.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class ProjectRepo {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final ProjectRepo.JGitFactory gitFactory;
|
||||
|
||||
private final File basedir;
|
||||
|
||||
ProjectRepo(File basedir) {
|
||||
this.basedir = basedir;
|
||||
this.gitFactory = new ProjectRepo.JGitFactory();
|
||||
}
|
||||
|
||||
ProjectRepo(File basedir, ProjectRepo.JGitFactory factory) {
|
||||
this.basedir = basedir;
|
||||
this.gitFactory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the project
|
||||
* @param projectUri - URI of the project
|
||||
* @return file where the project was cloned
|
||||
*/
|
||||
File cloneProject(URI projectUri) {
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
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);
|
||||
}
|
||||
return clonedRepo;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Exception occurred while cloning repo", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks out a branch for a project
|
||||
* @param project - a Git project
|
||||
* @param branch - branch to check out
|
||||
*/
|
||||
void checkout(File project, String branch) {
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Git cloneToBasedir(URI projectUrl, File destinationFolder)
|
||||
throws GitAPIException {
|
||||
CloneCommand command = this.gitFactory.getCloneCommandByCloneRepository()
|
||||
.setURI(projectUrl.toString() + ".git").setDirectory(destinationFolder);
|
||||
try {
|
||||
return command.call();
|
||||
}
|
||||
catch (GitAPIException e) {
|
||||
deleteBaseDirIfExists();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private Ref checkoutBranch(File projectDir, String branch)
|
||||
throws GitAPIException {
|
||||
Git git = this.gitFactory.open(projectDir);
|
||||
CheckoutCommand command = git.checkout().setName(branch);
|
||||
try {
|
||||
return command.call();
|
||||
}
|
||||
catch (GitAPIException e) {
|
||||
deleteBaseDirIfExists();
|
||||
throw e;
|
||||
} finally {
|
||||
git.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteBaseDirIfExists() {
|
||||
if (this.basedir.exists()) {
|
||||
try {
|
||||
FileUtils.delete(this.basedir, FileUtils.RECURSIVE);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException("Failed to initialize base directory", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the static method calls to {@link org.eclipse.jgit.api.Git} and
|
||||
* {@link org.eclipse.jgit.api.CloneCommand} allowing for easier unit testing.
|
||||
*/
|
||||
static class JGitFactory {
|
||||
CloneCommand getCloneCommandByCloneRepository() {
|
||||
return Git.cloneRepository();
|
||||
}
|
||||
|
||||
Git open(File file) {
|
||||
try {
|
||||
return Git.open(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.springframework.cloud.release;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents versions taken out from Spring Cloud Release pom
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class Versions {
|
||||
|
||||
String boot;
|
||||
String build;
|
||||
Map<String, String> projects = new HashMap<>();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.springframework.cloud.release;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.assertj.core.api.BDDAssertions.thenThrownBy;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public class PomParserTests {
|
||||
|
||||
File springCloudReleaseProject;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException, URISyntaxException {
|
||||
this.springCloudReleaseProject = new File(ProjectClonerTests.class.getResource("/projects/spring-cloud-release").toURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_throw_exception_when_boot_pom_is_missing() {
|
||||
PomParser parser = new PomParser(new File("."));
|
||||
|
||||
thenThrownBy(parser::bootVersion)
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Pom with boot version is not present");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_throw_exception_when_boot_version_is_missing_in_pom() {
|
||||
PomParser parser = new PomParser(this.springCloudReleaseProject, "pom.xml");
|
||||
|
||||
thenThrownBy(parser::bootVersion)
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("The pom doesn't have a boot version");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_populate_boot_version() {
|
||||
PomParser parser = new PomParser(this.springCloudReleaseProject);
|
||||
|
||||
String bootVersion = parser.bootVersion();
|
||||
|
||||
then(bootVersion).isEqualTo("1.5.1.BUILD-SNAPSHOT");
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package org.springframework.cloud.release;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.junit.Before;
|
||||
@@ -10,7 +11,9 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.assertj.core.api.BDDAssertions.thenThrownBy;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
@@ -20,38 +23,69 @@ public class ProjectClonerTests {
|
||||
@Rule public TemporaryFolder tmp = new TemporaryFolder();
|
||||
File springCloudReleaseProject;
|
||||
File tmpFolder;
|
||||
ProjectCloner projectCloner;
|
||||
ProjectRepo projectRepo;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException, URISyntaxException {
|
||||
this.tmpFolder = this.tmp.newFolder();
|
||||
this.springCloudReleaseProject = new File(ProjectClonerTests.class.getResource("/projects/spring-cloud-release").toURI());
|
||||
TestUtils.prepareLocalRepo();
|
||||
this.projectCloner = new ProjectCloner(this.tmpFolder);
|
||||
this.projectRepo = new ProjectRepo(this.tmpFolder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_clone_the_project_from_a_given_location() throws IOException {
|
||||
this.projectCloner.cloneProject(this.springCloudReleaseProject.toURI());
|
||||
this.projectRepo.cloneProject(this.springCloudReleaseProject.toURI());
|
||||
|
||||
then(new File(this.tmpFolder, ".git")).exists();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_throw_exception_when_there_is_no_repo()
|
||||
throws IOException, URISyntaxException {
|
||||
this.projectCloner.cloneProject(ProjectClonerTests.class.getResource("/projects/").toURI());
|
||||
@Test
|
||||
public void should_throw_exception_when_there_is_no_repo() throws IOException, URISyntaxException {
|
||||
thenThrownBy(() -> this.projectRepo.cloneProject(ProjectClonerTests.class.getResource("/projects/").toURI()))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Exception occurred while cloning repo");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@Test
|
||||
public void should_throw_an_exception_when_failed_to_initialize_the_repo() throws IOException {
|
||||
new ProjectCloner(this.tmpFolder, new ExceptionThrowingJGitFactory()).cloneProject(this.springCloudReleaseProject.toURI());
|
||||
thenThrownBy(() -> new ProjectRepo(this.tmpFolder, new ExceptionThrowingJGitFactory()).cloneProject(this.springCloudReleaseProject.toURI()))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Exception occurred while cloning repo")
|
||||
.hasCauseInstanceOf(CustomException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_check_out_a_branch_on_cloned_repo() throws IOException {
|
||||
File project = this.projectRepo.cloneProject(this.springCloudReleaseProject.toURI());
|
||||
this.projectRepo.checkout(project, "vCamden.SR3");
|
||||
|
||||
File pom = new File(this.tmpFolder, "pom.xml");
|
||||
then(pom).exists();
|
||||
then(Files.lines(pom.toPath()).anyMatch(s -> s.contains("<version>Camden.SR3</version>"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_throw_an_exception_when_checking_out_nonexisting_branch() throws IOException {
|
||||
File project = this.projectRepo.cloneProject(this.springCloudReleaseProject.toURI());
|
||||
try {
|
||||
this.projectRepo.checkout(project, "nonExistingBranch");
|
||||
fail("should throw an exception");
|
||||
} catch (IllegalStateException e) {
|
||||
then(e).hasMessageContaining("Ref nonExistingBranch can not be resolved");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ExceptionThrowingJGitFactory extends ProjectCloner.JGitFactory {
|
||||
class ExceptionThrowingJGitFactory extends ProjectRepo.JGitFactory {
|
||||
@Override CloneCommand getCloneCommandByCloneRepository() {
|
||||
throw new RuntimeException("foo");
|
||||
throw new CustomException("foo");
|
||||
}
|
||||
}
|
||||
|
||||
class CustomException extends RuntimeException {
|
||||
public CustomException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user