import org.sonar.alm.client.TimeoutConfiguration;
import org.sonar.api.server.ServerSide;
import org.sonar.auth.gitlab.GsonGroup;
+import org.sonar.auth.gitlab.GsonUser;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.client.OkHttpClientBuilder;
+import static java.lang.String.format;
import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import static java.nio.charset.StandardCharsets.UTF_8;
private static final Logger LOG = LoggerFactory.getLogger(GitlabApplicationClient.class);
private static final Gson GSON = new Gson();
private static final Type GITLAB_GROUP = TypeToken.getParameterized(List.class, GsonGroup.class).getType();
+ private static final Type GITLAB_USER = TypeToken.getParameterized(List.class, GsonUser.class).getType();
protected static final String PRIVATE_TOKEN = "Private-Token";
protected final OkHttpClient client;
}
private void checkProjectAccess(@Nullable String gitlabUrl, @Nullable String personalAccessToken, String errorMessage) {
- String url = String.format("%s/projects", gitlabUrl);
+ String url = format("%s/projects", gitlabUrl);
- LOG.debug(String.format("get projects : [%s]", url));
+ LOG.debug("get projects : [{}]", url);
Request.Builder builder = new Request.Builder()
.url(url)
.get();
}
private static void logException(String url, IOException e) {
- LOG.info(String.format("Gitlab API call to [%s] failed with error message : [%s]", url, e.getMessage()), e);
+ String errorMessage = format("Gitlab API call to [%s] failed with error message : [%s]", url, e.getMessage());
+ LOG.info(errorMessage, e);
}
public void checkToken(String gitlabUrl, String personalAccessToken) {
- String url = String.format("%s/user", gitlabUrl);
+ String url = format("%s/user", gitlabUrl);
- LOG.debug(String.format("get current user : [%s]", url));
+ LOG.debug("get current user : [{}]", url);
Request.Builder builder = new Request.Builder()
.addHeader(PRIVATE_TOKEN, personalAccessToken)
.url(url)
}
public void checkWritePermission(String gitlabUrl, String personalAccessToken) {
- String url = String.format("%s/markdown", gitlabUrl);
+ String url = format("%s/markdown", gitlabUrl);
- LOG.debug(String.format("verify write permission by formating some markdown : [%s]", url));
+ LOG.debug("verify write permission by formating some markdown : [{}]", url);
Request.Builder builder = new Request.Builder()
.url(url)
.addHeader(PRIVATE_TOKEN, personalAccessToken)
protected static void checkResponseIsSuccessful(Response response, String errorMessage) throws IOException {
if (!response.isSuccessful()) {
String body = response.body().string();
- LOG.error(String.format("Gitlab API call to [%s] failed with %s http code. gitlab response content : [%s]", response.request().url().toString(), response.code(), body));
+ LOG.error("Gitlab API call to [{}] failed with {} http code. gitlab response content : [{}]", response.request().url(), response.code(), body);
if (isTokenRevoked(response, body)) {
throw new GitlabServerException(response.code(), "Your GitLab token was revoked");
} else if (isTokenExpired(response, body)) {
}
public Project getProject(String gitlabUrl, String pat, Long gitlabProjectId) {
- String url = String.format("%s/projects/%s", gitlabUrl, gitlabProjectId);
- LOG.debug(String.format("get project : [%s]", url));
+ String url = format("%s/projects/%s", gitlabUrl, gitlabProjectId);
+ LOG.debug("get project : [{}]", url);
Request request = new Request.Builder()
.addHeader(PRIVATE_TOKEN, pat)
.get()
try (Response response = client.newCall(request).execute()) {
checkResponseIsSuccessful(response);
String body = response.body().string();
- LOG.trace(String.format("loading project payload result : [%s]", body));
+ LOG.trace("loading project payload result : [{}]", body);
return new GsonBuilder().create().fromJson(body, Project.class);
} catch (JsonSyntaxException e) {
throw new IllegalArgumentException("Could not parse GitLab answer to retrieve a project. Got a non-json payload as result.");
// As of June 9, 2021 there is no better way to do this check and still support GitLab 11.7.
//
public Optional<Project> getReporterLevelAccessProject(String gitlabUrl, String pat, Long gitlabProjectId) {
- String url = String.format("%s/projects?min_access_level=20&id_after=%s&id_before=%s", gitlabUrl, gitlabProjectId - 1,
+ String url = format("%s/projects?min_access_level=20&id_after=%s&id_before=%s", gitlabUrl, gitlabProjectId - 1,
gitlabProjectId + 1);
- LOG.debug(String.format("get project : [%s]", url));
+ LOG.debug("get project : [{}]", url);
Request request = new Request.Builder()
.addHeader(PRIVATE_TOKEN, pat)
.get()
try (Response response = client.newCall(request).execute()) {
checkResponseIsSuccessful(response);
String body = response.body().string();
- LOG.trace(String.format("loading project payload result : [%s]", body));
+ LOG.trace("loading project payload result : [{}]", body);
List<Project> projects = Project.parseJsonArray(body);
if (projects.isEmpty()) {
}
public List<GitLabBranch> getBranches(String gitlabUrl, String pat, Long gitlabProjectId) {
- String url = String.format("%s/projects/%s/repository/branches", gitlabUrl, gitlabProjectId);
- LOG.debug(String.format("get branches : [%s]", url));
+ String url = format("%s/projects/%s/repository/branches", gitlabUrl, gitlabProjectId);
+ LOG.debug("get branches : [{}]", url);
Request request = new Request.Builder()
.addHeader(PRIVATE_TOKEN, pat)
.get()
try (Response response = client.newCall(request).execute()) {
checkResponseIsSuccessful(response);
String body = response.body().string();
- LOG.trace(String.format("loading branches payload result : [%s]", body));
+ LOG.trace("loading branches payload result : [{}]", body);
return Arrays.asList(new GsonBuilder().create().fromJson(body, GitLabBranch[].class));
} catch (JsonSyntaxException e) {
throw new IllegalArgumentException("Could not parse GitLab answer to retrieve project branches. Got a non-json payload as result.");
public ProjectList searchProjects(String gitlabUrl, String personalAccessToken, @Nullable String projectName,
@Nullable Integer pageNumber, @Nullable Integer pageSize) {
- String url = String.format("%s/projects?archived=false&simple=true&membership=true&order_by=name&sort=asc&search=%s%s%s",
+ String url = format("%s/projects?archived=false&simple=true&membership=true&order_by=name&sort=asc&search=%s%s%s",
gitlabUrl,
projectName == null ? "" : urlEncode(projectName),
- pageNumber == null ? "" : String.format("&page=%d", pageNumber),
- pageSize == null ? "" : String.format("&per_page=%d", pageSize)
+ pageNumber == null ? "" : format("&page=%d", pageNumber),
+ pageSize == null ? "" : format("&per_page=%d", pageSize)
);
- LOG.debug(String.format("get projects : [%s]", url));
+ LOG.debug("get projects : [{}]", url);
Request request = new Request.Builder()
.addHeader(PRIVATE_TOKEN, personalAccessToken)
.url(url)
return Set.copyOf(executePaginatedQuery(gitlabUrl, token, "/groups", resp -> GSON.fromJson(resp, GITLAB_GROUP)));
}
+ public Set<GsonUser> getGroupMembers(String gitlabUrl, String token, String groupId) {
+ return Set.copyOf(executePaginatedQuery(gitlabUrl, token, format("/groups/%s/members", groupId), resp -> GSON.fromJson(resp, GITLAB_USER)));
+ }
+
private <E> List<E> executePaginatedQuery(String appUrl, String token, String query, Function<String, List<E>> responseDeserializer) {
GitlabToken gitlabToken = new GitlabToken(token);
return gitlabPaginatedHttpClient.get(appUrl, gitlabToken, query, responseDeserializer);
import org.sonar.alm.client.TimeoutConfiguration;
import org.sonar.api.testfixtures.log.LogTester;
import org.sonar.auth.gitlab.GsonGroup;
+import org.sonar.auth.gitlab.GsonUser;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
return gsonGroup;
}
+ @Test
+ public void getGroupMembers_whenCallIsInError_rethrows() throws IOException {
+ String token = "token-toto";
+ GitlabToken gitlabToken = new GitlabToken(token);
+ when(gitlabPaginatedHttpClient.get(eq(gitlabUrl), eq(gitlabToken), eq("/groups/42/members"), any())).thenThrow(new IllegalStateException("exception"));
+
+ assertThatIllegalStateException()
+ .isThrownBy(() -> underTest.getGroupMembers(gitlabUrl, token, "42"))
+ .withMessage("exception");
+ }
+
+ @Test
+ public void getGroupMembers_whenCallIsSuccessful_deserializesAndReturnsCorrectlyGroupMembers() throws IOException {
+ ArgumentCaptor<Function<String, List<GsonUser>>> deserializerCaptor = ArgumentCaptor.forClass(Function.class);
+
+ String token = "token-toto";
+ GitlabToken gitlabToken = new GitlabToken(token);
+ List<GsonUser> expectedGroupMembers = expectedGroupMembers();
+ when(gitlabPaginatedHttpClient.get(eq(gitlabUrl), eq(gitlabToken), eq("/groups/42/members"), deserializerCaptor.capture())).thenReturn(expectedGroupMembers);
+
+ Set<GsonUser> actualGroupMembers = underTest.getGroupMembers(gitlabUrl, token, "42");
+ assertThat(actualGroupMembers).containsExactlyInAnyOrderElementsOf(expectedGroupMembers);
+
+ String responseContent = getResponseContent("group-members-full-response.json");
+
+ List<GsonUser> deserializedUsers = deserializerCaptor.getValue().apply(responseContent);
+ assertThat(deserializedUsers).usingRecursiveComparison().isEqualTo(expectedGroupMembers);
+ }
+
+ private static List<GsonUser> expectedGroupMembers() {
+ GsonUser user1 = createGsonUser(12818153L, "aurelien-poscia-sonarsource", "Aurelien");
+ GsonUser user2 = createGsonUser(10941672L, "antoine.vigneau", "Antoine Vigneau");
+ GsonUser user3 = createGsonUser(13569073L, "wojciech.wajerowicz.sonarsource", "Wojciech Wajerowicz");
+ return List.of(user1, user2, user3);
+ }
+
+ private static GsonUser createGsonUser(Long id, String username, String name) {
+ GsonUser gsonUser = mock();
+ when(gsonUser.getId()).thenReturn(id);
+ when(gsonUser.getUsername()).thenReturn(username);
+ when(gsonUser.getName()).thenReturn(name);
+ return gsonUser;
+ }
+
private static String getResponseContent(String path) throws IOException {
return IOUtils.toString(GitlabApplicationClientTest.class.getResourceAsStream(path), StandardCharsets.UTF_8);
}