@@ -36,6 +36,7 @@ public class DbVersion66 implements DbVersion { | |||
.add(1806, "Create table project_branches", CreateTableProjectBranches.class) | |||
.add(1807, "Add on project_branches key", AddIndexOnProjectBranchesKey.class) | |||
.add(1808, "Add branch column to projects table", AddBranchColumnToProjectsTable.class) | |||
.add(1809, "Populate project_branches with existing main branches", PopulateMainProjectBranches.class) | |||
; | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 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.server.platform.db.migration.version.v66; | |||
import java.sql.SQLException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
import static org.apache.commons.lang.StringUtils.repeat; | |||
public class PopulateMainProjectBranches extends DataChange { | |||
private static final int KEE_MAX_LENGTH = 255; | |||
static final String NULL_KEY = repeat("_", KEE_MAX_LENGTH); | |||
private static final String INSERT_MAIN_PROJECT_BRANCHES = "INSERT INTO project_branches (uuid, project_uuid, kee_type, kee, branch_type, " | |||
+ "merge_branch_uuid, pull_request_title, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; | |||
private final System2 system2; | |||
public PopulateMainProjectBranches(Database db, System2 system2) { | |||
super(db); | |||
this.system2 = system2; | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
long now = system2.now(); | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select("SELECT uuid FROM projects p " | |||
+ "WHERE p.scope='PRJ' AND p.qualifier='TRK' AND p.main_branch_project_uuid IS NULL " | |||
+ "AND NOT EXISTS (SELECT uuid FROM project_branches b WHERE b.uuid = p.uuid)"); | |||
massUpdate.update(INSERT_MAIN_PROJECT_BRANCHES); | |||
massUpdate.rowPluralName("projects"); | |||
massUpdate.execute((row, update) -> { | |||
String uuid = row.getString(1); | |||
update.setString(1, uuid); | |||
update.setString(2, uuid); | |||
update.setString(3, "BRANCH"); | |||
update.setString(4, NULL_KEY); | |||
update.setString(5, "LONG"); | |||
update.setString(6, null); | |||
update.setString(7, null); | |||
update.setLong(8, now); | |||
update.setLong(9, now); | |||
return true; | |||
}); | |||
} | |||
} |
@@ -36,7 +36,7 @@ public class DbVersion66Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 9); | |||
verifyMigrationCount(underTest, 10); | |||
} | |||
} |
@@ -0,0 +1,109 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 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.server.platform.db.migration.version.v66; | |||
import java.sql.SQLException; | |||
import java.util.Map; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; | |||
import org.sonar.db.CoreDbTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class PopulateMainProjectBranchesTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(PopulateMainProjectBranchesTest.class, "initial.sql"); | |||
private System2 system2 = new AlwaysIncreasingSystem2(); | |||
private PopulateMainProjectBranches underTest = new PopulateMainProjectBranches(db.database(), system2); | |||
@Test | |||
public void populate_with_existing_project() throws SQLException { | |||
insertProject("project1"); | |||
insertProject("project2", "project1", "PRJ"); | |||
insertProject("project3", null, "XXX"); | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("project_branches")).isEqualTo(1); | |||
Map<String, Object> row = db.selectFirst("select * from project_branches"); | |||
assertThat(row.get("UUID")).isEqualTo("project1"); | |||
assertThat(row.get("PROJECT_UUID")).isEqualTo("project1"); | |||
assertThat(row.get("KEE")).isEqualTo(PopulateMainProjectBranches.NULL_KEY); | |||
assertThat(row.get("BRANCH_TYPE")).isEqualTo("LONG"); | |||
} | |||
@Test | |||
public void do_nothing_if_no_project() throws SQLException { | |||
insertProject("project2", "project1", "PRJ"); | |||
insertProject("project3", null, "XXX"); | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("project_branches")).isEqualTo(0); | |||
} | |||
@Test | |||
public void do_not_populate_if_already_exists() throws SQLException { | |||
insertProject("project1"); | |||
insertBranch("project1"); | |||
assertThat(db.countRowsOfTable("project_branches")).isEqualTo(1); | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("project_branches")).isEqualTo(1); | |||
} | |||
private void insertProject(String uuid) { | |||
insertProject(uuid, null, "PRJ"); | |||
} | |||
private void insertProject(String uuid, @Nullable String mainBranchUuid, String scope) { | |||
db.executeInsert("PROJECTS", | |||
"ORGANIZATION_UUID", "default-org", | |||
"KEE", uuid + "-key", | |||
"UUID", uuid, | |||
"PROJECT_UUID", uuid, | |||
"main_branch_project_uuid", mainBranchUuid, | |||
"UUID_PATH", ".", | |||
"ROOT_UUID", uuid, | |||
"PRIVATE", "true", | |||
"qualifier", "TRK", | |||
"scope", scope); | |||
} | |||
private void insertBranch(String uuid) { | |||
db.executeInsert("PROJECT_BRANCHES", | |||
"uuid", uuid, | |||
"project_uuid", uuid, | |||
"kee_type", "BRANCH", | |||
"kee", PopulateMainProjectBranches.NULL_KEY, | |||
"branch_type", "LONG", | |||
"created_at", 0, | |||
"updated_at", 0); | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
CREATE TABLE "PROJECTS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(400), | |||
"UUID" VARCHAR(50) NOT NULL, | |||
"UUID_PATH" VARCHAR(1500) NOT NULL, | |||
"ROOT_UUID" VARCHAR(50) NOT NULL, | |||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||
"MODULE_UUID" VARCHAR(50), | |||
"MODULE_UUID_PATH" VARCHAR(1500), | |||
"MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), | |||
"NAME" VARCHAR(2000), | |||
"DESCRIPTION" VARCHAR(2000), | |||
"PRIVATE" BOOLEAN NOT NULL, | |||
"TAGS" VARCHAR(500), | |||
"ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, | |||
"SCOPE" VARCHAR(3), | |||
"QUALIFIER" VARCHAR(10), | |||
"DEPRECATED_KEE" VARCHAR(400), | |||
"PATH" VARCHAR(2000), | |||
"LANGUAGE" VARCHAR(20), | |||
"COPY_COMPONENT_UUID" VARCHAR(50), | |||
"LONG_NAME" VARCHAR(2000), | |||
"DEVELOPER_UUID" VARCHAR(50), | |||
"CREATED_AT" TIMESTAMP, | |||
"AUTHORIZATION_UPDATED_AT" BIGINT, | |||
"B_CHANGED" BOOLEAN, | |||
"B_COPY_COMPONENT_UUID" VARCHAR(50), | |||
"B_DESCRIPTION" VARCHAR(2000), | |||
"B_ENABLED" BOOLEAN, | |||
"B_UUID_PATH" VARCHAR(1500), | |||
"B_LANGUAGE" VARCHAR(20), | |||
"B_LONG_NAME" VARCHAR(500), | |||
"B_MODULE_UUID" VARCHAR(50), | |||
"B_MODULE_UUID_PATH" VARCHAR(1500), | |||
"B_NAME" VARCHAR(500), | |||
"B_PATH" VARCHAR(2000), | |||
"B_QUALIFIER" VARCHAR(10) | |||
); | |||
CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); | |||
CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); | |||
CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); | |||
CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); | |||
CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); | |||
CREATE TABLE "PROJECT_BRANCHES" ( | |||
"UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | |||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||
"KEE_TYPE" VARCHAR(6) NOT NULL, | |||
"KEE" VARCHAR(255) NOT NULL, | |||
"BRANCH_TYPE" VARCHAR(5), | |||
"MERGE_BRANCH_UUID" VARCHAR(50), | |||
"PULL_REQUEST_TITLE" VARCHAR(4000), | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL | |||
); | |||
CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | |||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE_TYPE", "KEE"); |
@@ -24,12 +24,16 @@ import java.util.List; | |||
import java.util.Locale; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.i18n.I18n; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.resources.Scopes; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.core.util.Uuids; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.component.BranchKeyType; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.es.ProjectIndexer.Cause; | |||
import org.sonar.server.es.ProjectIndexers; | |||
@@ -70,6 +74,9 @@ public class ComponentUpdater { | |||
public ComponentDto create(DbSession dbSession, NewComponent newComponent, @Nullable Integer userId) { | |||
checkKeyFormat(newComponent.qualifier(), newComponent.key()); | |||
ComponentDto componentDto = createRootComponent(dbSession, newComponent); | |||
if (isRootProject(componentDto)) { | |||
createBranch(dbSession, componentDto.uuid()); | |||
} | |||
removeDuplicatedProjects(dbSession, componentDto.getDbKey()); | |||
handlePermissionTemplate(dbSession, componentDto, newComponent.getOrganizationUuid(), userId); | |||
projectIndexers.commitAndIndex(dbSession, singletonList(componentDto), Cause.PROJECT_CREATION); | |||
@@ -100,9 +107,28 @@ public class ComponentUpdater { | |||
.setPrivate(newComponent.isPrivate()) | |||
.setCreatedAt(new Date(system2.now())); | |||
dbClient.componentDao().insert(session, component); | |||
return component; | |||
} | |||
private static boolean isRootProject(ComponentDto componentDto) { | |||
return Scopes.PROJECT.equals(componentDto.scope()) && Qualifiers.PROJECT.equals(componentDto.qualifier()); | |||
} | |||
private BranchDto createBranch(DbSession session, String componentUuid) { | |||
BranchDto branch = new BranchDto() | |||
.setBranchType(BranchType.LONG) | |||
.setKeeType(BranchKeyType.BRANCH) | |||
.setUuid(componentUuid) | |||
.setKey(null) | |||
.setMergeBranchUuid(null) | |||
.setPullRequestTitle(null) | |||
.setProjectUuid(componentUuid); | |||
dbClient.branchDao().upsert(session, branch); | |||
return branch; | |||
} | |||
/** | |||
* On MySQL, as PROJECTS.KEE is not unique, if the same project is provisioned multiple times, then it will be duplicated in the database. | |||
* So, after creating a project, we commit, and we search in the db if their are some duplications and we remove them. |
@@ -0,0 +1,114 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 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.server.computation.task.projectanalysis.component; | |||
import java.util.Date; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.component.BranchKeyType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | |||
import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT; | |||
import static org.sonar.db.component.ComponentDto.UUID_PATH_SEPARATOR; | |||
public class BranchPersister { | |||
private final DbClient dbClient; | |||
private final System2 system2; | |||
private final TreeRootHolder treeRootHolder; | |||
private final AnalysisMetadataHolder analysisMetadataHolder; | |||
public BranchPersister(DbClient dbClient, System2 system2, TreeRootHolder treeRootHolder, AnalysisMetadataHolder analysisMetadataHolder) { | |||
this.dbClient = dbClient; | |||
this.system2 = system2; | |||
this.treeRootHolder = treeRootHolder; | |||
this.analysisMetadataHolder = analysisMetadataHolder; | |||
} | |||
public void persist(DbSession dbSession) { | |||
Optional<Branch> branchOpt = analysisMetadataHolder.getBranch(); | |||
if (!branchOpt.isPresent()) { | |||
return; | |||
} | |||
Branch branch = branchOpt.get(); | |||
String branchUuid = treeRootHolder.getRoot().getUuid(); | |||
com.google.common.base.Optional<ComponentDto> branchComponentDtoOpt = dbClient.componentDao().selectByUuid(dbSession, branchUuid); | |||
ComponentDto branchComponentDto; | |||
if (branch.isMain()) { | |||
checkState(branchComponentDtoOpt.isPresent(), "Project has been deleted by end-user during analysis"); | |||
branchComponentDto = branchComponentDtoOpt.get(); | |||
} else { | |||
// inserts new row in table projects if it's the first time branch is analyzed | |||
branchComponentDto = branchComponentDtoOpt.or(() -> insertIntoProjectsTable(dbSession, branchUuid)); | |||
} | |||
// insert or update in table project_branches | |||
dbClient.branchDao().upsert(dbSession, toBranchDto(branchComponentDto, branch)); | |||
} | |||
private static void checkState(boolean condition, String msg) { | |||
if (!condition) { | |||
throw new IllegalStateException(msg); | |||
} | |||
} | |||
private static <T> T firstNonNull(@Nullable T first, T second) { | |||
return (first != null) ? first : second; | |||
} | |||
private static BranchDto toBranchDto(ComponentDto componentDto, Branch branch) { | |||
BranchDto dto = new BranchDto(); | |||
dto.setUuid(componentDto.uuid()); | |||
// MainBranchProjectUuid will be null if it's a main branch | |||
dto.setProjectUuid(firstNonNull(componentDto.getMainBranchProjectUuid(), componentDto.projectUuid())); | |||
dto.setKeeType(BranchKeyType.BRANCH); | |||
dto.setKey(branch.getName().orElse(null)); | |||
dto.setBranchType(branch.getType()); | |||
// merge branch is only present if it's a short living branch | |||
dto.setMergeBranchUuid(branch.getMergeBranchUuid().orElse(null)); | |||
dto.setPullRequestTitle(null); | |||
return dto; | |||
} | |||
private ComponentDto insertIntoProjectsTable(DbSession dbSession, String branchUuid) { | |||
String mainBranchProjectUuid = analysisMetadataHolder.getProject().getUuid(); | |||
ComponentDto project = dbClient.componentDao().selectOrFailByUuid(dbSession, mainBranchProjectUuid); | |||
ComponentDto branchDto = project.copy(); | |||
branchDto.setUuid(branchUuid); | |||
branchDto.setProjectUuid(branchUuid); | |||
branchDto.setRootUuid(branchUuid); | |||
branchDto.setUuidPath(UUID_PATH_OF_ROOT); | |||
branchDto.setModuleUuidPath(UUID_PATH_SEPARATOR + branchUuid + UUID_PATH_SEPARATOR); | |||
branchDto.setMainBranchProjectUuid(mainBranchProjectUuid); | |||
branchDto.setDbKey(treeRootHolder.getRoot().getKey()); | |||
branchDto.setCreatedAt(new Date(system2.now())); | |||
dbClient.componentDao().insert(dbSession, branchDto); | |||
return branchDto; | |||
} | |||
} |
@@ -1,30 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 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.server.computation.task.projectanalysis.component; | |||
import org.sonar.api.ce.ComputeEngineSide; | |||
import org.sonar.db.DbSession; | |||
@ComputeEngineSide | |||
public interface BranchPersisterDelegate { | |||
void persist(DbSession dbSession); | |||
} |
@@ -71,7 +71,7 @@ public class DefaultBranchImpl implements Branch { | |||
@Override | |||
public boolean isLegacyFeature() { | |||
return true; | |||
return isLegacyBranch; | |||
} | |||
@Override |
@@ -36,6 +36,7 @@ import org.sonar.server.computation.task.projectanalysis.api.posttask.PostProjec | |||
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportDirectoryHolderImpl; | |||
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchLoader; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersister; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepositoryImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.DbIdsRepositoryImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.DisabledComponentsHolderImpl; | |||
@@ -244,6 +245,7 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop | |||
ComponentIssuesLoader.class, | |||
BaseIssuesLoader.class, | |||
IssueTrackingDelegator.class, | |||
BranchPersister.class, | |||
// filemove | |||
SourceSimilarityImpl.class, |
@@ -50,7 +50,7 @@ import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentUpdateDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersisterDelegate; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersister; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; | |||
import org.sonar.server.computation.task.projectanalysis.component.DbIdsRepositoryImpl; | |||
@@ -75,19 +75,12 @@ public class PersistComponentsStep implements ComputationStep { | |||
private final System2 system2; | |||
private final MutableDisabledComponentsHolder disabledComponentsHolder; | |||
private final AnalysisMetadataHolder analysisMetadataHolder; | |||
@Nullable | |||
private final BranchPersisterDelegate branchPersister; | |||
public PersistComponentsStep(DbClient dbClient, TreeRootHolder treeRootHolder, | |||
MutableDbIdsRepository dbIdsRepository, System2 system2, | |||
MutableDisabledComponentsHolder disabledComponentsHolder, AnalysisMetadataHolder analysisMetadataHolder) { | |||
this(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder, null); | |||
} | |||
private final BranchPersister branchPersister; | |||
public PersistComponentsStep(DbClient dbClient, TreeRootHolder treeRootHolder, | |||
MutableDbIdsRepository dbIdsRepository, System2 system2, | |||
MutableDisabledComponentsHolder disabledComponentsHolder, AnalysisMetadataHolder analysisMetadataHolder, | |||
@Nullable BranchPersisterDelegate branchPersister) { | |||
BranchPersister branchPersister) { | |||
this.dbClient = dbClient; | |||
this.treeRootHolder = treeRootHolder; | |||
this.dbIdsRepository = dbIdsRepository; | |||
@@ -105,7 +98,7 @@ public class PersistComponentsStep implements ComputationStep { | |||
@Override | |||
public void execute() { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ofNullable(branchPersister).ifPresent(p -> p.persist(dbSession)); | |||
branchPersister.persist(dbSession); | |||
String projectUuid = treeRootHolder.getRoot().getUuid(); | |||
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.component; | |||
import java.util.Optional; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
@@ -26,6 +27,9 @@ import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.resources.Scopes; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.component.BranchKeyType; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.user.UserDto; | |||
@@ -94,6 +98,16 @@ public class ComponentUpdaterTest { | |||
assertThat(db.getDbClient().componentDao().selectOrFailByKey(db.getSession(), DEFAULT_PROJECT_KEY)).isNotNull(); | |||
assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); | |||
Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.uuid()); | |||
assertThat(branch).isPresent(); | |||
assertThat(branch.get().getKeeType()).isEqualTo(BranchKeyType.BRANCH); | |||
assertThat(branch.get().getKey()).isNull(); | |||
assertThat(branch.get().getMergeBranchUuid()).isNull(); | |||
assertThat(branch.get().getPullRequestTitle()).isNull(); | |||
assertThat(branch.get().getBranchType()).isEqualTo(BranchType.LONG); | |||
assertThat(branch.get().getUuid()).isEqualTo(returned.uuid()); | |||
assertThat(branch.get().getProjectUuid()).isEqualTo(returned.uuid()); | |||
} | |||
@Test | |||
@@ -154,6 +168,8 @@ public class ComponentUpdaterTest { | |||
assertThat(loaded.name()).isEqualTo("view-name"); | |||
assertThat(loaded.qualifier()).isEqualTo("VW"); | |||
assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); | |||
Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.uuid()); | |||
assertThat(branch).isNotPresent(); | |||
} | |||
@Test | |||
@@ -172,6 +188,8 @@ public class ComponentUpdaterTest { | |||
assertThat(loaded.name()).isEqualTo("app-name"); | |||
assertThat(loaded.qualifier()).isEqualTo("APP"); | |||
assertThat(projectIndexers.hasBeenCalled(loaded.uuid(), ProjectIndexer.Cause.PROJECT_CREATION)).isTrue(); | |||
Optional<BranchDto> branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), returned.uuid()); | |||
assertThat(branch).isNotPresent(); | |||
} | |||
@Test |
@@ -0,0 +1,105 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 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.server.computation.task.projectanalysis.component; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ReportComponent.builder; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Project; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; | |||
public class BranchPersisterTest { | |||
private final static Component MAIN = builder(PROJECT, 1).setUuid("PROJECT_UUID").setKey("PROJECT_KEY").build(); | |||
private final static Component BRANCH = builder(PROJECT, 1).setUuid("BRANCH_UUID").setKey("BRANCH_KEY").build(); | |||
@Rule | |||
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule(); | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
@Rule | |||
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); | |||
@Rule | |||
public ExpectedException exception = ExpectedException.none(); | |||
BranchPersister underTest = new BranchPersister(dbTester.getDbClient(), System2.INSTANCE, treeRootHolder, analysisMetadataHolder); | |||
@Test | |||
public void fail_if_no_component_for_main_branches() { | |||
analysisMetadataHolder.setBranch(createBranch(BranchType.LONG, true, null)); | |||
treeRootHolder.setRoot(MAIN); | |||
exception.expect(IllegalStateException.class); | |||
exception.expectMessage("Project has been deleted by end-user during analysis"); | |||
underTest.persist(dbTester.getSession()); | |||
} | |||
@Test | |||
public void skip_if_no_branch() { | |||
analysisMetadataHolder.setBranch(null); | |||
underTest.persist(dbTester.getSession()); | |||
dbTester.assertTableDoesNotExist("project_branch"); | |||
} | |||
@Test | |||
public void persist_secondary_branch() { | |||
analysisMetadataHolder.setBranch(createBranch(BranchType.LONG, false, "branch")); | |||
treeRootHolder.setRoot(BRANCH); | |||
// add main branch in project table and in metadata | |||
ComponentDto dto = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), MAIN.getUuid()).setDbKey(MAIN.getKey()); | |||
analysisMetadataHolder.setProject(Project.copyOf(dto)); | |||
dbTester.getDbClient().componentDao().insert(dbTester.getSession(), dto); | |||
// this should add new columns in project and project_branches | |||
underTest.persist(dbTester.getSession()); | |||
dbTester.getSession().commit(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(2); | |||
assertThat(dbTester.countRowsOfTable("project_branches")).isEqualTo(1); | |||
} | |||
private static Branch createBranch(BranchType type, boolean isMain, @Nullable String name) { | |||
Branch branch = mock(Branch.class); | |||
when(branch.getType()).thenReturn(type); | |||
when(branch.getName()).thenReturn(Optional.ofNullable(name)); | |||
when(branch.isMain()).thenReturn(isMain); | |||
when(branch.getMergeBranchUuid()).thenReturn(Optional.empty()); | |||
return branch; | |||
} | |||
} |
@@ -28,7 +28,7 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDao; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersisterDelegate; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersister; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDisabledComponentsHolder; | |||
@@ -69,6 +69,6 @@ public class PersistComponentsStepTest { | |||
System2.INSTANCE, | |||
mock(MutableDisabledComponentsHolder.class), | |||
mock(AnalysisMetadataHolder.class), | |||
mock(BranchPersisterDelegate.class)).execute(); | |||
mock(BranchPersister.class)).execute(); | |||
} | |||
} |
@@ -40,7 +40,7 @@ import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Project; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersisterDelegate; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersister; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.FileAttributes; | |||
import org.sonar.server.computation.task.projectanalysis.component.DefaultBranchImpl; | |||
@@ -88,7 +88,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
private Date now; | |||
private MutableDisabledComponentsHolder disabledComponentsHolder = mock(MutableDisabledComponentsHolder.class, RETURNS_DEEP_STUBS); | |||
private PersistComponentsStep underTest; | |||
private BranchPersisterDelegate branchPersister; | |||
private BranchPersister branchPersister; | |||
@Before | |||
public void setup() throws Exception { | |||
@@ -96,6 +96,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
when(system2.now()).thenReturn(now.getTime()); | |||
db.organizations().insertForUuid(ORGANIZATION_UUID); | |||
branchPersister = mock(BranchPersister.class); | |||
underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder, branchPersister); | |||
} | |||
@@ -37,7 +37,7 @@ import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersisterDelegate; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchPersister; | |||
import org.sonar.server.computation.task.projectanalysis.component.DefaultBranchImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepositoryRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDisabledComponentsHolder; | |||
@@ -95,7 +95,7 @@ public class ViewsPersistComponentsStepTest extends BaseStepTest { | |||
private ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); | |||
private MutableDisabledComponentsHolder disabledComponentsHolder = mock(MutableDisabledComponentsHolder.class, RETURNS_DEEP_STUBS); | |||
private PersistComponentsStep underTest; | |||
private BranchPersisterDelegate branchPersister; | |||
private BranchPersister branchPersister; | |||
@Before | |||
public void setup() throws Exception { | |||
@@ -104,6 +104,7 @@ public class ViewsPersistComponentsStepTest extends BaseStepTest { | |||
dbTester.organizations().insertForUuid(ORGANIZATION_UUID); | |||
analysisMetadataHolder.setBranch(new DefaultBranchImpl(null)); | |||
branchPersister = mock(BranchPersister.class); | |||
underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder, branchPersister); | |||
} | |||