import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
+import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.i18n.I18n;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.portfolio.PortfolioDto;
import org.sonar.db.portfolio.PortfolioDto.SelectionMode;
import org.sonar.db.project.ProjectDto;
+import org.sonar.db.property.PropertiesDao;
+import org.sonar.db.property.PropertyDto;
import org.sonar.server.es.ProjectIndexer.Cause;
import org.sonar.server.es.ProjectIndexers;
import org.sonar.server.favorite.FavoriteUpdater;
private final FavoriteUpdater favoriteUpdater;
private final ProjectIndexers projectIndexers;
private final UuidFactory uuidFactory;
+ private final PropertiesDao propertiesDao;
public ComponentUpdater(DbClient dbClient, I18n i18n, System2 system2,
PermissionTemplateService permissionTemplateService, FavoriteUpdater favoriteUpdater,
- ProjectIndexers projectIndexers, UuidFactory uuidFactory) {
+ ProjectIndexers projectIndexers, UuidFactory uuidFactory, PropertiesDao propertiesDao) {
this.dbClient = dbClient;
this.i18n = i18n;
this.system2 = system2;
this.favoriteUpdater = favoriteUpdater;
this.projectIndexers = projectIndexers;
this.uuidFactory = uuidFactory;
+ this.propertiesDao = propertiesDao;
}
/**
* - Index component in es indexes
*/
public ComponentDto create(DbSession dbSession, NewComponent newComponent, @Nullable String userUuid, @Nullable String userLogin) {
- ComponentDto componentDto = createWithoutCommit(dbSession, newComponent, userUuid, userLogin, c -> {
+ return create(dbSession, newComponent, userUuid, userLogin, null);
+ }
+
+ public ComponentDto create(DbSession dbSession, NewComponent newComponent, @Nullable String userUuid, @Nullable String userLogin, @Nullable String mainBranchName) {
+ ComponentDto componentDto = createWithoutCommit(dbSession, newComponent, userUuid, userLogin, mainBranchName, c -> {
});
commitAndIndex(dbSession, componentDto);
return componentDto;
}
private void createMainBranch(DbSession session, String componentUuid, @Nullable String mainBranch) {
+
+ String branchKey = Optional.ofNullable(mainBranch)
+ .or(() -> Optional.ofNullable(propertiesDao.selectGlobalProperty(session, CorePropertyDefinitions.SONAR_PROJECTCREATION_MAINBRANCHNAME))
+ .map(PropertyDto::getValue))
+ .orElse(BranchDto.DEFAULT_MAIN_BRANCH_NAME);
+
BranchDto branch = new BranchDto()
.setBranchType(BranchType.BRANCH)
.setUuid(componentUuid)
- .setKey(Optional.ofNullable(mainBranch).orElse(BranchDto.DEFAULT_MAIN_BRANCH_NAME))
+ .setKey(branchKey)
.setMergeBranchUuid(null)
.setExcludeFromPurge(true)
.setProjectUuid(componentUuid);
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_CREATE;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_MAIN_BRANCH;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
.setHandler(this);
action.setChangelog(
+ new Change("9.8", "Field 'mainBranch' added to the request"),
new Change("7.1", "The 'visibility' parameter is public"));
action.createParam(PARAM_PROJECT)
.setRequired(true)
.setExampleValue("SonarQube");
+ action.createParam(PARAM_MAIN_BRANCH)
+ .setDescription("Key of the main branch of the project. If not provided, the default main branch key will be used.")
+ .setRequired(false)
+ .setSince("9.8")
+ .setExampleValue("develop");
+
action.createParam(PARAM_VISIBILITY)
.setDescription("Whether the created project should be visible to everyone, or only specific user/groups.<br/>" +
"If no visibility is specified, the default project visibility will be used.")
boolean changeToPrivate = visibility == null ? projectDefaultVisibility.get(dbSession).isPrivate() : "private".equals(visibility);
ComponentDto componentDto = componentUpdater.create(dbSession, newComponentBuilder()
- .setKey(request.getProjectKey())
- .setName(request.getName())
- .setPrivate(changeToPrivate)
- .setQualifier(PROJECT)
- .build(),
+ .setKey(request.getProjectKey())
+ .setName(request.getName())
+ .setPrivate(changeToPrivate)
+ .setQualifier(PROJECT)
+ .build(),
userSession.isLoggedIn() ? userSession.getUuid() : null,
- userSession.isLoggedIn() ? userSession.getLogin() : null);
+ userSession.isLoggedIn() ? userSession.getLogin() : null,
+ request.getMainBranchKey());
return toCreateResponse(componentDto);
}
}
.setProjectKey(request.mandatoryParam(PARAM_PROJECT))
.setName(abbreviate(request.mandatoryParam(PARAM_NAME), MAX_COMPONENT_NAME_LENGTH))
.setVisibility(request.param(PARAM_VISIBILITY))
+ .setMainBranchKey(request.param(PARAM_MAIN_BRANCH))
.build();
}
static class CreateRequest {
private final String projectKey;
private final String name;
+ private final String mainBranchKey;
@CheckForNull
private final String visibility;
this.projectKey = builder.projectKey;
this.name = builder.name;
this.visibility = builder.visibility;
+ this.mainBranchKey = builder.mainBranchKey;
}
public String getProjectKey() {
return visibility;
}
+ public String getMainBranchKey() {
+ return mainBranchKey;
+ }
+
public static Builder builder() {
return new Builder();
}
static class Builder {
private String projectKey;
private String name;
+ private String mainBranchKey;
+
@CheckForNull
private String visibility;
return this;
}
+ public Builder setMainBranchKey(@Nullable String mainBranchKey) {
+ this.mainBranchKey = mainBranchKey;
+ return this;
+ }
+
public CreateRequest build() {
requireNonNull(projectKey);
requireNonNull(name);
private final AzureDevOpsHttpClient azureDevOpsHttpClient = mock(AzureDevOpsHttpClient.class);
private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE,
- mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
+ mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(),
+ new SequenceUuidFactory(), db.getDbClient().propertiesDao());
private final Encryption encryption = mock(Encryption.class);
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
GsonAzureRepo repo = getGsonAzureRepo();
when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption),
"project-name", "repo-name"))
- .thenReturn(repo);
+ .thenReturn(repo);
Projects.CreateWsResponse response = ws.newRequest()
.setParam("almSetting", almSetting.getKey())
GsonAzureRepo repo = getEmptyGsonAzureRepo();
when(azureDevOpsHttpClient.getRepo(almSetting.getUrl(), almSetting.getDecryptedPersonalAccessToken(encryption),
"project-name", "repo-name"))
- .thenReturn(repo);
+ .thenReturn(repo);
Projects.CreateWsResponse response = ws.newRequest()
.setParam("almSetting", almSetting.getKey())
private final BitbucketCloudRestClient bitbucketCloudRestClient = mock(BitbucketCloudRestClient.class);
private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE,
- mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
+ mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
+ new TestProjectIndexers(), new SequenceUuidFactory(), db.getDbClient().propertiesDao());
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);
private final BitbucketServerRestClient bitbucketServerRestClient = mock(BitbucketServerRestClient.class);
private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE,
- mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
+ mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
+ new TestProjectIndexers(), new SequenceUuidFactory(), db.getDbClient().propertiesDao());
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);
public DbTester db = DbTester.create(system2);
private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE,
- mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
+ mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
+ new TestProjectIndexers(), new SequenceUuidFactory(), db.getDbClient().propertiesDao());
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);
public DbTester db = DbTester.create(system2);
private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE,
- mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory());
+ mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
+ new TestProjectIndexers(), new SequenceUuidFactory(), db.getDbClient().propertiesDao());
private final GitlabHttpClient gitlabHttpClient = mock(GitlabHttpClient.class);
private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.permission.GlobalPermission;
+import org.sonar.db.property.PropertiesDao;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.es.TestProjectIndexers;
private final CeQueue queue = mock(CeQueueImpl.class);
private final TestProjectIndexers projectIndexers = new TestProjectIndexers();
private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
+
+ private final PropertiesDao propertiesDao = mock(PropertiesDao.class);
+
private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService,
- new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory());
+ new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory(), propertiesDao);
private final BranchSupport ossEditionBranchSupport = new BranchSupport(null);
private final ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), ossEditionBranchSupport,
*/
package org.sonar.server.component;
+import java.util.Map;
import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
+import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
private final TestProjectIndexers projectIndexers = new TestProjectIndexers();
private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
-
private final ComponentUpdater underTest = new ComponentUpdater(db.getDbClient(), i18n, system2,
permissionTemplateService,
new FavoriteUpdater(db.getDbClient()),
- projectIndexers, new SequenceUuidFactory());
+ projectIndexers, new SequenceUuidFactory(), db.getDbClient().propertiesDao());
@Test
public void persist_and_index_when_creating_project() {
assertThat(branch.get().getProjectUuid()).isEqualTo(returned.uuid());
}
+ @Test
+ public void create_project_with_main_branch_global_property(){
+ String globalBranchName = "main-branch-global";
+ db.getDbClient().propertiesDao().saveGlobalProperties(Map.of(CorePropertyDefinitions.SONAR_PROJECTCREATION_MAINBRANCHNAME, globalBranchName));
+ NewComponent project = NewComponent.newComponentBuilder()
+ .setKey(DEFAULT_PROJECT_KEY)
+ .setName(DEFAULT_PROJECT_NAME)
+ .setPrivate(true)
+ .build();
+
+ ComponentDto returned = underTest.create(db.getSession(), project, null, null, null);
+
+ Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.branchUuid());
+ assertThat(branch).get().extracting(BranchDto::getBranchKey).isEqualTo(globalBranchName);
+
+ }
+
+ @Test
+ public void create_project_with_main_branch_param(){
+ String customBranchName = "main-branch-custom";
+ db.getDbClient().propertiesDao().saveGlobalProperties(Map.of(CorePropertyDefinitions.SONAR_PROJECTCREATION_MAINBRANCHNAME, customBranchName));
+ NewComponent project = NewComponent.newComponentBuilder()
+ .setKey(DEFAULT_PROJECT_KEY)
+ .setName(DEFAULT_PROJECT_NAME)
+ .setPrivate(true)
+ .build();
+
+ ComponentDto returned = underTest.create(db.getSession(), project, null, null, customBranchName);
+
+ Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.branchUuid());
+ assertThat(branch).get().extracting(BranchDto::getBranchKey).isEqualTo(customBranchName);
+
+ }
+
@Test
public void persist_private_flag_true_when_creating_project() {
NewComponent project = NewComponent.newComponentBuilder()
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentUpdater;
import static org.sonar.server.project.Visibility.PRIVATE;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.client.WsRequest.Method.POST;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_MAIN_BRANCH;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
private static final String DEFAULT_PROJECT_KEY = "project-key";
private static final String DEFAULT_PROJECT_NAME = "project-name";
+ private static final String MAIN_BRANCH = "main-branch";
private final System2 system2 = System2.INSTANCE;
private final WsActionTester ws = new WsActionTester(
new CreateAction(
db.getDbClient(), userSession,
- new ComponentUpdater(db.getDbClient(), i18n, system2, permissionTemplateService, new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory()),
+ new ComponentUpdater(db.getDbClient(), i18n, system2, permissionTemplateService, new FavoriteUpdater(db.getDbClient()), projectIndexers,
+ new SequenceUuidFactory(), db.getDbClient().propertiesDao()),
projectDefaultVisibility));
@Before
CreateWsResponse response = call(CreateRequest.builder()
.setProjectKey(DEFAULT_PROJECT_KEY)
.setName(DEFAULT_PROJECT_NAME)
+ .setMainBranchKey(MAIN_BRANCH)
.build());
assertThat(response.getProject())
.extracting(Project::getKey, Project::getName, Project::getQualifier, Project::getVisibility)
.containsOnly(DEFAULT_PROJECT_KEY, DEFAULT_PROJECT_NAME, "TRK", "public");
- assertThat(db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get())
+ ComponentDto component = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
+ assertThat(component)
.extracting(ComponentDto::getKey, ComponentDto::name, ComponentDto::qualifier, ComponentDto::scope, ComponentDto::isPrivate, ComponentDto::getMainBranchProjectUuid)
.containsOnly(DEFAULT_PROJECT_KEY, DEFAULT_PROJECT_NAME, "TRK", "PRJ", false, null);
+
+ assertThat(db.getDbClient().branchDao().selectByUuid(db.getSession(), component.branchUuid()).get())
+ .extracting(BranchDto::getKey)
+ .isEqualTo(MAIN_BRANCH);
}
@Test
public void fail_when_missing_project_parameter() {
userSession.addPermission(PROVISION_PROJECTS);
- assertThatThrownBy(() -> call(null, DEFAULT_PROJECT_NAME))
+ assertThatThrownBy(() -> call(null, DEFAULT_PROJECT_NAME, null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("The 'project' parameter is missing");
}
public void fail_when_missing_name_parameter() {
userSession.addPermission(PROVISION_PROJECTS);
- assertThatThrownBy(() -> call(DEFAULT_PROJECT_KEY, null))
+ assertThatThrownBy(() -> call(DEFAULT_PROJECT_KEY, null, null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("The 'name' parameter is missing");
}
assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder(
PARAM_VISIBILITY,
PARAM_NAME,
- PARAM_PROJECT);
+ PARAM_PROJECT, PARAM_MAIN_BRANCH);
WebService.Param visibilityParam = definition.param(PARAM_VISIBILITY);
assertThat(visibilityParam.description()).isNotEmpty();
}
private CreateWsResponse call(CreateRequest request) {
- return call(request.getProjectKey(), request.getName());
+ return call(request.getProjectKey(), request.getName(), request.getMainBranchKey());
}
- private CreateWsResponse call(@Nullable String projectKey, @Nullable String projectName) {
+ private CreateWsResponse call(@Nullable String projectKey, @Nullable String projectName, @Nullable String mainBranch) {
TestRequest httpRequest = ws.newRequest()
.setMethod(POST.name());
ofNullable(projectKey).ifPresent(key -> httpRequest.setParam("project", key));
ofNullable(projectName).ifPresent(name -> httpRequest.setParam("name", name));
+ ofNullable(mainBranch).ifPresent(name -> httpRequest.setParam("mainBranch", mainBranch));
return httpRequest.executeProtobuf(CreateWsResponse.class);
}
public static final String PARAM_PROJECT = "project";
public static final String PARAM_PROJECT_ID = "projectId";
public static final String PARAM_NAME = "name";
+ public static final String PARAM_MAIN_BRANCH = "mainBranch";
public static final String PARAM_BRANCH = "branch";
public static final String PARAM_QUALIFIERS = "qualifiers";
public static final String PARAM_FROM = "from";