7 changed files with 360 additions and 27 deletions
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.release; |
||||
|
||||
import org.gradle.api.DefaultTask; |
||||
import org.gradle.api.tasks.Input; |
||||
import org.gradle.api.tasks.TaskAction; |
||||
|
||||
import org.springframework.gradle.github.RepositoryRef; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
public class DispatchGitHubWorkflowTask extends DefaultTask { |
||||
@Input |
||||
private RepositoryRef repository = new RepositoryRef(); |
||||
|
||||
@Input |
||||
private String gitHubAccessToken; |
||||
|
||||
@Input |
||||
private String branch; |
||||
|
||||
@Input |
||||
private String workflowId; |
||||
|
||||
@TaskAction |
||||
public void dispatchGitHubWorkflow() { |
||||
GitHubActionsApi gitHubActionsApi = new GitHubActionsApi(this.gitHubAccessToken); |
||||
WorkflowDispatch workflowDispatch = new WorkflowDispatch(this.branch, null); |
||||
gitHubActionsApi.dispatchWorkflow(this.repository, this.workflowId, workflowDispatch); |
||||
} |
||||
|
||||
public RepositoryRef getRepository() { |
||||
return repository; |
||||
} |
||||
|
||||
public void setRepository(RepositoryRef repository) { |
||||
this.repository = repository; |
||||
} |
||||
|
||||
public String getGitHubAccessToken() { |
||||
return gitHubAccessToken; |
||||
} |
||||
|
||||
public void setGitHubAccessToken(String gitHubAccessToken) { |
||||
this.gitHubAccessToken = gitHubAccessToken; |
||||
} |
||||
|
||||
public String getBranch() { |
||||
return branch; |
||||
} |
||||
|
||||
public void setBranch(String branch) { |
||||
this.branch = branch; |
||||
} |
||||
|
||||
public String getWorkflowId() { |
||||
return workflowId; |
||||
} |
||||
|
||||
public void setWorkflowId(String workflowId) { |
||||
this.workflowId = workflowId; |
||||
} |
||||
} |
||||
@ -0,0 +1,98 @@
@@ -0,0 +1,98 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.release; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.google.gson.Gson; |
||||
import com.google.gson.GsonBuilder; |
||||
import okhttp3.Interceptor; |
||||
import okhttp3.MediaType; |
||||
import okhttp3.OkHttpClient; |
||||
import okhttp3.Request; |
||||
import okhttp3.RequestBody; |
||||
import okhttp3.Response; |
||||
|
||||
import org.springframework.gradle.github.RepositoryRef; |
||||
|
||||
/** |
||||
* Manage GitHub Actions. |
||||
* |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
public class GitHubActionsApi { |
||||
private String baseUrl = "https://api.github.com"; |
||||
|
||||
private final OkHttpClient client; |
||||
|
||||
private final Gson gson = new GsonBuilder().create(); |
||||
|
||||
public GitHubActionsApi() { |
||||
this.client = new OkHttpClient.Builder().build(); |
||||
} |
||||
|
||||
public GitHubActionsApi(String gitHubToken) { |
||||
this.client = new OkHttpClient.Builder() |
||||
.addInterceptor(new AuthorizationInterceptor(gitHubToken)) |
||||
.build(); |
||||
} |
||||
|
||||
public void setBaseUrl(String baseUrl) { |
||||
this.baseUrl = baseUrl; |
||||
} |
||||
|
||||
/** |
||||
* Create a workflow dispatch event. |
||||
* |
||||
* @param repository The repository owner/name |
||||
* @param workflowId The ID of the workflow or the name of the workflow file name |
||||
* @param workflowDispatch The workflow dispatch containing a ref (branch) and optional inputs |
||||
*/ |
||||
public void dispatchWorkflow(RepositoryRef repository, String workflowId, WorkflowDispatch workflowDispatch) { |
||||
String url = this.baseUrl + "/repos/" + repository.getOwner() + "/" + repository.getName() + "/actions/workflows/" + workflowId + "/dispatches"; |
||||
String json = this.gson.toJson(workflowDispatch); |
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json); |
||||
Request request = new Request.Builder().url(url).post(body).build(); |
||||
try { |
||||
Response response = this.client.newCall(request).execute(); |
||||
if (!response.isSuccessful()) { |
||||
throw new RuntimeException(String.format("Could not create workflow dispatch %s for repository %s/%s. Got response %s", |
||||
workflowId, repository.getOwner(), repository.getName(), response)); |
||||
} |
||||
} catch (IOException ex) { |
||||
throw new RuntimeException(String.format("Could not create workflow dispatch %s for repository %s/%s", |
||||
workflowId, repository.getOwner(), repository.getName()), ex); |
||||
} |
||||
} |
||||
|
||||
private static class AuthorizationInterceptor implements Interceptor { |
||||
private final String token; |
||||
|
||||
public AuthorizationInterceptor(String token) { |
||||
this.token = token; |
||||
} |
||||
|
||||
@Override |
||||
public Response intercept(Chain chain) throws IOException { |
||||
Request request = chain.request().newBuilder() |
||||
.addHeader("Authorization", "Bearer " + this.token) |
||||
.build(); |
||||
|
||||
return chain.proceed(request); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.release; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
public class WorkflowDispatch { |
||||
private String ref; |
||||
private Map<String, Object> inputs; |
||||
|
||||
public WorkflowDispatch() { |
||||
} |
||||
|
||||
public WorkflowDispatch(String ref, Map<String, Object> inputs) { |
||||
this.ref = ref; |
||||
this.inputs = inputs; |
||||
} |
||||
|
||||
public String getRef() { |
||||
return ref; |
||||
} |
||||
|
||||
public void setRef(String ref) { |
||||
this.ref = ref; |
||||
} |
||||
|
||||
public Map<String, Object> getInputs() { |
||||
return inputs; |
||||
} |
||||
|
||||
public void setInputs(Map<String, Object> inputs) { |
||||
this.inputs = inputs; |
||||
} |
||||
} |
||||
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.release; |
||||
|
||||
import java.nio.charset.Charset; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import okhttp3.mockwebserver.MockResponse; |
||||
import okhttp3.mockwebserver.MockWebServer; |
||||
import okhttp3.mockwebserver.RecordedRequest; |
||||
import org.junit.jupiter.api.AfterEach; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.gradle.github.RepositoryRef; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
public class GitHubActionsApiTests { |
||||
private GitHubActionsApi gitHubActionsApi; |
||||
|
||||
private MockWebServer server; |
||||
|
||||
private String baseUrl; |
||||
|
||||
private RepositoryRef repository; |
||||
|
||||
@BeforeEach |
||||
public void setup() throws Exception { |
||||
this.server = new MockWebServer(); |
||||
this.server.start(); |
||||
this.baseUrl = this.server.url("/api").toString(); |
||||
this.gitHubActionsApi = new GitHubActionsApi("mock-oauth-token"); |
||||
this.gitHubActionsApi.setBaseUrl(this.baseUrl); |
||||
this.repository = new RepositoryRef("spring-projects", "spring-security"); |
||||
} |
||||
|
||||
@AfterEach |
||||
public void cleanup() throws Exception { |
||||
this.server.shutdown(); |
||||
} |
||||
|
||||
@Test |
||||
public void dispatchWorkflowWhenValidParametersThenSuccess() throws Exception { |
||||
this.server.enqueue(new MockResponse().setResponseCode(204)); |
||||
|
||||
Map<String, Object> inputs = new LinkedHashMap<>(); |
||||
inputs.put("input-1", "value"); |
||||
inputs.put("input-2", false); |
||||
WorkflowDispatch workflowDispatch = new WorkflowDispatch("main", inputs); |
||||
this.gitHubActionsApi.dispatchWorkflow(this.repository, "test-workflow.yml", workflowDispatch); |
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); |
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("post"); |
||||
assertThat(recordedRequest.getRequestUrl().toString()) |
||||
.isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/actions/workflows/test-workflow.yml/dispatches"); |
||||
assertThat(recordedRequest.getBody().readString(Charset.defaultCharset())) |
||||
.isEqualTo("{\"ref\":\"main\",\"inputs\":{\"input-1\":\"value\",\"input-2\":false}}"); |
||||
} |
||||
|
||||
@Test |
||||
public void dispatchWorkflowWhenErrorResponseThenException() throws Exception { |
||||
this.server.enqueue(new MockResponse().setResponseCode(400)); |
||||
|
||||
WorkflowDispatch workflowDispatch = new WorkflowDispatch("main", null); |
||||
assertThatExceptionOfType(RuntimeException.class) |
||||
.isThrownBy(() -> this.gitHubActionsApi.dispatchWorkflow(this.repository, "test-workflow.yml", workflowDispatch)); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue