Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,19 @@
//
package com.spotify.github.v3.clients;

import com.spotify.github.v3.orgs.OrgMembership;
import com.spotify.github.v3.orgs.requests.OrgMembershipCreate;
import java.lang.invoke.MethodHandles;
import java.util.concurrent.CompletableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OrganisationClient {

private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

private static final String MEMBERSHIP_TEMPLATE = "/orgs/%s/memberships/%s";

private final GitHubClient github;

private final String org;
Expand Down Expand Up @@ -52,4 +63,28 @@ public TeamClient createTeamClient() {
public GithubAppClient createGithubAppClient() {
return new GithubAppClient(github, org);
}

/**
* Get an org membership of a user.
*
* @param username username of the org member
* @return membership
*/
public CompletableFuture<OrgMembership> getOrgMembership(final String username) {
final String path = String.format(MEMBERSHIP_TEMPLATE, org, username);
log.debug("Fetching org membership for: " + path);
return github.request(path, OrgMembership.class);
}

/**
* Add or update an org membership for a user.
*
* @param request update org membership request
* @return membership
*/
public CompletableFuture<OrgMembership> updateOrgMembership(final OrgMembershipCreate request, final String username) {
final String path = String.format(MEMBERSHIP_TEMPLATE, org, username);
log.debug("Updating membership in org: " + path);
return github.put(path, github.json().toJsonUnchecked(request), OrgMembership.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we're using json unchecked here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly was just following what was already being used in other tests.

}
}
59 changes: 59 additions & 0 deletions src/main/java/com/spotify/github/v3/orgs/OrgMembership.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*-
* -\-\-
* 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.orgs;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.spotify.github.GithubStyle;
import com.spotify.github.v3.User;
import com.spotify.github.v3.repos.Organization;
import java.net.URI;
import javax.annotation.Nullable;
import org.immutables.value.Value;

/**
* Org Membership resource represents data returned by a single Membership get operation.
*/
@Value.Immutable
@GithubStyle
@JsonSerialize(as = ImmutableOrgMembership.class)
@JsonDeserialize(as = ImmutableOrgMembership.class)
public interface OrgMembership {

/** URL */
@Nullable
URI url();

/** ROLE */
@Nullable
String role();

/** STATE */
@Nullable
String state();

@Nullable
Organization organization();

/** USER */
@Nullable
User user();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*-
* -\-\-
* 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.orgs.requests;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.spotify.github.GithubStyle;
import javax.annotation.Nullable;
import org.immutables.value.Value;

/** Request to create a member within a given org */
@Value.Immutable
@GithubStyle
@JsonSerialize(as = ImmutableOrgMembershipCreate.class)
@JsonDeserialize(as = ImmutableOrgMembershipCreate.class)
public interface OrgMembershipCreate {

/**
* The role that this user should have in the org.
* Defaults to 'member'
*/
@Nullable
String role();
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,17 @@
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;

import com.google.common.io.Resources;
import com.spotify.github.jackson.Json;
import com.spotify.github.v3.Team;
import com.spotify.github.v3.checks.Installation;
import com.spotify.github.v3.orgs.OrgMembership;
import com.spotify.github.v3.orgs.requests.OrgMembershipCreate;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import org.junit.Before;
Expand Down Expand Up @@ -78,4 +82,34 @@ public void testAppClient() throws Exception {
assertThat(installation.id(), is(1));
assertThat(installation.account().login(), is("github"));
}

@Test
public void getOrgMembership() throws Exception {
final CompletableFuture<OrgMembership> fixture =
completedFuture(json.fromJson(getFixture("org_membership.json"), OrgMembership.class));
when(github.request("/orgs/github/memberships/octocat", OrgMembership.class))
.thenReturn(fixture);
final OrgMembership orgMembership = organisationClient.getOrgMembership("octocat").get();
assertThat(
orgMembership.url().toString(), is("https://api.github.com/orgs/github/memberships/octocat"));
assertThat(orgMembership.role(), is("member"));
assertThat(orgMembership.state(), is("active"));
}

@Test
public void updateMembership() throws Exception {
final OrgMembershipCreate orgMembershipCreateRequest =
json.fromJson(getFixture("membership_update.json"), OrgMembershipCreate.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this fixture included in resources. Does it already exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this already exists, both the team memberships and org memberships have the same request schema so it didn't seem worth it to create a new file with the same content. They have different responses though, so that's been reflect with the new file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying.


final CompletableFuture<OrgMembership> fixtureResponse =
completedFuture(
json.fromJson(getFixture("org_membership.json"), OrgMembership.class));
when(github.put(any(), any(), eq(OrgMembership.class))).thenReturn(fixtureResponse);
final CompletableFuture<OrgMembership> actualResponse =
organisationClient.updateOrgMembership(orgMembershipCreateRequest, "octocat");

assertThat(actualResponse.get().role(), is("member"));
assertThat(actualResponse.get().organization().login(), is("github"));
assertThat(actualResponse.get().user().login(), is("octocat"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"url": "https://api.github.com/orgs/github/memberships/octocat",
"state": "active",
"role": "member",
"organization_url": "https://api.github.com/orgs/octocat",
"organization": {
"login": "github",
"id": 1,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE=",
"url": "https://api.github.com/orgs/github",
"repos_url": "https://api.github.com/orgs/github/repos",
"events_url": "https://api.github.com/orgs/github/events",
"hooks_url": "https://api.github.com/orgs/github/hooks",
"issues_url": "https://api.github.com/orgs/github/issues",
"members_url": "https://api.github.com/orgs/github/members{/member}",
"public_members_url": "https://api.github.com/orgs/github/public_members{/member}",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"description": "A great organization"
},
"user": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
}
}