Skip to content

Commit

Permalink
Add gitHubCheckMilestoneHasNoOpenIssues
Browse files Browse the repository at this point in the history
  • Loading branch information
rwinch committed Apr 29, 2021
1 parent 23eee9a commit 84d9629
Show file tree
Hide file tree
Showing 10 changed files with 1,118 additions and 3 deletions.
17 changes: 14 additions & 3 deletions RELEASE.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ $ git checkout -

The following command will update the dependencies again but this time creating a ticket for each update and placing `Closes gh-<number>` in the commit. Replacing the following values:

<github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`
<next-version> - Replace with the title of the milestone you are releasing now (i.e. 5.5.0-RC1)
* <github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`
* <next-version> - Replace with the title of the milestone you are releasing now (i.e. 5.5.0-RC1)
[source,bash]
----
Expand All @@ -61,7 +61,18 @@ Apply any fixes from your previous branch that were necessary.

= Check All Issues are Closed

Check that all issues are closed for the milestone https://github.com/spring-projects/spring-security/milestones
The following command will check if there are any open issues for the ticket.
Before running the command, replace the following values:

* <github-personal-access-token> - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`. This is optional since you are unlikely to reach the rate limit for such a simple check.
* <next-version> - Replace with the title of the milestone you are releasing now (i.e. 5.5.0-RC1)

[source,bash]
----
$ ./gradlew gitHubCheckMilestoneHasNoOpenIssues -PgitHubAccessToken=<github-personal-access-token> -PnextVersion=<next-version>
----

Alternatively, you can manually check using https://github.com/spring-projects/spring-security/milestones

= Update Release Version

Expand Down
8 changes: 8 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ apply plugin: 'io.spring.convention.root'
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'org.springframework.security.update-dependencies'
apply plugin: 'org.springframework.security.sagan'
apply plugin: 'org.springframework.github.milestone'

group = 'org.springframework.security'
description = 'Spring Security'
Expand All @@ -34,6 +35,13 @@ tasks.named("saganCreateRelease") {
apiDocUrl = "https://docs.spring.io/spring-security/site/docs/{version}/api/"
}

tasks.named("gitHubCheckMilestoneHasNoOpenIssues") {
repository {
owner = "spring-projects"
name = "spring-security"
}
}

updateDependenciesSettings {
gitHub {
organization = "spring-projects"
Expand Down
4 changes: 4 additions & 0 deletions buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ gradlePlugin {
id = "org.springframework.security.sagan"
implementationClass = "org.springframework.gradle.sagan.SaganPlugin"
}
githubMilestone {
id = "org.springframework.github.milestone"
implementationClass = "org.springframework.gradle.github.milestones.GitHubMilestonePlugin"
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.gradle.github.milestones;

import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.util.List;

public class GitHubMilestoneApi {
private String baseUrl = "https://api.github.com";

private OkHttpClient client;

private Gson gson = new Gson();

public GitHubMilestoneApi() {
this.client = new OkHttpClient.Builder().build();
}

public GitHubMilestoneApi(String gitHubToken) {
this.client = new OkHttpClient.Builder()
.addInterceptor(new AuthorizationInterceptor(gitHubToken))
.build();
}

public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}

public long findMilestoneNumberByTitle(RepositoryRef repositoryRef, String milestoneTitle) {
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/milestones?per_page=100";
Request request = new Request.Builder().get().url(url)
.build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Could not find milestone with title " + milestoneTitle + " for repository " + repositoryRef + ". Response " + response);
}
List<Milestone> milestones = this.gson.fromJson(response.body().charStream(), new TypeToken<List<Milestone>>(){}.getType());
for (Milestone milestone : milestones) {
if (milestoneTitle.equals(milestone.getTitle())) {
return milestone.getNumber();
}
}
if (milestones.size() <= 100) {
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
}
throw new RuntimeException("It is possible there are too many open milestones open (only 100 are supported). Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
} catch (IOException e) {
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef, e);
}
}

public boolean isOpenIssuesForMilestoneNumber(RepositoryRef repositoryRef, long milestoneNumber) {
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/issues?per_page=1&milestone=" + milestoneNumber;
Request request = new Request.Builder().get().url(url)
.build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Could not find issues for milestone number " + milestoneNumber + " for repository " + repositoryRef + ". Response " + response);
}
List<Object> issues = this.gson.fromJson(response.body().charStream(), new TypeToken<List<Object>>(){}.getType());
return !issues.isEmpty();
} catch (IOException e) {
throw new RuntimeException("Could not find issues for milestone number " + milestoneNumber + " for repository " + repositoryRef, e);
}
}

// public boolean isOpenIssuesForMilestoneName(String owner, String repository, String milestoneName) {
//
// }


private static class AuthorizationInterceptor implements Interceptor {

private final String token;

public AuthorizationInterceptor(String token) {
this.token = token;
}

@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + this.token).build();
return chain.proceed(request);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.gradle.github.milestones;

import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.TaskAction;

public class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();

@Input
private String milestoneTitle;

@Input @Optional
private String gitHubAccessToken;

private GitHubMilestoneApi milestones = new GitHubMilestoneApi();

@TaskAction
public void checkHasNoOpenIssues() {
long milestoneNumber = this.milestones.findMilestoneNumberByTitle(this.repository, this.milestoneTitle);
boolean isOpenIssues = this.milestones.isOpenIssuesForMilestoneNumber(this.repository, milestoneNumber);
if (isOpenIssues) {
throw new IllegalStateException("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
}
System.out.println("The repository " + this.repository + " has no open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
}

public RepositoryRef getRepository() {
return repository;
}

public void repository(Action<RepositoryRef> repository) {
repository.execute(this.repository);
}

public void setRepository(RepositoryRef repository) {
this.repository = repository;
}

public String getMilestoneTitle() {
return milestoneTitle;
}

public void setMilestoneTitle(String milestoneTitle) {
this.milestoneTitle = milestoneTitle;
}

public String getGitHubAccessToken() {
return gitHubAccessToken;
}

public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
this.milestones = new GitHubMilestoneApi(gitHubAccessToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.gradle.github.milestones;

import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;

public class GitHubMilestonePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getTasks().register("gitHubCheckMilestoneHasNoOpenIssues", GitHubMilestoneHasNoOpenIssuesTask.class, new Action<GitHubMilestoneHasNoOpenIssuesTask>() {
@Override
public void execute(GitHubMilestoneHasNoOpenIssuesTask githubCheckMilestoneHasNoOpenIssues) {
githubCheckMilestoneHasNoOpenIssues.setGroup("Release");
githubCheckMilestoneHasNoOpenIssues.setDescription("Checks if there are any open issues for the specified repository and milestone");
githubCheckMilestoneHasNoOpenIssues.setMilestoneTitle((String) project.findProperty("nextVersion"));
if (project.hasProperty("githubAccessToken")) {
githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
}
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.springframework.gradle.github.milestones;

public class Milestone {
private String title;

private long number;

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public long getNumber() {
return number;
}

public void setNumber(long number) {
this.number = number;
}

@Override
public String toString() {
return "Milestone{" +
"title='" + title + '\'' +
", number=" + number +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.springframework.gradle.github.milestones;
public class RepositoryRef {
private String owner;

private String name;

RepositoryRef() {
}

public RepositoryRef(String owner, String name) {
this.owner = owner;
this.name = name;
}

public String getOwner() {
return owner;
}

public void setOwner(String owner) {
this.owner = owner;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "RepositoryRef{" +
"owner='" + owner + '\'' +
", name='" + name + '\'' +
'}';
}

public static RepositoryRefBuilder owner(String owner) {
return new RepositoryRefBuilder().owner(owner);
}

public static final class RepositoryRefBuilder {
private String owner;
private String repository;

private RepositoryRefBuilder() {
}

private RepositoryRefBuilder owner(String owner) {
this.owner = owner;
return this;
}

public RepositoryRefBuilder repository(String repository) {
this.repository = repository;
return this;
}

public RepositoryRef build() {
return new RepositoryRef(owner, repository);
}
}
}

Loading

0 comments on commit 84d9629

Please sign in to comment.