Added automatic SC-Guides issue creation; fixes gh-69

This commit is contained in:
Marcin Grzejszczak
2018-02-04 21:53:49 +01:00
parent 6cfc436eaa
commit 06f7fa7160
8 changed files with 265 additions and 1 deletions

View File

@@ -1,7 +1,9 @@
package org.springframework.cloud.release.internal;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -132,6 +134,16 @@ public class Releaser {
}
File blog = this.templateGenerator.blog(projects);
log.info("\nSuccessfully created blog template at location [{}]", blog);
}
public void updateSpringGuides(ProjectVersion releaseVersion, Projects projects) {
if (!(releaseVersion.isRelease() || releaseVersion.isServiceRelease())) {
log.info("\nWon't updated Spring Guides for a non Release / Service Release version");
return;
}
this.projectGitHandler.createIssueInSpringGuides(projects, releaseVersion);
log.info("\nSuccessfully updated Spring Guides issues");
}
public void createTweet(ProjectVersion releaseVersion) {

View File

@@ -0,0 +1,118 @@
package org.springframework.cloud.release.internal.git;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import com.jcabi.github.Coordinates;
import com.jcabi.github.Github;
import com.jcabi.github.Issue;
import com.jcabi.github.Milestone;
import com.jcabi.github.Repo;
import com.jcabi.github.RtGithub;
import com.jcabi.http.wire.RetryWire;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import org.springframework.cloud.release.internal.pom.Projects;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author Marcin Grzejszczak
*/
class GithubIssues {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final String GITHUB_ISSUE_TITLE = "Spring Cloud Release took place";
private final Github github;
private final ReleaserProperties properties;
GithubIssues(ReleaserProperties properties) {
this.github = new RtGithub(new RtGithub(
properties.getGit().getOauthToken()).entry().through(RetryWire.class));
this.properties = properties;
}
GithubIssues(Github github, ReleaserProperties properties) {
this.github = github;
this.properties = properties;
}
void fileIssue(Projects projects, ProjectVersion version) {
Assert.hasText(this.properties.getGit().getOauthToken(),
"You have to pass Github OAuth token for milestone closing to be operational");
// do this only for RELEASE & SR
String releaseVersion = parsedVersion();
if (!(version.isRelease() || version.isServiceRelease())) {
log.info("Guide issue creation will occur only for Release or Service Release versions. Your version is [{}]", releaseVersion);
return;
}
Repo springGuides = this.github.repos()
.get(new Coordinates.Simple("spring-guides", "getting-started-guides"));
String issueTitle = StringUtils.capitalize(releaseVersion) + " " + GITHUB_ISSUE_TITLE;
// check if the issue is not already there
boolean issueAlreadyFiled = issueAlreadyFiled(springGuides, issueTitle);
if (issueAlreadyFiled) {
log.info("Issue already filed, will not do that again");
return;
}
try {
int number = springGuides.issues().create(issueTitle, issueText(projects))
.number();
log.info("Successfully created an issue with title [{}] in Spring Guides under: https://github.com/spring-guides/getting-started-guides/issues/" + number, issueTitle);
}
catch (IOException e) {
log.error("Exception occurred while trying to create the issue in guides", e);
}
}
private String parsedVersion() {
String version = this.properties.getPom().getBranch();
if (version.startsWith("v")) {
return version.substring(1);
}
return version;
}
private String issueText(Projects projects) {
StringBuilder builder = new StringBuilder()
.append("Spring Cloud [")
.append(parsedVersion())
.append("] Released with the following projects:")
.append("\n\n");
projects.forEach(project -> builder
.append(project.projectName).append(" : ")
.append("`").append(project.version).append("`")
.append("\n"));
return builder.toString();
}
private boolean issueAlreadyFiled(Repo springGuides, String issueTitle) {
Map<String, String> map = new HashMap<>();
map.put("state", "open");
int counter = 0;
int maxIssues = 10;
for (Issue issue : springGuides.issues().iterate(map)) {
if (counter >= maxIssues) {
return false;
}
Issue.Smart smartIssue = new Issue.Smart(issue);
try {
if (issueTitle.equals(smartIssue.title())) {
return true;
}
}
catch (IOException e) {
return false;
}
counter = counter + 1;
}
return false;
}
}

View File

@@ -9,6 +9,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import org.springframework.cloud.release.internal.pom.Projects;
/**
* Contains business logic around Git & Github operations
@@ -26,10 +27,12 @@ public class ProjectGitHandler {
private final ReleaserProperties properties;
private final GithubMilestones githubMilestones;
private final GithubIssues githubIssues;
public ProjectGitHandler(ReleaserProperties properties) {
this.properties = properties;
this.githubMilestones = new GithubMilestones(properties);
this.githubIssues = new GithubIssues(properties);
}
public void commitAndTagIfApplicable(File project, ProjectVersion version) {
@@ -90,6 +93,10 @@ public class ProjectGitHandler {
this.githubMilestones.closeMilestone(releaseVersion);
}
public void createIssueInSpringGuides(Projects projects, ProjectVersion version) {
this.githubIssues.fileIssue(projects, version);
}
public String milestoneUrl(ProjectVersion releaseVersion) {
return this.githubMilestones.milestoneUrl(releaseVersion);
}

View File

@@ -0,0 +1,106 @@
package org.springframework.cloud.release.internal.git;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collections;
import javax.json.Json;
import com.jcabi.github.Coordinates;
import com.jcabi.github.Issue;
import com.jcabi.github.Milestone;
import com.jcabi.github.Repo;
import com.jcabi.github.mock.MkGithub;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.test.rule.OutputCapture;
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.assertj.core.api.BDDAssertions.then;
import static org.assertj.core.api.BDDAssertions.thenThrownBy;
/**
* @author Marcin Grzejszczak
*/
public class GithubIssuesTests {
MkGithub github;
Repo repo;
@Rule public TemporaryFolder folder = new TemporaryFolder();
@Rule public OutputCapture capture = new OutputCapture();
@Before
public void setup() throws URISyntaxException, IOException {
this.github = new MkGithub("spring-guides");
this.repo = createGettingStartedGuides(this.github);
}
@Test
public void should_not_do_anything_for_non_release_train_version() throws IOException {
GithubIssues issues = new GithubIssues(this.github, withToken());
issues.fileIssue(new Projects(
new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")
), new ProjectVersion("sc-release", "Edgware.BUILD-SNAPSHOT"));
then(this.capture.toString()).contains("Guide issue creation will occur only");
}
@Test
public void should_file_an_issue_for_release_version() throws IOException {
GithubIssues issues = new GithubIssues(this.github, withToken());
issues.fileIssue(new Projects(
new ProjectVersion("foo", "1.0.0.RELEASE"),
new ProjectVersion("bar", "2.0.0.RELEASE"),
new ProjectVersion("baz", "3.0.0.RELEASE")
), new ProjectVersion("sc-release", "Edgware.RELEASE"));
then(this.capture.toString()).doesNotContain("Guide issue creation will occur only");
Issue issue = this.github.repos()
.get(new Coordinates.Simple("spring-guides", "getting-started-guides"))
.issues().get(1);
then(issue.exists()).isTrue();
Issue.Smart smartIssue = new Issue.Smart(issue);
then(smartIssue.title()).isEqualTo("Edgware.RELEASE Spring Cloud Release took place");
then(smartIssue.body())
.contains("Spring Cloud [Edgware.RELEASE]")
.contains("foo : `1.0.0.RELEASE`")
.contains("bar : `2.0.0.RELEASE`")
.contains("baz : `3.0.0.RELEASE`");
}
@Test
public void should_throw_exception_when_no_token_was_passed() {
GithubIssues issues = new GithubIssues(new ReleaserProperties());
thenThrownBy(() -> issues.fileIssue(new Projects(Collections.emptySet()),
nonGaSleuthProject()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("You have to pass Github OAuth token for milestone closing to be operational");
}
private Repo createGettingStartedGuides(MkGithub github) throws IOException {
return github.repos().create(
Json.createObjectBuilder().add(
"name",
"getting-started-guides"
).build()
);
}
private ProjectVersion nonGaSleuthProject() {
return new ProjectVersion("spring-cloud-sleuth", "0.2.0.BUILD-SNAPSHOT");
}
ReleaserProperties withToken() {
ReleaserProperties properties = new ReleaserProperties();
properties.getGit().setOauthToken("foo");
properties.getPom().setBranch("vEdgware.RELEASE");
return properties;
}
}