Skip to content

Commit 539443b

Browse files
author
Steve Riesenberg
committed
Add GitHubReleasePlugin with createGitHubRelease task
Issue gh-10456 Issue gh-10457
1 parent 28424f8 commit 539443b

File tree

13 files changed

+610
-13
lines changed

13 files changed

+610
-13
lines changed

build.gradle

+8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ apply plugin: 'org.springframework.security.update-dependencies'
2222
apply plugin: 'org.springframework.security.sagan'
2323
apply plugin: 'org.springframework.github.milestone'
2424
apply plugin: 'org.springframework.github.changelog'
25+
apply plugin: 'org.springframework.github.release'
2526

2627
group = 'org.springframework.security'
2728
description = 'Spring Security'
@@ -46,6 +47,13 @@ tasks.named("gitHubCheckMilestoneHasNoOpenIssues") {
4647
}
4748
}
4849

50+
tasks.named("createGitHubRelease") {
51+
repository {
52+
owner = "spring-projects"
53+
name = "spring-security"
54+
}
55+
}
56+
4957
tasks.named("updateDependencies") {
5058
// we aren't Gradle 7 compatible yet
5159
checkForGradleUpdate = false

buildSrc/build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ gradlePlugin {
5959
id = "org.springframework.github.changelog"
6060
implementationClass = "org.springframework.gradle.github.changelog.GitHubChangelogPlugin"
6161
}
62+
githubRelease {
63+
id = "org.springframework.github.release"
64+
implementationClass = "org.springframework.gradle.github.release.GitHubReleasePlugin"
65+
}
6266
s101 {
6367
id = "s101"
6468
implementationClass = "s101.S101Plugin"

buildSrc/src/main/java/org/springframework/gradle/github/milestones/RepositoryRef.java renamed to buildSrc/src/main/java/org/springframework/gradle/github/RepositoryRef.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
package org.springframework.gradle.github.milestones;
1+
package org.springframework.gradle.github;
2+
23
public class RepositoryRef {
34
private String owner;
45

56
private String name;
67

7-
RepositoryRef() {
8+
public RepositoryRef() {
89
}
910

1011
public RepositoryRef(String owner, String name) {
@@ -62,4 +63,3 @@ public RepositoryRef build() {
6263
}
6364
}
6465
}
65-

buildSrc/src/main/java/org/springframework/gradle/github/changelog/GitHubChangelogPlugin.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.gradle.github.changelog;
1818

19+
import java.io.File;
20+
import java.nio.file.Paths;
21+
1922
import org.gradle.api.Action;
2023
import org.gradle.api.Plugin;
2124
import org.gradle.api.Project;
@@ -28,12 +31,10 @@
2831
import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout;
2932
import org.gradle.api.tasks.JavaExec;
3033

31-
import java.io.File;
32-
import java.nio.file.Paths;
33-
3434
public class GitHubChangelogPlugin implements Plugin<Project> {
3535

3636
public static final String CHANGELOG_GENERATOR_CONFIGURATION_NAME = "changelogGenerator";
37+
public static final String RELEASE_NOTES_PATH = "changelog/release-notes.md";
3738

3839
@Override
3940
public void apply(Project project) {
@@ -42,7 +43,7 @@ public void apply(Project project) {
4243
project.getTasks().register("generateChangelog", JavaExec.class, new Action<JavaExec>() {
4344
@Override
4445
public void execute(JavaExec generateChangelog) {
45-
File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), "changelog/release-notes.md"));
46+
File outputFile = project.file(Paths.get(project.getBuildDir().getPath(), RELEASE_NOTES_PATH));
4647
outputFile.getParentFile().mkdirs();
4748
generateChangelog.setGroup("Release");
4849
generateChangelog.setDescription("Generates the changelog");

buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneApi.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,17 @@
1616

1717
package org.springframework.gradle.github.milestones;
1818

19+
import java.io.IOException;
20+
import java.util.List;
21+
1922
import com.google.common.reflect.TypeToken;
2023
import com.google.gson.Gson;
2124
import okhttp3.Interceptor;
2225
import okhttp3.OkHttpClient;
2326
import okhttp3.Request;
2427
import okhttp3.Response;
2528

26-
import java.io.IOException;
27-
import java.util.List;
29+
import org.springframework.gradle.github.RepositoryRef;
2830

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

buildSrc/src/main/java/org/springframework/gradle/github/milestones/GitHubMilestoneHasNoOpenIssuesTask.java

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import org.gradle.api.tasks.Optional;
2222
import org.gradle.api.tasks.TaskAction;
2323

24+
import org.springframework.gradle.github.RepositoryRef;
25+
2426
public class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
2527
@Input
2628
private RepositoryRef repository = new RepositoryRef();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.gradle.github.release;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.nio.file.Files;
22+
import java.nio.file.Paths;
23+
24+
import org.gradle.api.Action;
25+
import org.gradle.api.DefaultTask;
26+
import org.gradle.api.Project;
27+
import org.gradle.api.tasks.Input;
28+
import org.gradle.api.tasks.Optional;
29+
import org.gradle.api.tasks.TaskAction;
30+
31+
import org.springframework.gradle.github.RepositoryRef;
32+
import org.springframework.gradle.github.changelog.GitHubChangelogPlugin;
33+
34+
/**
35+
* @author Steve Riesenberg
36+
*/
37+
public class CreateGitHubReleaseTask extends DefaultTask {
38+
@Input
39+
private RepositoryRef repository = new RepositoryRef();
40+
41+
@Input @Optional
42+
private String gitHubAccessToken;
43+
44+
@Input
45+
private String version;
46+
47+
@Input @Optional
48+
private String branch = "main";
49+
50+
@Input
51+
private boolean createRelease = false;
52+
53+
@TaskAction
54+
public void createGitHubRelease() {
55+
String body = readReleaseNotes();
56+
Release release = Release.tag(this.version)
57+
.commit(this.branch)
58+
.name(this.version)
59+
.body(body)
60+
.preRelease(this.version.contains("-"))
61+
.build();
62+
63+
System.out.printf("%sCreating GitHub release for %s/%s@%s\n",
64+
this.createRelease ? "" : "[DRY RUN] ",
65+
this.repository.getOwner(),
66+
this.repository.getName(),
67+
this.version
68+
);
69+
System.out.printf(" Release Notes:\n\n----\n%s\n----\n\n", body.trim());
70+
71+
if (this.createRelease) {
72+
GitHubReleaseApi github = new GitHubReleaseApi(this.gitHubAccessToken);
73+
github.publishRelease(this.repository, release);
74+
}
75+
}
76+
77+
private String readReleaseNotes() {
78+
Project project = getProject();
79+
File inputFile = project.file(Paths.get(project.getBuildDir().getPath(), GitHubChangelogPlugin.RELEASE_NOTES_PATH));
80+
try {
81+
return Files.readString(inputFile.toPath());
82+
} catch (IOException ex) {
83+
throw new RuntimeException("Unable to read release notes from " + inputFile, ex);
84+
}
85+
}
86+
87+
public RepositoryRef getRepository() {
88+
return repository;
89+
}
90+
91+
public void repository(Action<RepositoryRef> repository) {
92+
repository.execute(this.repository);
93+
}
94+
95+
public void setRepository(RepositoryRef repository) {
96+
this.repository = repository;
97+
}
98+
99+
public String getGitHubAccessToken() {
100+
return gitHubAccessToken;
101+
}
102+
103+
public void setGitHubAccessToken(String gitHubAccessToken) {
104+
this.gitHubAccessToken = gitHubAccessToken;
105+
}
106+
107+
public String getVersion() {
108+
return version;
109+
}
110+
111+
public void setVersion(String version) {
112+
this.version = version;
113+
}
114+
115+
public String getBranch() {
116+
return branch;
117+
}
118+
119+
public void setBranch(String branch) {
120+
this.branch = branch;
121+
}
122+
123+
public boolean isCreateRelease() {
124+
return createRelease;
125+
}
126+
127+
public void setCreateRelease(boolean createRelease) {
128+
this.createRelease = createRelease;
129+
}
130+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.gradle.github.release;
18+
19+
import java.io.IOException;
20+
21+
import com.google.gson.Gson;
22+
import okhttp3.Interceptor;
23+
import okhttp3.MediaType;
24+
import okhttp3.OkHttpClient;
25+
import okhttp3.Request;
26+
import okhttp3.RequestBody;
27+
import okhttp3.Response;
28+
29+
import org.springframework.gradle.github.RepositoryRef;
30+
31+
/**
32+
* Manage GitHub releases.
33+
*
34+
* @author Steve Riesenberg
35+
*/
36+
public class GitHubReleaseApi {
37+
private String baseUrl = "https://api.github.com";
38+
39+
private final OkHttpClient httpClient;
40+
private Gson gson = new Gson();
41+
42+
public GitHubReleaseApi(String gitHubAccessToken) {
43+
this.httpClient = new OkHttpClient.Builder()
44+
.addInterceptor(new AuthorizationInterceptor(gitHubAccessToken))
45+
.build();
46+
}
47+
48+
public void setBaseUrl(String baseUrl) {
49+
this.baseUrl = baseUrl;
50+
}
51+
52+
/**
53+
* Publish a release with no binary attachments.
54+
*
55+
* @param repository The repository owner/name
56+
* @param release The contents of the release
57+
*/
58+
public void publishRelease(RepositoryRef repository, Release release) {
59+
String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/releases";
60+
String json = this.gson.toJson(release);
61+
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
62+
Request request = new Request.Builder().url(url).post(body).build();
63+
try {
64+
Response response = this.httpClient.newCall(request).execute();
65+
if (!response.isSuccessful()) {
66+
throw new RuntimeException(String.format("Could not create release %s for repository %s/%s. Got response %s",
67+
release.getName(), repository.getOwner(), repository.getName(), response));
68+
}
69+
} catch (IOException ex) {
70+
throw new RuntimeException(String.format("Could not create release %s for repository %s/%s",
71+
release.getName(), repository.getOwner(), repository.getName()), ex);
72+
}
73+
}
74+
75+
private static class AuthorizationInterceptor implements Interceptor {
76+
private final String token;
77+
78+
public AuthorizationInterceptor(String token) {
79+
this.token = token;
80+
}
81+
82+
@Override
83+
public Response intercept(Chain chain) throws IOException {
84+
Request request = chain.request().newBuilder()
85+
.addHeader("Authorization", "Bearer " + this.token)
86+
.build();
87+
88+
return chain.proceed(request);
89+
}
90+
}
91+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.gradle.github.release;
18+
19+
import groovy.lang.MissingPropertyException;
20+
import org.gradle.api.Action;
21+
import org.gradle.api.Plugin;
22+
import org.gradle.api.Project;
23+
24+
/**
25+
* @author Steve Riesenberg
26+
*/
27+
public class GitHubReleasePlugin implements Plugin<Project> {
28+
@Override
29+
public void apply(Project project) {
30+
project.getTasks().register("createGitHubRelease", CreateGitHubReleaseTask.class, new Action<CreateGitHubReleaseTask>() {
31+
@Override
32+
public void execute(CreateGitHubReleaseTask createGitHubRelease) {
33+
createGitHubRelease.setGroup("Release");
34+
createGitHubRelease.setDescription("Create a github release");
35+
createGitHubRelease.dependsOn("generateChangelog");
36+
37+
createGitHubRelease.setCreateRelease("true".equals(project.findProperty("createRelease")));
38+
createGitHubRelease.setVersion((String) project.findProperty("nextVersion"));
39+
if (project.hasProperty("branch")) {
40+
createGitHubRelease.setBranch((String) project.findProperty("branch"));
41+
}
42+
createGitHubRelease.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
43+
if (createGitHubRelease.isCreateRelease() && createGitHubRelease.getGitHubAccessToken() == null) {
44+
throw new MissingPropertyException("Please provide an access token with -PgitHubAccessToken=...");
45+
}
46+
}
47+
});
48+
}
49+
}

0 commit comments

Comments
 (0)