Meta release (#84)

## How it works?

- Uses the fixed versions to clone and check out each project (e.g. `spring-cloud-sleuth: 2.1.0.RELEASE`)
- From the version analyzes the branch and checks it out. E.g.
  - for `spring-cloud-release`'s `Finchley.RELEASE` version will resolve either `Finchley.x` branch or will fallback to `master` if there's no `Finchley.x` branch.
  - for `spring-cloud-sleuth`'s `2.1.0.RELEASE` version will resolve `2.1.x` branch
- Performs the release tasks per each project
- Performs the post release tasks at the end of the release

## Required options

- `releaser.fixed-versions` - A String to String mapping of manually set versions. E.g. `"spring-cloud-cli" -> "1.0.0.RELEASE"` will set
the `spring-cloud-cli.version` to `1.0.0.RELEASE` regardless of what was set in `spring-cloud-release` project. Example `--releaser.fixed-versions[spring-cloud-cli]=1.0.0.RELEASE`.
Use these properties to provide versions for the meta release.

- `releaser.meta-release.enabled` - You have to turn it on to enable a meta release. Defaults to `false`
- `releaser.meta-release.git-org-url` - The URL of the Git organization. We'll append each project's name to it.
Defaults to `https://github.com/spring-cloud`

run the task via `-x=true`
This commit is contained in:
Marcin Grzejszczak
2018-06-25 09:21:24 +02:00
committed by GitHub
parent 8f3936d727
commit 9578294fbd
39 changed files with 1156 additions and 214 deletions

View File

@@ -46,6 +46,10 @@ public class Releaser {
this.documentationUpdater = documentationUpdater;
}
public File clonedProjectFromOrg(String projectName) {
return this.projectGitHandler.cloneProjectFromOrg(projectName);
}
public Projects retrieveVersionsFromSCRelease() {
return this.projectPomUpdater.retrieveVersionsFromSCRelease();
}

View File

@@ -45,8 +45,56 @@ public class ReleaserProperties {
private Sagan sagan = new Sagan();
/**
* Project name to its version - overrides all versions
* retrieved from a repository like Spring Cloud Release
*/
private Map<String, String> fixedVersions = new HashMap<>();
private MetaRelease metaRelease = new MetaRelease();
public static class MetaRelease {
/**
* Are we releasing the whole suite of apps or only one?
*/
private boolean enabled = false;
/**
* Name of the release train project
*/
private String releaseTrainProjectName = "spring-cloud-release";
/**
* The URL of the Git organization. We'll append each project's
* name to it
*/
private String gitOrgUrl = "https://github.com/spring-cloud";
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getGitOrgUrl() {
return this.gitOrgUrl;
}
public void setGitOrgUrl(String gitOrgUrl) {
this.gitOrgUrl = gitOrgUrl;
}
public String getReleaseTrainProjectName() {
return this.releaseTrainProjectName;
}
public void setReleaseTrainProjectName(String releaseTrainProjectName) {
this.releaseTrainProjectName = releaseTrainProjectName;
}
}
public static class Git {
/**
@@ -388,6 +436,14 @@ public class ReleaserProperties {
this.fixedVersions = fixedVersions;
}
public MetaRelease getMetaRelease() {
return this.metaRelease;
}
public void setMetaRelease(MetaRelease metaRelease) {
this.metaRelease = metaRelease;
}
public Sagan getSagan() {
return this.sagan;
}

View File

@@ -0,0 +1,9 @@
package org.springframework.cloud.release.internal;
/**
* @author Marcin Grzejszczak
*/
public interface ReleaserPropertiesAware {
void setReleaserProperties(ReleaserProperties properties);
}

View File

@@ -112,13 +112,12 @@ class GitRepo {
/**
* Checks out a branch for a project
* @param project - a Git project
* @param branch - branch to check out
*/
void checkout(File project, String branch) {
void checkout(String branch) {
try {
log.info("Checking out branch [{}] for repo [{}]", branch, this.basedir);
checkoutBranch(project, branch);
checkoutBranch(this.basedir, branch);
log.info("Successfully checked out the branch [{}]", branch);
}
catch (Exception e) {
@@ -128,11 +127,10 @@ class GitRepo {
/**
* Performs a commit
* @param project - a Git project
* @param message - commit message
*/
void commit(File project, String message) {
try(Git git = this.gitFactory.open(file(project))) {
void commit(String message) {
try(Git git = this.gitFactory.open(file(this.basedir))) {
git.add().addFilepattern(".").call();
git.commit().setAllowEmpty(false).setMessage(message).call();
printLog(git);
@@ -143,6 +141,16 @@ class GitRepo {
}
}
boolean hasBranch(String branch) {
try(Git git = this.gitFactory.open(file(this.basedir))) {
List<Ref> refs = git.branchList().setListMode(ListBranchCommand.ListMode.ALL)
.call();
return refs.stream().anyMatch(ref -> ref.getName().contains(branch));
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
private void printLog(Git git) throws GitAPIException, IOException {
int maxCount = 5;
String currentBranch = git.getRepository().getBranch();
@@ -155,11 +163,10 @@ class GitRepo {
/**
* Creates a tag with a given name
* @param project
* @param tagName
*/
void tag(File project, String tagName) {
try(Git git = this.gitFactory.open(file(project))) {
void tag(String tagName) {
try(Git git = this.gitFactory.open(file(this.basedir))) {
git.tag().setName(tagName).call();
} catch (Exception e) {
throw new IllegalStateException(e);
@@ -168,11 +175,10 @@ class GitRepo {
/**
* Pushes the commits to {@code origin} remote branch
* @param project - Git project
* @param branch - remote branch to which the code should be pushed
*/
void pushBranch(File project, String branch) {
try(Git git = this.gitFactory.open(file(project))) {
void pushBranch(String branch) {
try(Git git = this.gitFactory.open(file(this.basedir))) {
String localBranch = git.getRepository().getFullBranch();
RefSpec refSpec = new RefSpec(localBranch + ":" + branch);
this.gitFactory.push(git).setPushTags().setRefSpecs(refSpec).call();
@@ -183,10 +189,9 @@ class GitRepo {
/**
* Pushes the commits od current branch
* @param project - Git project
*/
void pushCurrentBranch(File project) {
try(Git git = this.gitFactory.open(file(project))) {
void pushCurrentBranch() {
try(Git git = this.gitFactory.open(file(this.basedir))) {
this.gitFactory.push(git).call();
} catch (Exception e) {
throw new IllegalStateException(e);
@@ -195,11 +200,10 @@ class GitRepo {
/**
* Pushes the commits to {@code origin} remote tag
* @param project - Git project
* @param tagName - remote tag to which the code should be pushed
*/
void pushTag(File project, String tagName) {
try(Git git = this.gitFactory.open(file(project))) {
void pushTag(String tagName) {
try(Git git = this.gitFactory.open(file(this.basedir))) {
String localBranch = git.getRepository().getFullBranch();
RefSpec refSpec = new RefSpec(localBranch + ":" + "refs/tags/" + tagName);
this.gitFactory.push(git).setPushTags().setRefSpecs(refSpec).call();
@@ -208,8 +212,8 @@ class GitRepo {
}
}
void revert(File project, String message) {
try(Git git = this.gitFactory.open(file(project))) {
void revert(String message) {
try(Git git = this.gitFactory.open(file(this.basedir))) {
RevCommit commit = git.log().setMaxCount(1).call().iterator().next();
String shortMessage = commit.getShortMessage();
String id = commit.getId().getName();
@@ -227,8 +231,8 @@ class GitRepo {
}
}
String currentBranch(File project) {
try(Git git = this.gitFactory.open(file(project))) {
String currentBranch() {
try(Git git = this.gitFactory.open(file(this.basedir))) {
return git.getRepository().getBranch();
} catch (Exception e) {
throw new IllegalStateException(e);

View File

@@ -8,15 +8,17 @@ import java.nio.file.Files;
import org.slf4j.Logger;
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.pom.Projects;
import org.springframework.util.StringUtils;
/**
* Contains business logic around Git & Github operations
*
* @author Marcin Grzejszczak
*/
public class ProjectGitHandler {
public class ProjectGitHandler implements ReleaserPropertiesAware {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -25,7 +27,7 @@ public class ProjectGitHandler {
private static final String POST_RELEASE_MSG = "Going back to snapshots";
private static final String POST_RELEASE_BUMP_MSG = "Bumping versions to %s after release";
private final ReleaserProperties properties;
private ReleaserProperties properties;
private final GithubMilestones githubMilestones;
private final GithubIssues githubIssues;
@@ -39,13 +41,13 @@ public class ProjectGitHandler {
GitRepo gitRepo = gitRepo(project);
if (version.isSnapshot()) {
log.info("Snapshot version [{}] found. Will only commit the changed poms", version);
gitRepo.commit(project, MSG);
gitRepo.commit(MSG);
} else {
log.info("NON-snapshot version [{}] found. Will commit the changed poms, tag the version and push the tag", version);
gitRepo.commit(project, String.format(PRE_RELEASE_MSG, version.version));
gitRepo.commit(String.format(PRE_RELEASE_MSG, version.version));
String tagName = "v" + version.version;
gitRepo.tag(project, tagName);
gitRepo.pushTag(project, tagName);
gitRepo.tag(tagName);
gitRepo.pushTag(tagName);
}
}
@@ -60,7 +62,7 @@ public class ProjectGitHandler {
public void commit(File project, String message) {
GitRepo gitRepo = gitRepo(project);
gitRepo.commit(project, message);
gitRepo.commit(message);
}
public File cloneScReleaseProject() {
@@ -73,7 +75,36 @@ public class ProjectGitHandler {
return clonedProject;
}
private File cloneProject(String url) {
/**
* For meta-release. Works with fixed versions only
* @param projectName - name of the project to clone
* @return location of the cloned project
*/
public File cloneProjectFromOrg(String projectName) {
String orgUrl = this.properties.getMetaRelease().getGitOrgUrl();
String fullUrl = orgUrl.endsWith("/") ? orgUrl + projectName : orgUrl + "/" +
projectName + suffixNonHttpRepo(orgUrl);
File clonedProject = cloneProject(fullUrl);
String version = this.properties.getFixedVersions().get(projectName);
if (StringUtils.isEmpty(version)) {
throw new IllegalStateException("You haven't provided a version for project [" + projectName + "]");
}
String branchFromVersion = branchFromVersion(version);
boolean branchExists = gitRepo(clonedProject).hasBranch(branchFromVersion);
if (!branchExists) {
log.info("Branch [{}] does not exist. Assuming that should work with master branch", branchFromVersion);
return clonedProject;
}
log.info("Branch [{}] exists. Will check it out", branchFromVersion);
checkout(clonedProject, branchFromVersion);
return clonedProject;
}
private String suffixNonHttpRepo(String orgUrl) {
return orgUrl.startsWith("http") || orgUrl.startsWith("git") ? "" : "/";
}
File cloneProject(String url) {
try {
File destinationDir = properties.getGit().getCloneDestinationDir() != null ?
new File(properties.getGit().getCloneDestinationDir()) :
@@ -85,7 +116,28 @@ public class ProjectGitHandler {
}
public void checkout(File project, String branch) {
gitRepo(project).checkout(project, branch);
gitRepo(project).checkout(branch);
}
// let's go with convention... If fixed version contains e.g.
// 2.3.4.RELEASE of Sleuth, we will first check if `2.0.x` branch
// exists. If not, then we will assume that `master` contains it
private String branchFromVersion(String version) {
// 2.3.4.RELEASE -> 2.3.4
// Camden.RELEASE -> Camden
String versionTillPatch = version.substring(0, version.lastIndexOf("."));
// 2.3.4 -> [2,3,4]
// Camden -> [Camden]
String[] splitVersion = versionTillPatch.split("\\.");
if (splitVersion.length == 3) {
// [2,3,4] -> 2.3.x
return splitVersion[0] + "." + splitVersion[1] + ".x";
} else if (splitVersion.length == 1) {
// [Camden] -> [Camden.x]
return splitVersion[0] + ".x";
}
throw new IllegalStateException("Wrong version [" + version + "]. Can't extract semver pieces of it");
}
public void revertChangesIfApplicable(File project, ProjectVersion version) {
@@ -94,11 +146,11 @@ public class ProjectGitHandler {
return;
}
log.info("Reverting last commit");
gitRepo(project).revert(project, POST_RELEASE_MSG);
gitRepo(project).revert(POST_RELEASE_MSG);
}
public void pushCurrentBranch(File project) {
gitRepo(project).pushCurrentBranch(project);
gitRepo(project).pushCurrentBranch();
}
public void closeMilestone(ProjectVersion releaseVersion) {
@@ -114,10 +166,14 @@ public class ProjectGitHandler {
}
public String currentBranch(File project) {
return gitRepo(project).currentBranch(project);
return gitRepo(project).currentBranch();
}
GitRepo gitRepo(File workingDir) {
return new GitRepo(workingDir, this.properties);
}
@Override public void setReleaserProperties(ReleaserProperties properties) {
this.properties = properties;
}
}

View File

@@ -17,17 +17,18 @@ import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
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.pom.Projects;
/**
* @author Marcin Grzejszczak
*/
public class GradleUpdater {
public class GradleUpdater implements ReleaserPropertiesAware {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final ReleaserProperties properties;
private ReleaserProperties properties;
public GradleUpdater(ReleaserProperties properties) {
this.properties = properties;
@@ -59,6 +60,10 @@ public class GradleUpdater {
}
}
@Override public void setReleaserProperties(ReleaserProperties properties) {
this.properties = properties;
}
private class GradlePropertiesWalker extends SimpleFileVisitor<Path> {
private static final String GRADLE_PROPERTIES = "gradle.properties";

View File

@@ -29,12 +29,13 @@ import java.util.Scanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.ReleaserPropertiesAware;
import org.springframework.cloud.release.internal.git.ProjectGitHandler;
/**
* @author Marcin Grzejszczak
*/
public class ProjectPomUpdater {
public class ProjectPomUpdater implements ReleaserPropertiesAware {
private static final List<String> IGNORED_SNAPSHOT_LINE_PATTERNS = Arrays.asList(
"^.*replace=.*$",
@@ -44,7 +45,7 @@ public class ProjectPomUpdater {
private static final Logger log = LoggerFactory.getLogger(ProjectPomUpdater.class);
private final ReleaserProperties properties;
private ReleaserProperties properties;
private final ProjectGitHandler gitRepo;
private final PomUpdater pomUpdater = new PomUpdater();
@@ -103,6 +104,10 @@ public class ProjectPomUpdater {
}
}
@Override public void setReleaserProperties(ReleaserProperties properties) {
this.properties = properties;
}
private class PomWalker extends SimpleFileVisitor<Path> {
private static final String POM_XML = "pom.xml";

View File

@@ -66,6 +66,11 @@ public class Projects extends HashSet<ProjectVersion> {
.orElseThrow(() -> exception(projectName));
}
public boolean containsProject(String projectName) {
return this.stream()
.anyMatch(projectVersion -> projectVersion.projectName.equals(projectName));
}
public List<ProjectVersion> forNameStartingWith(String projectName) {
return this.stream().filter(projectVersion -> projectVersion.projectName.startsWith(projectName))
.collect(Collectors.toList());

View File

@@ -45,7 +45,7 @@ class SCReleasePomParser {
private final File springCloudReleaseDir;
private final String bootPom;
private final String dependenciesPom;
private final String dependenciesPomPath;
private final PomReader pomReader = new PomReader();
SCReleasePomParser(File springCloudReleaseDir) {
@@ -55,7 +55,7 @@ class SCReleasePomParser {
SCReleasePomParser(File springCloudReleaseDir, String bootPom, String dependenciesPom) {
this.springCloudReleaseDir = springCloudReleaseDir;
this.bootPom = bootPom;
this.dependenciesPom = dependenciesPom;
this.dependenciesPomPath = dependenciesPom;
}
Versions allVersions() {
@@ -96,7 +96,7 @@ class SCReleasePomParser {
}
Versions springCloudVersions() {
Model model = pom(this.dependenciesPom);
Model model = pom(this.dependenciesPomPath);
String buildArtifact = model.getParent().getArtifactId();
log.debug("[{}] artifact id is equal to [{}]", SpringCloudConstants.CLOUD_DEPENDENCIES_ARTIFACT_ID, buildArtifact);
if (!SpringCloudConstants.CLOUD_DEPENDENCIES_ARTIFACT_ID.equals(buildArtifact)) {
@@ -109,6 +109,8 @@ class SCReleasePomParser {
.filter(propertyMatchesSCPattern())
.map(toProject())
.collect(Collectors.toSet());
String scReleaseVersion = model.getVersion();
projects.add(new Project("spring-cloud-release", scReleaseVersion));
return new Versions(buildVersion, projects);
}

View File

@@ -18,6 +18,7 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.ReleaserPropertiesAware;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import org.springframework.util.StringUtils;
@@ -25,12 +26,12 @@ import org.springframework.util.StringUtils;
/**
* @author Marcin Grzejszczak
*/
public class ProjectBuilder {
public class ProjectBuilder implements ReleaserPropertiesAware {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final String VERSION_MUSTACHE = "{{version}}";
private final ReleaserProperties properties;
private ReleaserProperties properties;
private final ProcessExecutor executor;
public ProjectBuilder(ReleaserProperties properties) {
@@ -161,12 +162,17 @@ public class ProjectBuilder {
}
return commandsList.toArray(new String[commandsList.size()]);
}
@Override public void setReleaserProperties(ReleaserProperties properties) {
this.properties = properties;
this.executor.setReleaserProperties(properties);
}
}
class ProcessExecutor {
class ProcessExecutor implements ReleaserPropertiesAware {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final ReleaserProperties properties;
private ReleaserProperties properties;
ProcessExecutor(ReleaserProperties properties) {
this.properties = properties;
@@ -175,7 +181,8 @@ class ProcessExecutor {
void runCommand(String[] commands, long waitTimeInMinutes) {
try {
String workingDir = this.properties.getWorkingDir();
log.debug("Will run the build via {} and wait for result for [{}] minutes", commands, waitTimeInMinutes);
log.debug("Will run the build from [{}] via {} and wait for result for [{}] minutes",
workingDir, commands, waitTimeInMinutes);
ProcessBuilder builder = builder(commands, workingDir);
Process process = startProcess(builder);
boolean finished = process.waitFor(waitTimeInMinutes, TimeUnit.MINUTES);
@@ -202,6 +209,10 @@ class ProcessExecutor {
.directory(new File(workingDir))
.inheritIO();
}
@Override public void setReleaserProperties(ReleaserProperties properties) {
this.properties = properties;
}
}
class HtmlFileWalker extends SimpleFileVisitor<Path> {

View File

@@ -9,13 +9,14 @@ import java.io.File;
import java.io.IOException;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.ReleaserPropertiesAware;
import org.springframework.cloud.release.internal.git.ProjectGitHandler;
import org.springframework.cloud.release.internal.pom.Projects;
/**
* @author Marcin Grzejszczak
*/
public class TemplateGenerator {
public class TemplateGenerator implements ReleaserPropertiesAware {
private static final String EMAIL_TEMPLATE = "email";
private static final String BLOG_TEMPLATE = "blog";
@@ -25,7 +26,7 @@ public class TemplateGenerator {
private final File blogOutput;
private final File tweetOutput;
private final File releaseNotesOutput;
private final ReleaserProperties props;
private ReleaserProperties props;
private final ProjectGitHandler handler;
public TemplateGenerator(ReleaserProperties props, ProjectGitHandler handler) {
@@ -109,4 +110,8 @@ public class TemplateGenerator {
throw new IllegalStateException(e);
}
}
@Override public void setReleaserProperties(ReleaserProperties properties) {
this.props = properties;
}
}

View File

@@ -70,7 +70,7 @@ public class GitRepoTests {
@Test
public void should_check_out_a_branch_on_cloned_repo() throws IOException {
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
this.gitRepo.checkout(project, "vCamden.SR3");
new GitRepo(project).checkout("vCamden.SR3");
File pom = new File(this.tmpFolder, "pom.xml");
then(pom).exists();
@@ -80,18 +80,32 @@ public class GitRepoTests {
@Test
public void should_check_out_a_branch_on_cloned_repo2() throws IOException {
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
this.gitRepo.checkout(project, "Camden.x");
new GitRepo(project).checkout("Camden.x");
File pom = new File(this.tmpFolder, "pom.xml");
then(pom).exists();
then(Files.lines(pom.toPath()).anyMatch(s -> s.contains("<version>Camden.BUILD-SNAPSHOT</version>"))).isTrue();
}
@Test
public void should_return_true_if_branch_exists() throws IOException {
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
then(new GitRepo(project).hasBranch("Camden.x")).isTrue();
}
@Test
public void should_return_false_if_branch_does_not_exist() throws IOException {
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
then(new GitRepo(project).hasBranch("aksjdhkasjkajshd")).isFalse();
}
@Test
public void should_throw_an_exception_when_checking_out_nonexisting_branch() throws IOException {
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
try {
this.gitRepo.checkout(project, "nonExistingBranch");
new GitRepo(project).checkout("nonExistingBranch");
fail("should throw an exception");
} catch (IllegalStateException e) {
then(e).hasMessageContaining("Ref nonExistingBranch can not be resolved");
@@ -100,10 +114,10 @@ public class GitRepoTests {
@Test
public void should_commit_changes() throws Exception {
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
createNewFile(project);
this.gitRepo.commit(project, "some message");
new GitRepo(project).commit("some message");
try(Git git = openGitProject(project)) {
RevCommit revCommit = git.log().call().iterator().next();
@@ -113,11 +127,11 @@ public class GitRepoTests {
@Test
public void should_not_commit_empty_changes() throws Exception {
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
createNewFile(project);
this.gitRepo.commit(project, "some message");
new GitRepo(project).commit("some message");
this.gitRepo.commit(project, "empty commit");
new GitRepo(project).commit("empty commit");
try(Git git = openGitProject(project)) {
RevCommit revCommit = git.log().call().iterator().next();
@@ -127,11 +141,11 @@ public class GitRepoTests {
@Test
public void should_create_a_tag() throws Exception {
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
createNewFile(project);
this.gitRepo.commit(project, "some message");
new GitRepo(project).commit("some message");
this.gitRepo.tag(project, "v1.0.0");
new GitRepo(project).tag("v1.0.0");
try(Git git = openGitProject(project)) {
tagIsPresent(git, "v1.0.0");
@@ -147,12 +161,12 @@ public class GitRepoTests {
@Test
public void should_push_changes_to_master_branch() throws Exception {
File origin = clonedProject(this.tmp.newFolder(), this.springCloudReleaseProject);
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
setOriginOnProjectToTmp(origin, project);
createNewFile(project);
this.gitRepo.commit(project, "some message");
new GitRepo(project).commit("some message");
this.gitRepo.pushBranch(project, "master");
new GitRepo(project).pushBranch("master");
try(Git git = openGitProject(origin)) {
RevCommit revCommit = git.log().call().iterator().next();
@@ -163,12 +177,12 @@ public class GitRepoTests {
@Test
public void should_push_changes_to_current_branch() throws Exception {
File origin = clonedProject(this.tmp.newFolder(), this.springCloudReleaseProject);
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
setOriginOnProjectToTmp(origin, project);
createNewFile(project);
this.gitRepo.commit(project, "some message");
new GitRepo(project).commit("some message");
this.gitRepo.pushCurrentBranch(project);
new GitRepo(project).pushCurrentBranch();
try(Git git = openGitProject(origin)) {
RevCommit revCommit = git.log().call().iterator().next();
@@ -179,11 +193,11 @@ public class GitRepoTests {
@Test
public void should_return_the_branch_name() throws Exception {
File origin = clonedProject(this.tmp.newFolder(), this.springCloudReleaseProject);
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
setOriginOnProjectToTmp(origin, project);
createNewFile(project);
String branch = this.gitRepo.currentBranch(project);
String branch = new GitRepo(project).currentBranch();
then(branch).isEqualTo("master");
}
@@ -191,13 +205,13 @@ public class GitRepoTests {
@Test
public void should_push_a_tag_to_new_branch_in_origin() throws Exception {
File origin = clonedProject(this.tmp.newFolder(), this.springCloudReleaseProject);
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
setOriginOnProjectToTmp(origin, project);
createNewFile(project);
this.gitRepo.commit(project, "some message");
this.gitRepo.tag(project, "v5.6.7.RELEASE");
new GitRepo(project).commit("some message");
new GitRepo(project).tag("v5.6.7.RELEASE");
this.gitRepo.pushTag(project, "v5.6.7.RELEASE");
new GitRepo(project).pushTag("v5.6.7.RELEASE");
try(Git git = openGitProject(origin)) {
tagIsPresent(git, "v5.6.7");
@@ -225,12 +239,12 @@ public class GitRepoTests {
@Test
public void should_revert_changes() throws Exception {
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(this.tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
File foo = new File(project, "foo");
foo.createNewFile();
this.gitRepo.commit(project, "Update SNAPSHOT to 1.0.0.RC1");
new GitRepo(project).commit("Update SNAPSHOT to 1.0.0.RC1");
this.gitRepo.revert(project, "Reverting the commit");
new GitRepo(project).revert("Reverting the commit");
try(Git git = openGitProject(project)) {
RevCommit revCommit = git.log().call().iterator().next();
@@ -240,10 +254,10 @@ public class GitRepoTests {
@Test
public void should_not_revert_changes_when_commit_message_is_not_related_to_updating_snapshots() throws Exception {
File project = this.gitRepo.cloneProject(this.springCloudReleaseProject.toURI());
File project = new GitRepo(tmpFolder).cloneProject(this.springCloudReleaseProject.toURI());
BDDAssertions.thenThrownBy(
() -> this.gitRepo.revert(project, "some message"))
() -> new GitRepo(project).revert("some message"))
.hasMessageContaining("Won't revert the commit with id");
}

View File

@@ -2,13 +2,16 @@ package org.springframework.cloud.release.internal.git;
import java.io.File;
import org.assertj.core.api.BDDAssertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import org.springframework.cloud.release.internal.sagan.Release;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
@@ -22,10 +25,15 @@ import static org.mockito.Mockito.never;
public class ProjectGitHandlerTests {
@Mock GitRepo gitRepo;
ProjectGitHandler updater = new ProjectGitHandler(new ReleaserProperties()) {
ReleaserProperties properties = new ReleaserProperties();
ProjectGitHandler updater = new ProjectGitHandler(this.properties) {
@Override GitRepo gitRepo(File workingDir) {
return ProjectGitHandlerTests.this.gitRepo;
}
@Override File cloneProject(String url) {
return new File(".");
}
};
File file = new File("");
@@ -33,54 +41,95 @@ public class ProjectGitHandlerTests {
public void should_only_commit_without_pushing_changes_when_version_is_snapshot() {
this.updater.commitAndTagIfApplicable(this.file, projectVersion("1.0.0.BUILD-SNAPSHOT"));
then(this.gitRepo).should().commit(any(File.class), eq("Bumping versions"));
then(this.gitRepo).should(never()).tag(any(File.class), anyString());
then(this.gitRepo).should().commit(eq("Bumping versions"));
then(this.gitRepo).should(never()).tag(anyString());
}
@Test
public void should_commit_tag_and_push_tag_when_version_is_not_snapshot() {
this.updater.commitAndTagIfApplicable(this.file, projectVersion("1.0.0.RELEASE"));
then(this.gitRepo).should().commit(any(File.class), eq("Update SNAPSHOT to 1.0.0.RELEASE"));
then(this.gitRepo).should().tag(any(File.class), eq("v1.0.0.RELEASE"));
then(this.gitRepo).should().pushTag(any(File.class), eq("v1.0.0.RELEASE"));
then(this.gitRepo).should().commit(eq("Update SNAPSHOT to 1.0.0.RELEASE"));
then(this.gitRepo).should().tag(eq("v1.0.0.RELEASE"));
then(this.gitRepo).should().pushTag(eq("v1.0.0.RELEASE"));
}
@Test
public void should_commit_when_snapshot_version_is_present_with_post_release_msg() {
this.updater.commitAfterBumpingVersions(this.file, projectVersion("1.0.0.BUILD-SNAPSHOT"));
then(this.gitRepo).should().commit(any(File.class), eq("Bumping versions to 1.0.1.BUILD-SNAPSHOT after release"));
then(this.gitRepo).should(never()).tag(any(File.class), anyString());
then(this.gitRepo).should().commit(eq("Bumping versions to 1.0.1.BUILD-SNAPSHOT after release"));
then(this.gitRepo).should(never()).tag(anyString());
}
@Test
public void should_not_commit_when_non_snapshot_version_is_present() {
this.updater.commitAfterBumpingVersions(this.file, projectVersion("1.0.0.RELEASE"));
then(this.gitRepo).should(never()).commit(any(File.class), eq("Bumping versions after release"));
then(this.gitRepo).should(never()).tag(any(File.class), anyString());
then(this.gitRepo).should(never()).commit(eq("Bumping versions after release"));
then(this.gitRepo).should(never()).tag(anyString());
}
@Test
public void should_not_revert_changes_for_snapshots() {
this.updater.revertChangesIfApplicable(this.file, projectVersion("1.0.0.BUILD-SNAPSHOT"));
then(this.gitRepo).should(never()).revert(any(File.class), anyString());
then(this.gitRepo).should(never()).revert(anyString());
}
@Test
public void should_revert_changes_when_version_is_not_snapshot() {
this.updater.revertChangesIfApplicable(this.file, projectVersion("1.0.0.RELEASE"));
then(this.gitRepo).should().revert(any(File.class), eq("Going back to snapshots"));
then(this.gitRepo).should().revert(eq("Going back to snapshots"));
}
@Test
public void should_push_current_branch() {
this.updater.pushCurrentBranch(this.file);
then(this.gitRepo).should().pushCurrentBranch(any(File.class));
then(this.gitRepo).should().pushCurrentBranch();
}
@Test
public void should_throw_exception_when_no_fixed_version_passed_for_the_project() {
BDDAssertions.thenThrownBy(() -> this.updater
.cloneProjectFromOrg("spring-cloud-sleuth"))
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("You haven't provided a version");
}
@Test
public void should_not_check_out_a_branch_if_it_does_not_exist_when_cloning_from_org() {
this.properties.getFixedVersions().put("spring-cloud-sleuth", "2.3.4.RELEASE");
given(this.gitRepo.hasBranch(anyString())).willReturn(true);
given(this.gitRepo.hasBranch("2.3.x")).willReturn(false);
this.updater.cloneProjectFromOrg("spring-cloud-sleuth");
then(this.gitRepo).should(never()).checkout(anyString());
}
@Test
public void should_check_out_a_branch_if_it_exists_when_cloning_from_org() {
this.properties.getFixedVersions().put("spring-cloud-sleuth", "2.3.4.RELEASE");
given(this.gitRepo.hasBranch(anyString())).willReturn(false);
given(this.gitRepo.hasBranch("2.3.x")).willReturn(true);
this.updater.cloneProjectFromOrg("spring-cloud-sleuth");
then(this.gitRepo).should().checkout("2.3.x");
}
@Test
public void should_check_out_a_branch_if_it_exists_when_cloning_from_org_and_its_a_release_train_version() {
this.properties.getFixedVersions().put("spring-cloud-release", "Finchley.SR6");
given(this.gitRepo.hasBranch(anyString())).willReturn(false);
given(this.gitRepo.hasBranch("Finchley.x")).willReturn(true);
this.updater.cloneProjectFromOrg("spring-cloud-release");
then(this.gitRepo).should().checkout("Finchley.x");
}
private ProjectVersion projectVersion(String version) {

View File

@@ -35,6 +35,15 @@ public class ProjectsTests {
then(projects.forName("spring-cloud-starter-build").version).isEqualTo("1.0.0");
}
@Test
public void should_return_true_when_a_project_by_name_exists() {
Set<ProjectVersion> projectVersions = new HashSet<>();
projectVersions.add(new ProjectVersion("spring-cloud-starter-build", "1.0.0"));
Projects projects = new Projects(projectVersions);
then(projects.containsProject("spring-cloud-starter-build")).isTrue();
}
@Test
public void should_find_projects_starting_with_name() {
Set<ProjectVersion> projectVersions = new HashSet<>();

View File

@@ -2,14 +2,12 @@ package org.springframework.cloud.release.internal.pom;
import org.apache.maven.plugin.logging.Log;
import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.BDDMockito.then;
@@ -30,15 +28,8 @@ public class PropertyStorerTests {
}
private String containsWarnMsgAboutEmptyVersion() {
return BDDMockito.argThat(new TypeSafeMatcher<String>() {
@Override protected boolean matchesSafely(String item) {
return item.contains("is empty. Will not set it");
}
@Override public void describeTo(Description description) {
}
});
return BDDMockito.argThat(
argument -> argument.contains("is empty. Will not set it"));
}
}

View File

@@ -50,6 +50,15 @@ public class SCReleasePomParserTests {
.hasMessageContaining("The pom doesn't have a [spring-boot-starter-parent] artifact id");
}
@Test
public void should_populate_sc_release_version() {
SCReleasePomParser parser = new SCReleasePomParser(this.springCloudReleaseProject);
String scReleaseVersion = parser.allVersions().versionForProject("spring-cloud-release");
then(scReleaseVersion).isEqualTo("Dalston.BUILD-SNAPSHOT");
}
@Test
public void should_populate_boot_version() {
SCReleasePomParser parser = new SCReleasePomParser(this.springCloudReleaseProject);

View File

@@ -8,10 +8,11 @@ import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.BDDMockito;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import static org.mockito.BDDMockito.then;
@@ -103,23 +104,17 @@ public class SaganUpdaterTest {
"http://cloud.spring.io/foo/1.1.x/", "SNAPSHOT")));
}
private TypeSafeMatcher<List<ReleaseUpdate>> withReleaseUpdate(final String version,
private ArgumentMatcher<List<ReleaseUpdate>> withReleaseUpdate(final String version,
final String refDocUrl, final String releaseStatus) {
return new TypeSafeMatcher<List<ReleaseUpdate>>() {
@Override protected boolean matchesSafely(List<ReleaseUpdate> items) {
ReleaseUpdate item = items.get(0);
return argument -> {
ReleaseUpdate item = argument.get(0);
return "foo".equals(item.artifactId) &&
releaseStatus.equals(item.releaseStatus) &&
version.equals(item.version) &&
refDocUrl.equals(item.apiDocUrl) &&
refDocUrl.equals(item.refDocUrl) &&
item.current;
}
@Override public void describeTo(Description description) {
}
};
};
}
}