From 2ad8302058e9f4caf298cbe2006a6e1c4e2a9335 Mon Sep 17 00:00:00 2001 From: Harsh Vardhan Date: Tue, 17 Sep 2024 13:14:45 +0200 Subject: [PATCH 1/3] Add get and list workflows from github actions API --- .../github/v3/clients/GitHubClient.java | 9 ++ .../github/v3/clients/WorkflowsClient.java | 73 ++++++++++++++ .../WorkflowsRepositoryResponseList.java | 51 ++++++++++ .../v3/workflows/WorkflowsResponse.java | 93 ++++++++++++++++++ .../github/v3/workflows/WorkflowsState.java | 30 ++++++ .../v3/clients/WorkflowsClientTest.java | 97 +++++++++++++++++++ .../workflows-get-workflow-response.json | 13 +++ .../workflows-list-workflows-response.json | 31 ++++++ 8 files changed, 397 insertions(+) create mode 100644 src/main/java/com/spotify/github/v3/clients/WorkflowsClient.java create mode 100644 src/main/java/com/spotify/github/v3/workflows/WorkflowsRepositoryResponseList.java create mode 100644 src/main/java/com/spotify/github/v3/workflows/WorkflowsResponse.java create mode 100644 src/main/java/com/spotify/github/v3/workflows/WorkflowsState.java create mode 100644 src/test/java/com/spotify/github/v3/clients/WorkflowsClientTest.java create mode 100644 src/test/resources/com/spotify/github/v3/workflows/workflows-get-workflow-response.json create mode 100644 src/test/resources/com/spotify/github/v3/workflows/workflows-list-workflows-response.json diff --git a/src/main/java/com/spotify/github/v3/clients/GitHubClient.java b/src/main/java/com/spotify/github/v3/clients/GitHubClient.java index 803bfe51..e2b4fb3b 100644 --- a/src/main/java/com/spotify/github/v3/clients/GitHubClient.java +++ b/src/main/java/com/spotify/github/v3/clients/GitHubClient.java @@ -475,6 +475,15 @@ public UserClient createUserClient(final String owner) { return UserClient.create(this, owner); } + /** + * Workflows API client + * + * @return Workflows API client + */ + public WorkflowsClient createWorkflowsClient(final String owner, final String repo) { + return WorkflowsClient.create(this, owner, repo); + } + Json json() { return json; } diff --git a/src/main/java/com/spotify/github/v3/clients/WorkflowsClient.java b/src/main/java/com/spotify/github/v3/clients/WorkflowsClient.java new file mode 100644 index 00000000..8aeb6fa5 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/clients/WorkflowsClient.java @@ -0,0 +1,73 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * 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 + * + * http://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 com.spotify.github.v3.clients; + +import com.google.common.collect.ImmutableMap; +import com.spotify.github.v3.workflows.WorkflowsRepositoryResponseList; +import com.spotify.github.v3.workflows.WorkflowsResponse; + +import javax.ws.rs.core.HttpHeaders; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** Workflows API client */ +public class WorkflowsClient { + private static final String LIST_REPOSITORY_WORKFLOWS_URI = "/repos/%s/%s/actions/workflows"; + private static final String GET_WORKFLOW_URI = "/repos/%s/%s/actions/workflows/%s"; + + private final GitHubClient github; + private final String owner; + private final String repo; + + private final Map extraHeaders = + ImmutableMap.of(HttpHeaders.ACCEPT, "application/vnd.github+json"); + + public WorkflowsClient(final GitHubClient github, final String owner, final String repo) { + this.github = github; + this.owner = owner; + this.repo = repo; + } + + static WorkflowsClient create(final GitHubClient github, final String owner, final String repo) { + return new WorkflowsClient(github, owner, repo); + } + + /** + * List workflows for a repository. + * + * @return a list of workflows for the repository + */ + public CompletableFuture listWorkflows() { + final String path = String.format(LIST_REPOSITORY_WORKFLOWS_URI, owner, repo); + return github.request(path, WorkflowsRepositoryResponseList.class, extraHeaders); + } + + /** + * Gets a workflow by id. + * + * @param id the workflow id + * @return a WorkflowsResponse + */ + public CompletableFuture getWorkflow(final int id) { + final String path = String.format(GET_WORKFLOW_URI, owner, repo, id); + return github.request(path, WorkflowsResponse.class, extraHeaders); + } +} diff --git a/src/main/java/com/spotify/github/v3/workflows/WorkflowsRepositoryResponseList.java b/src/main/java/com/spotify/github/v3/workflows/WorkflowsRepositoryResponseList.java new file mode 100644 index 00000000..1995d242 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/workflows/WorkflowsRepositoryResponseList.java @@ -0,0 +1,51 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * 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 + * + * http://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 com.spotify.github.v3.workflows; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.spotify.github.GithubStyle; +import org.immutables.value.Value; + +import java.util.List; + +/** + * The WorkflowsResponse list resource + * + * @see "https://docs.github.com/en/rest/actions/workflows#list-repository-workflows" + */ +@Value.Immutable +@GithubStyle +@JsonDeserialize(as = ImmutableWorkflowsRepositoryResponseList.class) +public interface WorkflowsRepositoryResponseList { + /** + * The count of workflows in the response + * + * @return the int + */ + int totalCount(); + + /** + * Workflows list. + * + * @return the list of workflows + */ + List workflows(); +} diff --git a/src/main/java/com/spotify/github/v3/workflows/WorkflowsResponse.java b/src/main/java/com/spotify/github/v3/workflows/WorkflowsResponse.java new file mode 100644 index 00000000..8ae9b647 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/workflows/WorkflowsResponse.java @@ -0,0 +1,93 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * 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 + * + * http://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 com.spotify.github.v3.workflows; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.spotify.github.GithubStyle; +import org.immutables.value.Value; + +import java.time.ZonedDateTime; + +@Value.Immutable +@GithubStyle +@JsonDeserialize(as = ImmutableWorkflowsResponse.class) +public interface WorkflowsResponse { + /** + * The Workflow ID. + * + * @return the int + */ + int id(); + + /** Node ID */ + String nodeId(); + + /** Name. */ + String name(); + + /** The workflow path. */ + String path(); + + /** Indicates the state of the workflow. */ + WorkflowsState state(); + + /** + * Created At + * + * @return The time when the workflow was created + */ + ZonedDateTime createdAt(); + + /** + * Updated At + * + * @return The time when the workflow was updated + */ + ZonedDateTime updatedAt(); + + /** + * Deleted At + * + * @return The time when the workflow was updated + */ + ZonedDateTime deletedAt(); + + /** + * Url string. + * + * @return the string + */ + String url(); + + /** + * Html url string. + * + * @return the string + */ + String htmlUrl(); + + /** + * Badge Url string. + * + * @return the string + */ + String badgeUrl(); +} diff --git a/src/main/java/com/spotify/github/v3/workflows/WorkflowsState.java b/src/main/java/com/spotify/github/v3/workflows/WorkflowsState.java new file mode 100644 index 00000000..fea5de18 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/workflows/WorkflowsState.java @@ -0,0 +1,30 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * 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 + * + * http://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 com.spotify.github.v3.workflows; + +/** The Workflow State. */ +public enum WorkflowsState { + active, + deleted, + disabled_fork, + disabled_inactivity, + disabled_manually +} diff --git a/src/test/java/com/spotify/github/v3/clients/WorkflowsClientTest.java b/src/test/java/com/spotify/github/v3/clients/WorkflowsClientTest.java new file mode 100644 index 00000000..3a51722a --- /dev/null +++ b/src/test/java/com/spotify/github/v3/clients/WorkflowsClientTest.java @@ -0,0 +1,97 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * 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 + * + * http://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 com.spotify.github.v3.clients; + +import com.google.common.io.Resources; +import com.spotify.github.jackson.Json; +import com.spotify.github.v3.workflows.WorkflowsRepositoryResponseList; +import com.spotify.github.v3.workflows.WorkflowsResponse; +import com.spotify.github.v3.workflows.WorkflowsState; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.concurrent.CompletableFuture; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class WorkflowsClientTest { + + private static final String FIXTURES_PATH = "com/spotify/github/v3/workflows/"; + private GitHubClient github; + private WorkflowsClient workflowsClient; + private Json json; + + public static String loadResource(final String path) { + try { + return Resources.toString(Resources.getResource(path), UTF_8); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @BeforeEach + public void setUp() { + github = mock(GitHubClient.class); + workflowsClient = new WorkflowsClient(github, "someowner", "somerepo"); + json = Json.create(); + when(github.json()).thenReturn(json); + } + + @Test + public void getWorkflow() throws Exception { + final WorkflowsResponse workflowsResponse = + json.fromJson( + loadResource(FIXTURES_PATH + "workflows-get-workflow-response.json"), WorkflowsResponse.class); + final CompletableFuture fixtureResponse = completedFuture(workflowsResponse); + when(github.request(any(), eq(WorkflowsResponse.class), any())).thenReturn(fixtureResponse); + + final CompletableFuture actualResponse = + workflowsClient.getWorkflow(161335); + + assertThat(actualResponse.get().id(), is(161335)); + assertThat(actualResponse.get().state(), is(WorkflowsState.active)); + } + + @Test + public void listWorkflows() throws Exception { + final WorkflowsRepositoryResponseList workflowsListResponse = + json.fromJson( + loadResource(FIXTURES_PATH + "workflows-list-workflows-response.json"), WorkflowsRepositoryResponseList.class); + final CompletableFuture fixtureResponse = completedFuture(workflowsListResponse); + when(github.request(any(), eq(WorkflowsRepositoryResponseList.class), any())).thenReturn(fixtureResponse); + + final CompletableFuture actualResponse = + workflowsClient.listWorkflows(); + + assertThat(actualResponse.get().totalCount(), is(2)); + assertThat(actualResponse.get().workflows().get(0).name(), is("CI")); + assertThat(actualResponse.get().workflows().get(1).name(), is("Linter")); + } +} \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/workflows/workflows-get-workflow-response.json b/src/test/resources/com/spotify/github/v3/workflows/workflows-get-workflow-response.json new file mode 100644 index 00000000..a636603a --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/workflows/workflows-get-workflow-response.json @@ -0,0 +1,13 @@ +{ + "id": 161335, + "node_id": "MDg6V29ya2Zsb3cxNjEzMzU=", + "name": "CI", + "path": ".github/workflows/blank.yaml", + "state": "active", + "created_at": "2020-01-08T23:48:37.000-08:00", + "updated_at": "2020-01-08T23:50:21.000-08:00", + "deleted_at": "2020-01-09T23:50:21.000-08:00", + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/161335", + "html_url": "https://github.com/octo-org/octo-repo/blob/master/.github/workflows/161335", + "badge_url": "https://github.com/octo-org/octo-repo/workflows/CI/badge.svg" +} \ No newline at end of file diff --git a/src/test/resources/com/spotify/github/v3/workflows/workflows-list-workflows-response.json b/src/test/resources/com/spotify/github/v3/workflows/workflows-list-workflows-response.json new file mode 100644 index 00000000..d572e59f --- /dev/null +++ b/src/test/resources/com/spotify/github/v3/workflows/workflows-list-workflows-response.json @@ -0,0 +1,31 @@ +{ + "total_count": 2, + "workflows": [ + { + "id": 161335, + "node_id": "MDg6V29ya2Zsb3cxNjEzMzU=", + "name": "CI", + "path": ".github/workflows/blank.yaml", + "state": "active", + "created_at": "2020-01-08T23:48:37.000-08:00", + "updated_at": "2020-01-08T23:50:21.000-08:00", + "deleted_at": "2020-01-09T23:50:21.000-08:00", + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/161335", + "html_url": "https://github.com/octo-org/octo-repo/blob/master/.github/workflows/161335", + "badge_url": "https://github.com/octo-org/octo-repo/workflows/CI/badge.svg" + }, + { + "id": 269289, + "node_id": "MDE4OldvcmtmbG93IFNlY29uZGFyeTI2OTI4OQ==", + "name": "Linter", + "path": ".github/workflows/linter.yaml", + "state": "active", + "created_at": "2020-01-08T23:48:37.000-08:00", + "updated_at": "2020-01-08T23:50:21.000-08:00", + "deleted_at": "2020-01-09T23:50:21.000-08:00", + "url": "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/269289", + "html_url": "https://github.com/octo-org/octo-repo/blob/master/.github/workflows/269289", + "badge_url": "https://github.com/octo-org/octo-repo/workflows/Linter/badge.svg" + } + ] +} \ No newline at end of file From b15372ba50956216bb5ed424597458ebdedc3e4b Mon Sep 17 00:00:00 2001 From: Harsh Vardhan Date: Fri, 4 Oct 2024 15:25:59 +0200 Subject: [PATCH 2/3] Update workflows client hierarchy according to github API --- .../github/v3/clients/ActionsClient.java | 46 +++++++++++++++++++ .../github/v3/clients/GitHubClient.java | 9 ---- .../github/v3/clients/RepositoryClient.java | 9 ++++ .../v3/workflows/WorkflowsResponse.java | 2 +- .../github/v3/clients/GitHubClientTest.java | 29 ++++++++++++ 5 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/spotify/github/v3/clients/ActionsClient.java diff --git a/src/main/java/com/spotify/github/v3/clients/ActionsClient.java b/src/main/java/com/spotify/github/v3/clients/ActionsClient.java new file mode 100644 index 00000000..8dc25c86 --- /dev/null +++ b/src/main/java/com/spotify/github/v3/clients/ActionsClient.java @@ -0,0 +1,46 @@ +/*- + * -\-\- + * github-api + * -- + * Copyright (C) 2016 - 2020 Spotify AB + * -- + * 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 + * + * http://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 com.spotify.github.v3.clients; + +public class ActionsClient { + private final String owner; + private final String repo; + private final GitHubClient github; + + ActionsClient(final GitHubClient github, final String owner, final String repo) { + this.github = github; + this.owner = owner; + this.repo = repo; + } + + static ActionsClient create(final GitHubClient github, final String owner, final String repo) { + return new ActionsClient(github, owner, repo); + } + + /** + * Workflows API client + * + * @return Workflows API client + */ + public WorkflowsClient createWorkflowsClient() { + return WorkflowsClient.create(github, owner, repo); + } +} diff --git a/src/main/java/com/spotify/github/v3/clients/GitHubClient.java b/src/main/java/com/spotify/github/v3/clients/GitHubClient.java index e2b4fb3b..803bfe51 100644 --- a/src/main/java/com/spotify/github/v3/clients/GitHubClient.java +++ b/src/main/java/com/spotify/github/v3/clients/GitHubClient.java @@ -475,15 +475,6 @@ public UserClient createUserClient(final String owner) { return UserClient.create(this, owner); } - /** - * Workflows API client - * - * @return Workflows API client - */ - public WorkflowsClient createWorkflowsClient(final String owner, final String repo) { - return WorkflowsClient.create(this, owner, repo); - } - Json json() { return json; } diff --git a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java index c2c49c04..a4e2f8ef 100644 --- a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java +++ b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java @@ -150,6 +150,15 @@ public ChecksClient createChecksApiClient() { return new ChecksClient(github, owner, repo); } + /** + * Actions API client + * + * @return Actions API client + */ + public ActionsClient createActionsClient() { + return ActionsClient.create(github, owner, repo); + } + /** * Get information about this repository. * diff --git a/src/main/java/com/spotify/github/v3/workflows/WorkflowsResponse.java b/src/main/java/com/spotify/github/v3/workflows/WorkflowsResponse.java index 8ae9b647..d8b6add6 100644 --- a/src/main/java/com/spotify/github/v3/workflows/WorkflowsResponse.java +++ b/src/main/java/com/spotify/github/v3/workflows/WorkflowsResponse.java @@ -66,7 +66,7 @@ public interface WorkflowsResponse { /** * Deleted At * - * @return The time when the workflow was updated + * @return The time when the workflow was deleted */ ZonedDateTime deletedAt(); diff --git a/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java b/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java index 53541217..a3e1829a 100644 --- a/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java @@ -233,6 +233,35 @@ public void testGetCheckSuites() throws Throwable { } + @Test + public void testGetWorkflow() throws Throwable { + final Call call = mock(Call.class); + final ArgumentCaptor callbackCapture = ArgumentCaptor.forClass(Callback.class); + doNothing().when(call).enqueue(callbackCapture.capture()); + + final Response response = new okhttp3.Response.Builder() + .code(200) + .body( + ResponseBody.create( + MediaType.get("application/json"), + getFixture("../workflows/workflows-get-workflow-response.json"))) + .message("") + .protocol(Protocol.HTTP_1_1) + .request(new Request.Builder().url("http://localhost/").build()) + .build(); + + when(client.newCall(any())).thenReturn(call); + WorkflowsClient client = github.withTracer(tracer).createRepositoryClient("testorg", "testrepo") + .createActionsClient().createWorkflowsClient(); + + CompletableFuture future = client.getWorkflow(161335); + callbackCapture.getValue().onResponse(call, response); + var result = future.get(); + + assertThat(result.id(), is(161335)); + assertThat(result.state(), is(WorkflowsState.active)); + } + @Test void asAppScopedClientGetsUserClientIfOrgClientNotFound() { var appGithub = GitHubClient.create(client, URI.create("http://bogus"), new byte[] {}, 1); From 0975f78b00cf359eb53ba356c554897f0a0ec013 Mon Sep 17 00:00:00 2001 From: Harsh Vardhan Date: Fri, 4 Oct 2024 15:40:24 +0200 Subject: [PATCH 3/3] Fix import --- .../java/com/spotify/github/v3/clients/GitHubClientTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java b/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java index a3e1829a..5a710fdb 100644 --- a/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java +++ b/src/test/java/com/spotify/github/v3/clients/GitHubClientTest.java @@ -40,6 +40,8 @@ import com.spotify.github.v3.exceptions.RequestNotOkException; import com.spotify.github.v3.repos.CommitItem; import com.spotify.github.v3.repos.RepositoryInvitation; +import com.spotify.github.v3.workflows.WorkflowsResponse; +import com.spotify.github.v3.workflows.WorkflowsState; import java.io.File; import java.io.IOException;