aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAurelien Poscia <aurelien.poscia@sonarsource.com>2023-12-22 08:39:03 +0100
committersonartech <sonartech@sonarsource.com>2024-01-18 20:03:23 +0000
commit75f56ca6f7464ac834cae1f23bbdde838327e996 (patch)
treed972be1f2a01ef4b16b3b8804d5f8ca3547beb9c
parentf9deebc4558057ca6f1a521152e56527a9a0112c (diff)
downloadsonarqube-75f56ca6f7464ac834cae1f23bbdde838327e996.tar.gz
sonarqube-75f56ca6f7464ac834cae1f23bbdde838327e996.zip
SONAR-21121 Add GitLab provisioning ITs for groups and groups membership
-rw-r--r--.cirrus.yml5
-rw-r--r--server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GsonId.java9
-rw-r--r--server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GsonIdTest.java63
-rw-r--r--server/sonar-webserver-common/src/it/java/org/sonar/server/common/gitlab/config/GitlabConfigurationServiceIT.java7
-rw-r--r--server/sonar-webserver-common/src/main/java/org/sonar/server/common/gitlab/config/GitlabConfigurationService.java6
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/BaseService.java5
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java17
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java5
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/RequestWithPayload.java11
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java6
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfiguration.java25
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfigurationService.java77
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/package-info.java23
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/synchronization/run/GitlabSynchronizationRunService.java38
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/synchronization/run/package-info.java23
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfigurationServiceTest.java61
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/gitlab/synchronization/run/GitlabSynchronizationRunServiceTest.java46
17 files changed, 420 insertions, 7 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 9caad464b91..55f863729fe 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -106,8 +106,7 @@ gitlab_task_template: &IS_GITLAB_TASK_NEEDED >-
'private/it-branch/it-tests/src/test/java/com/sonarsource/branch/it/suite/pr/gitlab/**/*.java',
'private/core-extension-gitlab-vulnerability-report/src/main/**/*.java')
-gitlab_provisioning_task_template: &GITLAB_PROVISIONING_TASK_TEMPLATE
- only_if: >-
+gitlab_provisioning_task_template: &IS_GITLAB_PROVISIONING_TASK_NEEDED >-
$CIRRUS_BRANCH == $BRANCH_MAIN || $CIRRUS_BRANCH =~ $BRANCH_PATTERN_MAINTENANCE || $CIRRUS_BRANCH == $BRANCH_NIGHTLY ||
changesInclude('private/core-extension-gitlab-provisioning/**/*.java')
@@ -623,9 +622,9 @@ qa_github_provisioning_task:
qa_gitlab_provisioning_task:
<<: *DEFAULT_TEMPLATE
<<: *BUILD_DEPENDANT_TASK_TEMPLATE
- <<: *GITLAB_PROVISIONING_TASK_TEMPLATE
<<: *JAR_CACHE_TEMPLATE
<<: *GRADLE_CACHE_TEMPLATE
+ only_if: *IS_GITLAB_PROVISIONING_TASK_NEEDED
env:
QA_CATEGORY: GITLAB_PROVISIONING
matrix:
diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GsonId.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GsonId.java
index 62e86a23c30..4291e6b20b7 100644
--- a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GsonId.java
+++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/gitlab/GsonId.java
@@ -21,8 +21,12 @@ package org.sonar.alm.client.gitlab;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
+import com.google.gson.reflect.TypeToken;
+import java.util.Collection;
public class GsonId {
+ private static final TypeToken<Collection<GsonId>> COLLECTION_TYPE_TOKEN = new TypeToken<>() {
+ };
@SerializedName("id")
private final long id;
@@ -45,4 +49,9 @@ public class GsonId {
return gson.fromJson(json, GsonId.class);
}
+ public static Collection<GsonId> parseCollection(String json) {
+ Gson gson = new Gson();
+ return gson.fromJson(json, COLLECTION_TYPE_TOKEN);
+ }
+
}
diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GsonIdTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GsonIdTest.java
new file mode 100644
index 00000000000..0377f51d057
--- /dev/null
+++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GsonIdTest.java
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.alm.client.gitlab;
+
+import java.util.Collection;
+import org.junit.Test;
+
+import static java.util.stream.Collectors.toSet;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class GsonIdTest {
+
+ @Test
+ public void parseOne_whenSingleId_deserializesCorrectly() {
+ GsonId gsonId = GsonId.parseOne("""
+ {
+ "blu": "blue",
+ "id": "123",
+ "bla": "bli"
+ }
+ """);
+
+ assertThat(gsonId.getId()).isEqualTo(123);
+ }
+
+ @Test
+ public void parseCollection_whenMultipleIds_deserializeCorrectly() {
+ Collection<GsonId> gsonId = GsonId.parseCollection("""
+ [
+ {
+ "blu": "blue",
+ "id": "123",
+ "bla": "bli"
+ },
+
+ {
+ "id": "456",
+ "bla": "bli"
+ }
+ ]
+ """);
+
+ assertThat(gsonId.stream().map(GsonId::getId).collect(toSet())).containsExactlyInAnyOrder(123L, 456L);
+ }
+
+}
diff --git a/server/sonar-webserver-common/src/it/java/org/sonar/server/common/gitlab/config/GitlabConfigurationServiceIT.java b/server/sonar-webserver-common/src/it/java/org/sonar/server/common/gitlab/config/GitlabConfigurationServiceIT.java
index 6086c2cdcdd..e50fffe47e6 100644
--- a/server/sonar-webserver-common/src/it/java/org/sonar/server/common/gitlab/config/GitlabConfigurationServiceIT.java
+++ b/server/sonar-webserver-common/src/it/java/org/sonar/server/common/gitlab/config/GitlabConfigurationServiceIT.java
@@ -39,6 +39,7 @@ import org.sonar.db.user.ExternalGroupDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.management.ManagedInstanceService;
+import org.sonar.server.setting.ThreadLocalSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -82,6 +83,9 @@ public class GitlabConfigurationServiceIT {
@Mock
private GitlabGlobalSettingsValidator gitlabGlobalSettingsValidator;
+ @Mock
+ private ThreadLocalSettings threadLocalSettings;
+
private GitlabConfigurationService gitlabConfigurationService;
@Before
@@ -90,7 +94,8 @@ public class GitlabConfigurationServiceIT {
gitlabConfigurationService = new GitlabConfigurationService(
dbTester.getDbClient(),
managedInstanceService,
- gitlabGlobalSettingsValidator);
+ gitlabGlobalSettingsValidator,
+ threadLocalSettings);
}
@Test
diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/gitlab/config/GitlabConfigurationService.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/gitlab/config/GitlabConfigurationService.java
index 0f2fbaf88fd..5df75318455 100644
--- a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/gitlab/config/GitlabConfigurationService.java
+++ b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/gitlab/config/GitlabConfigurationService.java
@@ -36,6 +36,7 @@ import org.sonar.server.common.UpdatedValue;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.management.ManagedInstanceService;
+import org.sonar.server.setting.ThreadLocalSettings;
import static java.lang.String.format;
import static org.apache.commons.lang.StringUtils.isNotBlank;
@@ -73,12 +74,14 @@ public class GitlabConfigurationService {
private final DbClient dbClient;
private final ManagedInstanceService managedInstanceService;
private final GitlabGlobalSettingsValidator gitlabGlobalSettingsValidator;
+ private final ThreadLocalSettings threadLocalSettings;
public GitlabConfigurationService(DbClient dbClient,
- ManagedInstanceService managedInstanceService, GitlabGlobalSettingsValidator gitlabGlobalSettingsValidator) {
+ ManagedInstanceService managedInstanceService, GitlabGlobalSettingsValidator gitlabGlobalSettingsValidator, ThreadLocalSettings threadLocalSettings) {
this.dbClient = dbClient;
this.managedInstanceService = managedInstanceService;
this.gitlabGlobalSettingsValidator = gitlabGlobalSettingsValidator;
+ this.threadLocalSettings = threadLocalSettings;
}
public GitlabConfiguration updateConfiguration(UpdateGitlabConfigurationRequest updateRequest) {
@@ -112,6 +115,7 @@ public class GitlabConfigurationService {
value
.map(definedValue -> new PropertyDto().setKey(propertyName).setValue(definedValue))
.applyIfDefined(property -> dbClient.propertiesDao().saveProperty(dbSession, property));
+ threadLocalSettings.setProperty(propertyName, value.orElse(null));
}
private void deleteExternalGroupsWhenDisablingAutoProvisioning(
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseService.java
index 6ad3ac60fbe..f7817e66acf 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseService.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/BaseService.java
@@ -31,6 +31,7 @@ import static org.sonarqube.ws.WsUtils.checkArgument;
import static org.sonarqube.ws.WsUtils.isNullOrEmpty;
public abstract class BaseService {
+ protected static final String APPLICATION_MERGE_PATCH_JSON = "application/merge-patch+json";
private final WsConnector wsConnector;
protected final String controller;
@@ -64,6 +65,10 @@ public abstract class BaseService {
}
}
+ protected String path() {
+ return controller;
+ }
+
protected String path(String action) {
return String.format("%s/%s", controller, action);
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
index bd9a14eb95b..4ca293f2dd5 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
@@ -36,6 +36,8 @@ import org.sonarqube.ws.client.emails.EmailsService;
import org.sonarqube.ws.client.favorites.FavoritesService;
import org.sonarqube.ws.client.github.provisioning.permissions.GithubPermissionsService;
import org.sonarqube.ws.client.githubprovisioning.GithubProvisioningService;
+import org.sonarqube.ws.client.gitlab.configuration.GitlabConfigurationService;
+import org.sonarqube.ws.client.gitlab.synchronization.run.GitlabSynchronizationRunService;
import org.sonarqube.ws.client.governancereports.GovernanceReportsService;
import org.sonarqube.ws.client.hotspots.HotspotsService;
import org.sonarqube.ws.client.issues.IssuesService;
@@ -144,6 +146,9 @@ class DefaultWsClient implements WsClient {
private final SonarLintServerPushService sonarLintPushService;
private final GithubProvisioningService githubProvisioningService;
private final GithubPermissionsService githubPermissionsService;
+ private final GitlabConfigurationService gitlabConfigurationService;
+
+ private final GitlabSynchronizationRunService gitlabSynchronizationRunService;
DefaultWsClient(WsConnector wsConnector) {
this.wsConnector = wsConnector;
@@ -204,6 +209,8 @@ class DefaultWsClient implements WsClient {
this.regulatoryReportsService = new RegulatoryReportsService(wsConnector);
this.githubProvisioningService = new GithubProvisioningService(wsConnector);
this.githubPermissionsService = new GithubPermissionsService(wsConnector);
+ this.gitlabConfigurationService = new GitlabConfigurationService(wsConnector);
+ this.gitlabSynchronizationRunService = new GitlabSynchronizationRunService(wsConnector);
}
@Override
@@ -288,6 +295,16 @@ class DefaultWsClient implements WsClient {
}
@Override
+ public GitlabConfigurationService gitlabConfigurationService() {
+ return gitlabConfigurationService;
+ }
+
+ @Override
+ public GitlabSynchronizationRunService gitlabSynchronizationRunService() {
+ return gitlabSynchronizationRunService;
+ }
+
+ @Override
public GovernanceReportsService governanceReports() {
return governanceReportsService;
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java
index e61a331126e..fcf4cd991d4 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java
@@ -57,7 +57,7 @@ public class HttpConnector implements WsConnector {
public static final int DEFAULT_CONNECT_TIMEOUT_MILLISECONDS = 30_000;
public static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = 60_000;
- private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+ private static final String JSON = "application/json; charset=utf-8";
/**
* Base URL with trailing slash, for instance "https://localhost/sonarqube/".
@@ -134,7 +134,8 @@ public class HttpConnector implements WsConnector {
RequestBody body;
Map<String, Part> parts = request.getParts();
if (request.hasBody()) {
- body = RequestBody.create(JSON, request.getBody());
+ MediaType contentType = MediaType.parse(request.getContentType().orElse(JSON));
+ body = RequestBody.create(contentType, request.getBody());
} else if (parts.isEmpty()) {
// parameters are defined in the body (application/x-www-form-urlencoded)
FormBody.Builder formBody = new FormBody.Builder();
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/RequestWithPayload.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/RequestWithPayload.java
index b78dcdd1c64..a85b0bf077a 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/RequestWithPayload.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/RequestWithPayload.java
@@ -22,6 +22,7 @@ package org.sonarqube.ws.client;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Optional;
import java.util.function.Function;
import okhttp3.Request;
import okhttp3.RequestBody;
@@ -32,6 +33,7 @@ import okhttp3.RequestBody;
public abstract class RequestWithPayload<T extends RequestWithPayload<T>> extends BaseRequest<RequestWithPayload<T>> {
private String body;
+ private String contentType = null;
private final Map<String, Part> parts = new LinkedHashMap<>();
protected RequestWithPayload(String path) {
@@ -51,6 +53,15 @@ public abstract class RequestWithPayload<T extends RequestWithPayload<T>> extend
return this.body != null;
}
+ public T setContentType(String contentType) {
+ this.contentType = contentType;
+ return (T) this;
+ }
+
+ public Optional<String> getContentType() {
+ return Optional.ofNullable(contentType);
+ }
+
public T setPart(String name, Part part) {
this.parts.put(name, part);
return (T) this;
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
index f805faebbee..aee175fb7a3 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
@@ -36,6 +36,8 @@ import org.sonarqube.ws.client.emails.EmailsService;
import org.sonarqube.ws.client.favorites.FavoritesService;
import org.sonarqube.ws.client.github.provisioning.permissions.GithubPermissionsService;
import org.sonarqube.ws.client.githubprovisioning.GithubProvisioningService;
+import org.sonarqube.ws.client.gitlab.configuration.GitlabConfigurationService;
+import org.sonarqube.ws.client.gitlab.synchronization.run.GitlabSynchronizationRunService;
import org.sonarqube.ws.client.governancereports.GovernanceReportsService;
import org.sonarqube.ws.client.hotspots.HotspotsService;
import org.sonarqube.ws.client.issues.IssuesService;
@@ -128,6 +130,10 @@ public interface WsClient {
GithubPermissionsService githubPermissionsService();
+ GitlabConfigurationService gitlabConfigurationService();
+
+ GitlabSynchronizationRunService gitlabSynchronizationRunService();
+
GovernanceReportsService governanceReports();
HotspotsService hotspots();
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfiguration.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfiguration.java
new file mode 100644
index 00000000000..9bc3fbe3efb
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfiguration.java
@@ -0,0 +1,25 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.ws.client.gitlab.configuration;
+
+public record GitlabConfiguration(boolean enabled, String applicationId, String url, String secret, boolean synchronizeGroups,
+ String provisioningType, boolean allowUsersToSignUp, String provisioningToken,
+ String singleProvisioningGroup) {
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfigurationService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfigurationService.java
new file mode 100644
index 00000000000..b0f530395d7
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfigurationService.java
@@ -0,0 +1,77 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.ws.client.gitlab.configuration;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import org.sonarqube.ws.client.BaseService;
+import org.sonarqube.ws.client.PatchRequest;
+import org.sonarqube.ws.client.PostRequest;
+import org.sonarqube.ws.client.WsConnector;
+import org.sonarqube.ws.client.WsResponse;
+
+public class GitlabConfigurationService extends BaseService {
+
+
+ public GitlabConfigurationService(WsConnector wsConnector) {
+ super(wsConnector, "api/v2/dop-translation/gitlab-configurations");
+ }
+
+ public String saveGitlabConfiguration(GitlabConfiguration gitlabConfiguration) {
+ String body = String.format("""
+ {
+ "enabled": "%s",
+ "applicationId": "%s",
+ "url": "%s",
+ "secret": "%s",
+ "synchronizeGroups": "%s",
+ "provisioningType": "%s",
+ "allowUsersToSignUp": "%s",
+ "provisioningToken": "%s",
+ "provisioningGroups": ["%s"]
+ }
+ """, gitlabConfiguration.enabled(), gitlabConfiguration.applicationId(), gitlabConfiguration.url(), gitlabConfiguration.secret(),
+ gitlabConfiguration.synchronizeGroups(), gitlabConfiguration.provisioningType(), gitlabConfiguration.allowUsersToSignUp(),
+ gitlabConfiguration.provisioningToken(), gitlabConfiguration.singleProvisioningGroup());
+ WsResponse response = call(
+ new PostRequest(path()).setBody(body)
+ );
+ return new Gson().fromJson(response.content(), JsonObject.class).get("id").getAsString();
+ }
+
+ public void enableAutoProvisioning(String configId) {
+ setProvisioningMode(configId, "AUTO_PROVISIONING");
+ }
+
+ public void disableAutoProvisioning(String configId) {
+ setProvisioningMode(configId, "JIT");
+ }
+
+ private void setProvisioningMode(String configId, String provisioningMode) {
+ String body = String.format("""
+ {
+ "provisioningType": "%s"
+ }
+ """, provisioningMode);
+ call(
+ new PatchRequest(path(configId)).setBody(body).setContentType(APPLICATION_MERGE_PATCH_JSON)
+ );
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/package-info.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/package-info.java
new file mode 100644
index 00000000000..4e9f84eca7f
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/configuration/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonarqube.ws.client.gitlab.configuration;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/synchronization/run/GitlabSynchronizationRunService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/synchronization/run/GitlabSynchronizationRunService.java
new file mode 100644
index 00000000000..007dd8d40c9
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/synchronization/run/GitlabSynchronizationRunService.java
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.ws.client.gitlab.synchronization.run;
+
+import org.sonarqube.ws.client.BaseService;
+import org.sonarqube.ws.client.PostRequest;
+import org.sonarqube.ws.client.WsConnector;
+
+public class GitlabSynchronizationRunService extends BaseService {
+
+ public GitlabSynchronizationRunService(WsConnector wsConnector) {
+ super(wsConnector, "api/v2/dop-translation/gitlab-synchronization-runs");
+ }
+
+ public void triggerRun() {
+ call(
+ new PostRequest(path())
+ );
+ }
+
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/synchronization/run/package-info.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/synchronization/run/package-info.java
new file mode 100644
index 00000000000..45a93e03190
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/gitlab/synchronization/run/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonarqube.ws.client.gitlab.synchronization.run;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfigurationServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfigurationServiceTest.java
new file mode 100644
index 00000000000..847029c4561
--- /dev/null
+++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/gitlab/configuration/GitlabConfigurationServiceTest.java
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.ws.client.gitlab.configuration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.sonarqube.ws.client.WsConnector;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GitlabConfigurationServiceTest {
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private WsConnector wsConnector;
+
+ @InjectMocks
+ private GitlabConfigurationService gitlabConfigurationService;
+
+ @Test
+ public void saveGitlabConfiguration_shouldNotFail() {
+ when(wsConnector.call(any()).failIfNotSuccessful().content()).thenReturn("{\"id\": \"configId\"}");
+ assertThatNoException().isThrownBy(() -> gitlabConfigurationService.saveGitlabConfiguration(new GitlabConfiguration(true, "appId", "url", "secret",
+ true, "JIT", false, "token", "group")));
+ }
+
+ @Test
+ public void enableAutoProvisioning_shouldNotFail() {
+ assertThatNoException().isThrownBy(() -> gitlabConfigurationService.enableAutoProvisioning("configId"));
+ }
+
+ @Test
+ public void disableAutoProvisioning_shouldNotFail() {
+ assertThatNoException().isThrownBy(() -> gitlabConfigurationService.disableAutoProvisioning("configId"));
+ }
+
+
+}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/gitlab/synchronization/run/GitlabSynchronizationRunServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/gitlab/synchronization/run/GitlabSynchronizationRunServiceTest.java
new file mode 100644
index 00000000000..b976349f2c9
--- /dev/null
+++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/gitlab/synchronization/run/GitlabSynchronizationRunServiceTest.java
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.ws.client.gitlab.synchronization.run;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.sonarqube.ws.client.WsConnector;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GitlabSynchronizationRunServiceTest {
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private WsConnector wsConnector;
+
+ @InjectMocks
+ private GitlabSynchronizationRunService gitlabSynchronizationRunService;
+
+ @Test
+ public void triggerRun_whenTriggered_shouldNotFail() {
+ assertThatNoException().isThrownBy(() ->gitlabSynchronizationRunService.triggerRun());
+ }
+
+}