Skip to content

Commit

Permalink
Add support for Sonarqube 8.2.0
Browse files Browse the repository at this point in the history
Sonarqube 8.2 introduced a new `ProjectDto` with associated changes in `ProjectAlmSettingsDao` to require this new class in various methods, as well as changes in `ComponentFinder` to allow retrieval of instances of a project. This change makes use of these new classes and methods to allow the Web Services for setting up ALM bindings to operate.

As this class and the associated methods did not exist in previous versions of Sonarqube, this change breaks backwards compatibility, so means the plugin will now only support Sonarqube 8.2.

Sonarqube 8.2 also provides the ability to set the optional URL parameter on a Gitlab project so that scans run outside of Gitlab CI operate properly, so the additional parameter is now included in the appropriate WebServices and the Gitlab decorator.
  • Loading branch information
mc1arke committed Jul 17, 2020
1 parent 7cf8e36 commit f624269
Show file tree
Hide file tree
Showing 17 changed files with 264 additions and 108 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ repositories {
}
}

def sonarqubeVersion = '8.1.0.31237'
def sonarqubeVersion = '8.2.0.32929'
def sonarqubeLibDir = "${projectDir}/sonarqube-lib"
def sonarLibraries = "${sonarqubeLibDir}/sonarqube-${sonarqubeVersion}/lib"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.github.mc1arke.sonarqube.plugin.ce.pullrequest.gitlab.response.User;
import com.github.mc1arke.sonarqube.plugin.ce.pullrequest.markup.MarkdownFormatterFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
Expand Down Expand Up @@ -102,10 +103,11 @@ public DecorationResult decorateQualityGateStatus(AnalysisDetails analysis, AlmS
String revision = analysis.getCommitSha();

try {
final String apiURL = analysis.getScannerProperty(PULLREQUEST_GITLAB_INSTANCE_URL).orElseThrow(
() -> new IllegalStateException(String.format(
final String apiURL = Optional.ofNullable(StringUtils.stripToNull(almSettingDto.getUrl()))
.orElse(analysis.getScannerProperty(PULLREQUEST_GITLAB_INSTANCE_URL)
.orElseThrow(() -> new IllegalStateException(String.format(
"Could not decorate Gitlab merge request. '%s' has not been set in scanner properties",
PULLREQUEST_GITLAB_INSTANCE_URL)));
PULLREQUEST_GITLAB_INSTANCE_URL))));
final String apiToken = almSettingDto.getPersonalAccessToken();
final String projectId = analysis.getScannerProperty(PULLREQUEST_GITLAB_PROJECT_ID).orElseThrow(
() -> new IllegalStateException(String.format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.user.UserSession;

Expand All @@ -32,7 +32,7 @@ public class DeleteBindingAction extends ProjectWsAction {
private final DbClient dbClient;

public DeleteBindingAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) {
super("delete_binding", dbClient, componentFinder, userSession);
super("delete_binding", dbClient, componentFinder, userSession, true);
this.dbClient = dbClient;
}

Expand All @@ -43,7 +43,7 @@ protected void configureAction(WebService.NewAction action) {
}

@Override
protected void handleProjectRequest(ComponentDto project, Request request, Response response, DbSession dbSession) {
protected void handleProjectRequest(ProjectDto project, Request request, Response response, DbSession dbSession) {
dbClient.projectAlmSettingDao().deleteByProject(dbSession, project);
dbSession.commit();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,24 @@
*/
package com.github.mc1arke.sonarqube.plugin.server.pullrequest.ws.action;

import static java.lang.String.format;

import java.util.Optional;

import com.github.mc1arke.sonarqube.plugin.server.pullrequest.ws.AlmTypeMapper;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;
import org.sonar.server.ws.WsUtils;
import org.sonarqube.ws.AlmSettings.GetBindingWsResponse;

import com.github.mc1arke.sonarqube.plugin.server.pullrequest.ws.AlmTypeMapper;
import java.util.Optional;

import static java.lang.String.format;

public class GetBindingAction extends ProjectWsAction {

Expand All @@ -48,7 +47,7 @@ public GetBindingAction(DbClient dbClient, ComponentFinder componentFinder, User
}

GetBindingAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, ProtoBufWriter protoBufWriter) {
super("get_binding", dbClient, componentFinder, userSession);
super("get_binding", dbClient, componentFinder, userSession, true);
this.dbClient = dbClient;
this.protoBufWriter = protoBufWriter;
}
Expand All @@ -59,7 +58,7 @@ protected void configureAction(WebService.NewAction action) {
}

@Override
protected void handleProjectRequest(ComponentDto project, Request request, Response response, DbSession dbSession) {
protected void handleProjectRequest(ProjectDto project, Request request, Response response, DbSession dbSession) {
ProjectAlmSettingDto projectAlmSetting = dbClient.projectAlmSettingDao().selectByProject(dbSession, project)
.orElseThrow(() -> new NotFoundException(
format("Project '%s' is not bound to any ALM", project.getKey())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,24 @@
*/
package com.github.mc1arke.sonarqube.plugin.server.pullrequest.ws.action;

import static java.util.Optional.ofNullable;

import java.util.List;
import java.util.stream.Collectors;

import com.github.mc1arke.sonarqube.plugin.server.pullrequest.ws.AlmTypeMapper;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.user.UserSession;
import org.sonar.server.ws.WsUtils;
import org.sonarqube.ws.AlmSettings.AlmSetting;
import org.sonarqube.ws.AlmSettings.ListWsResponse;

import com.github.mc1arke.sonarqube.plugin.server.pullrequest.ws.AlmTypeMapper;
import java.util.List;
import java.util.stream.Collectors;

import static java.util.Optional.ofNullable;

public class ListAction extends ProjectWsAction {

Expand All @@ -48,7 +47,7 @@ public ListAction(DbClient dbClient, UserSession userSession, ComponentFinder co
}

public ListAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, ProtoBufWriter protoBufWriter) {
super("list", dbClient, componentFinder, userSession);
super("list", dbClient, componentFinder, userSession, false);
this.dbClient = dbClient;
this.protoBufWriter = protoBufWriter;
}
Expand All @@ -59,7 +58,7 @@ protected void configureAction(WebService.NewAction action) {
}

@Override
protected void handleProjectRequest(ComponentDto project, Request request, Response response, DbSession dbSession) {
protected void handleProjectRequest(ProjectDto project, Request request, Response response, DbSession dbSession) {
List<AlmSettingDto> settings = dbClient.almSettingDao().selectAll(dbSession);
List<AlmSetting> wsAlmSettings = settings.stream().map(almSetting -> {
AlmSetting.Builder almSettingBuilder = AlmSetting.newBuilder().setKey(almSetting.getKey())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static java.util.Collections.emptyList;
Expand Down Expand Up @@ -115,8 +116,12 @@ private static AlmSettingBitbucket toBitbucket(AlmSettingDto settingDto) {
}

private static AlmSettings.AlmSettingGitlab toGitlab(AlmSettingDto settingDto) {
return AlmSettings.AlmSettingGitlab.newBuilder()
AlmSettings.AlmSettingGitlab.Builder almSettingBuilder = AlmSettings.AlmSettingGitlab.newBuilder()
.setKey(settingDto.getKey())
.setPersonalAccessToken(requireNonNull(settingDto.getPersonalAccessToken(), "Personal Access Token cannot be null for Gitlab ALM setting")).build();
.setPersonalAccessToken(requireNonNull(settingDto.getPersonalAccessToken(), "Personal Access Token cannot be null for Gitlab ALM setting"));

Optional.ofNullable(settingDto.getUrl()).ifPresent(almSettingBuilder::setUrl);

return almSettingBuilder.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package com.github.mc1arke.sonarqube.plugin.server.pullrequest.ws.action;

import static org.sonar.api.web.UserRole.ADMIN;

import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.user.UserSession;

import java.util.Optional;

import static org.sonar.api.web.UserRole.ADMIN;

public abstract class ProjectWsAction extends AlmSettingsWsAction {

private static final String PROJECT_PARAMETER = "project";
Expand All @@ -19,19 +21,21 @@ public abstract class ProjectWsAction extends AlmSettingsWsAction {
private final DbClient dbClient;
private final ComponentFinder componentFinder;
private final UserSession userSession;
private final boolean projectParameterRequired;

protected ProjectWsAction(String actionName, DbClient dbClient, ComponentFinder componentFinder, UserSession userSession) {
protected ProjectWsAction(String actionName, DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, boolean projectParameterRequired) {
super(dbClient);
this.actionName = actionName;
this.dbClient = dbClient;
this.componentFinder = componentFinder;
this.userSession = userSession;
this.projectParameterRequired = projectParameterRequired;
}

@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction(actionName).setHandler(this);
action.createParam(PROJECT_PARAMETER).setRequired(true);
action.createParam(PROJECT_PARAMETER).setRequired(projectParameterRequired);

configureAction(action);
}
Expand All @@ -41,14 +45,23 @@ public void define(WebService.NewController context) {

@Override
public void handle(Request request, Response response) {
String projectKey = request.mandatoryParam(PROJECT_PARAMETER);
try (DbSession dbSession = dbClient.openSession(false)) {
ComponentDto project = componentFinder.getByKey(dbSession, projectKey);
userSession.checkComponentPermission(ADMIN, project);
Optional<String> projectKey = Optional.ofNullable(request.param(PROJECT_PARAMETER));

try (DbSession dbSession = dbClient.openSession(false)) {
ProjectDto project;
if (projectKey.isPresent()) {
project = componentFinder.getProjectByKey(dbSession, projectKey.get());
userSession.checkProjectPermission(ADMIN, project);
} else {
if (projectParameterRequired) {
throw new IllegalArgumentException("The 'project' parameter is missing");
} else {
project = null;
}
}
handleProjectRequest(project, request, response, dbSession);
}
}

protected abstract void handleProjectRequest(ComponentDto project, Request request, Response response, DbSession dbSession);
protected abstract void handleProjectRequest(ProjectDto project, Request request, Response response, DbSession dbSession);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.sonar.db.DbSession;
import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.alm.setting.ProjectAlmSettingDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.user.UserSession;

Expand All @@ -34,18 +34,20 @@ public abstract class SetBindingAction extends ProjectWsAction {
private static final String ALM_SETTING_PARAMETER = "almSetting";

protected SetBindingAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, String actionName) {
super(actionName, dbClient, componentFinder, userSession);
super(actionName, dbClient, componentFinder, userSession, true);
}

@Override
protected void configureAction(WebService.NewAction action) {
action.createParam(ALM_SETTING_PARAMETER).setRequired(true);
}

protected void handleProjectRequest(ComponentDto project, Request request, Response response, DbSession dbSession) {
@Override
protected void handleProjectRequest(ProjectDto project, Request request, Response response, DbSession dbSession) {
String almSetting = request.mandatoryParam(ALM_SETTING_PARAMETER);

AlmSettingDto almSettingDto = getAlmSetting(dbSession, almSetting);
getDbClient().projectAlmSettingDao().insertOrUpdate(dbSession, createProjectAlmSettingDto(project.uuid(), almSettingDto.getUuid(), request));
getDbClient().projectAlmSettingDao().insertOrUpdate(dbSession, createProjectAlmSettingDto(project.getUuid(), almSettingDto.getUuid(), request));
dbSession.commit();

response.noContent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

public class CreateGitlabAction extends CreateAction {

private static final String URL_PARAMETER = "url";
private static final String PERSONAL_ACCESS_TOKEN_PARAMETER = "personalAccessToken";

public CreateGitlabAction(DbClient dbClient, UserSession userSession) {
Expand All @@ -37,6 +38,7 @@ public CreateGitlabAction(DbClient dbClient, UserSession userSession) {

@Override
public void configureAction(WebService.NewAction action) {
action.createParam(URL_PARAMETER).setMaximumLength(2000);
action.createParam(PERSONAL_ACCESS_TOKEN_PARAMETER).setRequired(true).setMaximumLength(2000);
}

Expand All @@ -45,6 +47,7 @@ public AlmSettingDto createAlmSettingDto(String key, Request request) {
return new AlmSettingDto()
.setAlm(GITLAB)
.setKey(key)
.setUrl(request.param(URL_PARAMETER))
.setPersonalAccessToken(request.mandatoryParam(PERSONAL_ACCESS_TOKEN_PARAMETER));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

public class UpdateGitlabAction extends UpdateAction {

private static final String URL_PARAMETER = "url";
private static final String PERSONAL_ACCESS_TOKEN_PARAMETER = "personalAccessToken";

public UpdateGitlabAction(DbClient dbClient, UserSession userSession) {
Expand All @@ -35,12 +36,14 @@ public UpdateGitlabAction(DbClient dbClient, UserSession userSession) {

@Override
protected void configureAction(WebService.NewAction action) {
action.createParam(URL_PARAMETER).setMaximumLength(2000);
action.createParam(PERSONAL_ACCESS_TOKEN_PARAMETER).setRequired(true).setMaximumLength(2000);
}

@Override
protected AlmSettingDto updateAlmSettingsDto(AlmSettingDto almSettingDto, Request request) {
return almSettingDto.setPersonalAccessToken(request.mandatoryParam(PERSONAL_ACCESS_TOKEN_PARAMETER));
return almSettingDto.setPersonalAccessToken(request.mandatoryParam(PERSONAL_ACCESS_TOKEN_PARAMETER))
.setUrl(request.param(URL_PARAMETER));
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
package com.github.mc1arke.sonarqube.plugin.server.pullrequest.ws.action;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.Test;
import org.mockito.Mockito;
import org.sonar.api.server.ws.Request;
Expand All @@ -14,10 +9,15 @@
import org.sonar.db.DbSession;
import org.sonar.db.alm.setting.AlmSettingDao;
import org.sonar.db.alm.setting.ProjectAlmSettingDao;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.project.ProjectDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.user.UserSession;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class DeleteBindingActionTest {

@Test
Expand Down Expand Up @@ -58,22 +58,22 @@ public void testHandle() {

UserSession userSession = mock(UserSession.class);

ComponentDto componentDto = mock(ComponentDto.class);
ProjectDto componentDto = mock(ProjectDto.class);
ComponentFinder componentFinder = mock(ComponentFinder.class);
when(componentFinder.getByKey(eq(dbSession), eq("projectKey"))).thenReturn(componentDto);
when(componentFinder.getProjectByKey(eq(dbSession), eq("projectKey"))).thenReturn(componentDto);

DeleteBindingAction testCase = new DeleteBindingAction(dbClient, userSession, componentFinder);

Request request = mock(Request.class, Mockito.RETURNS_DEEP_STUBS);
when(request.mandatoryParam("project")).thenReturn("projectKey");
when(request.param("project")).thenReturn("projectKey");
Response response = mock(Response.class, Mockito.RETURNS_DEEP_STUBS);

testCase.handle(request, response);

verify(dbSession).commit();
verify(projectAlmSettingDao).deleteByProject(eq(dbSession), eq(componentDto));
verify(response).noContent();
verify(userSession).checkComponentPermission("admin", componentDto);
verify(userSession).checkProjectPermission("admin", componentDto);

}

Expand Down
Loading

0 comments on commit f624269

Please sign in to comment.