@@ -2,6 +2,10 @@ package org.springframework.cloud.release.internal.spring;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -10,6 +14,8 @@ import org.springframework.cloud.release.internal.ReleaserProperties;
|
||||
import org.springframework.cloud.release.internal.pom.ProjectVersion;
|
||||
import org.springframework.cloud.release.internal.pom.Projects;
|
||||
|
||||
import static org.springframework.cloud.release.internal.spring.Task.task;
|
||||
|
||||
/**
|
||||
* Releaser that gets input from console
|
||||
*
|
||||
@@ -18,10 +24,6 @@ import org.springframework.cloud.release.internal.pom.Projects;
|
||||
public class SpringReleaser {
|
||||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private static final String MSG = "'q' to quit and 's' to skip\n\n";
|
||||
private static final String SKIP = "s";
|
||||
private static final String QUIT = "q";
|
||||
|
||||
private final Releaser releaser;
|
||||
private final ReleaserProperties properties;
|
||||
|
||||
@@ -30,80 +32,168 @@ public class SpringReleaser {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
private final List<Task> TASKS = Stream.of(
|
||||
task("UPDATING POMS",
|
||||
"Update poms with versions from Spring Cloud Release",
|
||||
args -> args.releaser.updateProjectFromScRelease(args.project, args.projects)),
|
||||
task("BUILD PROJECT",
|
||||
"Build the project",
|
||||
args -> args.releaser.buildProject()),
|
||||
task("COMMITTING (ALL) AND PUSHING TAGS (NON-SNAPSHOTS)",
|
||||
"Commit, tag and push the tag",
|
||||
args -> args.releaser.commitAndPushTags(args.project, args.versionFromScRelease)),
|
||||
task("ARTIFACT DEPLOYMENT",
|
||||
"Deploy the artifacts to Artifactory",
|
||||
args -> args.releaser.deploy()),
|
||||
task("PUBLISHING DOCS",
|
||||
"Publish the docs",
|
||||
args -> args.releaser.publishDocs(args.versionFromScRelease)),
|
||||
task("REVERTING CHANGES & BUMPING VERSION (RELEASE ONLY)",
|
||||
"Go back to snapshots and bump originalVersion by patch",
|
||||
args -> args.releaser.rollbackReleaseVersion(args.project, args.originalVersion, args.versionFromScRelease)),
|
||||
task("PUSHING CHANGES",
|
||||
"Push the commits",
|
||||
args -> args.releaser.pushCurrentBranch(args.project)),
|
||||
task("CLOSING MILESTONE",
|
||||
"Close the milestone at Github",
|
||||
args -> args.releaser.closeMilestone(args.versionFromScRelease)),
|
||||
task("CREATING TEMPLATES",
|
||||
"Create email / tweet etc. templates",
|
||||
args -> {
|
||||
args.releaser.createEmail(args.versionFromScRelease);
|
||||
args.releaser.createBlog(args.versionFromScRelease, args.projects);
|
||||
})
|
||||
).collect(Collectors.toList());
|
||||
|
||||
private final List<Task> COMPOSITE_TASKS = Stream.of(
|
||||
task("FULL RELEASE",
|
||||
"Perform a full release of this project without interruptions",
|
||||
args -> TASKS.forEach(task -> task.execute(args))),
|
||||
task("FULL VERBOSE RELEASE",
|
||||
"Perform a full release of this project in a verbose mode (you'll be asked about skipping steps)",
|
||||
args -> TASKS.forEach(task -> task.execute(args)))
|
||||
).collect(Collectors.toList());
|
||||
|
||||
private final List<Task> ALL_TASKS = Stream.of(
|
||||
COMPOSITE_TASKS,
|
||||
TASKS
|
||||
).flatMap(List::stream).collect(Collectors.toList());
|
||||
|
||||
public void release() {
|
||||
log.info("\n\n\n=== RETRIEVING VERSIONS ===\n\nWill clone Spring Cloud Release"
|
||||
+ " to retrieve all versions for the branch [{}]", this.properties.getPom().getBranch());
|
||||
log.info(buildOptionsText().toString());
|
||||
printVersionRetreival();
|
||||
String workingDir = this.properties.getWorkingDir();
|
||||
File project = new File(workingDir);
|
||||
ProjectVersion originalVersion = new ProjectVersion(project);
|
||||
Projects projects = this.releaser.retrieveVersionsFromSCRelease();
|
||||
ProjectVersion versionFromScRelease = projects.forFile(project);
|
||||
log.info("\n\n\n=== UPDATING POMS ===\n\nWill run the application "
|
||||
+ "for root folder [{}]. \n\nPress ENTER to continue {}", workingDir, MSG);
|
||||
boolean skipPoms = skipStep();
|
||||
if (!skipPoms) {
|
||||
versionFromScRelease = this.releaser.updateProjectFromScRelease(project, projects);
|
||||
int chosenOption = chosenOption();
|
||||
log.info("\n\n\nYou chose [{}]: [{}]\n\n\n", chosenOption, ALL_TASKS.get(chosenOption).description);
|
||||
boolean verbose = chosenOption == 1;
|
||||
Task task = taskFromOption(chosenOption);
|
||||
Args args = new Args(this.releaser, project, projects, originalVersion, versionFromScRelease,
|
||||
this.properties, verbose);
|
||||
task.consumer.accept(args);
|
||||
}
|
||||
|
||||
private StringBuilder buildOptionsText() {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("\n\n\n=== WHAT DO YOU WANT TO DO? ===\n\n");
|
||||
for (int i = 0; i < ALL_TASKS.size(); i++) {
|
||||
msg.append(i).append(") ").append(ALL_TASKS.get(i).description).append("\n");
|
||||
}
|
||||
log.info("\n\n\n=== BUILD PROJECT ===\n\nPress ENTER to build the project {}", MSG);
|
||||
boolean skipBuild = skipStep();
|
||||
if (!skipBuild) {
|
||||
this.releaser.buildProject();
|
||||
msg.append("\n\n").append("You can press 'q' to quit\n\n");
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void printVersionRetreival() {
|
||||
log.info("\n\n\n=== RETRIEVING VERSIONS ===\n\nWill clone Spring Cloud Release"
|
||||
+ " to retrieve all versions for the branch [{}]", this.properties.getPom().getBranch());
|
||||
}
|
||||
|
||||
private Task taskFromOption(int option) {
|
||||
return ALL_TASKS.get(option);
|
||||
}
|
||||
|
||||
int chosenOption() {
|
||||
String input = System.console().readLine();
|
||||
switch (input.toLowerCase()) {
|
||||
case "q":
|
||||
System.exit(0);
|
||||
default:
|
||||
return Integer.parseInt(input);
|
||||
}
|
||||
log.info("\n\n\n=== COMMITTING (ALL) AND PUSHING TAGS (NON-SNAPSHOTS) ===\n\nPress ENTER to commit, tag and push the tag {}", MSG);
|
||||
boolean skipCommit = skipStep();
|
||||
if (!skipCommit) {
|
||||
this.releaser.commitAndPushTags(project, versionFromScRelease);
|
||||
}
|
||||
log.info("\n\n\n=== ARTIFACT DEPLOYMENT ===\n\nPress ENTER to deploy the artifacts {}", MSG);
|
||||
boolean skipDeployment = skipStep();
|
||||
if (!skipDeployment) {
|
||||
this.releaser.deploy();
|
||||
}
|
||||
log.info("\n\n\n=== PUBLISHING DOCS ===\n\nPress ENTER to publish the docs {}", MSG);
|
||||
boolean skipDocs = skipStep();
|
||||
if (!skipDocs) {
|
||||
this.releaser.publishDocs(versionFromScRelease);
|
||||
}
|
||||
if (!versionFromScRelease.isSnapshot()) {
|
||||
log.info("\n\n\n=== REVERTING CHANGES & BUMPING VERSION (RELEASE ONLY)===\n\nPress ENTER to go "
|
||||
+ "back to snapshots and bump originalVersion by patch {}", MSG);
|
||||
boolean skipRevert = skipStep();
|
||||
if (!skipRevert) {
|
||||
this.releaser.rollbackReleaseVersion(project, originalVersion, versionFromScRelease);
|
||||
}
|
||||
}
|
||||
log.info("\n\n\n=== PUSHING CHANGES===\n\nPress ENTER to push the commits {}", MSG);
|
||||
boolean skipPush = skipStep();
|
||||
if (!skipPush) {
|
||||
this.releaser.pushCurrentBranch(project);
|
||||
}
|
||||
if (!versionFromScRelease.isSnapshot()) {
|
||||
log.info("\n\n\n=== CLOSING MILESTONE===\n\nPress ENTER to close the milestone at Github {}", MSG);
|
||||
boolean skipMilestone = skipStep();
|
||||
if (!skipMilestone) {
|
||||
this.releaser.closeMilestone(versionFromScRelease);
|
||||
}
|
||||
}
|
||||
if (!versionFromScRelease.isSnapshot()) {
|
||||
log.info("\n\n\n=== CREATING TEMPLATES===\n\nPress ENTER to create email / tweet etc. templates {}", MSG);
|
||||
boolean skipTemplates = skipStep();
|
||||
if (!skipTemplates) {
|
||||
this.releaser.createEmail(versionFromScRelease);
|
||||
this.releaser.createBlog(versionFromScRelease, projects);
|
||||
}
|
||||
}
|
||||
|
||||
class Task {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final String MSG = "'q' to quit and 's' to skip\n\n";
|
||||
|
||||
final String header;
|
||||
final String description;
|
||||
final Consumer<Args> consumer;
|
||||
|
||||
Task(String header, String description, Consumer<Args> consumer) {
|
||||
this.header = header;
|
||||
this.description = description;
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
void execute(Args args) {
|
||||
boolean verbose = args.verbose;
|
||||
printLog(verbose);
|
||||
if (verbose) {
|
||||
boolean skipStep = skipStep();
|
||||
if (!skipStep) {
|
||||
consumer.accept(args);
|
||||
}
|
||||
} else {
|
||||
consumer.accept(args);
|
||||
}
|
||||
}
|
||||
|
||||
private void printLog(boolean shouldSkip) {
|
||||
log.info("\n\n\n=== {} ===\n\n{} {}\n\n", header, description, shouldSkip ? MSG : "");
|
||||
}
|
||||
|
||||
boolean skipStep() {
|
||||
String input = System.console().readLine();
|
||||
switch (input.toLowerCase()) {
|
||||
case SKIP:
|
||||
case "s":
|
||||
return true;
|
||||
case QUIT:
|
||||
case "q":
|
||||
System.exit(0);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Task task(String header, String description, Consumer<Args> function) {
|
||||
return new Task(header, description, function);
|
||||
}
|
||||
}
|
||||
|
||||
class Args {
|
||||
final Releaser releaser;
|
||||
final File project;
|
||||
final Projects projects;
|
||||
final ProjectVersion originalVersion;
|
||||
final ProjectVersion versionFromScRelease;
|
||||
final ReleaserProperties properties;
|
||||
final boolean verbose;
|
||||
|
||||
Args(Releaser releaser, File project, Projects projects, ProjectVersion originalVersion,
|
||||
ProjectVersion versionFromScRelease, ReleaserProperties properties,
|
||||
boolean verbose) {
|
||||
this.releaser = releaser;
|
||||
this.project = project;
|
||||
this.projects = projects;
|
||||
this.originalVersion = originalVersion;
|
||||
this.versionFromScRelease = versionFromScRelease;
|
||||
this.properties = properties;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import java.nio.file.Files;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.maven.model.Model;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.junit.Before;
|
||||
@@ -16,7 +15,6 @@ import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.cloud.release.internal.Releaser;
|
||||
import org.springframework.cloud.release.internal.ReleaserProperties;
|
||||
import org.springframework.cloud.release.internal.template.TemplateGenerator;
|
||||
import org.springframework.cloud.release.internal.git.GitTestUtils;
|
||||
import org.springframework.cloud.release.internal.git.ProjectGitUpdater;
|
||||
import org.springframework.cloud.release.internal.pom.ProjectPomUpdater;
|
||||
@@ -24,6 +22,7 @@ import org.springframework.cloud.release.internal.pom.ProjectVersion;
|
||||
import org.springframework.cloud.release.internal.pom.TestPomReader;
|
||||
import org.springframework.cloud.release.internal.pom.TestUtils;
|
||||
import org.springframework.cloud.release.internal.project.ProjectBuilder;
|
||||
import org.springframework.cloud.release.internal.template.TemplateGenerator;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
@@ -105,6 +104,27 @@ public class AcceptanceTests {
|
||||
.contains("I am pleased to announce that the Release Candidate 1 (RC1)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_generate_templates_only() throws Exception {
|
||||
File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), this.springCloudConsulProject);
|
||||
pomVersionIsEqualTo(origin, "1.2.0.BUILD-SNAPSHOT");
|
||||
pomParentVersionIsEqualTo(origin, "1.2.0.BUILD-SNAPSHOT");
|
||||
File project = GitTestUtils.clonedProject(this.tmp.newFolder(), tmpFile("spring-cloud-consul"));
|
||||
GitTestUtils.setOriginOnProjectToTmp(origin, project);
|
||||
SpringReleaser releaser = templateOnlyReleaser(project, "Dalston.RC1", "1.2.0.RC1");
|
||||
|
||||
releaser.release();
|
||||
|
||||
then(this.gitUpdater.executed).isFalse();
|
||||
then(emailTemplate()).exists();
|
||||
then(emailTemplateContents())
|
||||
.contains("Spring Cloud Dalston.RC1 available")
|
||||
.contains("Spring Cloud Dalston RC1 Train release");
|
||||
then(blogTemplate()).exists();
|
||||
then(blogTemplateContents())
|
||||
.contains("I am pleased to announce that the Release Candidate 1 (RC1)");
|
||||
}
|
||||
|
||||
private Iterable<RevCommit> listOfCommits(File project) throws GitAPIException {
|
||||
return GitTestUtils.openGitProject(project).log().call();
|
||||
}
|
||||
@@ -132,8 +152,7 @@ public class AcceptanceTests {
|
||||
}
|
||||
|
||||
private void tagIsPresentInOrigin(File origin, String expectedTag) throws GitAPIException {
|
||||
BDDAssertions
|
||||
.then(GitTestUtils.openGitProject(origin).tagList()
|
||||
then(GitTestUtils.openGitProject(origin).tagList()
|
||||
.call().iterator().next().getName()).endsWith(expectedTag);
|
||||
}
|
||||
|
||||
@@ -159,6 +178,25 @@ public class AcceptanceTests {
|
||||
|
||||
private SpringReleaser releaser(File projectFile, String branch, String expectedVersion) throws Exception {
|
||||
ReleaserProperties properties = releaserProperties(projectFile, branch);
|
||||
Releaser releaser = defaultReleaser(expectedVersion, properties);
|
||||
return new SpringReleaser(releaser, properties) {
|
||||
@Override int chosenOption() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private SpringReleaser templateOnlyReleaser(File projectFile, String branch, String expectedVersion) throws Exception {
|
||||
ReleaserProperties properties = releaserProperties(projectFile, branch);
|
||||
Releaser releaser = defaultReleaser(expectedVersion, properties);
|
||||
return new SpringReleaser(releaser, properties) {
|
||||
@Override int chosenOption() {
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Releaser defaultReleaser(String expectedVersion, ReleaserProperties properties) throws Exception {
|
||||
ProjectPomUpdater pomUpdater = new ProjectPomUpdater(properties);
|
||||
ProjectBuilder projectBuilder = new ProjectBuilder(properties, pomUpdater);
|
||||
TestProjectGitUpdater gitUpdater = new TestProjectGitUpdater(properties,
|
||||
@@ -167,11 +205,7 @@ public class AcceptanceTests {
|
||||
Releaser releaser = new Releaser(pomUpdater, projectBuilder, gitUpdater,
|
||||
templateGenerator);
|
||||
this.gitUpdater = gitUpdater;
|
||||
return new SpringReleaser(releaser, properties) {
|
||||
@Override boolean skipStep() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return releaser;
|
||||
}
|
||||
|
||||
private ReleaserProperties releaserProperties(File project, String branch) throws URISyntaxException {
|
||||
|
||||
Reference in New Issue
Block a user