import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.core.i18n.I18n;
+import org.sonar.core.platform.EditionProvider;
+import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbTester;
import org.sonar.db.alm.setting.AlmSettingDto;
import org.sonar.db.component.BranchDto;
+import org.sonar.db.newcodeperiod.NewCodePeriodDto;
import org.sonar.db.permission.GlobalPermission;
import org.sonar.db.project.ProjectDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.favorite.FavoriteUpdater;
+import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.project.DefaultBranchNameResolver;
import org.sonar.server.project.ProjectDefaultVisibility;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
+import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
import static org.sonar.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING;
import static org.sonar.server.almintegration.ws.github.ImportGithubProjectAction.PARAM_ORGANIZATION;
import static org.sonar.server.almintegration.ws.github.ImportGithubProjectAction.PARAM_REPOSITORY_KEY;
import static org.sonar.server.tester.UserSessionRule.standalone;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE;
public class ImportGithubProjectActionIT {
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);
private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class);
+ private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
+ private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider);
private final WsActionTester ws = new WsActionTester(new ImportGithubProjectAction(db.getDbClient(), userSession,
- projectDefaultVisibility, appClient, componentUpdater, importHelper, projectKeyGenerator));
+ projectDefaultVisibility, appClient, componentUpdater, importHelper, projectKeyGenerator, newCodeDefinitionResolver,
+ defaultBranchNameResolver));
@Before
public void before() {
AlmSettingDto githubAlmSetting = setupAlm();
db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid()));
- GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false, "octocat/" + PROJECT_KEY_NAME,
+ GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false,
+ "octocat/" + PROJECT_KEY_NAME,
"https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "default-branch");
when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository));
when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME);
Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
assertThat(projectDto).isPresent();
assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent();
- Optional<BranchDto> mainBranch = db.getDbClient().branchDao().selectByProject(db.getSession(), projectDto.get()).stream().filter(BranchDto::isMain).findAny();
+ Optional<BranchDto> mainBranch =
+ db.getDbClient().branchDao().selectByProject(db.getSession(), projectDto.get()).stream().filter(BranchDto::isMain).findAny();
assertThat(mainBranch).isPresent();
assertThat(mainBranch.get().getKey()).isEqualTo("default-branch");
+
+ }
+
+ @Test
+ public void importProject_withNCD_developer_edition() {
+ when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
+
+ AlmSettingDto githubAlmSetting = setupAlm();
+ db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid()));
+
+ GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false,
+ "octocat/" + PROJECT_KEY_NAME,
+ "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "default-branch");
+ when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository));
+ when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME);
+
+ Projects.CreateWsResponse response = ws.newRequest()
+ .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey())
+ .setParam(PARAM_ORGANIZATION, "octocat")
+ .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME)
+ .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "NUMBER_OF_DAYS")
+ .setParam(PARAM_NEW_CODE_DEFINITION_VALUE, "30")
+ .executeProtobuf(Projects.CreateWsResponse.class);
+
+ Projects.CreateWsResponse.Project result = response.getProject();
+
+ Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
+ assertThat(projectDto).isPresent();
+
+ assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid()))
+ .isPresent()
+ .get()
+ .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid)
+ .containsExactly(NUMBER_OF_DAYS, "30", null);
+ }
+
+ @Test
+ public void importProject_withNCD_community_edition() {
+ when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
+
+ AlmSettingDto githubAlmSetting = setupAlm();
+ db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid()));
+
+ GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false,
+ "octocat/" + PROJECT_KEY_NAME,
+ "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "default-branch");
+ when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository));
+ when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME);
+
+ Projects.CreateWsResponse response = ws.newRequest()
+ .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey())
+ .setParam(PARAM_ORGANIZATION, "octocat")
+ .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME)
+ .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "NUMBER_OF_DAYS")
+ .setParam(PARAM_NEW_CODE_DEFINITION_VALUE, "30")
+ .executeProtobuf(Projects.CreateWsResponse.class);
+
+ Projects.CreateWsResponse.Project result = response.getProject();
+
+ Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
+ assertThat(projectDto).isPresent();
+
+ String projectUuid = projectDto.get().getUuid();
+ assertThat(db.getDbClient().newCodePeriodDao().selectByBranch(db.getSession(), projectUuid, projectUuid))
+ .isPresent()
+ .get()
+ .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid)
+ .containsExactly(NUMBER_OF_DAYS, "30", projectUuid);
+ }
+
+ @Test
+ public void importProject_reference_branch_ncd_no_default_branch() {
+ when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
+ when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn("default-branch");
+
+ AlmSettingDto githubAlmSetting = setupAlm();
+ db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid()));
+
+ GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false,
+ "octocat/" + PROJECT_KEY_NAME,
+ "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, null);
+ when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository));
+ when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME);
+
+ Projects.CreateWsResponse response = ws.newRequest()
+ .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey())
+ .setParam(PARAM_ORGANIZATION, "octocat")
+ .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME)
+ .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "reference_branch")
+ .executeProtobuf(Projects.CreateWsResponse.class);
+
+ Projects.CreateWsResponse.Project result = response.getProject();
+
+ Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
+ assertThat(projectDto).isPresent();
+
+ assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid()))
+ .isPresent()
+ .get()
+ .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
+ .containsExactly(REFERENCE_BRANCH, "default-branch");
+ }
+
+ @Test
+ public void importProject_reference_branch_ncd() {
+ when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
+
+ AlmSettingDto githubAlmSetting = setupAlm();
+ db.almPats().insert(p -> p.setAlmSettingUuid(githubAlmSetting.getUuid()).setUserUuid(userSession.getUuid()));
+
+ GithubApplicationClient.Repository repository = new GithubApplicationClient.Repository(1L, PROJECT_KEY_NAME, false,
+ "octocat/" + PROJECT_KEY_NAME,
+ "https://github.sonarsource.com/api/v3/repos/octocat/" + PROJECT_KEY_NAME, "mainBranch");
+ when(appClient.getRepository(any(), any(), any(), any())).thenReturn(Optional.of(repository));
+ when(projectKeyGenerator.generateUniqueProjectKey(repository.getFullName())).thenReturn(PROJECT_KEY_NAME);
+
+ Projects.CreateWsResponse response = ws.newRequest()
+ .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey())
+ .setParam(PARAM_ORGANIZATION, "octocat")
+ .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME)
+ .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "reference_branch")
+ .executeProtobuf(Projects.CreateWsResponse.class);
+
+ Projects.CreateWsResponse.Project result = response.getProject();
+
+ Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
+ assertThat(projectDto).isPresent();
+
+ assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectDto.get().getUuid()))
+ .isPresent()
+ .get()
+ .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
+ .containsExactly(REFERENCE_BRANCH, "mainBranch");
}
@Test
.containsExactlyInAnyOrder(
tuple(PARAM_ALM_SETTING, true),
tuple(PARAM_ORGANIZATION, true),
- tuple(PARAM_REPOSITORY_KEY, true));
+ tuple(PARAM_REPOSITORY_KEY, true),
+ tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false),
+ tuple(PARAM_NEW_CODE_DEFINITION_VALUE, false));
}
private AlmSettingDto setupAlm() {
package org.sonar.server.almintegration.ws.github;
import java.util.Optional;
+import javax.inject.Inject;
import org.sonar.alm.client.github.GithubApplicationClient;
import org.sonar.alm.client.github.GithubApplicationClient.Repository;
import org.sonar.alm.client.github.GithubApplicationClientImpl;
import org.sonar.server.component.ComponentCreationData;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
+import org.sonar.server.project.DefaultBranchNameResolver;
import org.sonar.server.project.ProjectDefaultVisibility;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Projects;
import static org.sonar.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING;
import static org.sonar.server.almintegration.ws.ImportHelper.toCreateResponse;
import static org.sonar.server.component.NewComponent.newComponentBuilder;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION;
+import static org.sonar.server.newcodeperiod.NewCodeDefinitionResolver.checkNewCodeDefinitionParam;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE;
public class ImportGithubProjectAction implements AlmIntegrationsWsAction {
private final ImportHelper importHelper;
private final ProjectKeyGenerator projectKeyGenerator;
+ private final NewCodeDefinitionResolver newCodeDefinitionResolver;
+
+ private final DefaultBranchNameResolver defaultBranchNameResolver;
+
+ @Inject
public ImportGithubProjectAction(DbClient dbClient, UserSession userSession, ProjectDefaultVisibility projectDefaultVisibility,
- GithubApplicationClientImpl githubApplicationClient, ComponentUpdater componentUpdater, ImportHelper importHelper, ProjectKeyGenerator projectKeyGenerator) {
+ GithubApplicationClientImpl githubApplicationClient, ComponentUpdater componentUpdater, ImportHelper importHelper,
+ ProjectKeyGenerator projectKeyGenerator, NewCodeDefinitionResolver newCodeDefinitionResolver,
+ DefaultBranchNameResolver defaultBranchNameResolver) {
this.dbClient = dbClient;
this.userSession = userSession;
this.projectDefaultVisibility = projectDefaultVisibility;
this.componentUpdater = componentUpdater;
this.importHelper = importHelper;
this.projectKeyGenerator = projectKeyGenerator;
+ this.newCodeDefinitionResolver = newCodeDefinitionResolver;
+ this.defaultBranchNameResolver = defaultBranchNameResolver;
}
@Override
.setRequired(true)
.setMaximumLength(256)
.setDescription("GitHub repository key");
+
+ action.createParam(PARAM_NEW_CODE_DEFINITION_TYPE)
+ .setDescription(NEW_CODE_PERIOD_TYPE_DESCRIPTION_PROJECT_CREATION)
+ .setSince("10.1");
+
+ action.createParam(PARAM_NEW_CODE_DEFINITION_VALUE)
+ .setDescription(NEW_CODE_PERIOD_VALUE_DESCRIPTION_PROJECT_CREATION)
+ .setSince("10.1");
}
@Override
private Projects.CreateWsResponse doHandle(Request request) {
importHelper.checkProvisionProjectPermission();
AlmSettingDto almSettingDto = importHelper.getAlmSetting(request);
- String userUuid = importHelper.getUserUuid();
+
+
+ String newCodeDefinitionType = request.param(PARAM_NEW_CODE_DEFINITION_TYPE);
+ String newCodeDefinitionValue = request.param(PARAM_NEW_CODE_DEFINITION_VALUE);
try (DbSession dbSession = dbClient.openSession(false)) {
- AccessToken accessToken = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto)
- .map(AlmPatDto::getPersonalAccessToken)
- .map(UserAccessToken::new)
- .orElseThrow(() -> new IllegalArgumentException("No personal access token found"));
+ AccessToken accessToken = getAccessToken(dbSession, almSettingDto);
String githubOrganization = request.mandatoryParam(PARAM_ORGANIZATION);
String repositoryKey = request.mandatoryParam(PARAM_REPOSITORY_KEY);
ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow();
populatePRSetting(dbSession, repository, projectDto, almSettingDto);
+
+ checkNewCodeDefinitionParam(newCodeDefinitionType, newCodeDefinitionValue);
+
+ if (newCodeDefinitionType != null) {
+ newCodeDefinitionResolver.createNewCodeDefinition(dbSession, projectDto.getUuid(),
+ Optional.ofNullable(repository.getDefaultBranch()).orElse(defaultBranchNameResolver.getEffectiveMainBranchName()),
+ newCodeDefinitionType, newCodeDefinitionValue);
+ }
+
componentUpdater.commitAndIndex(dbSession, componentCreationData.mainBranchComponent());
return toCreateResponse(projectDto);
}
}
+ private AccessToken getAccessToken(DbSession dbSession, AlmSettingDto almSettingDto) {
+ String userUuid = importHelper.getUserUuid();
+ return dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto)
+ .map(AlmPatDto::getPersonalAccessToken)
+ .map(UserAccessToken::new)
+ .orElseThrow(() -> new IllegalArgumentException("No personal access token found"));
+ }
+
private ComponentCreationData createProject(DbSession dbSession, Repository repo, String mainBranchName) {
boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate();
String uniqueProjectKey = projectKeyGenerator.generateUniqueProjectKey(repo.getFullName());