Skip to content

Commit 7b503c6

Browse files
authored
feat: add organisation app installation functionality (#142)
* feat: update get installation endpoint to allow for orgs * feat: add test for org installation * feat: refactoring * feat: refactor and add repo path test * fix: wording
1 parent 844c59c commit 7b503c6

File tree

5 files changed

+118
-16
lines changed

5 files changed

+118
-16
lines changed

src/main/java/com/spotify/github/v3/clients/GithubAppClient.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.spotify.github.v3.checks.Installation;
2828
import java.util.List;
2929
import java.util.Map;
30+
import java.util.Optional;
3031
import java.util.concurrent.CompletableFuture;
3132
import javax.ws.rs.core.HttpHeaders;
3233

@@ -38,9 +39,15 @@ public class GithubAppClient {
3839
private static final String GET_INSTALLATION_REPO_URL = "/repos/%s/%s/installation";
3940
private static final String LIST_ACCESSIBLE_REPOS_URL = "/installation/repositories";
4041

42+
/*
43+
Owner and org are interchangeable and therefore "owner" is used to
44+
refer to the organisation in the installation endpoint
45+
*/
46+
private static final String GET_INSTALLATION_ORG_URL = "/orgs/%s/installation";
47+
4148
private final GitHubClient github;
4249
private final String owner;
43-
private final String repo;
50+
private final Optional<String> maybeRepo;
4451

4552
private final Map<String, String> extraHeaders =
4653
ImmutableMap.of(HttpHeaders.ACCEPT, "application/vnd.github.machine-man-preview+json");
@@ -51,7 +58,13 @@ public class GithubAppClient {
5158
GithubAppClient(final GitHubClient github, final String owner, final String repo) {
5259
this.github = github;
5360
this.owner = owner;
54-
this.repo = repo;
61+
this.maybeRepo = Optional.of(repo);
62+
}
63+
64+
GithubAppClient(final GitHubClient github, final String owner) {
65+
this.github = github;
66+
this.owner = owner;
67+
this.maybeRepo = Optional.empty();
5568
}
5669

5770
/**
@@ -64,13 +77,30 @@ public CompletableFuture<List<Installation>> getInstallations() {
6477
}
6578

6679
/**
67-
* Get Installation of a repo
80+
* Get Installation
6881
*
69-
* @return a list of Installation
82+
* @return an Installation
7083
*/
7184
public CompletableFuture<Installation> getInstallation() {
85+
return maybeRepo.map(this::getRepoInstallation).orElseGet(this::getOrgInstallation);
86+
}
87+
88+
/**
89+
* Get an installation of a repo
90+
* @return an Installation
91+
*/
92+
private CompletableFuture<Installation> getRepoInstallation(final String repo) {
93+
return github.request(
94+
String.format(GET_INSTALLATION_REPO_URL, owner, repo), Installation.class);
95+
}
96+
97+
/**
98+
* Get an installation of an org
99+
* @return an Installation
100+
*/
101+
private CompletableFuture<Installation> getOrgInstallation() {
72102
return github.request(
73-
String.format(GET_INSTALLATION_REPO_URL, owner, repo), Installation.class, extraHeaders);
103+
String.format(GET_INSTALLATION_ORG_URL, owner), Installation.class);
74104
}
75105

76106
/**

src/main/java/com/spotify/github/v3/clients/OrganisationClient.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,8 @@
2020
//
2121
package com.spotify.github.v3.clients;
2222

23-
import java.lang.invoke.MethodHandles;
24-
import org.slf4j.Logger;
25-
import org.slf4j.LoggerFactory;
26-
2723
public class OrganisationClient {
2824

29-
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
30-
31-
private static final String TEAM_TEMPLATE = "/orgs/%s/teams";
32-
33-
private static final String TEAM_SLUG_TEMPLATE = "/orgs/%s/teams/%s";
34-
3525
private final GitHubClient github;
3626

3727
private final String org;
@@ -53,4 +43,13 @@ static OrganisationClient create(final GitHubClient github, final String org) {
5343
public TeamClient createTeamClient() {
5444
return TeamClient.create(github, org);
5545
}
46+
47+
/**
48+
* Create GitHub App API client
49+
*
50+
* @return GitHub App API client
51+
*/
52+
public GithubAppClient createGithubAppClient() {
53+
return new GithubAppClient(github, org);
54+
}
5655
}

src/test/java/com/spotify/github/v3/clients/GithubAppClientTest.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,25 @@
2020

2121
package com.spotify.github.v3.clients;
2222

23+
import static com.google.common.io.Resources.getResource;
24+
import static java.nio.charset.Charset.defaultCharset;
25+
import static java.util.concurrent.CompletableFuture.completedFuture;
2326
import static org.hamcrest.MatcherAssert.assertThat;
2427
import static org.hamcrest.Matchers.containsInAnyOrder;
2528
import static org.hamcrest.core.Is.is;
29+
import static org.mockito.Mockito.when;
2630

2731
import com.fasterxml.jackson.databind.ObjectMapper;
32+
import com.google.common.io.Resources;
2833
import com.spotify.github.FixtureHelper;
2934
import com.spotify.github.v3.apps.InstallationRepositoriesResponse;
3035
import com.spotify.github.v3.checks.Installation;
3136
import java.io.File;
37+
import java.io.IOException;
3238
import java.net.URI;
3339
import java.time.ZonedDateTime;
3440
import java.util.List;
41+
import java.util.concurrent.CompletableFuture;
3542
import java.util.concurrent.TimeUnit;
3643
import okhttp3.mockwebserver.MockResponse;
3744
import okhttp3.mockwebserver.MockWebServer;
@@ -49,13 +56,17 @@ public class GithubAppClientTest {
4956
private final int appId = 42;
5057
private GithubAppClient client;
5158

59+
private static String getFixture(String resource) throws IOException {
60+
return Resources.toString(getResource(GithubAppClientTest.class, resource), defaultCharset());
61+
}
62+
5263
@Before
5364
public void setUp() throws Exception {
5465
URI uri = mockServer.url("").uri();
5566
File key = FixtureHelper.loadFile("githubapp/key.pem");
5667

5768
GitHubClient rootclient = GitHubClient.create(uri, key, appId);
58-
client = rootclient.createRepositoryClient("", "").createGithubAppClient();
69+
client = rootclient.createRepositoryClient("owner", "repo").createGithubAppClient();
5970
}
6071

6172
@Test
@@ -122,4 +133,20 @@ public void listAccessibleRepositories() throws Exception {
122133
assertThat(listReposRequest.getMethod(), is("GET"));
123134
assertThat(listReposRequest.getRequestUrl().encodedPath(), is("/installation/repositories"));
124135
}
136+
137+
@Test
138+
public void getInstallation() throws Exception {
139+
mockServer.enqueue(
140+
new MockResponse()
141+
.setResponseCode(200)
142+
.setBody(FixtureHelper.loadFixture("githubapp/installation.json")));
143+
144+
Installation installation = client.getInstallation().join();
145+
146+
assertThat(installation.id(), is(1));
147+
assertThat(installation.account().login(), is("github"));
148+
149+
RecordedRequest recordedRequest = mockServer.takeRequest(1, TimeUnit.MILLISECONDS);
150+
assertThat(recordedRequest.getRequestUrl().encodedPath(), is("/repos/owner/repo/installation"));
151+
}
125152
}

src/test/java/com/spotify/github/v3/clients/OrganisationClientTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.google.common.io.Resources;
3232
import com.spotify.github.jackson.Json;
3333
import com.spotify.github.v3.Team;
34+
import com.spotify.github.v3.checks.Installation;
3435
import java.io.IOException;
3536
import java.util.concurrent.CompletableFuture;
3637
import org.junit.Before;
@@ -66,4 +67,15 @@ public void testTeamClient() throws Exception {
6667
assertThat(team.id(), is(1));
6768
assertThat(team.name(), is("Justice League"));
6869
}
70+
71+
@Test
72+
public void testAppClient() throws Exception {
73+
final GithubAppClient githubAppClient = organisationClient.createGithubAppClient();
74+
final CompletableFuture<Installation> fixture =
75+
completedFuture(json.fromJson(getFixture("../githubapp/installation.json"), Installation.class));
76+
when(github.request("/orgs/github/installation", Installation.class)).thenReturn(fixture);
77+
final Installation installation = githubAppClient.getInstallation().get();
78+
assertThat(installation.id(), is(1));
79+
assertThat(installation.account().login(), is("github"));
80+
}
6981
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"id": 1,
3+
"account": {
4+
"login": "github",
5+
"id": 1,
6+
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE=",
7+
"url": "https://api.github.com/orgs/github",
8+
"repos_url": "https://api.github.com/orgs/github/repos",
9+
"events_url": "https://api.github.com/orgs/github/events",
10+
"hooks_url": "https://api.github.com/orgs/github/hooks",
11+
"issues_url": "https://api.github.com/orgs/github/issues",
12+
"members_url": "https://api.github.com/orgs/github/members{/member}",
13+
"public_members_url": "https://api.github.com/orgs/github/public_members{/member}",
14+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
15+
"description": "A great organization"
16+
},
17+
"access_tokens_url": "https://api.github.com/installations/1/access_tokens",
18+
"repositories_url": "https://api.github.com/installation/repositories",
19+
"html_url": "https://github.com/organizations/github/settings/installations/1",
20+
"app_id": 1,
21+
"target_id": 1,
22+
"target_type": "Organization",
23+
"permissions": {
24+
"metadata": "read",
25+
"contents": "read",
26+
"issues": "write",
27+
"single_file": "write"
28+
},
29+
"events": [
30+
"push",
31+
"pull_request"
32+
],
33+
"single_file_name": "config.yml"
34+
}

0 commit comments

Comments
 (0)