@@ -148,7 +148,7 @@ public class ComputeEngineContainerImplTest { | |||
+ 25 // level 1 | |||
+ 49 // content of DaoModule | |||
+ 3 // content of EsSearchModule | |||
+ 61 // content of CorePropertyDefinitions | |||
+ 63 // content of CorePropertyDefinitions | |||
+ 1 // StopFlagContainer | |||
); | |||
assertThat( |
@@ -80,10 +80,10 @@ public final class SqTables { | |||
"perm_tpl_characteristics", | |||
"plugins", | |||
"projects", | |||
"project_branches", | |||
"project_links", | |||
"project_measures", | |||
"project_qprofiles", | |||
"project_branches", | |||
"properties", | |||
"qprofile_changes", | |||
"quality_gates", |
@@ -701,7 +701,8 @@ CREATE TABLE "PROJECT_BRANCHES" ( | |||
"BRANCH_TYPE" VARCHAR(5), | |||
"MERGE_BRANCH_UUID" VARCHAR(50), | |||
"PULL_REQUEST_TITLE" VARCHAR(4000), | |||
"CREATED_AT" BIGINT NOT NULL | |||
"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"); |
@@ -26,6 +26,7 @@ import org.sonar.db.ce.CeQueueDao; | |||
import org.sonar.db.ce.CeScannerContextDao; | |||
import org.sonar.db.ce.CeTaskCharacteristicDao; | |||
import org.sonar.db.ce.CeTaskInputDao; | |||
import org.sonar.db.component.BranchDao; | |||
import org.sonar.db.component.ComponentDao; | |||
import org.sonar.db.component.ComponentKeyUpdaterDao; | |||
import org.sonar.db.component.ComponentLinkDao; | |||
@@ -75,6 +76,7 @@ public class DbClient { | |||
private final Database database; | |||
private final MyBatis myBatis; | |||
private final DBSessions dbSessions; | |||
private final SchemaMigrationDao schemaMigrationDao; | |||
private final AuthorizationDao authorizationDao; | |||
private final OrganizationDao organizationDao; | |||
@@ -123,6 +125,7 @@ public class DbClient { | |||
private final DefaultQProfileDao defaultQProfileDao; | |||
private final EsQueueDao esQueueDao; | |||
private final PluginDao pluginDao; | |||
private final BranchDao branchDao; | |||
public DbClient(Database database, MyBatis myBatis, DBSessions dbSessions, Dao... daos) { | |||
this.database = database; | |||
@@ -181,6 +184,7 @@ public class DbClient { | |||
defaultQProfileDao = getDao(map, DefaultQProfileDao.class); | |||
esQueueDao = getDao(map, EsQueueDao.class); | |||
pluginDao = getDao(map, PluginDao.class); | |||
branchDao = getDao(map, BranchDao.class); | |||
} | |||
public DbSession openSession(boolean batch) { | |||
@@ -383,6 +387,10 @@ public class DbClient { | |||
return pluginDao; | |||
} | |||
public BranchDao branchDao() { | |||
return branchDao; | |||
} | |||
protected <K extends Dao> K getDao(Map<Class, Dao> map, Class<K> clazz) { | |||
return (K) map.get(clazz); | |||
} |
@@ -19,6 +19,9 @@ | |||
*/ | |||
package org.sonar.db.component; | |||
import java.util.Collection; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
@@ -35,6 +38,27 @@ public class BranchDao implements Dao { | |||
mapper(dbSession).insert(dto, system2.now()); | |||
} | |||
public void upsert(DbSession dbSession, BranchDto dto) { | |||
BranchMapper mapper = mapper(dbSession); | |||
long now = system2.now(); | |||
if (mapper.update(dto, now) == 0) { | |||
mapper.insert(dto, now); | |||
} | |||
} | |||
public Optional<BranchDto> selectByKey(DbSession dbSession, String projectUuid, BranchKeyType keyType, @Nullable String key) { | |||
String keyInDb = BranchDto.convertKeyToDb(key); | |||
return Optional.ofNullable(mapper(dbSession).selectByKey(projectUuid, keyType, keyInDb)); | |||
} | |||
public Collection<BranchDto> selectByComponent(DbSession dbSession, ComponentDto component) { | |||
String projectUuid = component.getMainBranchProjectUuid(); | |||
if (projectUuid == null) { | |||
projectUuid = component.projectUuid(); | |||
} | |||
return mapper(dbSession).selectByProjectUuid(projectUuid); | |||
} | |||
private static BranchMapper mapper(DbSession dbSession) { | |||
return dbSession.getMapper(BranchMapper.class); | |||
} |
@@ -19,19 +19,26 @@ | |||
*/ | |||
package org.sonar.db.component; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static org.apache.commons.lang.StringUtils.repeat; | |||
public class BranchDto { | |||
/** | |||
* Maximum length of column "kee" | |||
*/ | |||
public static final int KEE_MAX_LENGTH = 255; | |||
/** | |||
* Value of {@link #kee} when the name of main branch is not known. | |||
* Used only if {@link #keeType} is {@link BranchKeyType#BRANCH}. | |||
* It does not conflict with names of real branches because the character ':' | |||
* It does not conflict with names of real branches because the term ':BRANCH:' | |||
* is not accepted. | |||
*/ | |||
public static final String DEFAULT_KEY_OF_MAIN_BRANCH = ":main:"; | |||
public static final String NULL_KEY = repeat("_", KEE_MAX_LENGTH); | |||
/** | |||
* Branch UUID is the projects.uuid that reference projects, branches or pull requests | |||
@@ -56,7 +63,7 @@ public class BranchDto { | |||
/** | |||
* If {@link #keeType} is {@link BranchKeyType#BRANCH}, then name of branch, for example | |||
* "feature/foo". Can be {@link #DEFAULT_KEY_OF_MAIN_BRANCH} is the name is not known. | |||
* "feature/foo". Can be {@link #NULL_KEY} is the name is not known. | |||
* | |||
* If {@link #keeType} is {@link BranchKeyType#PR}, then id of the pull request, for | |||
* example "1204". | |||
@@ -102,6 +109,10 @@ public class BranchDto { | |||
this.projectUuid = s; | |||
} | |||
public boolean isMain() { | |||
return projectUuid.equals(uuid); | |||
} | |||
public BranchKeyType getKeeType() { | |||
return keeType; | |||
} | |||
@@ -110,15 +121,33 @@ public class BranchDto { | |||
this.keeType = t; | |||
} | |||
public String getKee() { | |||
/** | |||
* This is the getter used by MyBatis mapper. It does | |||
* not handle the special value used to map null field. | |||
*/ | |||
private String getKee() { | |||
return kee; | |||
} | |||
public void setKee(String s) { | |||
checkArgument(s.length() <= 255, "Maximum length of branch name or pull request id is 255: %s", s); | |||
@CheckForNull | |||
public String getKey() { | |||
return convertKeyFromDb(getKee()); | |||
} | |||
/** | |||
* This is the setter used by MyBatis mapper. It does | |||
* not handle the special value used to map null field. | |||
*/ | |||
private void setKee(String s) { | |||
this.kee = s; | |||
} | |||
public void setKey(@Nullable String s) { | |||
checkArgument(s == null || s.length() <= KEE_MAX_LENGTH, "Maximum length of branch name or pull request id is %s: %s", KEE_MAX_LENGTH, s); | |||
checkArgument(!NULL_KEY.equals(s), "Branch name is not allowed: %s", s); | |||
setKee(convertKeyToDb(s)); | |||
} | |||
@Nullable | |||
public BranchType getBranchType() { | |||
return branchType; | |||
@@ -151,9 +180,22 @@ public class BranchDto { | |||
public String toString() { | |||
StringBuilder sb = new StringBuilder("BranchDto{"); | |||
sb.append("uuid='").append(uuid).append('\''); | |||
sb.append(", projectUuid='").append(projectUuid).append('\''); | |||
sb.append(", keeType=").append(keeType); | |||
sb.append(", kee='").append(kee).append('\''); | |||
sb.append(", branchType=").append(branchType); | |||
sb.append(", mergeBranchUuid='").append(mergeBranchUuid).append('\''); | |||
sb.append(", pullRequestTitle='").append(pullRequestTitle).append('\''); | |||
sb.append('}'); | |||
return sb.toString(); | |||
} | |||
static String convertKeyToDb(@Nullable String s) { | |||
return s == null ? NULL_KEY : s; | |||
} | |||
@CheckForNull | |||
static String convertKeyFromDb(String s) { | |||
return NULL_KEY.equals(s) ? null : s; | |||
} | |||
} |
@@ -19,10 +19,17 @@ | |||
*/ | |||
package org.sonar.db.component; | |||
import java.util.Collection; | |||
import org.apache.ibatis.annotations.Param; | |||
public interface BranchMapper { | |||
void insert(@Param("dto") BranchDto dto, @Param("now") long now); | |||
int update(@Param("dto") BranchDto dto, @Param("now") long now); | |||
BranchDto selectByKey(@Param("projectUuid") String projectUuid, | |||
@Param("keyType") BranchKeyType keyType, @Param("key") String key); | |||
Collection<BranchDto> selectByProjectUuid(@Param("projectUuid") String projectUuid); | |||
} |
@@ -216,9 +216,6 @@ public class ComponentDto { | |||
return this; | |||
} | |||
public String getKey() { | |||
return getDbKey(); | |||
} | |||
public String scope() { | |||
return scope; | |||
@@ -476,4 +473,34 @@ public class ComponentDto { | |||
.append("private", isPrivate) | |||
.toString(); | |||
} | |||
public ComponentDto copy() { | |||
ComponentDto copy = new ComponentDto(); | |||
copy.projectUuid = projectUuid; | |||
copy.id = id; | |||
copy.organizationUuid = organizationUuid; | |||
copy.kee = kee; | |||
copy.uuid = uuid; | |||
copy.uuidPath = uuidPath; | |||
copy.projectUuid = projectUuid; | |||
copy.rootUuid = rootUuid; | |||
copy.mainBranchProjectUuid = mainBranchProjectUuid; | |||
copy.moduleUuid = moduleUuid; | |||
copy.moduleUuidPath = moduleUuidPath; | |||
copy.copyComponentUuid = copyComponentUuid; | |||
copy.developerUuid = developerUuid; | |||
copy.scope = scope; | |||
copy.qualifier = qualifier; | |||
copy.path = path; | |||
copy.deprecatedKey = deprecatedKey; | |||
copy.name = name; | |||
copy.longName = longName; | |||
copy.language = language; | |||
copy.description = description; | |||
copy.tags = tags; | |||
copy.enabled = enabled; | |||
copy.isPrivate = isPrivate; | |||
copy.createdAt = createdAt; | |||
return copy; | |||
} | |||
} |
@@ -153,11 +153,7 @@ public class PropertiesDao implements Dao { | |||
} | |||
public List<PropertyDto> selectGlobalPropertiesByKeys(DbSession session, Set<String> keys) { | |||
return selectByKeys(session, keys, null); | |||
} | |||
public List<PropertyDto> selectPropertiesByKeysAndComponentId(DbSession session, Set<String> keys, long componentId) { | |||
return selectByKeys(session, keys, componentId); | |||
return executeLargeInputs(keys, partitionKeys -> getMapper(session).selectByKeys(partitionKeys)); | |||
} | |||
public List<PropertyDto> selectPropertiesByKeysAndComponentIds(DbSession session, Set<String> keys, Set<Long> componentIds) { | |||
@@ -169,10 +165,6 @@ public class PropertiesDao implements Dao { | |||
return executeLargeInputs(componentIds, getMapper(session)::selectByComponentIds); | |||
} | |||
private List<PropertyDto> selectByKeys(DbSession session, Set<String> keys, @Nullable Long componentId) { | |||
return executeLargeInputs(keys, partitionKeys -> getMapper(session).selectByKeys(partitionKeys, componentId)); | |||
} | |||
public List<PropertyDto> selectGlobalPropertiesByKeyQuery(DbSession session, String keyQuery) { | |||
return getMapper(session).selectGlobalPropertiesByKeyQuery(buildLikeValue(keyQuery, WildcardPosition.BEFORE_AND_AFTER)); | |||
} |
@@ -35,7 +35,7 @@ public interface PropertiesMapper { | |||
PropertyDto selectByKey(PropertyDto key); | |||
List<PropertyDto> selectByKeys(@Param("keys") List<String> keys, @Nullable @Param("componentId") Long componentId); | |||
List<PropertyDto> selectByKeys(@Param("keys") List<String> keys); | |||
List<PropertyDto> selectByKeysAndComponentIds(@Param("keys") List<String> keys, @Param("componentIds") List<Long> componentIds); | |||
@@ -21,7 +21,8 @@ | |||
branch_type, | |||
merge_branch_uuid, | |||
pull_request_title, | |||
created_at | |||
created_at, | |||
updated_at | |||
) values ( | |||
#{dto.uuid, jdbcType=VARCHAR}, | |||
#{dto.projectUuid, jdbcType=VARCHAR}, | |||
@@ -30,8 +31,34 @@ | |||
#{dto.branchType, jdbcType=VARCHAR}, | |||
#{dto.mergeBranchUuid, jdbcType=VARCHAR}, | |||
#{dto.pullRequestTitle, jdbcType=VARCHAR}, | |||
#{now, jdbcType=BIGINT}, | |||
#{now, jdbcType=BIGINT} | |||
) | |||
</insert> | |||
<update id="update" parameterType="map" useGeneratedKeys="false"> | |||
update project_branches | |||
set | |||
merge_branch_uuid = #{dto.mergeBranchUuid, jdbcType=VARCHAR}, | |||
pull_request_title = #{dto.pullRequestTitle, jdbcType=VARCHAR}, | |||
updated_at = #{now, jdbcType=BIGINT} | |||
where | |||
uuid = #{dto.uuid, jdbcType=VARCHAR} | |||
</update> | |||
<select id="selectByKey" resultType="org.sonar.db.component.BranchDto"> | |||
select <include refid="columns" /> | |||
from project_branches pb | |||
where | |||
pb.project_uuid = #{projectUuid, jdbcType=VARCHAR} and | |||
pb.kee_type = #{keyType, jdbcType=VARCHAR} and | |||
pb.kee = #{key, jdbcType=VARCHAR} | |||
</select> | |||
<select id="selectByProjectUuid" parameterType="string" resultType="org.sonar.db.component.BranchDto"> | |||
select <include refid="columns" /> | |||
from project_branches pb | |||
where | |||
pb.project_uuid = #{projectUuid, jdbcType=VARCHAR} | |||
</select> | |||
</mapper> |
@@ -123,12 +123,7 @@ | |||
<foreach collection="keys" open="(" close=")" item="key" separator=","> | |||
#{key} | |||
</foreach> | |||
<if test="componentId == null"> | |||
and p.resource_id is null | |||
</if> | |||
<if test="componentId != null"> | |||
and p.resource_id=#{componentId} | |||
</if> | |||
and p.resource_id is null | |||
and p.user_id is null | |||
order by p.id | |||
</select> |
@@ -0,0 +1,175 @@ | |||
/* | |||
* 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.db.component; | |||
import java.util.Map; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.internal.TestSystem2; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import static org.apache.commons.lang.StringUtils.repeat; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
public class BranchDaoTest { | |||
private static final long NOW = 1_000L; | |||
private static final String SELECT_FROM = "select project_uuid as \"projectUuid\", uuid as \"uuid\", branch_type as \"branchType\", kee_type as \"keeType\", " + | |||
"kee as \"kee\", merge_branch_uuid as \"mergeBranchUuid\", pull_request_title as \"pullRequestTitle\", created_at as \"createdAt\", updated_at as \"updatedAt\" " + | |||
"from project_branches "; | |||
private System2 system2 = new TestSystem2().setNow(NOW); | |||
@Rule | |||
public DbTester db = DbTester.create(system2); | |||
private DbSession dbSession = db.getSession(); | |||
private BranchDao underTest = new BranchDao(system2); | |||
@Test | |||
public void insert_branch_with_only_nonnull_fields() { | |||
BranchDto dto = new BranchDto(); | |||
dto.setProjectUuid("U1"); | |||
dto.setUuid("U2"); | |||
dto.setBranchType(BranchType.SHORT); | |||
dto.setKeeType(BranchKeyType.BRANCH); | |||
dto.setKey("feature/foo"); | |||
underTest.insert(dbSession, dto); | |||
Map<String, Object> map = db.selectFirst(dbSession, SELECT_FROM + " where uuid='" + dto.getUuid() + "'"); | |||
assertThat(map).contains( | |||
entry("projectUuid", "U1"), | |||
entry("uuid", "U2"), | |||
entry("branchType", "SHORT"), | |||
entry("keeType", "BRANCH"), | |||
entry("kee", "feature/foo"), | |||
entry("mergeBranchUuid", null), | |||
entry("pullRequestTitle", null), | |||
entry("createdAt", 1_000L), | |||
entry("updatedAt", 1_000L) | |||
); | |||
} | |||
@Test | |||
public void insert_branch_with_all_fields_and_max_length_values() { | |||
BranchDto dto = new BranchDto(); | |||
dto.setProjectUuid(repeat("a", 50)); | |||
dto.setUuid(repeat("b", 50)); | |||
dto.setBranchType(BranchType.SHORT); | |||
dto.setKeeType(BranchKeyType.BRANCH); | |||
dto.setKey(repeat("c", 255)); | |||
dto.setMergeBranchUuid(repeat("d", 50)); | |||
dto.setPullRequestTitle(repeat("e", 4_000)); | |||
underTest.insert(dbSession, dto); | |||
Map<String, Object> map = db.selectFirst(dbSession, SELECT_FROM + " where uuid='" + dto.getUuid() + "'"); | |||
assertThat((String)map.get("projectUuid")).contains("a").isEqualTo(dto.getProjectUuid()); | |||
assertThat((String)map.get("uuid")).contains("b").isEqualTo(dto.getUuid()); | |||
assertThat((String)map.get("kee")).contains("c").isEqualTo(dto.getKey()); | |||
assertThat((String)map.get("mergeBranchUuid")).contains("d").isEqualTo(dto.getMergeBranchUuid()); | |||
assertThat((String)map.get("pullRequestTitle")).contains("e").isEqualTo(dto.getPullRequestTitle()); | |||
} | |||
@Test | |||
public void null_value_of_kee_column_is_converted_in_db() { | |||
BranchDto dto = new BranchDto(); | |||
dto.setProjectUuid("u1"); | |||
dto.setUuid("u2"); | |||
dto.setKeeType(BranchKeyType.BRANCH); | |||
dto.setKey(null); | |||
underTest.insert(dbSession, dto); | |||
Map<String, Object> map = db.selectFirst(dbSession, SELECT_FROM + " where uuid='" + dto.getUuid() + "'"); | |||
assertThat(map).contains(entry("kee", BranchDto.NULL_KEY)); | |||
BranchDto loaded = underTest.selectByKey(dbSession, dto.getProjectUuid(), dto.getKeeType(), null).get(); | |||
assertThat(loaded.getKey()).isNull(); | |||
} | |||
@Test | |||
public void upsert() { | |||
BranchDto dto = new BranchDto(); | |||
dto.setProjectUuid("U1"); | |||
dto.setUuid("U2"); | |||
dto.setBranchType(BranchType.LONG); | |||
dto.setKeeType(BranchKeyType.BRANCH); | |||
dto.setKey("foo"); | |||
underTest.insert(dbSession, dto); | |||
// the fields that can be updated | |||
dto.setMergeBranchUuid("U3"); | |||
dto.setPullRequestTitle("theTitle"); | |||
// the fields that can't be updated. New values are ignored. | |||
dto.setProjectUuid("ignored"); | |||
dto.setBranchType(BranchType.SHORT); | |||
dto.setKeeType(BranchKeyType.PR); | |||
underTest.upsert(dbSession, dto); | |||
BranchDto loaded = underTest.selectByKey(dbSession, "U1", BranchKeyType.BRANCH, "foo").get(); | |||
assertThat(loaded.getMergeBranchUuid()).isEqualTo("U3"); | |||
assertThat(loaded.getPullRequestTitle()).isEqualTo("theTitle"); | |||
assertThat(loaded.getProjectUuid()).isEqualTo("U1"); | |||
assertThat(loaded.getBranchType()).isEqualTo(BranchType.LONG); | |||
assertThat(loaded.getKeeType()).isEqualTo(BranchKeyType.BRANCH); | |||
} | |||
@Test | |||
public void selectByKey() { | |||
BranchDto mainBranch = new BranchDto(); | |||
mainBranch.setProjectUuid("U1"); | |||
mainBranch.setUuid("U1"); | |||
mainBranch.setBranchType(BranchType.LONG); | |||
mainBranch.setKeeType(BranchKeyType.BRANCH); | |||
mainBranch.setKey("master"); | |||
underTest.insert(dbSession, mainBranch); | |||
BranchDto featureBranch = new BranchDto(); | |||
featureBranch.setProjectUuid("U1"); | |||
featureBranch.setUuid("U2"); | |||
featureBranch.setBranchType(BranchType.SHORT); | |||
featureBranch.setKeeType(BranchKeyType.BRANCH); | |||
featureBranch.setKey("feature/foo"); | |||
featureBranch.setMergeBranchUuid("U3"); | |||
underTest.insert(dbSession, featureBranch); | |||
// select the feature branch | |||
BranchDto loaded = underTest.selectByKey(dbSession, "U1", BranchKeyType.BRANCH, "feature/foo").get(); | |||
assertThat(loaded.getUuid()).isEqualTo(featureBranch.getUuid()); | |||
assertThat(loaded.getKey()).isEqualTo(featureBranch.getKey()); | |||
assertThat(loaded.getProjectUuid()).isEqualTo(featureBranch.getProjectUuid()); | |||
assertThat(loaded.getBranchType()).isEqualTo(featureBranch.getBranchType()); | |||
assertThat(loaded.getKeeType()).isEqualTo(featureBranch.getKeeType()); | |||
assertThat(loaded.getMergeBranchUuid()).isEqualTo(featureBranch.getMergeBranchUuid()); | |||
assertThat(loaded.getPullRequestTitle()).isEqualTo(featureBranch.getPullRequestTitle()); | |||
// select a pull request with same key than the feature branch | |||
assertThat(underTest.selectByKey(dbSession, "U1", BranchKeyType.PR, "feature/foo")).isEmpty(); | |||
// select a branch on another project with same branch name | |||
assertThat(underTest.selectByKey(dbSession, "U3", BranchKeyType.BRANCH, "feature/foo")).isEmpty(); | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* 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.db.component; | |||
import org.junit.Test; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class BranchDtoTest { | |||
private BranchDto underTest = new BranchDto(); | |||
@Test | |||
public void isMain_is_true_if_branch_uuid_equals_project_uuid() { | |||
underTest.setProjectUuid("U1"); | |||
underTest.setUuid("U1"); | |||
assertThat(underTest.isMain()).isTrue(); | |||
} | |||
@Test | |||
public void isMain_is_false_if_branch_uuid_does_not_equal_project_uuid() { | |||
underTest.setProjectUuid("U1"); | |||
underTest.setUuid("U2"); | |||
assertThat(underTest.isMain()).isFalse(); | |||
} | |||
} |
@@ -202,7 +202,7 @@ public class ComponentDaoTest { | |||
public void get_by_key_on_disabled_component() { | |||
ComponentDto project = db.components().insertPrivateProject(p -> p.setEnabled(false)); | |||
ComponentDto result = underTest.selectOrFailByKey(dbSession, project.getKey()); | |||
ComponentDto result = underTest.selectOrFailByKey(dbSession, project.getDbKey()); | |||
assertThat(result.isEnabled()).isFalse(); | |||
} | |||
@@ -211,7 +211,7 @@ public class ComponentDaoTest { | |||
public void get_by_key_on_a_root_project() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto result = underTest.selectOrFailByKey(dbSession, project.getKey()); | |||
ComponentDto result = underTest.selectOrFailByKey(dbSession, project.getDbKey()); | |||
assertThat(result.getDbKey()).isEqualTo(project.getDbKey()); | |||
assertThat(result.uuid()).isEqualTo(project.uuid()); | |||
@@ -225,13 +225,13 @@ public class ComponentDaoTest { | |||
ComponentDto project1 = db.components().insertPrivateProject(); | |||
ComponentDto project2 = db.components().insertPrivateProject(); | |||
List<ComponentDto> results = underTest.selectByKeys(dbSession, asList(project1.getKey(), project2.getKey())); | |||
List<ComponentDto> results = underTest.selectByKeys(dbSession, asList(project1.getDbKey(), project2.getDbKey())); | |||
assertThat(results) | |||
.extracting(ComponentDto::uuid, ComponentDto::getKey) | |||
.extracting(ComponentDto::uuid, ComponentDto::getDbKey) | |||
.containsExactlyInAnyOrder( | |||
tuple(project1.uuid(), project1.getKey()), | |||
tuple(project2.uuid(), project2.getKey())); | |||
tuple(project1.uuid(), project1.getDbKey()), | |||
tuple(project2.uuid(), project2.getDbKey())); | |||
assertThat(underTest.selectByKeys(dbSession, singletonList("unknown"))).isEmpty(); | |||
} | |||
@@ -244,10 +244,10 @@ public class ComponentDaoTest { | |||
List<ComponentDto> results = underTest.selectByIds(dbSession, asList(project1.getId(), project2.getId())); | |||
assertThat(results) | |||
.extracting(ComponentDto::uuid, ComponentDto::getKey) | |||
.extracting(ComponentDto::uuid, ComponentDto::getDbKey) | |||
.containsExactlyInAnyOrder( | |||
tuple(project1.uuid(), project1.getKey()), | |||
tuple(project2.uuid(), project2.getKey())); | |||
tuple(project1.uuid(), project1.getDbKey()), | |||
tuple(project2.uuid(), project2.getDbKey())); | |||
assertThat(underTest.selectByIds(dbSession, singletonList(0L))).isEmpty(); | |||
} | |||
@@ -260,10 +260,10 @@ public class ComponentDaoTest { | |||
List<ComponentDto> results = underTest.selectByUuids(dbSession, asList(project1.uuid(), project2.uuid())); | |||
assertThat(results) | |||
.extracting(ComponentDto::uuid, ComponentDto::getKey) | |||
.extracting(ComponentDto::uuid, ComponentDto::getDbKey) | |||
.containsExactlyInAnyOrder( | |||
tuple(project1.uuid(), project1.getKey()), | |||
tuple(project2.uuid(), project2.getKey())); | |||
tuple(project1.uuid(), project1.getDbKey()), | |||
tuple(project2.uuid(), project2.getDbKey())); | |||
assertThat(underTest.selectByUuids(dbSession, singletonList("unknown"))).isEmpty(); | |||
} | |||
@@ -276,7 +276,7 @@ public class ComponentDaoTest { | |||
List<ComponentDto> results = underTest.selectByUuids(dbSession, asList(project1.uuid(), project2.uuid())); | |||
assertThat(results) | |||
.extracting(ComponentDto::getKey, ComponentDto::isEnabled) | |||
.extracting(ComponentDto::getDbKey, ComponentDto::isEnabled) | |||
.containsExactlyInAnyOrder( | |||
tuple(project1.getDbKey(), true), | |||
tuple(project2.getDbKey(), false)); |
@@ -402,27 +402,6 @@ public class PropertiesDaoTest { | |||
.isEmpty(); | |||
} | |||
@Test | |||
public void select_component_properties_by_keys() throws Exception { | |||
ComponentDto project = dbTester.components().insertPrivateProject(); | |||
UserDto user = dbTester.users().insertUser(); | |||
String key = "key"; | |||
String anotherKey = "anotherKey"; | |||
insertProperties( | |||
newGlobalPropertyDto().setKey(key), | |||
newComponentPropertyDto(project).setKey(key), | |||
newUserPropertyDto(user).setKey(key), | |||
newComponentPropertyDto(project).setKey(anotherKey)); | |||
assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet(key), project.getId())).extracting("key").containsOnly(key); | |||
assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet(key, anotherKey), project.getId())).extracting("key").containsOnly(key, anotherKey); | |||
assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet(key, anotherKey, "unknown"), project.getId())).extracting("key").containsOnly(key, anotherKey); | |||
assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet("unknown"), project.getId())).isEmpty(); | |||
assertThat(underTest.selectPropertiesByKeysAndComponentId(session, newHashSet(key), 123456789L)).isEmpty(); | |||
} | |||
@Test | |||
public void select_component_properties_by_ids() throws Exception { | |||
ComponentDto project = dbTester.components().insertPrivateProject(); |
@@ -17,7 +17,6 @@ | |||
* 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; |
@@ -76,6 +76,10 @@ public class CreateTableProjectBranches extends DdlChange { | |||
.setColumnName("created_at") | |||
.setIsNullable(false) | |||
.build()) | |||
.addColumn(BigIntegerColumnDef.newBigIntegerColumnDefBuilder() | |||
.setColumnName("updated_at") | |||
.setIsNullable(false) | |||
.build()) | |||
.build() | |||
); | |||
} |
@@ -53,6 +53,7 @@ public class CreateTableProjectBranchesTest { | |||
db.assertColumnDefinition(TABLE, "merge_branch_uuid", Types.VARCHAR, 50, true); | |||
db.assertColumnDefinition(TABLE, "pull_request_title", Types.VARCHAR, 4000, true); | |||
db.assertColumnDefinition(TABLE, "created_at", Types.BIGINT, null, false); | |||
db.assertColumnDefinition(TABLE, "updated_at", Types.BIGINT, null, false); | |||
db.assertPrimaryKey(TABLE, "pk_" + TABLE, "uuid"); | |||
} | |||
@@ -87,8 +87,8 @@ public class ReportSubmitter { | |||
public CeTask submit(String organizationKey, String projectKey, @Nullable String projectBranch, @Nullable String projectName, Map<String, String> characteristics, | |||
InputStream reportInput) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
String effectiveProjectKey = ComponentKeys.createKey(projectKey, projectBranch); | |||
OrganizationDto organizationDto = getOrganizationDtoOrFail(dbSession, organizationKey); | |||
String effectiveProjectKey = ComponentKeys.createKey(projectKey, projectBranch); | |||
Optional<ComponentDto> opt = dbClient.componentDao().selectByKey(dbSession, effectiveProjectKey); | |||
ensureOrganizationIsConsistent(opt, organizationDto); | |||
ComponentDto project = opt.or(() -> createProject(dbSession, organizationDto, projectKey, projectBranch, projectName)); | |||
@@ -122,12 +122,13 @@ public class ReportSubmitter { | |||
} | |||
} | |||
private ComponentDto createProject(DbSession dbSession, OrganizationDto organization, String projectKey, @Nullable String projectBranch, @Nullable String projectName) { | |||
private ComponentDto createProject(DbSession dbSession, OrganizationDto organization, String projectKey, @Nullable String deprecatedBranch, @Nullable String projectName) { | |||
userSession.checkPermission(OrganizationPermission.PROVISION_PROJECTS, organization); | |||
Integer userId = userSession.getUserId(); | |||
String effectiveProjectKey = ComponentKeys.createEffectiveKey(projectKey, deprecatedBranch); | |||
boolean wouldCurrentUserHaveScanPermission = permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate( | |||
dbSession, organization.getUuid(), userId, projectBranch, projectKey, Qualifiers.PROJECT); | |||
dbSession, organization.getUuid(), userId, effectiveProjectKey, Qualifiers.PROJECT); | |||
if (!wouldCurrentUserHaveScanPermission) { | |||
throw insufficientPrivilegesException(); | |||
} | |||
@@ -138,7 +139,7 @@ public class ReportSubmitter { | |||
.setOrganizationUuid(organization.getUuid()) | |||
.setKey(projectKey) | |||
.setName(StringUtils.defaultIfBlank(projectName, projectKey)) | |||
.setBranch(projectBranch) | |||
.setBranch(deprecatedBranch) | |||
.setQualifier(Qualifiers.PROJECT) | |||
.setPrivate(newProjectPrivate) | |||
.build(); |
@@ -20,6 +20,7 @@ | |||
package org.sonar.server.computation.task.projectanalysis.analysis; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.server.qualityprofile.QualityProfile; | |||
@@ -74,10 +75,28 @@ public interface AnalysisMetadataHolder { | |||
boolean isCrossProjectDuplicationEnabled(); | |||
/** | |||
* Branch is present whatever the type of branch (long or short, main or not). However | |||
* it is absent when analyzing a pull request. | |||
* | |||
* @throws IllegalStateException if branch has not been set | |||
*/ | |||
@CheckForNull | |||
String getBranch(); | |||
Optional<Branch> getBranch(); | |||
/** | |||
* The project as represented by the main branch. It is used to load settings | |||
* like Quality gates, webhooks and configuration. | |||
* | |||
* In case of analysis of main branch, the returned value is the main branch, | |||
* so its uuid and key are the same in | |||
* {@link org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder#getRoot(). | |||
* | |||
* In case of analysis of non-main branch or pull request, the returned value | |||
* is the main branch. Its uuid and key are different than | |||
* {@link org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder#getRoot(). | |||
* | |||
* @throws IllegalStateException if project has not been set | |||
*/ | |||
Project getProject(); | |||
/** | |||
* @throws IllegalStateException if root component ref has not been set |
@@ -21,6 +21,7 @@ package org.sonar.server.computation.task.projectanalysis.analysis; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.server.computation.util.InitializedProperty; | |||
@@ -37,7 +38,8 @@ public class AnalysisMetadataHolderImpl implements MutableAnalysisMetadataHolder | |||
private final InitializedProperty<Boolean> incrementalAnalysis = new InitializedProperty<>(); | |||
private final InitializedProperty<Analysis> baseProjectSnapshot = new InitializedProperty<>(); | |||
private final InitializedProperty<Boolean> crossProjectDuplicationEnabled = new InitializedProperty<>(); | |||
private final InitializedProperty<String> branch = new InitializedProperty<>(); | |||
private final InitializedProperty<Branch> branch = new InitializedProperty<>(); | |||
private final InitializedProperty<Project> project = new InitializedProperty<>(); | |||
private final InitializedProperty<Integer> rootComponentRef = new InitializedProperty<>(); | |||
private final InitializedProperty<Map<String, QualityProfile>> qProfilesPerLanguage = new InitializedProperty<>(); | |||
private final InitializedProperty<Map<String, ScannerPlugin>> pluginsByKey = new InitializedProperty<>(); | |||
@@ -134,16 +136,29 @@ public class AnalysisMetadataHolderImpl implements MutableAnalysisMetadataHolder | |||
} | |||
@Override | |||
public MutableAnalysisMetadataHolder setBranch(@Nullable String branch) { | |||
public MutableAnalysisMetadataHolder setBranch(@Nullable Branch branch) { | |||
checkState(!this.branch.isInitialized(), "Branch has already been set"); | |||
this.branch.setProperty(branch); | |||
return this; | |||
} | |||
@Override | |||
public String getBranch() { | |||
public Optional<Branch> getBranch() { | |||
checkState(branch.isInitialized(), "Branch has not been set"); | |||
return branch.getProperty(); | |||
return Optional.ofNullable(branch.getProperty()); | |||
} | |||
@Override | |||
public MutableAnalysisMetadataHolder setProject(Project project) { | |||
checkState(!this.project.isInitialized(), "Project has already been set"); | |||
this.project.setProperty(project); | |||
return this; | |||
} | |||
@Override | |||
public Project getProject() { | |||
checkState(project.isInitialized(), "Project has not been set"); | |||
return project.getProperty(); | |||
} | |||
@Override |
@@ -0,0 +1,45 @@ | |||
/* | |||
* 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.analysis; | |||
import java.util.Optional; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.server.computation.task.projectanalysis.component.ComponentKeyGenerator; | |||
@Immutable | |||
public interface Branch extends ComponentKeyGenerator { | |||
BranchType getType(); | |||
boolean isMain(); | |||
/** | |||
* Name can be empty when it's not known on the main branch | |||
* (regular analysis without the branch parameters) | |||
*/ | |||
Optional<String> getName(); | |||
/** | |||
* Whether the cross-project duplication tracker must be enabled | |||
* or not. | |||
*/ | |||
boolean supportsCrossProjectCpd(); | |||
} |
@@ -58,7 +58,12 @@ public interface MutableAnalysisMetadataHolder extends AnalysisMetadataHolder { | |||
/** | |||
* @throws IllegalStateException if branch has already been set | |||
*/ | |||
MutableAnalysisMetadataHolder setBranch(@Nullable String branch); | |||
MutableAnalysisMetadataHolder setBranch(@Nullable Branch branch); | |||
/** | |||
* @throws IllegalStateException if project has already been set | |||
*/ | |||
MutableAnalysisMetadataHolder setProject(Project project); | |||
/** | |||
* @throws IllegalStateException if root component ref has already been set |
@@ -0,0 +1,91 @@ | |||
/* | |||
* 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.analysis; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
@Immutable | |||
public class Project { | |||
private final String uuid; | |||
private final String key; | |||
private final String name; | |||
public Project(String uuid, String key, String name) { | |||
this.uuid = uuid; | |||
this.key = key; | |||
this.name = name; | |||
} | |||
/** | |||
* Always links to a row that exists in database. | |||
*/ | |||
public String getUuid() { | |||
return uuid; | |||
} | |||
/** | |||
* Always links to a row that exists in database. | |||
*/ | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
Project project = (Project) o; | |||
return uuid.equals(project.uuid); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return uuid.hashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
StringBuilder sb = new StringBuilder("Project{"); | |||
sb.append("uuid='").append(uuid).append('\''); | |||
sb.append(", key='").append(key).append('\''); | |||
sb.append(", name='").append(name).append('\''); | |||
sb.append('}'); | |||
return sb.toString(); | |||
} | |||
public static Project copyOf(Component component) { | |||
return new Project(component.getUuid(), component.getKey(), component.getName()); | |||
} | |||
public static Project copyOf(ComponentDto component) { | |||
return new Project(component.uuid(), component.getDbKey(), component.name()); | |||
} | |||
} |
@@ -35,7 +35,6 @@ import org.sonar.api.ce.measure.Measure; | |||
import org.sonar.api.ce.measure.MeasureComputer.MeasureComputerContext; | |||
import org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition; | |||
import org.sonar.api.ce.measure.Settings; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.issue.ComponentIssuesRepository; | |||
@@ -97,20 +96,16 @@ public class MeasureComputerContextImpl implements MeasureComputerContext { | |||
@Override | |||
@CheckForNull | |||
public String getString(String key) { | |||
return getComponentSettings().get(key).orElse(null); | |||
return config.getConfiguration().get(key).orElse(null); | |||
} | |||
@Override | |||
public String[] getStringArray(String key) { | |||
return getComponentSettings().getStringArray(key); | |||
return config.getConfiguration().getStringArray(key); | |||
} | |||
}; | |||
} | |||
private Configuration getComponentSettings() { | |||
return config.getConfiguration(internalComponent); | |||
} | |||
@Override | |||
@CheckForNull | |||
public Measure getMeasure(String metric) { |
@@ -0,0 +1,57 @@ | |||
/* | |||
* 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 javax.annotation.Nullable; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; | |||
import static org.apache.commons.lang.StringUtils.trimToNull; | |||
public class BranchLoader { | |||
private final MutableAnalysisMetadataHolder metadataHolder; | |||
private final BranchLoaderDelegate delegate; | |||
public BranchLoader(MutableAnalysisMetadataHolder metadataHolder) { | |||
this(metadataHolder, null); | |||
} | |||
public BranchLoader(MutableAnalysisMetadataHolder metadataHolder, @Nullable BranchLoaderDelegate delegate) { | |||
this.metadataHolder = metadataHolder; | |||
this.delegate = delegate; | |||
} | |||
public void load(ScannerReport.Metadata metadata) { | |||
String deprecatedBranch = trimToNull(metadata.getDeprecatedBranch()); | |||
String branchName = trimToNull(metadata.getBranchName()); | |||
if (deprecatedBranch != null && branchName != null) { | |||
throw MessageException.of("Properties sonar.branch and sonar.branch.name can't be set together"); | |||
} | |||
if (delegate != null && deprecatedBranch == null) { | |||
delegate.load(metadata); | |||
} else { | |||
metadataHolder.setBranch(new MainBranchImpl(deprecatedBranch)); | |||
} | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* 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.scanner.protocol.output.ScannerReport; | |||
@ComputeEngineSide | |||
public interface BranchLoaderDelegate { | |||
void load(ScannerReport.Metadata metadata); | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* 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); | |||
} |
@@ -72,7 +72,9 @@ public interface Component { | |||
String getUuid(); | |||
/** | |||
* Returns the component key | |||
* Returns the component key <b>as defined in database</b> | |||
* It may differ from keys listed in scanner report | |||
* when analyzing a branch. | |||
*/ | |||
String getKey(); | |||
@@ -0,0 +1,30 @@ | |||
/* | |||
* 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 javax.annotation.Nullable; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
@FunctionalInterface | |||
public interface ComponentKeyGenerator { | |||
String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir); | |||
} |
@@ -0,0 +1,204 @@ | |||
/* | |||
* 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.function.Function; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Project; | |||
import static com.google.common.base.MoreObjects.firstNonNull; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.lang.String.format; | |||
import static org.apache.commons.lang.StringUtils.trimToNull; | |||
public class ComponentTreeBuilder { | |||
private static final String DEFAULT_PROJECT_VERSION = "not provided"; | |||
private final ComponentKeyGenerator keyGenerator; | |||
/** | |||
* Will supply the UUID for any component in the tree, given it's key. | |||
* <p> | |||
* The String argument of the {@link Function#apply(Object)} method is the component's key. | |||
* </p> | |||
*/ | |||
private final Function<String, String> uuidSupplier; | |||
/** | |||
* Will supply the {@link ScannerReport.Component} of all the components in the component tree as we crawl it from the | |||
* root. | |||
* <p> | |||
* The Integer argument of the {@link Function#apply(Object)} method is the component's ref. | |||
* </p> | |||
*/ | |||
private final Function<Integer, ScannerReport.Component> scannerComponentSupplier; | |||
private final Project project; | |||
@Nullable | |||
private final SnapshotDto baseAnalysis; | |||
public ComponentTreeBuilder( | |||
ComponentKeyGenerator keyGenerator, | |||
Function<String, String> uuidSupplier, | |||
Function<Integer, ScannerReport.Component> scannerComponentSupplier, | |||
Project project, | |||
@Nullable SnapshotDto baseAnalysis) { | |||
this.keyGenerator = keyGenerator; | |||
this.uuidSupplier = uuidSupplier; | |||
this.scannerComponentSupplier = scannerComponentSupplier; | |||
this.project = project; | |||
this.baseAnalysis = baseAnalysis; | |||
} | |||
public Component buildProject(ScannerReport.Component project) { | |||
return buildComponent(project, project); | |||
} | |||
private Component[] buildChildren(ScannerReport.Component component, ScannerReport.Component parentModule) { | |||
return component.getChildRefList() | |||
.stream() | |||
.map(componentRef -> buildComponent(scannerComponentSupplier.apply(componentRef), parentModule)) | |||
.toArray(Component[]::new); | |||
} | |||
private ComponentImpl buildComponent(ScannerReport.Component component, ScannerReport.Component closestModule) { | |||
switch (component.getType()) { | |||
case PROJECT: | |||
String projectKey = keyGenerator.generateKey(component, null); | |||
String uuid = uuidSupplier.apply(projectKey); | |||
return ComponentImpl.builder(Component.Type.PROJECT) | |||
.setUuid(uuid) | |||
.setKey(projectKey) | |||
.setName(nameOfProject(component)) | |||
.setStatus(convertStatus(component.getStatus())) | |||
.setDescription(trimToNull(component.getDescription())) | |||
.setReportAttributes(createAttributesBuilder(component) | |||
.setVersion(createProjectVersion(component)) | |||
.build()) | |||
.addChildren(buildChildren(component, component)) | |||
.build(); | |||
case MODULE: | |||
String moduleKey = keyGenerator.generateKey(component, null); | |||
return ComponentImpl.builder(Component.Type.MODULE) | |||
.setUuid(uuidSupplier.apply(moduleKey)) | |||
.setKey(moduleKey) | |||
.setName(nameOfOthers(component, moduleKey)) | |||
.setStatus(convertStatus(component.getStatus())) | |||
.setDescription(trimToNull(component.getDescription())) | |||
.setReportAttributes(createAttributesBuilder(component).build()) | |||
.addChildren(buildChildren(component, component)) | |||
.build(); | |||
case DIRECTORY: | |||
case FILE: | |||
String key = keyGenerator.generateKey(closestModule, component); | |||
return ComponentImpl.builder(convertDirOrFileType(component.getType())) | |||
.setUuid(uuidSupplier.apply(key)) | |||
.setKey(key) | |||
.setName(nameOfOthers(component, key)) | |||
.setStatus(convertStatus(component.getStatus())) | |||
.setDescription(trimToNull(component.getDescription())) | |||
.setReportAttributes(createAttributesBuilder(component).build()) | |||
.setFileAttributes(createFileAttributes(component)) | |||
.addChildren(buildChildren(component, closestModule)) | |||
.build(); | |||
default: | |||
throw new IllegalArgumentException(format("Unsupported component type '%s'", component.getType())); | |||
} | |||
} | |||
private static Component.Status convertStatus(FileStatus status) { | |||
switch(status) { | |||
case ADDED: | |||
return Component.Status.ADDED; | |||
case SAME: | |||
return Component.Status.SAME; | |||
case CHANGED: | |||
return Component.Status.CHANGED; | |||
case UNAVAILABLE: | |||
return Component.Status.UNAVAILABLE; | |||
case UNRECOGNIZED: | |||
default: | |||
throw new IllegalArgumentException("Unsupported ComponentType value " + status); | |||
} | |||
} | |||
private String nameOfProject(ScannerReport.Component component) { | |||
String name = trimToNull(component.getName()); | |||
if (name != null) { | |||
return name; | |||
} | |||
return project.getName(); | |||
} | |||
private static String nameOfOthers(ScannerReport.Component reportComponent, String defaultName) { | |||
String name = trimToNull(reportComponent.getName()); | |||
return name == null ? defaultName : name; | |||
} | |||
private String createProjectVersion(ScannerReport.Component component) { | |||
String version = trimToNull(component.getVersion()); | |||
if (version != null) { | |||
return version; | |||
} | |||
if (baseAnalysis != null) { | |||
return firstNonNull(baseAnalysis.getVersion(), DEFAULT_PROJECT_VERSION); | |||
} | |||
return DEFAULT_PROJECT_VERSION; | |||
} | |||
private static ReportAttributes.Builder createAttributesBuilder(ScannerReport.Component component) { | |||
return ReportAttributes.newBuilder(component.getRef()) | |||
.setVersion(trimToNull(component.getVersion())) | |||
.setPath(trimToNull(component.getPath())); | |||
} | |||
@CheckForNull | |||
private static FileAttributes createFileAttributes(ScannerReport.Component component) { | |||
if (component.getType() != ScannerReport.Component.ComponentType.FILE) { | |||
return null; | |||
} | |||
checkArgument(component.getLines() > 0, "File '%s' has no line", component.getPath()); | |||
return new FileAttributes( | |||
component.getIsTest(), | |||
trimToNull(component.getLanguage()), | |||
component.getLines()); | |||
} | |||
private static Component.Type convertDirOrFileType(ScannerReport.Component.ComponentType type) { | |||
switch (type) { | |||
case DIRECTORY: | |||
return Component.Type.DIRECTORY; | |||
case FILE: | |||
return Component.Type.FILE; | |||
default: | |||
throw new IllegalArgumentException("Unsupported ComponentType value " + type); | |||
} | |||
} | |||
} |
@@ -27,23 +27,21 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
public class UuidFactory { | |||
public class ComponentUuidFactory { | |||
private final Map<String, String> uuidsByKey = new HashMap<>(); | |||
public UuidFactory(DbClient dbClient, String rootKey) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
List<ComponentDto> components = dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, rootKey); | |||
for (ComponentDto componentDto : components) { | |||
uuidsByKey.put(componentDto.getDbKey(), componentDto.uuid()); | |||
} | |||
public ComponentUuidFactory(DbClient dbClient, DbSession dbSession, String rootKey) { | |||
List<ComponentDto> components = dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, rootKey); | |||
for (ComponentDto dto : components) { | |||
uuidsByKey.put(dto.getDbKey(), dto.uuid()); | |||
} | |||
} | |||
/** | |||
* Get UUID from database if it exists, else generate a new one | |||
* Get UUID from database if it exists, otherwise generate a new one. | |||
*/ | |||
public String getOrCreateForKey(String key) { | |||
String uuid = uuidsByKey.get(key); | |||
return (uuid == null) ? Uuids.create() : uuid; | |||
return uuidsByKey.computeIfAbsent(key, k -> Uuids.create()); | |||
} | |||
} |
@@ -21,12 +21,8 @@ package org.sonar.server.computation.task.projectanalysis.component; | |||
import org.sonar.api.config.Configuration; | |||
/** | |||
* Repository of component settings. | |||
*/ | |||
public interface ConfigurationRepository { | |||
/** | |||
* Returns the configuration for the specified Component. | |||
*/ | |||
Configuration getConfiguration(Component component); | |||
Configuration getConfiguration(); | |||
} |
@@ -19,38 +19,28 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.component; | |||
import java.util.Collection; | |||
import java.util.Map; | |||
import com.google.common.base.Supplier; | |||
import com.google.common.base.Suppliers; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.ce.queue.CeTask; | |||
import org.sonar.ce.settings.ProjectConfigurationFactory; | |||
import org.sonar.server.util.cache.CacheLoader; | |||
import org.sonar.server.util.cache.MemoryCache; | |||
/** | |||
* Repository of component settings implementation based on a memory cache. | |||
*/ | |||
public class ConfigurationRepositoryImpl implements ConfigurationRepository { | |||
private final ProjectConfigurationFactory projectConfigurationFactory; | |||
private final MemoryCache<String, Configuration> cache = new MemoryCache<>(new CacheLoader<String, Configuration>() { | |||
@Override | |||
public Configuration load(String key) { | |||
return projectConfigurationFactory.newProjectConfiguration(key); | |||
} | |||
private final Supplier<Configuration> configuration; | |||
@Override | |||
public Map<String, Configuration> loadAll(Collection<? extends String> keys) { | |||
throw new UnsupportedOperationException("loadAll is not supported"); | |||
} | |||
}); | |||
public ConfigurationRepositoryImpl(ProjectConfigurationFactory projectSettingsFactory) { | |||
this.projectConfigurationFactory = projectSettingsFactory; | |||
public ConfigurationRepositoryImpl(CeTask ceTask, ProjectConfigurationFactory f) { | |||
// project key is loaded from task because | |||
// analysisMetadataHolder.getProject() may be not set yet | |||
// when the first ComputationSteps are executed. | |||
this.configuration = Suppliers.memoize(() -> f.newProjectConfiguration(ceTask.getComponentKey())); | |||
} | |||
@Override | |||
public Configuration getConfiguration(Component component) { | |||
return cache.get(component.getKey()); | |||
public Configuration getConfiguration() { | |||
return configuration.get(); | |||
} | |||
} |
@@ -0,0 +1,82 @@ | |||
/* | |||
* 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.Optional; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | |||
import static java.lang.String.format; | |||
import static org.apache.commons.lang.StringUtils.isEmpty; | |||
import static org.apache.commons.lang.StringUtils.trimToNull; | |||
/** | |||
* The default (and legacy) implementation of {@link Branch}. It is used | |||
* when scanner is configured with parameter "sonar.branch". | |||
* A legacy branch is implemented as a fork of the project, so any branch | |||
* is considered as "main". | |||
*/ | |||
public class MainBranchImpl implements Branch { | |||
@Nullable | |||
private final String branchName; | |||
public MainBranchImpl(@Nullable String name) { | |||
this.branchName = name; | |||
if (name != null && !ComponentKeys.isValidBranch(name)) { | |||
throw MessageException.of(format("\"%s\" is not a valid branch name. " | |||
+ "Allowed characters are alphanumeric, '-', '_', '.' and '/'.", name)); | |||
} | |||
} | |||
@Override | |||
public BranchType getType() { | |||
return BranchType.LONG; | |||
} | |||
@Override | |||
public boolean isMain() { | |||
return true; | |||
} | |||
@Override | |||
public Optional<String> getName() { | |||
return Optional.ofNullable(branchName); | |||
} | |||
@Override | |||
public boolean supportsCrossProjectCpd() { | |||
// only on regular project, not on branches | |||
return branchName == null; | |||
} | |||
@Override | |||
public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { | |||
String moduleWithBranch = ComponentKeys.createKey(module.getKey(), branchName); | |||
if (fileOrDir == null || isEmpty(fileOrDir.getPath())) { | |||
return moduleWithBranch; | |||
} | |||
return ComponentKeys.createEffectiveKey(moduleWithBranch, trimToNull(fileOrDir.getPath())); | |||
} | |||
} |
@@ -24,7 +24,7 @@ package org.sonar.server.computation.task.projectanalysis.component; | |||
*/ | |||
public interface TreeRootHolder { | |||
/** | |||
* The root of the tree of Component representing the component in the current ScannerReport. | |||
* The root of the tree, for example the project or the portfolio. | |||
* | |||
* @throws IllegalStateException if the holder is empty (ie. there is no root yet) | |||
*/ |
@@ -33,9 +33,10 @@ import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetada | |||
import org.sonar.server.computation.task.projectanalysis.api.posttask.PostProjectAnalysisTasksExecutor; | |||
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.ConfigurationRepositoryImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.DbIdsRepositoryImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.DisabledComponentsHolderImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepositoryImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderImpl; | |||
import org.sonar.server.computation.task.projectanalysis.duplication.CrossProjectDuplicationStatusHolderImpl; | |||
import org.sonar.server.computation.task.projectanalysis.duplication.DuplicationMeasures; | |||
@@ -161,7 +162,6 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop | |||
ActiveRulesHolderImpl.class, | |||
MeasureComputersHolderImpl.class, | |||
MutableTaskResultHolderImpl.class, | |||
BatchReportReaderImpl.class, | |||
// repositories | |||
@@ -243,6 +243,7 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop | |||
// views | |||
ViewIndex.class, | |||
BranchLoader.class, | |||
MeasureToMeasureDto.class, | |||
// webhooks |
@@ -19,11 +19,13 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.duplication; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | |||
import static com.google.common.base.Preconditions.checkState; | |||
@@ -47,13 +49,14 @@ public class CrossProjectDuplicationStatusHolderImpl implements CrossProjectDupl | |||
@Override | |||
public void start() { | |||
boolean crossProjectDuplicationIsEnabledInReport = analysisMetadataHolder.isCrossProjectDuplicationEnabled(); | |||
boolean branchIsUsed = analysisMetadataHolder.getBranch() != null; | |||
if (crossProjectDuplicationIsEnabledInReport && !branchIsUsed) { | |||
boolean enabledInReport = analysisMetadataHolder.isCrossProjectDuplicationEnabled(); | |||
Optional<Branch> branch = analysisMetadataHolder.getBranch(); | |||
boolean supportedByBranch = !branch.isPresent() || branch.get().supportsCrossProjectCpd(); | |||
if (enabledInReport && supportedByBranch) { | |||
LOGGER.debug("Cross project duplication is enabled"); | |||
this.enabled = true; | |||
} else { | |||
if (!crossProjectDuplicationIsEnabledInReport) { | |||
if (!enabledInReport) { | |||
LOGGER.debug("Cross project duplication is disabled because it's disabled in the analysis report"); | |||
} else { | |||
LOGGER.debug("Cross project duplication is disabled because of a branch is used"); |
@@ -28,7 +28,6 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; | |||
import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE; | |||
@@ -41,16 +40,14 @@ public class DefaultAssignee { | |||
private static final Logger LOG = Loggers.get(DefaultAssignee.class); | |||
private final DbClient dbClient; | |||
private final TreeRootHolder treeRootHolder; | |||
private final ConfigurationRepository configRepository; | |||
private final AnalysisMetadataHolder analysisMetadataHolder; | |||
private boolean loaded = false; | |||
private String login = null; | |||
public DefaultAssignee(DbClient dbClient, TreeRootHolder treeRootHolder, ConfigurationRepository configRepository, AnalysisMetadataHolder analysisMetadataHolder) { | |||
public DefaultAssignee(DbClient dbClient, ConfigurationRepository configRepository, AnalysisMetadataHolder analysisMetadataHolder) { | |||
this.dbClient = dbClient; | |||
this.treeRootHolder = treeRootHolder; | |||
this.configRepository = configRepository; | |||
this.analysisMetadataHolder = analysisMetadataHolder; | |||
} | |||
@@ -60,7 +57,7 @@ public class DefaultAssignee { | |||
if (loaded) { | |||
return login; | |||
} | |||
String configuredLogin = configRepository.getConfiguration(treeRootHolder.getRoot()).get(DEFAULT_ISSUE_ASSIGNEE).orElse(null); | |||
String configuredLogin = configRepository.getConfiguration().get(DEFAULT_ISSUE_ASSIGNEE).orElse(null); | |||
if (!Strings.isNullOrEmpty(configuredLogin) && isValidLogin(configuredLogin)) { | |||
this.login = configuredLogin; | |||
} |
@@ -30,7 +30,6 @@ import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Strings.isNullOrEmpty; | |||
@@ -49,8 +48,8 @@ public class IssueFilter { | |||
private final List<IssuePattern> exclusionPatterns; | |||
private final List<IssuePattern> inclusionPatterns; | |||
public IssueFilter(TreeRootHolder treeRootHolder, ConfigurationRepository configRepository) { | |||
Configuration config = configRepository.getConfiguration(treeRootHolder.getRoot()); | |||
public IssueFilter(ConfigurationRepository configRepository) { | |||
Configuration config = configRepository.getConfiguration(); | |||
this.exclusionPatterns = loadPatterns(PATTERNS_MULTICRITERIA_EXCLUSION_KEY, config); | |||
this.inclusionPatterns = loadPatterns(PATTERNS_MULTICRITERIA_INCLUSION_KEY, config); | |||
} |
@@ -34,7 +34,7 @@ public class QualityGateServiceImpl implements QualityGateService { | |||
private final DbClient dbClient; | |||
private final MetricRepository metricRepository; | |||
public QualityGateServiceImpl(DbClient dbClient, final MetricRepository metricRepository) { | |||
public QualityGateServiceImpl(DbClient dbClient, MetricRepository metricRepository) { | |||
this.dbClient = dbClient; | |||
this.metricRepository = metricRepository; | |||
} |
@@ -19,10 +19,11 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.step; | |||
import com.google.common.base.Optional; | |||
import java.util.Objects; | |||
import java.util.function.Function; | |||
import java.util.Optional; | |||
import java.util.stream.Stream; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.SnapshotDto; | |||
@@ -32,13 +33,14 @@ import org.sonar.server.computation.task.projectanalysis.analysis.Analysis; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder; | |||
import org.sonar.server.computation.task.projectanalysis.component.ComponentKeyGenerator; | |||
import org.sonar.server.computation.task.projectanalysis.component.ComponentTreeBuilder; | |||
import org.sonar.server.computation.task.projectanalysis.component.ComponentUuidFactory; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.UuidFactory; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static org.sonar.core.component.ComponentKeys.createKey; | |||
import static org.apache.commons.lang.StringUtils.isEmpty; | |||
import static org.apache.commons.lang.StringUtils.trimToNull; | |||
/** | |||
* Populates the {@link MutableTreeRootHolder} and {@link MutableAnalysisMetadataHolder} from the {@link BatchReportReader} | |||
@@ -50,7 +52,8 @@ public class BuildComponentTreeStep implements ComputationStep { | |||
private final MutableTreeRootHolder treeRootHolder; | |||
private final MutableAnalysisMetadataHolder analysisMetadataHolder; | |||
public BuildComponentTreeStep(DbClient dbClient, BatchReportReader reportReader, MutableTreeRootHolder treeRootHolder, MutableAnalysisMetadataHolder analysisMetadataHolder) { | |||
public BuildComponentTreeStep(DbClient dbClient, BatchReportReader reportReader, | |||
MutableTreeRootHolder treeRootHolder, MutableAnalysisMetadataHolder analysisMetadataHolder) { | |||
this.dbClient = dbClient; | |||
this.reportReader = reportReader; | |||
this.treeRootHolder = treeRootHolder; | |||
@@ -64,64 +67,52 @@ public class BuildComponentTreeStep implements ComputationStep { | |||
@Override | |||
public void execute() { | |||
String branch = analysisMetadataHolder.getBranch(); | |||
ScannerReport.Component reportProject = reportReader.readComponent(analysisMetadataHolder.getRootComponentRef()); | |||
String projectKey = createKey(reportProject.getKey(), branch); | |||
UuidFactory uuidFactory = new UuidFactory(dbClient, projectKey); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
BaseAnalysisSupplier baseAnalysisSupplier = new BaseAnalysisSupplier(dbClient, dbSession); | |||
ComponentRootBuilder rootBuilder = new ComponentRootBuilder(branch, | |||
uuidFactory::getOrCreateForKey, | |||
ScannerReport.Component reportProject = reportReader.readComponent(analysisMetadataHolder.getRootComponentRef()); | |||
ComponentKeyGenerator keyGenerator = loadKeyGenerator(); | |||
// root key of branch, not necessarily of project | |||
String rootKey = keyGenerator.generateKey(reportProject, null); | |||
// loads the UUIDs from database. If they don't exist, then generate new ones | |||
ComponentUuidFactory componentUuidFactory = new ComponentUuidFactory(dbClient, dbSession, rootKey); | |||
String rootUuid = componentUuidFactory.getOrCreateForKey(rootKey); | |||
SnapshotDto baseAnalysis = loadBaseAnalysis(dbSession, rootUuid); | |||
ComponentTreeBuilder builder = new ComponentTreeBuilder(keyGenerator, | |||
componentUuidFactory::getOrCreateForKey, | |||
reportReader::readComponent, | |||
() -> dbClient.componentDao().selectByKey(dbSession, projectKey), | |||
baseAnalysisSupplier); | |||
Component project = rootBuilder.build(reportProject, projectKey); | |||
analysisMetadataHolder.getProject(), | |||
baseAnalysis); | |||
Component project = builder.buildProject(reportProject); | |||
treeRootHolder.setRoot(project); | |||
analysisMetadataHolder.setBaseAnalysis(toAnalysis(baseAnalysisSupplier.apply(project.getUuid()))); | |||
analysisMetadataHolder.setBaseAnalysis(toAnalysis(baseAnalysis)); | |||
} | |||
} | |||
/** | |||
* A supplier of the base analysis of the project (if it exists) that will cache the retrieved SnapshotDto and | |||
* implement a sanity check to ensure it is always call with the same UUID value (since it's the project's UUID, it | |||
* is unique for a whole task). | |||
*/ | |||
private static final class BaseAnalysisSupplier implements Function<String, Optional<SnapshotDto>> { | |||
private final DbClient dbClient; | |||
private final DbSession dbSession; | |||
private String projectUuid = null; | |||
private Optional<SnapshotDto> cache = null; | |||
private BaseAnalysisSupplier(DbClient dbClient, DbSession dbSession) { | |||
this.dbClient = dbClient; | |||
this.dbSession = dbSession; | |||
} | |||
private ComponentKeyGenerator loadKeyGenerator() { | |||
return Stream.of(analysisMetadataHolder.getBranch(), Optional.of(new DefaultKeyGenerator())) | |||
// TODO pull request generator will be added here | |||
.filter(Optional::isPresent) | |||
.flatMap(x -> x.map(Stream::of).orElseGet(Stream::empty)) | |||
.findFirst() | |||
.get(); | |||
} | |||
@Override | |||
public Optional<SnapshotDto> apply(String projectUuid) { | |||
if (this.cache == null) { | |||
this.cache = Optional.fromNullable( | |||
dbClient.snapshotDao().selectAnalysisByQuery( | |||
dbSession, | |||
new SnapshotQuery() | |||
.setComponentUuid(projectUuid) | |||
.setIsLast(true))); | |||
this.projectUuid = projectUuid; | |||
} else { | |||
checkState( | |||
Objects.equals(this.projectUuid, projectUuid), | |||
"BaseAnalysisSupplier called with different project uuid values. First one was %s but current one is %s", | |||
this.projectUuid, projectUuid); | |||
} | |||
return this.cache; | |||
} | |||
@CheckForNull | |||
private SnapshotDto loadBaseAnalysis(DbSession dbSession, String rootUuid) { | |||
return dbClient.snapshotDao().selectAnalysisByQuery( | |||
dbSession, | |||
new SnapshotQuery() | |||
.setComponentUuid(rootUuid) | |||
.setIsLast(true)); | |||
} | |||
@CheckForNull | |||
private static Analysis toAnalysis(Optional<SnapshotDto> snapshotDto) { | |||
if (snapshotDto.isPresent()) { | |||
SnapshotDto dto = snapshotDto.get(); | |||
private static Analysis toAnalysis(@Nullable SnapshotDto dto) { | |||
if (dto != null) { | |||
return new Analysis.Builder() | |||
.setId(dto.getId()) | |||
.setUuid(dto.getUuid()) | |||
@@ -131,4 +122,14 @@ public class BuildComponentTreeStep implements ComputationStep { | |||
return null; | |||
} | |||
private static class DefaultKeyGenerator implements ComponentKeyGenerator { | |||
@Override | |||
public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { | |||
String moduleKey = module.getKey(); | |||
if (fileOrDir == null || isEmpty(fileOrDir.getPath())) { | |||
return moduleKey; | |||
} | |||
return ComponentKeys.createEffectiveKey(moduleKey, trimToNull(fileOrDir.getPath())); | |||
} | |||
} | |||
} |
@@ -93,7 +93,7 @@ public class LoadPeriodsStep implements ComputationStep { | |||
PeriodResolver periodResolver = new PeriodResolver(dbClient, session, projectDto.get().uuid(), analysisMetadataHolder.getAnalysisDate(), | |||
isReportType ? projectOrView.getReportAttributes().getVersion() : null); | |||
Configuration config = configRepository.getConfiguration(projectOrView); | |||
Configuration config = configRepository.getConfiguration(); | |||
Period period = periodResolver.resolve(config); | |||
// SONAR-4700 Add a past snapshot only if it exists | |||
if (period != null) { |
@@ -20,22 +20,16 @@ | |||
package org.sonar.server.computation.task.projectanalysis.step; | |||
import com.google.common.base.Optional; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; | |||
import org.sonar.server.computation.task.projectanalysis.component.DepthTraversalTypeAwareCrawler; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.TypeAwareVisitorAdapter; | |||
import org.sonar.server.computation.task.projectanalysis.qualitygate.MutableQualityGateHolder; | |||
import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGate; | |||
import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateService; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; | |||
import static org.apache.commons.lang.StringUtils.isBlank; | |||
/** | |||
* This step retrieves the QualityGate and stores it in | |||
@@ -46,14 +40,12 @@ public class LoadQualityGateStep implements ComputationStep { | |||
private static final String PROPERTY_QUALITY_GATE = "sonar.qualitygate"; | |||
private final TreeRootHolder treeRootHolder; | |||
private final ConfigurationRepository configRepository; | |||
private final QualityGateService qualityGateService; | |||
private final MutableQualityGateHolder qualityGateHolder; | |||
public LoadQualityGateStep(TreeRootHolder treeRootHolder, ConfigurationRepository settingsRepository, | |||
public LoadQualityGateStep(ConfigurationRepository settingsRepository, | |||
QualityGateService qualityGateService, MutableQualityGateHolder qualityGateHolder) { | |||
this.treeRootHolder = treeRootHolder; | |||
this.configRepository = settingsRepository; | |||
this.qualityGateService = qualityGateService; | |||
this.qualityGateHolder = qualityGateHolder; | |||
@@ -61,22 +53,11 @@ public class LoadQualityGateStep implements ComputationStep { | |||
@Override | |||
public void execute() { | |||
new DepthTraversalTypeAwareCrawler( | |||
new TypeAwareVisitorAdapter(CrawlerDepthLimit.PROJECT, PRE_ORDER) { | |||
@Override | |||
public void visitProject(Component project) { | |||
executeForProject(project); | |||
} | |||
}).visit(treeRootHolder.getRoot()); | |||
} | |||
private void executeForProject(Component project) { | |||
String projectKey = project.getKey(); | |||
Configuration config = configRepository.getConfiguration(project); | |||
Configuration config = configRepository.getConfiguration(); | |||
String qualityGateSetting = config.get(PROPERTY_QUALITY_GATE).orElse(null); | |||
if (StringUtils.isBlank(qualityGateSetting)) { | |||
LOGGER.debug("No quality gate is configured for project " + projectKey); | |||
if (isBlank(qualityGateSetting)) { | |||
LOGGER.debug("No quality gate is configured"); | |||
qualityGateHolder.setNoQualityGate(); | |||
return; | |||
} |
@@ -25,13 +25,16 @@ import java.util.List; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.ce.queue.CeTask; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.core.platform.PluginInfo; | |||
import org.sonar.core.platform.PluginRepository; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.qualityprofile.QProfileDto; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
@@ -39,18 +42,18 @@ import org.sonar.scanner.protocol.output.ScannerReport.Metadata.Plugin; | |||
import org.sonar.scanner.protocol.output.ScannerReport.Metadata.QProfile; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Organization; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Project; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.ScannerPlugin; | |||
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchLoader; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import org.sonar.server.organization.BillingValidations; | |||
import org.sonar.server.organization.BillingValidations.BillingValidationsException; | |||
import org.sonar.server.organization.BillingValidationsProxy; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.qualityprofile.QualityProfile; | |||
import static java.util.stream.Collectors.toMap; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static com.google.common.collect.Maps.transformValues; | |||
import static java.lang.String.format; | |||
import static java.util.stream.Collectors.toMap; | |||
import static org.apache.commons.lang.StringUtils.isNotEmpty; | |||
import static org.sonar.core.util.stream.MoreCollectors.toList; | |||
@@ -58,50 +61,73 @@ import static org.sonar.core.util.stream.MoreCollectors.toList; | |||
* Feed analysis metadata holder with metadata from the analysis report. | |||
*/ | |||
public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { | |||
private final CeTask ceTask; | |||
private final BatchReportReader reportReader; | |||
private final MutableAnalysisMetadataHolder mutableAnalysisMetadataHolder; | |||
private final MutableAnalysisMetadataHolder analysisMetadata; | |||
private final DefaultOrganizationProvider defaultOrganizationProvider; | |||
private final DbClient dbClient; | |||
private final BillingValidations billingValidations; | |||
private final BranchLoader branchLoader; | |||
private final PluginRepository pluginRepository; | |||
public LoadReportAnalysisMetadataHolderStep(CeTask ceTask, BatchReportReader reportReader, MutableAnalysisMetadataHolder mutableAnalysisMetadataHolder, | |||
DefaultOrganizationProvider defaultOrganizationProvider, DbClient dbClient, BillingValidationsProxy billingValidations, PluginRepository pluginRepository) { | |||
public LoadReportAnalysisMetadataHolderStep(CeTask ceTask, BatchReportReader reportReader, MutableAnalysisMetadataHolder analysisMetadata, | |||
DefaultOrganizationProvider defaultOrganizationProvider, DbClient dbClient, BranchLoader branchLoader, PluginRepository pluginRepository) { | |||
this.ceTask = ceTask; | |||
this.reportReader = reportReader; | |||
this.mutableAnalysisMetadataHolder = mutableAnalysisMetadataHolder; | |||
this.analysisMetadata = analysisMetadata; | |||
this.defaultOrganizationProvider = defaultOrganizationProvider; | |||
this.dbClient = dbClient; | |||
this.billingValidations = billingValidations; | |||
this.branchLoader = branchLoader; | |||
this.pluginRepository = pluginRepository; | |||
} | |||
@Override | |||
public void execute() { | |||
ScannerReport.Metadata reportMetadata = reportReader.readMetadata(); | |||
mutableAnalysisMetadataHolder.setAnalysisDate(reportMetadata.getAnalysisDate()); | |||
checkProjectKeyConsistency(reportMetadata); | |||
loadMetadata(reportMetadata); | |||
Organization organization = loadOrganization(reportMetadata); | |||
loadProject(reportMetadata, organization); | |||
loadIncrementalMode(reportMetadata); | |||
loadQualityProfiles(reportMetadata, organization); | |||
branchLoader.load(reportMetadata); | |||
} | |||
private void loadMetadata(ScannerReport.Metadata reportMetadata) { | |||
analysisMetadata.setAnalysisDate(reportMetadata.getAnalysisDate()); | |||
analysisMetadata.setRootComponentRef(reportMetadata.getRootComponentRef()); | |||
analysisMetadata.setCrossProjectDuplicationEnabled(reportMetadata.getCrossProjectDuplicationActivated()); | |||
} | |||
private void loadProject(ScannerReport.Metadata reportMetadata, Organization organization) { | |||
String reportProjectKey = projectKeyFromReport(reportMetadata); | |||
checkProjectKeyConsistency(reportProjectKey); | |||
ComponentDto dto = toProject(reportProjectKey); | |||
if (!dto.getOrganizationUuid().equals(organization.getUuid())) { | |||
throw MessageException.of(format("Project is not in the expected organization: %s", organization.getKey())); | |||
} | |||
if (dto.getMainBranchProjectUuid() != null) { | |||
throw MessageException.of("Project should not reference a branch"); | |||
} | |||
analysisMetadata.setProject(new Project(dto.uuid(), dto.getDbKey(), dto.name())); | |||
} | |||
private Organization loadOrganization(ScannerReport.Metadata reportMetadata) { | |||
Organization organization = toOrganization(ceTask.getOrganizationUuid()); | |||
checkOrganizationKeyConsistency(reportMetadata, organization); | |||
checkOrganizationCanExecuteAnalysis(organization); | |||
checkQualityProfilesConsistency(reportMetadata, organization); | |||
analysisMetadata.setOrganization(organization); | |||
return organization; | |||
} | |||
mutableAnalysisMetadataHolder.setRootComponentRef(reportMetadata.getRootComponentRef()); | |||
mutableAnalysisMetadataHolder.setBranch(isNotEmpty(reportMetadata.getBranch()) ? reportMetadata.getBranch() : null); | |||
mutableAnalysisMetadataHolder.setCrossProjectDuplicationEnabled(reportMetadata.getCrossProjectDuplicationActivated()); | |||
mutableAnalysisMetadataHolder.setIncrementalAnalysis(reportMetadata.getIncremental()); | |||
mutableAnalysisMetadataHolder.setQProfilesByLanguage(reportMetadata.getQprofilesPerLanguage().values().stream() | |||
private void loadQualityProfiles(ScannerReport.Metadata reportMetadata, Organization organization) { | |||
checkQualityProfilesConsistency(reportMetadata, organization); | |||
analysisMetadata.setQProfilesByLanguage(reportMetadata.getQprofilesPerLanguage().values().stream() | |||
.collect(toMap( | |||
QProfile::getLanguage, | |||
qp -> new QualityProfile(qp.getKey(), qp.getName(), qp.getLanguage(), new Date(qp.getRulesUpdatedAt()))))); | |||
mutableAnalysisMetadataHolder.setScannerPluginsByKey(reportMetadata.getPluginsByKey().values().stream() | |||
analysisMetadata.setScannerPluginsByKey(reportMetadata.getPluginsByKey().values().stream() | |||
.collect(toMap( | |||
Plugin::getKey, | |||
p -> new ScannerPlugin(p.getKey(), getBasePluginKey(p), p.getUpdatedAt())))); | |||
mutableAnalysisMetadataHolder.setOrganization(organization); | |||
} | |||
@CheckForNull | |||
@@ -115,6 +141,10 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { | |||
return pluginInfo.getBasePlugin(); | |||
} | |||
private void loadIncrementalMode(ScannerReport.Metadata reportMetadata) { | |||
analysisMetadata.setIncrementalAnalysis(reportMetadata.getIncremental()); | |||
} | |||
/** | |||
* Check that the Quality profiles sent by scanner correctly relate to the project organization. | |||
*/ | |||
@@ -134,8 +164,7 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { | |||
} | |||
} | |||
private void checkProjectKeyConsistency(ScannerReport.Metadata reportMetadata) { | |||
String reportProjectKey = projectKeyFromReport(reportMetadata); | |||
private void checkProjectKeyConsistency(String reportProjectKey) { | |||
String componentKey = ceTask.getComponentKey(); | |||
if (componentKey == null) { | |||
throw MessageException.of(format( | |||
@@ -168,14 +197,6 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { | |||
} | |||
} | |||
private void checkOrganizationCanExecuteAnalysis(Organization organization) { | |||
try { | |||
billingValidations.checkOnProjectAnalysis(new BillingValidations.Organization(organization.getKey(), organization.getUuid())); | |||
} catch (BillingValidationsException e) { | |||
throw MessageException.of(e.getMessage()); | |||
} | |||
} | |||
private String resolveReportOrganizationKey(@Nullable String organizationKey) { | |||
if (reportBelongsToDefaultOrganization(organizationKey)) { | |||
return defaultOrganizationProvider.get().getKey(); | |||
@@ -190,14 +211,23 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { | |||
private Organization toOrganization(String organizationUuid) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
Optional<OrganizationDto> organizationDto = dbClient.organizationDao().selectByUuid(dbSession, organizationUuid); | |||
checkState(organizationDto.isPresent(), "Organization with uuid '{}' can't be found", organizationUuid); | |||
checkState(organizationDto.isPresent(), "Organization with uuid '%s' can't be found", organizationUuid); | |||
return Organization.from(organizationDto.get()); | |||
} | |||
} | |||
private ComponentDto toProject(String projectKey) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
com.google.common.base.Optional<ComponentDto> opt = dbClient.componentDao().selectByKey(dbSession, projectKey); | |||
checkState(opt.isPresent(), "Project with key '%s' can't be found", projectKey); | |||
return opt.get(); | |||
} | |||
} | |||
private static String projectKeyFromReport(ScannerReport.Metadata reportMetadata) { | |||
if (isNotEmpty(reportMetadata.getBranch())) { | |||
return reportMetadata.getProjectKey() + ":" + reportMetadata.getBranch(); | |||
String deprecatedBranch = reportMetadata.getDeprecatedBranch(); | |||
if (StringUtils.isNotEmpty(deprecatedBranch)) { | |||
return ComponentKeys.createKey(reportMetadata.getProjectKey(), deprecatedBranch); | |||
} | |||
return reportMetadata.getProjectKey(); | |||
} |
@@ -26,7 +26,9 @@ import java.util.Map; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import java.util.function.Function; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nonnull; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.io.FilenameUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.resources.Qualifiers; | |||
@@ -38,6 +40,8 @@ import org.sonar.db.DbSession; | |||
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.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; | |||
import org.sonar.server.computation.task.projectanalysis.component.DbIdsRepositoryImpl; | |||
@@ -50,6 +54,7 @@ import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolde | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static java.util.Optional.ofNullable; | |||
import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT; | |||
import static org.sonar.db.component.ComponentDto.UUID_PATH_SEPARATOR; | |||
import static org.sonar.db.component.ComponentDto.formatUuidPathFromParent; | |||
@@ -66,16 +71,26 @@ 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); | |||
} | |||
public PersistComponentsStep(DbClient dbClient, TreeRootHolder treeRootHolder, | |||
MutableDbIdsRepository dbIdsRepository, System2 system2, | |||
MutableDisabledComponentsHolder disabledComponentsHolder, AnalysisMetadataHolder analysisMetadataHolder, | |||
@Nullable BranchPersisterDelegate branchPersister) { | |||
this.dbClient = dbClient; | |||
this.treeRootHolder = treeRootHolder; | |||
this.dbIdsRepository = dbIdsRepository; | |||
this.system2 = system2; | |||
this.disabledComponentsHolder = disabledComponentsHolder; | |||
this.analysisMetadataHolder = analysisMetadataHolder; | |||
this.branchPersister = branchPersister; | |||
} | |||
@Override | |||
@@ -86,6 +101,8 @@ public class PersistComponentsStep implements ComputationStep { | |||
@Override | |||
public void execute() { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ofNullable(branchPersister).ifPresent(p -> p.persist(dbSession)); | |||
String projectUuid = treeRootHolder.getRoot().getUuid(); | |||
// safeguard, reset all rows to b-changed=false | |||
@@ -93,9 +110,11 @@ public class PersistComponentsStep implements ComputationStep { | |||
Map<String, ComponentDto> existingDtosByKeys = indexExistingDtosByKey(dbSession); | |||
boolean isRootPrivate = isRootPrivate(treeRootHolder.getRoot(), existingDtosByKeys); | |||
String mainBranchProjectUuid = loadProjectUuidOfMainBranch(); | |||
// Insert or update the components in database. They are removed from existingDtosByKeys | |||
// at the same time. | |||
new PathAwareCrawler<>(new PersistComponentStepsVisitor(existingDtosByKeys, dbSession)) | |||
new PathAwareCrawler<>(new PersistComponentStepsVisitor(existingDtosByKeys, dbSession, mainBranchProjectUuid)) | |||
.visit(treeRootHolder.getRoot()); | |||
disableRemainingComponents(dbSession, existingDtosByKeys.values()); | |||
@@ -105,6 +124,19 @@ public class PersistComponentsStep implements ComputationStep { | |||
} | |||
} | |||
/** | |||
* See {@link ComponentDto#mainBranchProjectUuid} : value is null on main branches, otherwise it is | |||
* the uuid of the main branch. | |||
*/ | |||
@CheckForNull | |||
private String loadProjectUuidOfMainBranch() { | |||
Optional<Branch> branch = analysisMetadataHolder.getBranch(); | |||
if (branch.isPresent() && !branch.get().isMain()) { | |||
return analysisMetadataHolder.getProject().getUuid(); | |||
} | |||
return null; | |||
} | |||
private void disableRemainingComponents(DbSession dbSession, Collection<ComponentDto> dtos) { | |||
Set<String> uuids = dtos.stream() | |||
.filter(ComponentDto::isEnabled) | |||
@@ -144,8 +176,10 @@ public class PersistComponentsStep implements ComputationStep { | |||
private final Map<String, ComponentDto> existingComponentDtosByKey; | |||
private final DbSession dbSession; | |||
@Nullable | |||
private final String mainBranchProjectUuid; | |||
public PersistComponentStepsVisitor(Map<String, ComponentDto> existingComponentDtosByKey, DbSession dbSession) { | |||
PersistComponentStepsVisitor(Map<String, ComponentDto> existingComponentDtosByKey, DbSession dbSession, @Nullable String mainBranchProjectUuid) { | |||
super( | |||
CrawlerDepthLimit.LEAVES, | |||
PRE_ORDER, | |||
@@ -169,6 +203,7 @@ public class PersistComponentsStep implements ComputationStep { | |||
}); | |||
this.existingComponentDtosByKey = existingComponentDtosByKey; | |||
this.dbSession = dbSession; | |||
this.mainBranchProjectUuid = mainBranchProjectUuid; | |||
} | |||
@Override | |||
@@ -250,141 +285,143 @@ public class PersistComponentsStep implements ComputationStep { | |||
private void addToCache(Component component, ComponentDto componentDto) { | |||
dbIdsRepository.setComponentId(component, componentDto.getId()); | |||
} | |||
} | |||
public ComponentDto createForProject(Component project) { | |||
ComponentDto res = createBase(project); | |||
public ComponentDto createForProject(Component project) { | |||
ComponentDto res = createBase(project); | |||
res.setScope(Scopes.PROJECT); | |||
res.setQualifier(Qualifiers.PROJECT); | |||
res.setName(project.getName()); | |||
res.setLongName(res.name()); | |||
res.setDescription(project.getDescription()); | |||
res.setScope(Scopes.PROJECT); | |||
res.setQualifier(Qualifiers.PROJECT); | |||
res.setName(project.getName()); | |||
res.setLongName(res.name()); | |||
res.setDescription(project.getDescription()); | |||
res.setProjectUuid(res.uuid()); | |||
res.setRootUuid(res.uuid()); | |||
res.setUuidPath(UUID_PATH_OF_ROOT); | |||
res.setModuleUuidPath(UUID_PATH_SEPARATOR + res.uuid() + UUID_PATH_SEPARATOR); | |||
res.setProjectUuid(res.uuid()); | |||
res.setRootUuid(res.uuid()); | |||
res.setUuidPath(UUID_PATH_OF_ROOT); | |||
res.setModuleUuidPath(UUID_PATH_SEPARATOR + res.uuid() + UUID_PATH_SEPARATOR); | |||
return res; | |||
} | |||
return res; | |||
} | |||
public ComponentDto createForModule(Component module, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(module); | |||
public ComponentDto createForModule(Component module, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(module); | |||
res.setScope(Scopes.PROJECT); | |||
res.setQualifier(Qualifiers.MODULE); | |||
res.setName(module.getName()); | |||
res.setLongName(res.name()); | |||
res.setPath(module.getReportAttributes().getPath()); | |||
res.setDescription(module.getDescription()); | |||
res.setScope(Scopes.PROJECT); | |||
res.setQualifier(Qualifiers.MODULE); | |||
res.setName(module.getName()); | |||
res.setLongName(res.name()); | |||
res.setPath(module.getReportAttributes().getPath()); | |||
res.setDescription(module.getDescription()); | |||
setRootAndParentModule(res, path); | |||
setRootAndParentModule(res, path); | |||
return res; | |||
} | |||
return res; | |||
} | |||
public ComponentDto createForDirectory(Component directory, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(directory); | |||
public ComponentDto createForDirectory(Component directory, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(directory); | |||
res.setScope(Scopes.DIRECTORY); | |||
res.setQualifier(Qualifiers.DIRECTORY); | |||
res.setName(directory.getReportAttributes().getPath()); | |||
res.setLongName(directory.getReportAttributes().getPath()); | |||
res.setPath(directory.getReportAttributes().getPath()); | |||
res.setScope(Scopes.DIRECTORY); | |||
res.setQualifier(Qualifiers.DIRECTORY); | |||
res.setName(directory.getReportAttributes().getPath()); | |||
res.setLongName(directory.getReportAttributes().getPath()); | |||
res.setPath(directory.getReportAttributes().getPath()); | |||
setParentModuleProperties(res, path); | |||
setParentModuleProperties(res, path); | |||
return res; | |||
} | |||
return res; | |||
} | |||
public ComponentDto createForFile(Component file, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(file); | |||
public ComponentDto createForFile(Component file, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(file); | |||
res.setScope(Scopes.FILE); | |||
res.setQualifier(getFileQualifier(file)); | |||
res.setName(FilenameUtils.getName(file.getReportAttributes().getPath())); | |||
res.setLongName(file.getReportAttributes().getPath()); | |||
res.setPath(file.getReportAttributes().getPath()); | |||
res.setLanguage(file.getFileAttributes().getLanguageKey()); | |||
res.setScope(Scopes.FILE); | |||
res.setQualifier(getFileQualifier(file)); | |||
res.setName(FilenameUtils.getName(file.getReportAttributes().getPath())); | |||
res.setLongName(file.getReportAttributes().getPath()); | |||
res.setPath(file.getReportAttributes().getPath()); | |||
res.setLanguage(file.getFileAttributes().getLanguageKey()); | |||
setParentModuleProperties(res, path); | |||
setParentModuleProperties(res, path); | |||
return res; | |||
} | |||
return res; | |||
} | |||
private ComponentDto createForView(Component view) { | |||
ComponentDto res = createBase(view); | |||
private ComponentDto createForView(Component view) { | |||
ComponentDto res = createBase(view); | |||
res.setScope(Scopes.PROJECT); | |||
res.setQualifier(view.getViewAttributes().getType().getQualifier()); | |||
res.setName(view.getName()); | |||
res.setDescription(view.getDescription()); | |||
res.setLongName(res.name()); | |||
res.setScope(Scopes.PROJECT); | |||
res.setQualifier(view.getViewAttributes().getType().getQualifier()); | |||
res.setName(view.getName()); | |||
res.setDescription(view.getDescription()); | |||
res.setLongName(res.name()); | |||
res.setProjectUuid(res.uuid()); | |||
res.setRootUuid(res.uuid()); | |||
res.setUuidPath(UUID_PATH_OF_ROOT); | |||
res.setModuleUuidPath(UUID_PATH_SEPARATOR + res.uuid() + UUID_PATH_SEPARATOR); | |||
res.setProjectUuid(res.uuid()); | |||
res.setRootUuid(res.uuid()); | |||
res.setUuidPath(UUID_PATH_OF_ROOT); | |||
res.setModuleUuidPath(UUID_PATH_SEPARATOR + res.uuid() + UUID_PATH_SEPARATOR); | |||
return res; | |||
} | |||
return res; | |||
} | |||
private ComponentDto createForSubView(Component subView, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(subView); | |||
private ComponentDto createForSubView(Component subView, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(subView); | |||
res.setScope(Scopes.PROJECT); | |||
res.setQualifier(Qualifiers.SUBVIEW); | |||
res.setName(subView.getName()); | |||
res.setDescription(subView.getDescription()); | |||
res.setLongName(res.name()); | |||
res.setCopyComponentUuid(subView.getSubViewAttributes().getOriginalViewUuid()); | |||
res.setScope(Scopes.PROJECT); | |||
res.setQualifier(Qualifiers.SUBVIEW); | |||
res.setName(subView.getName()); | |||
res.setDescription(subView.getDescription()); | |||
res.setLongName(res.name()); | |||
res.setCopyComponentUuid(subView.getSubViewAttributes().getOriginalViewUuid()); | |||
setRootAndParentModule(res, path); | |||
setRootAndParentModule(res, path); | |||
return res; | |||
} | |||
return res; | |||
} | |||
private ComponentDto createForProjectView(Component projectView, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(projectView); | |||
private ComponentDto createForProjectView(Component projectView, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto res = createBase(projectView); | |||
res.setScope(Scopes.FILE); | |||
res.setQualifier(Qualifiers.PROJECT); | |||
res.setName(projectView.getName()); | |||
res.setLongName(res.name()); | |||
res.setCopyComponentUuid(projectView.getProjectViewAttributes().getProjectUuid()); | |||
res.setScope(Scopes.FILE); | |||
res.setQualifier(Qualifiers.PROJECT); | |||
res.setName(projectView.getName()); | |||
res.setLongName(res.name()); | |||
res.setCopyComponentUuid(projectView.getProjectViewAttributes().getProjectUuid()); | |||
setRootAndParentModule(res, path); | |||
setRootAndParentModule(res, path); | |||
return res; | |||
} | |||
return res; | |||
} | |||
private ComponentDto createBase(Component component) { | |||
String componentKey = component.getKey(); | |||
String componentUuid = component.getUuid(); | |||
ComponentDto componentDto = new ComponentDto(); | |||
componentDto.setOrganizationUuid(analysisMetadataHolder.getOrganization().getUuid()); | |||
componentDto.setUuid(componentUuid); | |||
componentDto.setDbKey(componentKey); | |||
componentDto.setDeprecatedKey(componentKey); | |||
componentDto.setEnabled(true); | |||
componentDto.setCreatedAt(new Date(system2.now())); | |||
return componentDto; | |||
} | |||
private ComponentDto createBase(Component component) { | |||
String componentKey = component.getKey(); | |||
String componentUuid = component.getUuid(); | |||
/** | |||
* Applies to a node of type either MODULE, SUBVIEW, PROJECT_VIEW | |||
*/ | |||
private static void setRootAndParentModule(ComponentDto res, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto rootDto = path.root().getDto(); | |||
res.setRootUuid(rootDto.uuid()); | |||
res.setProjectUuid(rootDto.uuid()); | |||
ComponentDto parentModule = path.parent().getDto(); | |||
res.setUuidPath(formatUuidPathFromParent(parentModule)); | |||
res.setModuleUuid(parentModule.uuid()); | |||
res.setModuleUuidPath(parentModule.moduleUuidPath() + res.uuid() + UUID_PATH_SEPARATOR); | |||
ComponentDto componentDto = new ComponentDto(); | |||
componentDto.setOrganizationUuid(analysisMetadataHolder.getOrganization().getUuid()); | |||
componentDto.setUuid(componentUuid); | |||
componentDto.setDbKey(componentKey); | |||
componentDto.setDeprecatedKey(componentKey); | |||
componentDto.setMainBranchProjectUuid(mainBranchProjectUuid); | |||
componentDto.setEnabled(true); | |||
componentDto.setCreatedAt(new Date(system2.now())); | |||
return componentDto; | |||
} | |||
/** | |||
* Applies to a node of type either MODULE, SUBVIEW, PROJECT_VIEW | |||
*/ | |||
private void setRootAndParentModule(ComponentDto res, PathAwareVisitor.Path<ComponentDtoHolder> path) { | |||
ComponentDto rootDto = path.root().getDto(); | |||
res.setRootUuid(rootDto.uuid()); | |||
res.setProjectUuid(rootDto.uuid()); | |||
ComponentDto parentModule = path.parent().getDto(); | |||
res.setUuidPath(formatUuidPathFromParent(parentModule)); | |||
res.setModuleUuid(parentModule.uuid()); | |||
res.setModuleUuidPath(parentModule.moduleUuidPath() + res.uuid() + UUID_PATH_SEPARATOR); | |||
} | |||
} | |||
/** | |||
@@ -424,7 +461,7 @@ public class PersistComponentsStep implements ComputationStep { | |||
.copyFrom(target) | |||
.setBChanged(true); | |||
} | |||
return Optional.ofNullable(update); | |||
return ofNullable(update); | |||
} | |||
private static String getFileQualifier(Component component) { |
@@ -75,7 +75,7 @@ public class PurgeDatastoresStep implements ComputationStep { | |||
private void execute(Component root) { | |||
try (DbSession dbSession = dbClient.openSession(true)) { | |||
IdUuidPair idUuidPair = new IdUuidPair(dbIdsRepository.getComponentId(root), root.getUuid()); | |||
projectCleaner.purge(dbSession, idUuidPair, configRepository.getConfiguration(root), disabledComponentsHolder.getUuids()); | |||
projectCleaner.purge(dbSession, idUuidPair, configRepository.getConfiguration(), disabledComponentsHolder.getUuids()); | |||
dbSession.commit(); | |||
} | |||
} |
@@ -92,7 +92,7 @@ public class QualityGateEventsStep implements ComputationStep { | |||
} | |||
if (!baseMeasure.get().hasQualityGateStatus()) { | |||
LOGGER.warn(String.format("Previous alterStatus for project %s is not a supported value. Can not compute Quality Gate event", project.getKey())); | |||
LOGGER.warn(String.format("Previous Quality gate status for project %s is not a supported value. Can not compute Quality Gate event", project.getKey())); | |||
checkNewQualityGate(project, rawStatus); | |||
return; | |||
} |
@@ -37,6 +37,7 @@ public class ReportComputationSteps extends AbstractComputationSteps { | |||
// Builds Component tree | |||
LoadReportAnalysisMetadataHolderStep.class, | |||
VerifyBillingStep.class, | |||
BuildComponentTreeStep.class, | |||
ValidateProjectStep.class, | |||
@@ -126,7 +126,6 @@ public class ValidateProjectStep implements ComputationStep { | |||
public void visitProject(Component rawProject) { | |||
this.rawProject = rawProject; | |||
String rawProjectKey = rawProject.getKey(); | |||
validateBranch(); | |||
validateIncremental(rawProjectKey); | |||
validateNotIncrementalAndFirstAnalysis(rawProjectKey); | |||
validateBatchKey(rawProject); | |||
@@ -140,6 +139,7 @@ public class ValidateProjectStep implements ComputationStep { | |||
private void validateRootIsProject(Optional<ComponentDto> baseProject) { | |||
if (baseProject.isPresent()) { | |||
ComponentDto componentDto = baseProject.get(); | |||
// the scope field is verified for excluding the project copies generated by portfolios | |||
if (!Qualifiers.PROJECT.equals(componentDto.qualifier()) || !Scopes.PROJECT.equals(componentDto.scope())) { | |||
validationMessages.add(format("Component (uuid=%s, key=%s) is not a project", rawProject.getUuid(), rawProject.getKey())); | |||
} | |||
@@ -226,17 +226,6 @@ public class ValidateProjectStep implements ComputationStep { | |||
} | |||
} | |||
private void validateBranch() { | |||
String branch = analysisMetadataHolder.getBranch(); | |||
if (branch == null) { | |||
return; | |||
} | |||
if (!ComponentKeys.isValidBranch(branch)) { | |||
validationMessages.add(format("\"%s\" is not a valid branch name. " | |||
+ "Allowed characters are alphanumeric, '-', '_', '.' and '/'.", branch)); | |||
} | |||
} | |||
private Optional<ComponentDto> loadBaseComponent(String rawComponentKey) { | |||
ComponentDto baseComponent = baseModulesByKey.get(rawComponentKey); | |||
if (baseComponent == null) { |
@@ -0,0 +1,57 @@ | |||
/* | |||
* 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.step; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Organization; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import org.sonar.server.organization.BillingValidations; | |||
import org.sonar.server.organization.BillingValidationsProxy; | |||
/** | |||
* Verify that organization can execute analysis | |||
*/ | |||
public class VerifyBillingStep implements ComputationStep { | |||
private final AnalysisMetadataHolder analysisMetadata; | |||
private final BillingValidations billingValidations; | |||
public VerifyBillingStep(AnalysisMetadataHolder analysisMetadata, BillingValidationsProxy billingValidations) { | |||
this.analysisMetadata = analysisMetadata; | |||
this.billingValidations = billingValidations; | |||
} | |||
@Override | |||
public void execute() { | |||
try { | |||
Organization organization = analysisMetadata.getOrganization(); | |||
BillingValidations.Organization billingOrganization = new BillingValidations.Organization(organization.getKey(), organization.getUuid()); | |||
billingValidations.checkOnProjectAnalysis(billingOrganization); | |||
} catch (BillingValidations.BillingValidationsException e) { | |||
throw MessageException.of(e.getMessage()); | |||
} | |||
} | |||
@Override | |||
public String getDescription() { | |||
return "Verify billing"; | |||
} | |||
} |
@@ -30,7 +30,6 @@ import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.config.WebhookProperties; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; | |||
import static java.lang.String.format; | |||
import static org.sonar.core.config.WebhookProperties.MAX_WEBHOOKS_PER_TYPE; | |||
@@ -39,16 +38,14 @@ public class WebhookPostTask implements PostProjectAnalysisTask { | |||
private static final Logger LOGGER = Loggers.get(WebhookPostTask.class); | |||
private final TreeRootHolder rootHolder; | |||
private final ConfigurationRepository configRepository; | |||
private final WebhookPayloadFactory payloadFactory; | |||
private final WebhookCaller caller; | |||
private final WebhookDeliveryStorage deliveryStorage; | |||
public WebhookPostTask(TreeRootHolder rootHolder, ConfigurationRepository settingsRepository, WebhookPayloadFactory payloadFactory, | |||
public WebhookPostTask(ConfigurationRepository configRepository, WebhookPayloadFactory payloadFactory, | |||
WebhookCaller caller, WebhookDeliveryStorage deliveryStorage) { | |||
this.rootHolder = rootHolder; | |||
this.configRepository = settingsRepository; | |||
this.configRepository = configRepository; | |||
this.payloadFactory = payloadFactory; | |||
this.caller = caller; | |||
this.deliveryStorage = deliveryStorage; | |||
@@ -56,7 +53,7 @@ public class WebhookPostTask implements PostProjectAnalysisTask { | |||
@Override | |||
public void finished(ProjectAnalysis analysis) { | |||
Configuration config = configRepository.getConfiguration(rootHolder.getRoot()); | |||
Configuration config = configRepository.getConfiguration(); | |||
Iterable<String> webhookProps = Iterables.concat( | |||
getWebhookProperties(config, WebhookProperties.GLOBAL_KEY), |
@@ -20,12 +20,15 @@ | |||
package org.sonar.server.organization; | |||
import javax.annotation.Nullable; | |||
public class BillingValidationsProxyImpl implements BillingValidationsProxy { | |||
@Nullable | |||
private final BillingValidationsExtension billingValidationsExtension; | |||
public BillingValidationsProxyImpl(BillingValidationsExtension billingValidationsExtension) { | |||
this.billingValidationsExtension = billingValidationsExtension; | |||
public BillingValidationsProxyImpl(BillingValidationsExtension e) { | |||
this.billingValidationsExtension = e; | |||
} | |||
// Used when no plugin is providing the extension |
@@ -30,7 +30,6 @@ import javax.annotation.Nullable; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.core.permission.ProjectPermissions; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
@@ -73,14 +72,12 @@ public class PermissionTemplateService { | |||
public boolean wouldUserHaveScanPermissionWithDefaultTemplate(DbSession dbSession, | |||
String organizationUuid, @Nullable Integer userId, | |||
@Nullable String branch, String projectKey, | |||
String qualifier) { | |||
String projectKey, String qualifier) { | |||
if (userSession.hasPermission(OrganizationPermission.SCAN, organizationUuid)) { | |||
return true; | |||
} | |||
String effectiveKey = ComponentKeys.createKey(projectKey, branch); | |||
ComponentDto dto = new ComponentDto().setOrganizationUuid(organizationUuid).setDbKey(effectiveKey).setQualifier(qualifier); | |||
ComponentDto dto = new ComponentDto().setOrganizationUuid(organizationUuid).setDbKey(projectKey).setQualifier(qualifier); | |||
PermissionTemplateDto template = findTemplate(dbSession, organizationUuid, dto); | |||
if (template == null) { | |||
return false; |
@@ -0,0 +1,85 @@ | |||
/* | |||
* 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.project.ws; | |||
import java.util.Collection; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.web.UserRole; | |||
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.user.UserSession; | |||
import org.sonar.server.ws.WsUtils; | |||
import org.sonarqube.ws.WsProjects; | |||
import static org.sonar.core.util.Protobuf.setNullable; | |||
public class BranchesAction implements ProjectsWsAction { | |||
private static final String PROJECT_PARAM = "project"; | |||
private final DbClient dbClient; | |||
private final UserSession userSession; | |||
public BranchesAction(DbClient dbClient, UserSession userSession) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
} | |||
@Override | |||
public void define(WebService.NewController context) { | |||
WebService.NewAction action = context.createAction("branches") | |||
.setSince("6.6") | |||
.setHandler(this); | |||
action | |||
.createParam(PROJECT_PARAM) | |||
.setRequired(true); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
String projectKey = request.mandatoryParam(PROJECT_PARAM); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ComponentDto project = dbClient.componentDao().selectOrFailByKey(dbSession, projectKey); | |||
userSession.checkComponentPermission(UserRole.USER, project); | |||
Collection<BranchDto> branches = dbClient.branchDao().selectByComponent(dbSession, project); | |||
WsProjects.BranchesWsResponse.Builder protobufResponse = WsProjects.BranchesWsResponse.newBuilder(); | |||
branches.stream() | |||
.filter(b -> b.getKeeType().equals(BranchKeyType.BRANCH)) | |||
.forEach(b -> addToProtobuf(protobufResponse, b)); | |||
WsUtils.writeProtobuf(protobufResponse.build(), request, response); | |||
} | |||
} | |||
private static void addToProtobuf(WsProjects.BranchesWsResponse.Builder response, BranchDto branch) { | |||
WsProjects.BranchesWsResponse.Branch.Builder builder = response.addBranchesBuilder(); | |||
setNullable(branch.getKey(), builder::setName); | |||
builder.setIsMain(branch.isMain()); | |||
builder.setType(WsProjects.BranchesWsResponse.BranchType.valueOf(branch.getBranchType().name())); | |||
builder.build(); | |||
} | |||
} |
@@ -29,6 +29,7 @@ public class ProjectsWsModule extends Module { | |||
ProjectsWs.class, | |||
CreateAction.class, | |||
IndexAction.class, | |||
BranchesAction.class, | |||
BulkDeleteAction.class, | |||
DeleteAction.class, | |||
UpdateKeyAction.class, |
@@ -58,7 +58,6 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Matchers.anyInt; | |||
import static org.mockito.Matchers.anyString; | |||
import static org.mockito.Matchers.argThat; | |||
import static org.mockito.Matchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
@@ -127,9 +126,9 @@ public class ReportSubmitterTest { | |||
mockSuccessfulPrepareSubmitCall(); | |||
ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(project); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), anyString(), | |||
eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), eq(PROJECT_KEY), | |||
eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
Map<String, String> taskCharacteristics = new HashMap<>(); | |||
taskCharacteristics.put("incremental", "true"); | |||
@@ -183,9 +182,9 @@ public class ReportSubmitterTest { | |||
mockSuccessfulPrepareSubmitCall(); | |||
ComponentDto createdProject = newPrivateProjectDto(organization, PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(createdProject); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), anyInt(), anyString(), | |||
eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
when( | |||
permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), anyInt(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), eq(organization.getUuid()), any(ComponentDto.class))).thenReturn(true); | |||
underTest.submit(organization.getKey(), PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}")); | |||
@@ -214,9 +213,9 @@ public class ReportSubmitterTest { | |||
mockSuccessfulPrepareSubmitCall(); | |||
ComponentDto createdProject = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(createdProject); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), anyString(), | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), | |||
eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
.thenReturn(true); | |||
when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), eq(defaultOrganizationUuid), any(ComponentDto.class))).thenReturn(false); | |||
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}")); | |||
@@ -233,9 +232,9 @@ public class ReportSubmitterTest { | |||
mockSuccessfulPrepareSubmitCall(); | |||
ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(project); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), anyString(), | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), anyInt(), | |||
eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
.thenReturn(true); | |||
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, IOUtils.toInputStream("{binary}")); | |||
@@ -30,9 +30,9 @@ public class AnalysisImplTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
static final long ID = 10; | |||
static final String UUID = "uuid "; | |||
static final long CREATED_AT = 123456789L; | |||
private static final long ID = 10; | |||
private static final String UUID = "uuid "; | |||
private static final long CREATED_AT = 123456789L; | |||
@Test | |||
public void build_snapshot() throws Exception { |
@@ -23,6 +23,7 @@ import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.computation.task.projectanalysis.component.MainBranchImpl; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -260,36 +261,55 @@ public class AnalysisMetadataHolderImplTest { | |||
public void set_branch() { | |||
AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl(); | |||
underTest.setBranch("origin/master"); | |||
underTest.setBranch(new MainBranchImpl("master")); | |||
assertThat(underTest.getBranch()).isEqualTo("origin/master"); | |||
assertThat(underTest.getBranch().get().getName()).hasValue("master"); | |||
} | |||
@Test | |||
public void set_no_branch() { | |||
public void getBranch_throws_ISE_when_holder_is_not_initialized() { | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Branch has not been set"); | |||
new AnalysisMetadataHolderImpl().getBranch(); | |||
} | |||
@Test | |||
public void setBranch_throws_ISE_when_called_twice() { | |||
AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl(); | |||
underTest.setBranch(new MainBranchImpl("master")); | |||
underTest.setBranch(null); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Branch has already been set"); | |||
underTest.setBranch(new MainBranchImpl("master")); | |||
} | |||
@Test | |||
public void set_and_get_project() { | |||
AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl(); | |||
Project project = new Project("U", "K", "N"); | |||
underTest.setProject(project); | |||
assertThat(underTest.getBranch()).isNull(); | |||
assertThat(underTest.getProject()).isSameAs(project); | |||
} | |||
@Test | |||
public void getBranch_throws_ISE_when_holder_is_not_initialized() { | |||
public void getProject_throws_ISE_when_holder_is_not_initialized() { | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Branch has not been set"); | |||
expectedException.expectMessage("Project has not been set"); | |||
new AnalysisMetadataHolderImpl().getBranch(); | |||
new AnalysisMetadataHolderImpl().getProject(); | |||
} | |||
@Test | |||
public void setBranch_throws_ISE_when_called_twice() { | |||
public void setProject_throws_ISE_when_called_twice() { | |||
AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl(); | |||
underTest.setBranch("origin/master"); | |||
underTest.setProject(new Project("U", "K", "N")); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Branch has already been set"); | |||
underTest.setBranch("origin/master"); | |||
expectedException.expectMessage("Project has already been set"); | |||
underTest.setProject(new Project("U", "K", "N")); | |||
} | |||
@Test |
@@ -21,6 +21,7 @@ package org.sonar.server.computation.task.projectanalysis.analysis; | |||
import java.util.Date; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.junit.rules.ExternalResource; | |||
@@ -46,7 +47,9 @@ public class AnalysisMetadataHolderRule extends ExternalResource implements Muta | |||
private final InitializedProperty<Boolean> crossProjectDuplicationEnabled = new InitializedProperty<>(); | |||
private final InitializedProperty<String> branch = new InitializedProperty<>(); | |||
private final InitializedProperty<Branch> branch = new InitializedProperty<>(); | |||
private final InitializedProperty<Project> project = new InitializedProperty<>(); | |||
private final InitializedProperty<Integer> rootComponentRef = new InitializedProperty<>(); | |||
@@ -141,15 +144,27 @@ public class AnalysisMetadataHolderRule extends ExternalResource implements Muta | |||
} | |||
@Override | |||
public AnalysisMetadataHolderRule setBranch(@Nullable String branch) { | |||
public AnalysisMetadataHolderRule setBranch(@Nullable Branch branch) { | |||
this.branch.setProperty(branch); | |||
return this; | |||
} | |||
@Override | |||
public String getBranch() { | |||
public Optional<Branch> getBranch() { | |||
checkState(branch.isInitialized(), "Branch has not been set"); | |||
return branch.getProperty(); | |||
return Optional.ofNullable(branch.getProperty()); | |||
} | |||
@Override | |||
public AnalysisMetadataHolderRule setProject(Project p) { | |||
this.project.setProperty(p); | |||
return this; | |||
} | |||
@Override | |||
public Project getProject() { | |||
checkState(project.isInitialized(), "Project has not been set"); | |||
return project.getProperty(); | |||
} | |||
@Override |
@@ -20,6 +20,7 @@ | |||
package org.sonar.server.computation.task.projectanalysis.analysis; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.junit.rules.ExternalResource; | |||
@@ -35,8 +36,9 @@ public class MutableAnalysisMetadataHolderRule extends ExternalResource implemen | |||
} | |||
@Override | |||
public MutableAnalysisMetadataHolder setOrganization(Organization organization) { | |||
return delegate.setOrganization(organization); | |||
public MutableAnalysisMetadataHolderRule setOrganization(Organization organization) { | |||
delegate.setOrganization(organization); | |||
return this; | |||
} | |||
@Override | |||
@@ -98,16 +100,27 @@ public class MutableAnalysisMetadataHolderRule extends ExternalResource implemen | |||
} | |||
@Override | |||
public String getBranch() { | |||
public Optional<Branch> getBranch() { | |||
return delegate.getBranch(); | |||
} | |||
@Override | |||
public MutableAnalysisMetadataHolderRule setBranch(@Nullable String branch) { | |||
public MutableAnalysisMetadataHolderRule setBranch(Branch branch) { | |||
delegate.setBranch(branch); | |||
return this; | |||
} | |||
@Override | |||
public MutableAnalysisMetadataHolderRule setProject(@Nullable Project project) { | |||
delegate.setProject(project); | |||
return this; | |||
} | |||
@Override | |||
public Project getProject() { | |||
return delegate.getProject(); | |||
} | |||
@Override | |||
public MutableAnalysisMetadataHolderRule setRootComponentRef(int rootComponentRef) { | |||
delegate.setRootComponentRef(rootComponentRef); |
@@ -0,0 +1,65 @@ | |||
/* | |||
* 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.analysis; | |||
import org.junit.Test; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; | |||
public class ProjectTest { | |||
@Test | |||
public void test_bean() { | |||
Project project = new Project("U1", "K1", "N1"); | |||
assertThat(project.getUuid()).isEqualTo("U1"); | |||
assertThat(project.getKey()).isEqualTo("K1"); | |||
assertThat(project.getName()).isEqualTo("N1"); | |||
assertThat(project.toString()).isEqualTo("Project{uuid='U1', key='K1', name='N1'}"); | |||
} | |||
@Test | |||
public void test_equals_and_hashCode() { | |||
Project project1 = new Project("U1", "K1", "N1"); | |||
Project project1bis = new Project("U1", "K1", "N1"); | |||
Project project2 = new Project("U2", "K2", project1.getName() /* same name */); | |||
assertThat(project1.equals(project1)).isTrue(); | |||
assertThat(project1.equals(project1bis)).isTrue(); | |||
assertThat(project1.equals(project2)).isFalse(); | |||
assertThat(project1.equals("U1")).isFalse(); | |||
assertThat(project1.hashCode()).isEqualTo(project1.hashCode()); | |||
assertThat(project1.hashCode()).isEqualTo(project1bis.hashCode()); | |||
} | |||
@Test | |||
public void test_copyOf() { | |||
Component root = ReportComponent.builder(PROJECT, 1).setKey("ROOT").build(); | |||
Project project = Project.copyOf(root); | |||
assertThat(project.getUuid()).isEqualTo(root.getUuid()).isNotNull(); | |||
assertThat(project.getKey()).isEqualTo(root.getKey()).isNotNull(); | |||
assertThat(project.getName()).isEqualTo(root.getName()).isNotNull(); | |||
} | |||
} |
@@ -107,7 +107,7 @@ public class MeasureComputerContextImplTest { | |||
public void get_string_settings() throws Exception { | |||
MapSettings serverSettings = new MapSettings(); | |||
serverSettings.setProperty("prop", "value"); | |||
when(settingsRepository.getConfiguration(FILE_1)).thenReturn(serverSettings.asConfig()); | |||
when(settingsRepository.getConfiguration()).thenReturn(serverSettings.asConfig()); | |||
MeasureComputerContextImpl underTest = newContext(FILE_1_REF); | |||
assertThat(underTest.getSettings().getString("prop")).isEqualTo("value"); | |||
@@ -118,7 +118,7 @@ public class MeasureComputerContextImplTest { | |||
public void get_string_array_settings() throws Exception { | |||
MapSettings serverSettings = new MapSettings(); | |||
serverSettings.setProperty("prop", "1,3.4,8,50"); | |||
when(settingsRepository.getConfiguration(FILE_1)).thenReturn(serverSettings.asConfig()); | |||
when(settingsRepository.getConfiguration()).thenReturn(serverSettings.asConfig()); | |||
MeasureComputerContextImpl underTest = newContext(FILE_1_REF); | |||
assertThat(underTest.getSettings().getStringArray("prop")).containsExactly("1", "3.4", "8", "50"); |
@@ -0,0 +1,107 @@ | |||
/* | |||
* 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.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.MessageException; | |||
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 static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
public class BranchLoaderTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public AnalysisMetadataHolderRule metadataHolder = new AnalysisMetadataHolderRule(); | |||
@Test | |||
public void throw_ME_if_both_branch_properties_are_set() { | |||
ScannerReport.Metadata metadata = ScannerReport.Metadata.newBuilder() | |||
.setDeprecatedBranch("foo") | |||
.setBranchName("bar") | |||
.build(); | |||
expectedException.expect(MessageException.class); | |||
expectedException.expectMessage("Properties sonar.branch and sonar.branch.name can't be set together"); | |||
new BranchLoader(metadataHolder).load(metadata); | |||
} | |||
@Test | |||
public void regular_analysis_of_project_is_enabled_if_delegate_is_absent() { | |||
ScannerReport.Metadata metadata = ScannerReport.Metadata.newBuilder() | |||
.build(); | |||
new BranchLoader(metadataHolder).load(metadata); | |||
assertThat(metadataHolder.getBranch()).isPresent(); | |||
Branch branch = metadataHolder.getBranch().get(); | |||
assertThat(branch.isMain()).isTrue(); | |||
assertThat(branch.getName()).isEmpty(); | |||
} | |||
@Test | |||
public void default_support_of_branches_is_enabled_if_delegate_is_absent() { | |||
ScannerReport.Metadata metadata = ScannerReport.Metadata.newBuilder() | |||
.setDeprecatedBranch("foo") | |||
.build(); | |||
new BranchLoader(metadataHolder).load(metadata); | |||
assertThat(metadataHolder.getBranch()).isPresent(); | |||
Branch branch = metadataHolder.getBranch().get(); | |||
assertThat(branch.isMain()).isTrue(); | |||
assertThat(branch.getName()).hasValue("foo"); | |||
} | |||
@Test | |||
public void default_support_of_branches_is_enabled_if_delegate_is_present() { | |||
ScannerReport.Metadata metadata = ScannerReport.Metadata.newBuilder() | |||
.setDeprecatedBranch("foo") | |||
.build(); | |||
FakeDelegate delegate = new FakeDelegate(); | |||
new BranchLoader(metadataHolder, delegate).load(metadata); | |||
assertThat(metadataHolder.getBranch()).isPresent(); | |||
Branch branch = metadataHolder.getBranch().get(); | |||
assertThat(branch.isMain()).isTrue(); | |||
assertThat(branch.getName()).hasValue("foo"); | |||
} | |||
private class FakeDelegate implements BranchLoaderDelegate { | |||
Branch branch = mock(Branch.class); | |||
@Override | |||
public void load(ScannerReport.Metadata metadata) { | |||
metadataHolder.setBranch(branch); | |||
} | |||
} | |||
} |
@@ -29,12 +29,7 @@ import static org.sonar.server.computation.task.projectanalysis.component.Compon | |||
public class ComponentFunctionsTest { | |||
public static final int SOME_INT = new Random().nextInt(); | |||
@Test(expected = NullPointerException.class) | |||
public void toReportRef_throws_NPE_if_Component_is_null() { | |||
toReportRef().apply(null); | |||
} | |||
private static final int SOME_INT = new Random().nextInt(); | |||
@Test(expected = IllegalStateException.class) | |||
public void toReportRef_throws_ISE_if_Component_has_no_ReportAttributes() { |
@@ -1,545 +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 com.google.common.base.Optional; | |||
import com.google.common.base.Supplier; | |||
import java.util.Arrays; | |||
import java.util.EnumSet; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.function.Function; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.rules.ExternalResource; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Preconditions.checkNotNull; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.fail; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.DIRECTORY; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.MODULE; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNSET; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder.createFileAttributes; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder.createOtherReportAttributes; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentRootBuilder.createProjectReportAttributes; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class ComponentRootBuilderTest { | |||
private static final Function<String, String> SIMPLE_UUID_GENERATOR = (componentKey) -> componentKey + "_uuid"; | |||
private static final String NO_BRANCH = null; | |||
private static final String PROJECT_KEY = "this is the key"; | |||
private static final String MODULE_KEY = "module key"; | |||
private static final String DIRECTORY_PATH = "directory path"; | |||
private static final String DIRECTORY_KEY = MODULE_KEY + ":" + DIRECTORY_PATH; | |||
private static final String FILE_PATH = "file path"; | |||
private static final String FILE_KEY = MODULE_KEY + ":" + FILE_PATH; | |||
private static final ComponentDto PROJECT_DTO = new ComponentDto().setName("name in db"); | |||
private static final Supplier<Optional<ComponentDto>> NO_COMPONENT_DTO_FOR_PROJECT = Optional::absent; | |||
private static final Function<String, Optional<SnapshotDto>> NO_BASEANALYSIS = (projectUuid) -> Optional.absent(); | |||
private static final Supplier<Optional<ComponentDto>> COMPONENT_DTO_FOR_PROJECT = () -> Optional.of(PROJECT_DTO); | |||
private static final EnumSet<ScannerReport.Component.ComponentType> REPORT_TYPES = EnumSet.of( | |||
PROJECT, MODULE, DIRECTORY, FILE); | |||
private static final String PROJECT_UUID = "project uuid"; | |||
private static final String DEFAULT_VERSION = "not provided"; | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public ScannerComponentProvider scannerComponentProvider = new ScannerComponentProvider(); | |||
private ComponentRootBuilder underTest = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS); | |||
@Test | |||
public void build_throws_IAE_for_all_types_but_PROJECT_MODULE_DIRECTORY_FILE() { | |||
Arrays.stream(ScannerReport.Component.ComponentType.values()) | |||
.filter((type) -> type != UNRECOGNIZED) | |||
.filter((type) -> !REPORT_TYPES.contains(type)) | |||
.forEach( | |||
(type) -> { | |||
ScannerReport.Component component = newBuilder().setType(type).build(); | |||
try { | |||
underTest.build(component, "don't care"); | |||
fail("Should have thrown a IllegalArgumentException"); | |||
} catch (IllegalArgumentException e) { | |||
assertThat(e).hasMessage("Unsupported component type '" + type + "'"); | |||
} | |||
}); | |||
} | |||
@Test | |||
public void name_of_project_is_name_in_Scanner_Component_when_set() { | |||
String expected = "the name"; | |||
Component root = underTest.build(newBuilder().setType(PROJECT).setName(expected).build(), PROJECT_KEY); | |||
assertThat(root.getName()).isEqualTo(expected); | |||
} | |||
@Test | |||
public void name_of_project_is_name_in_Scanner_Component_when_set_even_if_there_is_a_ComponentDto() { | |||
String expected = "the name"; | |||
Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS) | |||
.build(newBuilder().setType(PROJECT).setName(expected).build(), PROJECT_KEY); | |||
assertThat(root.getName()).isEqualTo(expected); | |||
} | |||
@Test | |||
public void name_of_project_is_specified_key_when_name_is_unset_in_Scanner_Component_and_there_is_no_ComponentDto() { | |||
Component root = underTest.build(newBuilder().setType(PROJECT).build(), PROJECT_KEY); | |||
assertThat(root.getName()).isEqualTo(PROJECT_KEY); | |||
} | |||
@Test | |||
public void name_of_project_is_specified_key_when_name_is_empty_in_Scanner_Component_and_there_is_no_ComponentDto() { | |||
Component root = underTest.build(newBuilder().setType(PROJECT).setName("").build(), PROJECT_KEY); | |||
assertThat(root.getName()).isEqualTo(PROJECT_KEY); | |||
} | |||
@Test | |||
public void name_of_project_is_name_of_ComponentDto_when_name_is_unset_in_Scanner_Component_and_there_is_a_ComponentDto() { | |||
Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS) | |||
.build(newBuilder().setType(PROJECT).build(), PROJECT_KEY); | |||
assertThat(root.getName()).isEqualTo(PROJECT_DTO.name()); | |||
} | |||
@Test | |||
public void name_of_project_is_name_of_ComponentDto_when_name_is_empty_in_Scanner_Component_and_there_is_a_ComponentDto() { | |||
Component root = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS) | |||
.build(newBuilder().setType(PROJECT).setName("").build(), PROJECT_KEY); | |||
assertThat(root.getName()).isEqualTo(PROJECT_DTO.name()); | |||
} | |||
@Test | |||
public void name_of_module_directory_and_file_contains_branch_when_non_empty() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setLines(1)); | |||
String branch = "BRANCH"; | |||
ComponentRootBuilder builder = new ComponentRootBuilder(branch, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, NO_BASEANALYSIS); | |||
Component root = builder.build(project, PROJECT_KEY); | |||
assertThat(root.getKey()).isEqualTo(PROJECT_KEY); | |||
assertThat(root.getChildren()).hasSize(1); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getKey()).isEqualTo(MODULE_KEY + ":" + branch); | |||
assertThat(module.getChildren()).hasSize(1); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getKey()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH); | |||
assertThat(directory.getChildren()).hasSize(1); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getKey()).isEqualTo(module.getKey() + ":" + FILE_PATH); | |||
assertThat(file.getChildren()).isEmpty(); | |||
} | |||
@Test | |||
public void name_of_module_directory_and_file_is_key_of_Scanner_Component_when_name_is_unset() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setLines(1)); | |||
Component root = underTest.build(project, PROJECT_KEY); | |||
assertThat(root.getKey()).isEqualTo(PROJECT_KEY); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getName()).isEqualTo(MODULE_KEY); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getName()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getName()).isEqualTo(module.getKey() + ":" + FILE_PATH); | |||
} | |||
@Test | |||
public void name_of_module_directory_and_file_is_key_of_Scanner_Component_when_name_is_empty() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setName("").addChildRef(2).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).setName("").addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).setName("").addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setName("").setLines(1)); | |||
Component root = underTest.build(project, PROJECT_KEY); | |||
assertThat(root.getKey()).isEqualTo(PROJECT_KEY); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getName()).isEqualTo(MODULE_KEY); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getName()).isEqualTo(module.getKey() + ":" + DIRECTORY_PATH); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getName()).isEqualTo(module.getKey() + ":" + FILE_PATH); | |||
} | |||
@Test | |||
public void name_of_module_directory_and_files_includes_name_of_closest_module() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(11).addChildRef(21).addChildRef(31).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(11).setType(MODULE).setKey("module 1").addChildRef(12).addChildRef(22).addChildRef(32)); | |||
scannerComponentProvider.add(newBuilder().setRef(12).setType(MODULE).setKey("module 2").addChildRef(13).addChildRef(23).addChildRef(33)); | |||
scannerComponentProvider.add(newBuilder().setRef(13).setType(MODULE).setKey("module 3").addChildRef(24).addChildRef(34)); | |||
scannerComponentProvider.add(newBuilder().setRef(21).setType(DIRECTORY).setPath("directory in project").addChildRef(35)); | |||
scannerComponentProvider.add(newBuilder().setRef(22).setType(DIRECTORY).setPath("directory in module 1").addChildRef(36)); | |||
scannerComponentProvider.add(newBuilder().setRef(23).setType(DIRECTORY).setPath("directory in module 2").addChildRef(37)); | |||
scannerComponentProvider.add(newBuilder().setRef(24).setType(DIRECTORY).setPath("directory in module 3").addChildRef(38)); | |||
scannerComponentProvider.add(newBuilder().setRef(31).setType(FILE).setPath("file in project").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(32).setType(FILE).setPath("file in module 1").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(33).setType(FILE).setPath("file in module 2").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(34).setType(FILE).setPath("file in module 3").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(35).setType(FILE).setPath("file in directory in project").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(36).setType(FILE).setPath("file in directory in module 1").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(37).setType(FILE).setPath("file in directory in module 2").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(38).setType(FILE).setPath("file in directory in module 3").setLines(1)); | |||
Component root = underTest.build(project, PROJECT_KEY); | |||
Map<Integer, Component> componentsByRef = indexComponentByRef(root); | |||
assertThat(componentsByRef.get(11).getKey()).isEqualTo("module 1"); | |||
assertThat(componentsByRef.get(12).getKey()).isEqualTo("module 2"); | |||
assertThat(componentsByRef.get(13).getKey()).isEqualTo("module 3"); | |||
assertThat(componentsByRef.get(21).getKey()).startsWith(PROJECT_KEY + ":"); | |||
assertThat(componentsByRef.get(22).getKey()).startsWith("module 1" + ":"); | |||
assertThat(componentsByRef.get(23).getKey()).startsWith("module 2" + ":"); | |||
assertThat(componentsByRef.get(24).getKey()).startsWith("module 3" + ":"); | |||
assertThat(componentsByRef.get(31).getKey()).startsWith(PROJECT_KEY + ":"); | |||
assertThat(componentsByRef.get(32).getKey()).startsWith("module 1" + ":"); | |||
assertThat(componentsByRef.get(33).getKey()).startsWith("module 2" + ":"); | |||
assertThat(componentsByRef.get(34).getKey()).startsWith("module 3" + ":"); | |||
assertThat(componentsByRef.get(35).getKey()).startsWith(PROJECT_KEY + ":"); | |||
assertThat(componentsByRef.get(36).getKey()).startsWith("module 1" + ":"); | |||
assertThat(componentsByRef.get(37).getKey()).startsWith("module 2" + ":"); | |||
assertThat(componentsByRef.get(38).getKey()).startsWith("module 3" + ":"); | |||
} | |||
@Test | |||
public void version_of_project_is_set_to_default_value_when_unset_in_Scanner_Component_and_no_base_analysis() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).build(); | |||
ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, | |||
NO_COMPONENT_DTO_FOR_PROJECT, this::noBaseAnalysisButValidateProjectUuidArgument); | |||
Component root = builder.build(project, PROJECT_KEY); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo(DEFAULT_VERSION); | |||
} | |||
@Test | |||
public void version_of_project_is_set_to_default_value_when_empty_in_Scanner_Component_and_no_base_analysis() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setVersion("").build(); | |||
ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, | |||
NO_COMPONENT_DTO_FOR_PROJECT, this::noBaseAnalysisButValidateProjectUuidArgument); | |||
Component root = builder.build(project, PROJECT_KEY); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo(DEFAULT_VERSION); | |||
} | |||
private Optional<SnapshotDto> noBaseAnalysisButValidateProjectUuidArgument(String projectUuid) { | |||
assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); | |||
return Optional.absent(); | |||
} | |||
@Test | |||
public void version_of_project_is_set_to_base_analysis_version_when_unset_in_Scanner_Component_and_base_analysis_has_a_version() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).build(); | |||
String expected = "some version"; | |||
ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, | |||
NO_COMPONENT_DTO_FOR_PROJECT, | |||
(projectUuid) -> { | |||
assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); | |||
return Optional.of(new SnapshotDto().setVersion(expected)); | |||
}); | |||
Component root = builder.build(project, PROJECT_KEY); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo(expected); | |||
} | |||
@Test | |||
public void version_of_project_is_set_to_base_analysis_version_when_empty_in_Scanner_Component_and_base_analysis_has_a_version() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setVersion("").build(); | |||
String expected = "some version"; | |||
ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, | |||
(projectUuid) -> { | |||
assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); | |||
return Optional.of(new SnapshotDto().setVersion(expected)); | |||
}); | |||
Component root = builder.build(project, PROJECT_KEY); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo(expected); | |||
} | |||
@Test | |||
public void version_of_project_is_set_to_default_value_when_unset_in_Scanner_Component_and_base_analysis_has_no_version() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).build(); | |||
ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, | |||
NO_COMPONENT_DTO_FOR_PROJECT, | |||
(projectUuid) -> { | |||
assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); | |||
return Optional.of(new SnapshotDto()); | |||
}); | |||
Component root = builder.build(project, PROJECT_KEY); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo(DEFAULT_VERSION); | |||
} | |||
@Test | |||
public void version_of_project_is_set_to_default_value_when_empty_in_Scanner_Component_and_base_analysis_has_no_version() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setVersion("").build(); | |||
ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, | |||
(projectUuid) -> { | |||
assertThat(projectUuid).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); | |||
return Optional.of(new SnapshotDto()); | |||
}); | |||
Component root = builder.build(project, PROJECT_KEY); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo(DEFAULT_VERSION); | |||
} | |||
@Test | |||
public void version_of_project_is_set_to_value_in_Scanner_Component_when_set() { | |||
String expected = "some version"; | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setVersion(expected).build(); | |||
ComponentRootBuilder builder = new ComponentRootBuilder(NO_BRANCH, SIMPLE_UUID_GENERATOR, scannerComponentProvider, NO_COMPONENT_DTO_FOR_PROJECT, | |||
this::noBaseAnalysisButEnsureIsNotCalled); | |||
assertThat(builder.build(project, PROJECT_KEY).getReportAttributes().getVersion()).isEqualTo(expected); | |||
} | |||
private Optional<SnapshotDto> noBaseAnalysisButEnsureIsNotCalled(String projectUuid) { | |||
fail("baseAnalysis provider should not have been called"); | |||
return Optional.absent(); | |||
} | |||
@Test | |||
public void uuid_is_value_from_uuid_supplier_for_project_module_directory_and_file() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setKey(MODULE_KEY).addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setPath(DIRECTORY_PATH).addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setPath(FILE_PATH).setLines(1)); | |||
Component root = underTest.build(project, PROJECT_KEY); | |||
Map<Integer, Component> componentByRef = indexComponentByRef(root); | |||
assertThat(componentByRef.get(1).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(PROJECT_KEY)); | |||
assertThat(componentByRef.get(2).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(MODULE_KEY)); | |||
assertThat(componentByRef.get(3).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(DIRECTORY_KEY)); | |||
assertThat(componentByRef.get(4).getUuid()).isEqualTo(SIMPLE_UUID_GENERATOR.apply(FILE_KEY)); | |||
} | |||
@Test | |||
public void description_of_project_module_directory_and_file_is_null_when_unset_in_Scanner_Component() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).addChildRef(2).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setLines(1)); | |||
Component root = underTest.build(project, PROJECT_KEY); | |||
Map<Integer, Component> componentByRef = indexComponentByRef(root); | |||
assertThat(componentByRef.get(1).getDescription()).isNull(); | |||
assertThat(componentByRef.get(2).getDescription()).isNull(); | |||
assertThat(componentByRef.get(3).getDescription()).isNull(); | |||
assertThat(componentByRef.get(4).getDescription()).isNull(); | |||
} | |||
@Test | |||
public void description_of_project_module_directory_and_file_is_null_when_empty_in_Scanner_Component() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setDescription("").addChildRef(2).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setDescription("").addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setDescription("").addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setLines(1).setDescription("")); | |||
Component root = underTest.build(project, PROJECT_KEY); | |||
Map<Integer, Component> componentByRef = indexComponentByRef(root); | |||
assertThat(componentByRef.get(1).getDescription()).isNull(); | |||
assertThat(componentByRef.get(2).getDescription()).isNull(); | |||
assertThat(componentByRef.get(3).getDescription()).isNull(); | |||
assertThat(componentByRef.get(4).getDescription()).isNull(); | |||
} | |||
@Test | |||
public void description_of_project_module_directory_and_file_is_description_of_Scanner_Component_when_set() { | |||
ScannerReport.Component project = newBuilder().setType(PROJECT).setRef(1).setDescription("desc of project").addChildRef(2).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(2).setType(MODULE).setDescription("desc of module").addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder().setRef(3).setType(DIRECTORY).setDescription("desc of directory").addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder().setRef(4).setType(FILE).setLines(1).setDescription("desc of file")); | |||
Component root = underTest.build(project, PROJECT_KEY); | |||
Map<Integer, Component> componentByRef = indexComponentByRef(root); | |||
assertThat(componentByRef.get(1).getDescription()).isEqualTo("desc of project"); | |||
assertThat(componentByRef.get(2).getDescription()).isEqualTo("desc of module"); | |||
assertThat(componentByRef.get(3).getDescription()).isEqualTo("desc of directory"); | |||
assertThat(componentByRef.get(4).getDescription()).isEqualTo("desc of file"); | |||
} | |||
@Test | |||
public void all_types_but_UNSET_and_UNRECOGNIZED_are_converted() { | |||
Arrays.stream(ScannerReport.Component.ComponentType.values()) | |||
.filter((type) -> type != UNRECOGNIZED) | |||
.filter((type) -> type != UNSET) | |||
.forEach((type) -> assertThat(ComponentRootBuilder.convertType(type)).isEqualTo(Component.Type.valueOf(type.name()))); | |||
} | |||
@Test | |||
public void createOtherReportAttributes_takes_ref_version_and_path_from_Scanner_Component() { | |||
int ref = 123; | |||
String version = "1.0"; | |||
String path = "some path"; | |||
ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder() | |||
.setRef(ref) | |||
.setVersion(version) | |||
.setPath(path) | |||
.build()); | |||
assertThat(reportAttributes.getRef()).isEqualTo(ref); | |||
assertThat(reportAttributes.getPath()).isEqualTo(path); | |||
assertThat(reportAttributes.getVersion()).isEqualTo(version); | |||
} | |||
@Test | |||
public void createOtherReportAttributes_sets_null_version_when_unset_in_Scanner_Component() { | |||
ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder().build()); | |||
assertThat(reportAttributes.getVersion()).isNull(); | |||
} | |||
@Test | |||
public void createOtherReportAttributes_sets_null_version_when_empty_in_Scanner_Component() { | |||
ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder().setVersion("").build()); | |||
assertThat(reportAttributes.getVersion()).isNull(); | |||
} | |||
@Test | |||
public void createOtherReportAttributes_sets_null_path_when_unset_in_Scanner_Component() { | |||
ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder().build()); | |||
assertThat(reportAttributes.getPath()).isNull(); | |||
} | |||
@Test | |||
public void createOtherReportAttributes_sets_null_path_when_empty_in_Scanner_Component() { | |||
ReportAttributes reportAttributes = createOtherReportAttributes(newBuilder().setPath("").build()); | |||
assertThat(reportAttributes.getPath()).isNull(); | |||
} | |||
@Test | |||
public void createProjectReportAttributes_sets_null_path_when_unset_in_Scanner_Component() { | |||
ReportAttributes reportAttributes = createProjectReportAttributes(newBuilder().build(), PROJECT_UUID, NO_BASEANALYSIS); | |||
assertThat(reportAttributes.getPath()).isNull(); | |||
} | |||
@Test | |||
public void createProjectReportAttributes_sets_null_path_when_empty_in_Scanner_Component() { | |||
ReportAttributes reportAttributes = createProjectReportAttributes(newBuilder().setPath("").build(), PROJECT_UUID, NO_BASEANALYSIS); | |||
assertThat(reportAttributes.getPath()).isNull(); | |||
} | |||
@Test | |||
public void createFileAttributes_returns_null_when_type_is_not_FILE() { | |||
Arrays.stream(ScannerReport.Component.ComponentType.values()) | |||
.filter((type) -> type != UNRECOGNIZED) | |||
.filter((type) -> type != FILE) | |||
.map( | |||
(type) -> newBuilder().setType(type).build()) | |||
.forEach( | |||
(component) -> assertThat(createFileAttributes(component)).isNull()); | |||
} | |||
@Test | |||
public void createFileAttributes_sets_language_to_null_when_unset_in_Scanner_Component() { | |||
assertThat(createFileAttributes(newBuilder().setType(FILE).setLines(1).build()).getLanguageKey()).isNull(); | |||
} | |||
@Test | |||
public void createFileAttributes_sets_language_to_null_when_empty_in_Scanner_Component() { | |||
assertThat(createFileAttributes(newBuilder().setType(FILE).setLanguage("").setLines(1).build()).getLanguageKey()).isNull(); | |||
} | |||
@Test | |||
public void createFileAttributes_sets_unitTest_from_Scanner_Component() { | |||
assertThat(createFileAttributes(newBuilder().setType(FILE).setLines(1).build()).isUnitTest()).isFalse(); | |||
assertThat(createFileAttributes(newBuilder().setType(FILE).setIsTest(true).setLines(1).build()).isUnitTest()).isTrue(); | |||
} | |||
@Test | |||
public void createFileAttributes_sets_lines_in_Scanner_Component() { | |||
assertThat(createFileAttributes(newBuilder().setType(FILE).setLines(10).build()).getLines()).isEqualTo(10); | |||
} | |||
@Test | |||
public void fail_with_IAE_when_createFileAttributes_lines_is_not_set() throws Exception { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("File 'src/main/java/Main.java' has no line"); | |||
createFileAttributes(newBuilder().setType(FILE).setPath("src/main/java/Main.java").build()); | |||
} | |||
@Test | |||
public void fail_with_IAE_when_createFileAttributes_sets_lines_to_0() throws Exception { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("File 'src/main/java/Main.java' has no line"); | |||
createFileAttributes(newBuilder().setType(FILE).setPath("src/main/java/Main.java").setLines(0).build()); | |||
} | |||
@Test | |||
public void fail_with_IAE_when_createFileAttributes_sets_lines_to_less_than_0() throws Exception { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("File 'src/main/java/Main.java' has no line"); | |||
createFileAttributes(newBuilder().setType(FILE).setPath("src/main/java/Main.java").setLines(-10).build()); | |||
} | |||
private static class ScannerComponentProvider extends ExternalResource implements Function<Integer, ScannerReport.Component> { | |||
private final Map<Integer, ScannerReport.Component> components = new HashMap<>(); | |||
@Override | |||
protected void before() throws Throwable { | |||
components.clear(); | |||
} | |||
@Override | |||
public ScannerReport.Component apply(Integer componentRef) { | |||
return checkNotNull(components.get(componentRef), "No Component for componentRef %s", componentRef); | |||
} | |||
public ScannerReport.Component add(ScannerReport.Component.Builder builder) { | |||
ScannerReport.Component component = builder.build(); | |||
ScannerReport.Component existing = components.put(component.getRef(), component); | |||
checkArgument(existing == null, "Component %s already set for ref %s", existing, component.getRef()); | |||
return component; | |||
} | |||
} | |||
private static Map<Integer, Component> indexComponentByRef(Component root) { | |||
Map<Integer, Component> componentsByRef = new HashMap<>(); | |||
new DepthTraversalTypeAwareCrawler( | |||
new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, PRE_ORDER) { | |||
@Override | |||
public void visitAny(Component any) { | |||
componentsByRef.put(any.getReportAttributes().getRef(), any); | |||
} | |||
}).visit(root); | |||
return componentsByRef; | |||
} | |||
} |
@@ -0,0 +1,735 @@ | |||
/* | |||
* 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.Arrays; | |||
import java.util.EnumSet; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.function.Function; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.rules.ExternalResource; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Project; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.Assert.fail; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.DIRECTORY; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.MODULE; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class ComponentTreeBuilderTest { | |||
private static final ComponentKeyGenerator KEY_GENERATOR = (module, component) -> "generated_" | |||
+ ComponentKeys.createEffectiveKey(module.getKey(), component != null ? component.getPath() : null); | |||
private static final Function<String, String> UUID_SUPPLIER = (componentKey) -> componentKey + "_uuid"; | |||
private static final EnumSet<ScannerReport.Component.ComponentType> REPORT_TYPES = EnumSet.of(PROJECT, MODULE, DIRECTORY, FILE); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public ScannerComponentProvider scannerComponentProvider = new ScannerComponentProvider(); | |||
private Project projectInDb = new Project(UUID_SUPPLIER.apply("K1"), "K1", "theProjectName"); | |||
@Test | |||
public void build_throws_IAE_for_all_types_but_PROJECT_MODULE_DIRECTORY_FILE() { | |||
Arrays.stream(ScannerReport.Component.ComponentType.values()) | |||
.filter((type) -> type != UNRECOGNIZED) | |||
.filter((type) -> !REPORT_TYPES.contains(type)) | |||
.forEach( | |||
(type) -> { | |||
ScannerReport.Component component = newBuilder().setType(type).build(); | |||
try { | |||
call(component); | |||
fail("Should have thrown a IllegalArgumentException"); | |||
} catch (IllegalArgumentException e) { | |||
assertThat(e).hasMessage("Unsupported component type '" + type + "'"); | |||
} | |||
}); | |||
} | |||
@Test | |||
public void by_default_project_is_loaded_from_report() { | |||
String nameInReport = "the name"; | |||
String descriptionInReport = "the desc"; | |||
Component root = call(newBuilder() | |||
.setType(PROJECT) | |||
.setKey(projectInDb.getKey()) | |||
.setRef(42) | |||
.setName(nameInReport) | |||
.setDescription(descriptionInReport) | |||
.setVersion("6.5") | |||
.build()); | |||
assertThat(root.getUuid()).isEqualTo("generated_K1_uuid"); | |||
assertThat(root.getKey()).isEqualTo("generated_K1"); | |||
assertThat(root.getType()).isEqualTo(Component.Type.PROJECT); | |||
assertThat(root.getName()).isEqualTo(nameInReport); | |||
assertThat(root.getDescription()).isEqualTo(descriptionInReport); | |||
assertThat(root.getReportAttributes().getRef()).isEqualTo(42); | |||
assertThat(root.getReportAttributes().getPath()).isNull(); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo("6.5"); | |||
assertThatFileAttributesAreNotSet(root); | |||
} | |||
@Test | |||
public void project_name_is_loaded_from_db_if_absent_from_report() { | |||
Component root = call(newBuilder() | |||
.setType(PROJECT) | |||
.build()); | |||
assertThat(root.getName()).isEqualTo(projectInDb.getName()); | |||
} | |||
@Test | |||
public void project_version_is_loaded_from_db_if_absent_from_report() { | |||
SnapshotDto baseAnalysis = new SnapshotDto().setVersion("6.5"); | |||
Component root = call(newBuilder() | |||
.setType(PROJECT) | |||
.build(), baseAnalysis); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo("6.5"); | |||
} | |||
@Test | |||
public void project_version_is_loaded_from_db_if_empty_report() { | |||
SnapshotDto baseAnalysis = new SnapshotDto().setVersion("6.5"); | |||
Component root = call(newBuilder() | |||
.setType(PROJECT) | |||
.setVersion("") | |||
.build(), baseAnalysis); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo("6.5"); | |||
} | |||
@Test | |||
public void project_version_is_hardcoded_if_absent_from_report_and_db() { | |||
Component root = call(newBuilder() | |||
.setType(PROJECT) | |||
.build()); | |||
assertThat(root.getReportAttributes().getVersion()).isEqualTo("not provided"); | |||
} | |||
@Test | |||
public void project_description_is_null_if_absent_from_report() { | |||
Component root = call(newBuilder() | |||
.setType(PROJECT) | |||
.build()); | |||
assertThat(root.getDescription()).isNull(); | |||
} | |||
@Test | |||
public void keys_of_module_directory_and_file_are_generated() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setKey(projectInDb.getKey()) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.setKey("M") | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
assertThat(root.getKey()).isEqualTo("generated_" + projectInDb.getKey()); | |||
assertThat(root.getChildren()).hasSize(1); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getKey()).isEqualTo("generated_M"); | |||
assertThat(module.getChildren()).hasSize(1); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getKey()).isEqualTo("generated_M:src/js"); | |||
assertThat(directory.getChildren()).hasSize(1); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getKey()).isEqualTo("generated_M:src/js/Foo.js"); | |||
assertThat(file.getChildren()).isEmpty(); | |||
} | |||
@Test | |||
public void names_of_module_directory_and_file_are_keys_if_names_are_absent_from_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setKey(projectInDb.getKey()) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.setKey("M") | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getName()).isEqualTo("generated_M"); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getName()).isEqualTo("generated_M:src/js"); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getName()).isEqualTo("generated_M:src/js/Foo.js"); | |||
} | |||
@Test | |||
public void names_of_module_directory_and_file_are_keys_if_names_are_empty_in_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setKey(projectInDb.getKey()) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.setKey("M") | |||
.setName("") | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setPath("src/js") | |||
.setName("") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setName("") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getName()).isEqualTo("generated_M"); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getName()).isEqualTo("generated_M:src/js"); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getName()).isEqualTo("generated_M:src/js/Foo.js"); | |||
} | |||
private void assertThatFileAttributesAreNotSet(Component root) { | |||
try { | |||
root.getFileAttributes(); | |||
fail(); | |||
} catch (IllegalStateException e) { | |||
assertThat(e).hasMessage("Only component of type FILE have a FileAttributes object"); | |||
} | |||
} | |||
@Test | |||
public void name_of_module_directory_and_files_includes_name_of_closest_module() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setKey("project 1") | |||
.setRef(1) | |||
.addChildRef(11).addChildRef(21).addChildRef(31).build(); | |||
scannerComponentProvider.add(newBuilder().setRef(11).setType(MODULE).setKey("module 1").addChildRef(12).addChildRef(22).addChildRef(32)); | |||
scannerComponentProvider.add(newBuilder().setRef(12).setType(MODULE).setKey("module 2").addChildRef(13).addChildRef(23).addChildRef(33)); | |||
scannerComponentProvider.add(newBuilder().setRef(13).setType(MODULE).setKey("module 3").addChildRef(24).addChildRef(34)); | |||
scannerComponentProvider.add(newBuilder().setRef(21).setType(DIRECTORY).setPath("directory in project").addChildRef(35)); | |||
scannerComponentProvider.add(newBuilder().setRef(22).setType(DIRECTORY).setPath("directory in module 1").addChildRef(36)); | |||
scannerComponentProvider.add(newBuilder().setRef(23).setType(DIRECTORY).setPath("directory in module 2").addChildRef(37)); | |||
scannerComponentProvider.add(newBuilder().setRef(24).setType(DIRECTORY).setPath("directory in module 3").addChildRef(38)); | |||
scannerComponentProvider.add(newBuilder().setRef(31).setType(FILE).setPath("file in project").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(32).setType(FILE).setPath("file in module 1").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(33).setType(FILE).setPath("file in module 2").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(34).setType(FILE).setPath("file in module 3").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(35).setType(FILE).setPath("file in directory in project").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(36).setType(FILE).setPath("file in directory in module 1").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(37).setType(FILE).setPath("file in directory in module 2").setLines(1)); | |||
scannerComponentProvider.add(newBuilder().setRef(38).setType(FILE).setPath("file in directory in module 3").setLines(1)); | |||
Component root = call(project); | |||
Map<Integer, Component> componentsByRef = indexComponentByRef(root); | |||
assertThat(componentsByRef.get(11).getKey()).isEqualTo("generated_module 1"); | |||
assertThat(componentsByRef.get(12).getKey()).isEqualTo("generated_module 2"); | |||
assertThat(componentsByRef.get(13).getKey()).isEqualTo("generated_module 3"); | |||
assertThat(componentsByRef.get(21).getKey()).startsWith("generated_project 1:"); | |||
assertThat(componentsByRef.get(22).getKey()).startsWith("generated_module 1:"); | |||
assertThat(componentsByRef.get(23).getKey()).startsWith("generated_module 2:"); | |||
assertThat(componentsByRef.get(24).getKey()).startsWith("generated_module 3:"); | |||
assertThat(componentsByRef.get(31).getKey()).startsWith("generated_project 1:"); | |||
assertThat(componentsByRef.get(32).getKey()).startsWith("generated_module 1:"); | |||
assertThat(componentsByRef.get(33).getKey()).startsWith("generated_module 2:"); | |||
assertThat(componentsByRef.get(34).getKey()).startsWith("generated_module 3:"); | |||
assertThat(componentsByRef.get(35).getKey()).startsWith("generated_project 1:"); | |||
assertThat(componentsByRef.get(36).getKey()).startsWith("generated_module 1:"); | |||
assertThat(componentsByRef.get(37).getKey()).startsWith("generated_module 2:"); | |||
assertThat(componentsByRef.get(38).getKey()).startsWith("generated_module 3:"); | |||
} | |||
@Test | |||
public void uuids_are_provided_by_supplier() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setKey("c1") | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.setKey("c2") | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
assertThat(root.getUuid()).isEqualTo("generated_c1_uuid"); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getUuid()).isEqualTo("generated_c2_uuid"); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getUuid()).isEqualTo("generated_c2:src/js_uuid"); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getUuid()).isEqualTo("generated_c2:src/js/Foo.js_uuid"); | |||
} | |||
@Test | |||
public void descriptions_of_module_directory_and_file_are_null_if_absent_from_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getDescription()).isNull(); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getDescription()).isNull(); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getDescription()).isNull(); | |||
} | |||
@Test | |||
public void descriptions_of_module_directory_and_file_are_null_if_empty_in_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.setDescription("") | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.setDescription("") | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setDescription("") | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setDescription("") | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getDescription()).isNull(); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getDescription()).isNull(); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getDescription()).isNull(); | |||
} | |||
@Test | |||
public void descriptions_of_module_directory_and_file_are_set_from_report_if_present() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.setDescription("b") | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setDescription("c") | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setDescription("d") | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getDescription()).isEqualTo("b"); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getDescription()).isEqualTo("c"); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getDescription()).isEqualTo("d"); | |||
} | |||
@Test | |||
public void versions_of_module_directory_and_file_are_set_from_report_if_present() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.setVersion("v1") | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setVersion("v2") | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setVersion("v3") | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getReportAttributes().getVersion()).isEqualTo("v1"); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getReportAttributes().getVersion()).isEqualTo("v2"); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getReportAttributes().getVersion()).isEqualTo("v3"); | |||
} | |||
@Test | |||
public void versions_of_module_directory_and_file_are_null_if_absent_from_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getReportAttributes().getVersion()).isNull(); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getReportAttributes().getVersion()).isNull(); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getReportAttributes().getVersion()).isNull(); | |||
} | |||
@Test | |||
public void versions_of_module_directory_and_file_are_null_if_empty_in_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(MODULE) | |||
.setVersion("") | |||
.addChildRef(3)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(3) | |||
.setType(DIRECTORY) | |||
.setVersion("") | |||
.setPath("src/js") | |||
.addChildRef(4)); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(4) | |||
.setType(FILE) | |||
.setVersion("") | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component module = root.getChildren().iterator().next(); | |||
assertThat(module.getReportAttributes().getVersion()).isNull(); | |||
Component directory = module.getChildren().iterator().next(); | |||
assertThat(directory.getReportAttributes().getVersion()).isNull(); | |||
Component file = directory.getChildren().iterator().next(); | |||
assertThat(file.getReportAttributes().getVersion()).isNull(); | |||
} | |||
@Test | |||
public void only_nb_of_lines_is_mandatory_on_file_attributes() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(1)); | |||
Component root = call(project); | |||
Component file = root.getChildren().iterator().next(); | |||
assertThat(file.getFileAttributes().getLines()).isEqualTo(1); | |||
assertThat(file.getFileAttributes().getLanguageKey()).isNull(); | |||
assertThat(file.getFileAttributes().isUnitTest()).isFalse(); | |||
} | |||
@Test | |||
public void language_file_attributes_is_null_if_empty_in_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(1) | |||
.setLanguage("")); | |||
Component root = call(project); | |||
Component file = root.getChildren().iterator().next(); | |||
assertThat(file.getFileAttributes().getLanguageKey()).isNull(); | |||
} | |||
@Test | |||
public void file_attributes_are_fully_loaded_from_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(1) | |||
.setLanguage("js") | |||
.setIsTest(true)); | |||
Component root = call(project); | |||
Component file = root.getChildren().iterator().next(); | |||
assertThat(file.getFileAttributes().getLines()).isEqualTo(1); | |||
assertThat(file.getFileAttributes().getLanguageKey()).isEqualTo("js"); | |||
assertThat(file.getFileAttributes().isUnitTest()).isTrue(); | |||
} | |||
@Test | |||
public void throw_IAE_if_lines_is_absent_from_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js")); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("File 'src/js/Foo.js' has no line"); | |||
call(project); | |||
} | |||
@Test | |||
public void throw_IAE_if_lines_is_zero_in_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(0)); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("File 'src/js/Foo.js' has no line"); | |||
call(project); | |||
} | |||
@Test | |||
public void throw_IAE_if_lines_is_negative_in_report() { | |||
ScannerReport.Component project = newBuilder() | |||
.setType(PROJECT) | |||
.setRef(1) | |||
.addChildRef(2) | |||
.build(); | |||
scannerComponentProvider.add(newBuilder() | |||
.setRef(2) | |||
.setType(FILE) | |||
.setPath("src/js/Foo.js") | |||
.setLines(-10)); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("File 'src/js/Foo.js' has no line"); | |||
call(project); | |||
} | |||
private static class ScannerComponentProvider extends ExternalResource implements Function<Integer, ScannerReport.Component> { | |||
private final Map<Integer, ScannerReport.Component> components = new HashMap<>(); | |||
@Override | |||
protected void before() throws Throwable { | |||
components.clear(); | |||
} | |||
@Override | |||
public ScannerReport.Component apply(Integer componentRef) { | |||
return Objects.requireNonNull(components.get(componentRef), "No Component for componentRef " + componentRef); | |||
} | |||
public ScannerReport.Component add(ScannerReport.Component.Builder builder) { | |||
ScannerReport.Component component = builder.build(); | |||
ScannerReport.Component existing = components.put(component.getRef(), component); | |||
checkArgument(existing == null, "Component %s already set for ref %s", existing, component.getRef()); | |||
return component; | |||
} | |||
} | |||
private Component call(ScannerReport.Component project) { | |||
return newUnderTest(null).buildProject(project); | |||
} | |||
private Component call(ScannerReport.Component project, @Nullable SnapshotDto baseAnalysis) { | |||
return newUnderTest(baseAnalysis).buildProject(project); | |||
} | |||
private ComponentTreeBuilder newUnderTest(@Nullable SnapshotDto baseAnalysis) { | |||
return new ComponentTreeBuilder(KEY_GENERATOR, UUID_SUPPLIER, scannerComponentProvider, projectInDb, baseAnalysis); | |||
} | |||
private static Map<Integer, Component> indexComponentByRef(Component root) { | |||
Map<Integer, Component> componentsByRef = new HashMap<>(); | |||
new DepthTraversalTypeAwareCrawler( | |||
new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, PRE_ORDER) { | |||
@Override | |||
public void visitAny(Component any) { | |||
componentsByRef.put(any.getReportAttributes().getRef(), any); | |||
} | |||
}).visit(root); | |||
return componentsByRef; | |||
} | |||
} |
@@ -0,0 +1,57 @@ | |||
/* | |||
* 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.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class ComponentUuidFactoryTest { | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
@Test | |||
public void load_uuids_from_existing_components_in_db() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project)); | |||
ComponentUuidFactory underTest = new ComponentUuidFactory(db.getDbClient(), db.getSession(), project.getDbKey()); | |||
assertThat(underTest.getOrCreateForKey(project.getDbKey())).isEqualTo(project.uuid()); | |||
assertThat(underTest.getOrCreateForKey(module.getDbKey())).isEqualTo(module.uuid()); | |||
} | |||
@Test | |||
public void generate_uuid_if_it_does_not_exist_in_db() { | |||
ComponentUuidFactory underTest = new ComponentUuidFactory(db.getDbClient(), db.getSession(), "theProjectKey"); | |||
String generatedKey = underTest.getOrCreateForKey("foo"); | |||
assertThat(generatedKey).isNotEmpty(); | |||
// uuid is kept in memory for further calls with same key | |||
assertThat(underTest.getOrCreateForKey("foo")).isEqualTo(generatedKey); | |||
} | |||
} |
@@ -19,19 +19,17 @@ | |||
*/ | |||
package org.sonar.server.computation.task.projectanalysis.component; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.ce.queue.CeTask; | |||
import org.sonar.ce.settings.ProjectConfigurationFactory; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.ce.CeTaskTypes; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.property.PropertyDto; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -40,47 +38,36 @@ import static org.sonar.server.computation.task.projectanalysis.component.Compon | |||
public class ConfigurationRepositoryTest { | |||
private static final Component ROOT = ReportComponent.builder(PROJECT, 1).setKey("ROOT").build(); | |||
private static final CeTask TASK = new CeTask.Builder() | |||
.setOrganizationUuid("foo") | |||
.setUuid("bar") | |||
.setType(CeTaskTypes.REPORT) | |||
.setComponentUuid(ROOT.getUuid()) | |||
.setComponentKey(ROOT.getKey()) | |||
.build(); | |||
@Rule | |||
public final DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
public final DbTester db = DbTester.create(System2.INSTANCE); | |||
DbClient dbClient = dbTester.getDbClient(); | |||
DbSession session; | |||
MapSettings globalSettings; | |||
ConfigurationRepository underTest; | |||
@Before | |||
public void createDao() { | |||
globalSettings = new MapSettings(); | |||
session = dbClient.openSession(false); | |||
underTest = new ConfigurationRepositoryImpl(new ProjectConfigurationFactory(globalSettings, dbClient)); | |||
} | |||
@After | |||
public void tearDown() { | |||
session.close(); | |||
} | |||
private DbClient dbClient = db.getDbClient(); | |||
private MapSettings globalSettings = new MapSettings(); | |||
private ConfigurationRepository underTest = new ConfigurationRepositoryImpl(TASK, new ProjectConfigurationFactory(globalSettings, dbClient)); | |||
@Test | |||
public void get_project_settings_from_global_settings() { | |||
globalSettings.setProperty("key", "value"); | |||
Configuration config = underTest.getConfiguration(ROOT); | |||
Configuration config = underTest.getConfiguration(); | |||
assertThat(config.get("key")).hasValue("value"); | |||
} | |||
@Test | |||
public void get_project_settings_from_db() { | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()).setDbKey(ROOT.getKey()); | |||
dbClient.componentDao().insert(session, project); | |||
dbClient.propertiesDao().saveProperty(session, new PropertyDto().setResourceId(project.getId()).setKey("key").setValue("value")); | |||
session.commit(); | |||
ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey(ROOT.getKey())); | |||
insertProjectProperty(project, "key", "value"); | |||
Configuration config = underTest.getConfiguration(ROOT); | |||
Configuration config = underTest.getConfiguration(); | |||
assertThat(config.get("key")).hasValue("value"); | |||
} | |||
@@ -89,10 +76,38 @@ public class ConfigurationRepositoryTest { | |||
public void call_twice_get_project_settings() { | |||
globalSettings.setProperty("key", "value"); | |||
Configuration config = underTest.getConfiguration(ROOT); | |||
Configuration config = underTest.getConfiguration(); | |||
assertThat(config.get("key")).hasValue("value"); | |||
config = underTest.getConfiguration(ROOT); | |||
config = underTest.getConfiguration(); | |||
assertThat(config.get("key")).hasValue("value"); | |||
} | |||
@Test | |||
public void project_settings_override_global_settings() { | |||
globalSettings.setProperty("key", "value1"); | |||
ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey(ROOT.getKey())); | |||
insertProjectProperty(project, "key", "value2"); | |||
Configuration config = underTest.getConfiguration(); | |||
assertThat(config.get("key")).hasValue("value2"); | |||
} | |||
@Test | |||
public void project_settings_are_cached_to_avoid_db_access() { | |||
ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey(ROOT.getKey())); | |||
insertProjectProperty(project, "key", "value"); | |||
Configuration config = underTest.getConfiguration(); | |||
assertThat(config.get("key")).hasValue("value"); | |||
db.executeUpdateSql("delete from properties"); | |||
db.commit(); | |||
assertThat(config.get("key")).hasValue("value"); | |||
} | |||
private void insertProjectProperty(ComponentDto project, String propertyKey, String propertyValue) { | |||
db.properties().insertProperties(new PropertyDto().setKey(propertyKey).setValue(propertyValue).setResourceId(project.getId())); | |||
} | |||
} |
@@ -0,0 +1,92 @@ | |||
/* | |||
* 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 javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class MainBranchImplTest { | |||
private static final ScannerReport.Component PROJECT = ScannerReport.Component.newBuilder().setType(ComponentType.PROJECT).setKey("P").build(); | |||
private static final ScannerReport.Component MODULE = ScannerReport.Component.newBuilder().setType(ComponentType.MODULE).setKey("M").build(); | |||
private static final ScannerReport.Component FILE = ScannerReport.Component.newBuilder().setType(ComponentType.FILE).setPath("src/Foo.js").build(); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Test | |||
public void throw_ME_if_name_contains_invalid_characters() { | |||
assertThatNameIsCorrect("master"); | |||
assertThatNameIsCorrect("feature/foo"); | |||
assertThatNameIsCorrect("feature_foo"); | |||
assertThatNameIsNotCorrect("feature foo"); | |||
assertThatNameIsNotCorrect("feature#foo"); | |||
} | |||
@Test | |||
public void default_branch_represents_the_project() { | |||
MainBranchImpl branch = new MainBranchImpl(null); | |||
assertThat(branch.isMain()).isTrue(); | |||
assertThat(branch.getType()).isEqualTo(BranchType.LONG); | |||
assertThat(branch.getName()).isEmpty(); | |||
assertThat(branch.supportsCrossProjectCpd()).isTrue(); | |||
assertThat(branch.generateKey(PROJECT, null)).isEqualTo("P"); | |||
assertThat(branch.generateKey(MODULE, null)).isEqualTo("M"); | |||
assertThat(branch.generateKey(MODULE, FILE)).isEqualTo("M:src/Foo.js"); | |||
} | |||
@Test | |||
public void branch_represents_a_forked_project_with_different_key() { | |||
MainBranchImpl branch = new MainBranchImpl("bar"); | |||
// not a real branch. Parameter sonar.branch forks project. | |||
assertThat(branch.isMain()).isTrue(); | |||
assertThat(branch.getType()).isEqualTo(BranchType.LONG); | |||
assertThat(branch.getName()).hasValue("bar"); | |||
assertThat(branch.supportsCrossProjectCpd()).isFalse(); | |||
assertThat(branch.generateKey(PROJECT, null)).isEqualTo("P:bar"); | |||
assertThat(branch.generateKey(MODULE, null)).isEqualTo("M:bar"); | |||
assertThat(branch.generateKey(MODULE, FILE)).isEqualTo("M:bar:src/Foo.js"); | |||
} | |||
private void assertThatNameIsCorrect(@Nullable String name) { | |||
MainBranchImpl branch = new MainBranchImpl(name); | |||
assertThat(branch.getName()).hasValue(name); | |||
} | |||
private void assertThatNameIsNotCorrect(String name) { | |||
expectedException.expect(MessageException.class); | |||
expectedException.expectMessage("\"" + name + "\" is not a valid branch name. Allowed characters are alphanumeric, '-', '_', '.' and '/'."); | |||
new MainBranchImpl(name); | |||
} | |||
} |
@@ -34,7 +34,7 @@ public class TestSettingsRepository implements ConfigurationRepository { | |||
} | |||
@Override | |||
public Configuration getConfiguration(Component component) { | |||
public Configuration getConfiguration() { | |||
return config; | |||
} | |||
} |
@@ -25,13 +25,14 @@ import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.log.LogTester; | |||
import org.sonar.api.utils.log.LoggerLevel; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
public class CrossProjectDuplicationStatusHolderImplTest { | |||
private static String BRANCH = "origin/master"; | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@Rule | |||
@@ -45,7 +46,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { | |||
public void cross_project_duplication_is_enabled_when_enabled_in_report_and_no_branch() throws Exception { | |||
analysisMetadataHolder | |||
.setCrossProjectDuplicationEnabled(true) | |||
.setBranch(null); | |||
.setBranch(newBranch(true)); | |||
underTest.start(); | |||
assertThat(underTest.isEnabled()).isTrue(); | |||
@@ -56,7 +57,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { | |||
public void cross_project_duplication_is_disabled_when_not_enabled_in_report() throws Exception { | |||
analysisMetadataHolder | |||
.setCrossProjectDuplicationEnabled(false) | |||
.setBranch(null); | |||
.setBranch(newBranch(true)); | |||
underTest.start(); | |||
assertThat(underTest.isEnabled()).isFalse(); | |||
@@ -67,7 +68,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { | |||
public void cross_project_duplication_is_disabled_when_branch_is_used() throws Exception { | |||
analysisMetadataHolder | |||
.setCrossProjectDuplicationEnabled(true) | |||
.setBranch(BRANCH); | |||
.setBranch(newBranch(false)); | |||
underTest.start(); | |||
assertThat(underTest.isEnabled()).isFalse(); | |||
@@ -78,7 +79,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { | |||
public void cross_project_duplication_is_disabled_when_not_enabled_in_report_and_when_branch_is_used() throws Exception { | |||
analysisMetadataHolder | |||
.setCrossProjectDuplicationEnabled(false) | |||
.setBranch(BRANCH); | |||
.setBranch(newBranch(false)); | |||
underTest.start(); | |||
assertThat(underTest.isEnabled()).isFalse(); | |||
@@ -89,7 +90,7 @@ public class CrossProjectDuplicationStatusHolderImplTest { | |||
public void flag_is_build_in_start() throws Exception { | |||
analysisMetadataHolder | |||
.setCrossProjectDuplicationEnabled(true) | |||
.setBranch(null); | |||
.setBranch(newBranch(true)); | |||
underTest.start(); | |||
assertThat(underTest.isEnabled()).isTrue(); | |||
@@ -105,4 +106,10 @@ public class CrossProjectDuplicationStatusHolderImplTest { | |||
underTest.isEnabled(); | |||
} | |||
private static Branch newBranch(boolean supportsCrossProjectCpd) { | |||
Branch branch = mock(Branch.class); | |||
when(branch.supportsCrossProjectCpd()).thenReturn(supportsCrossProjectCpd); | |||
return branch; | |||
} | |||
} |
@@ -31,10 +31,8 @@ import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetada | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Organization; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.TestSettingsRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ReportComponent.DUMB_PROJECT; | |||
public class DefaultAssigneeTest { | |||
@@ -44,15 +42,12 @@ public class DefaultAssigneeTest { | |||
@Rule | |||
public DbTester db = DbTester.create(); | |||
@Rule | |||
public TreeRootHolderRule rootHolder = new TreeRootHolderRule().setRoot(DUMB_PROJECT); | |||
private MapSettings settings = new MapSettings(); | |||
private ConfigurationRepository settingsRepository = new TestSettingsRepository(settings.asConfig()); | |||
private AnalysisMetadataHolderImpl analysisMetadataHolder = new AnalysisMetadataHolderImpl(); | |||
private OrganizationDto organizationDto; | |||
private DefaultAssignee underTest = new DefaultAssignee(db.getDbClient(), rootHolder, settingsRepository, analysisMetadataHolder); | |||
private DefaultAssignee underTest = new DefaultAssignee(db.getDbClient(), settingsRepository, analysisMetadataHolder); | |||
@Before | |||
public void setUp() throws Exception { |
@@ -80,7 +80,7 @@ public class IssueFilterTest { | |||
@Test | |||
public void ignore_all() throws Exception { | |||
IssueFilter underTest = newIssueFilter(newSettings(asList("*", "**"), Collections.<String>emptyList())); | |||
IssueFilter underTest = newIssueFilter(newSettings(asList("*", "**"), Collections.emptyList())); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isFalse(); | |||
assertThat(underTest.accept(ISSUE_2, COMPONENT_1)).isFalse(); | |||
@@ -89,7 +89,7 @@ public class IssueFilterTest { | |||
@Test | |||
public void ignore_some_rule_and_component() throws Exception { | |||
IssueFilter underTest = newIssueFilter(newSettings(asList("xoo:x1", "**/xoo/File1*"), Collections.<String>emptyList())); | |||
IssueFilter underTest = newIssueFilter(newSettings(asList("xoo:x1", "**/xoo/File1*"), Collections.emptyList())); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isFalse(); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_2)).isTrue(); | |||
@@ -101,7 +101,7 @@ public class IssueFilterTest { | |||
public void ignore_many_rules() throws Exception { | |||
IssueFilter underTest = newIssueFilter(newSettings( | |||
asList("xoo:x1", "**/xoo/File1*", "xoo:x2", "**/xoo/File1*"), | |||
Collections.<String>emptyList())); | |||
Collections.emptyList())); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isFalse(); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_2)).isTrue(); | |||
@@ -111,7 +111,7 @@ public class IssueFilterTest { | |||
@Test | |||
public void include_all() throws Exception { | |||
IssueFilter underTest = newIssueFilter(newSettings(Collections.<String>emptyList(), asList("*", "**"))); | |||
IssueFilter underTest = newIssueFilter(newSettings(Collections.emptyList(), asList("*", "**"))); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isTrue(); | |||
assertThat(underTest.accept(ISSUE_2, COMPONENT_1)).isTrue(); | |||
@@ -120,7 +120,7 @@ public class IssueFilterTest { | |||
@Test | |||
public void include_some_rule_and_component() throws Exception { | |||
IssueFilter underTest = newIssueFilter(newSettings(Collections.<String>emptyList(), asList("xoo:x1", "**/xoo/File1*"))); | |||
IssueFilter underTest = newIssueFilter(newSettings(Collections.emptyList(), asList("xoo:x1", "**/xoo/File1*"))); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isTrue(); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_2)).isFalse(); | |||
@@ -145,7 +145,7 @@ public class IssueFilterTest { | |||
@Test | |||
public void include_many_rules() throws Exception { | |||
IssueFilter underTest = newIssueFilter(newSettings( | |||
Collections.<String>emptyList(), | |||
Collections.emptyList(), | |||
asList("xoo:x1", "**/xoo/File1*", "xoo:x2", "**/xoo/File1*"))); | |||
assertThat(underTest.accept(ISSUE_1, COMPONENT_1)).isTrue(); | |||
@@ -169,7 +169,7 @@ public class IssueFilterTest { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("File path pattern cannot be empty. Please check 'sonar.issue.ignore.multicriteria' settings"); | |||
newIssueFilter(newSettings(asList("xoo:x1", ""), Collections.<String>emptyList())); | |||
newIssueFilter(newSettings(asList("xoo:x1", ""), Collections.emptyList())); | |||
} | |||
@Test | |||
@@ -177,12 +177,12 @@ public class IssueFilterTest { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Rule key pattern cannot be empty. Please check 'sonar.issue.enforce.multicriteria' settings"); | |||
newIssueFilter(newSettings(Collections.<String>emptyList(), asList("", "**"))); | |||
newIssueFilter(newSettings(Collections.emptyList(), asList("", "**"))); | |||
} | |||
private IssueFilter newIssueFilter(MapSettings settings) { | |||
when(settingsRepository.getConfiguration(PROJECT)).thenReturn(settings.asConfig()); | |||
return new IssueFilter(treeRootHolder, settingsRepository); | |||
when(settingsRepository.getConfiguration()).thenReturn(settings.asConfig()); | |||
return new IssueFilter(settingsRepository); | |||
} | |||
private static MapSettings newSettings(List<String> exclusionsProperties, List<String> inclusionsProperties) { |
@@ -37,9 +37,8 @@ import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; | |||
import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderImpl; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Project; | |||
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolderRule; | |||
@@ -91,7 +90,8 @@ public class BuildComponentTreeStepTest { | |||
public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule() | |||
.setRootComponentRef(ROOT_REF) | |||
.setAnalysisDate(ANALYSIS_DATE) | |||
.setBranch(null); | |||
.setBranch(null) | |||
.setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY)); | |||
private DbClient dbClient = dbTester.getDbClient(); | |||
private BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); | |||
@@ -190,27 +190,27 @@ public class BuildComponentTreeStepTest { | |||
verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1, "DEFG"); | |||
} | |||
@Test | |||
public void use_branch_to_generate_keys() { | |||
MutableAnalysisMetadataHolder analysisMetadataHolder = new AnalysisMetadataHolderImpl() | |||
.setRootComponentRef(ROOT_REF) | |||
.setAnalysisDate(ANALYSIS_DATE) | |||
.setBranch("origin/master"); | |||
BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); | |||
reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); | |||
reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); | |||
reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); | |||
reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); | |||
underTest.execute(); | |||
verifyComponent(ROOT_REF, REPORT_PROJECT_KEY + ":origin/master"); | |||
verifyComponent(MODULE_REF, REPORT_MODULE_KEY + ":origin/master"); | |||
verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":origin/master:" + REPORT_DIR_KEY_1); | |||
verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":origin/master:" + REPORT_FILE_KEY_1); | |||
} | |||
// @Test | |||
// public void use_branch_to_generate_keys() { | |||
// MutableAnalysisMetadataHolder analysisMetadataHolder = new AnalysisMetadataHolderImpl() | |||
// .setRootComponentRef(ROOT_REF) | |||
// .setAnalysisDate(ANALYSIS_DATE) | |||
// .setBranch("origin/master"); | |||
// | |||
// BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); | |||
// | |||
// reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); | |||
// reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); | |||
// reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); | |||
// reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); | |||
// | |||
// underTest.execute(); | |||
// | |||
// verifyComponent(ROOT_REF, REPORT_PROJECT_KEY + ":origin/master"); | |||
// verifyComponent(MODULE_REF, REPORT_MODULE_KEY + ":origin/master"); | |||
// verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":origin/master:" + REPORT_DIR_KEY_1); | |||
// verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":origin/master:" + REPORT_FILE_KEY_1); | |||
// } | |||
@Test | |||
public void compute_keys_and_uuids_on_project_having_module_and_directory() { |
@@ -86,7 +86,7 @@ public class LoadPeriodsStepTest extends BaseStepTest { | |||
private void setupRoot(Component root) { | |||
treeRootHolder.setRoot(root); | |||
when(settingsRepository.getConfiguration(root)).thenReturn(settings.asConfig()); | |||
when(settingsRepository.getConfiguration()).thenReturn(settings.asConfig()); | |||
} | |||
@Test |
@@ -25,12 +25,7 @@ import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.VisitException; | |||
import org.sonar.server.computation.task.projectanalysis.qualitygate.Condition; | |||
import org.sonar.server.computation.task.projectanalysis.qualitygate.MutableQualityGateHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGate; | |||
import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateService; | |||
@@ -42,57 +37,46 @@ import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.test.ExceptionCauseMatcher.hasType; | |||
public class QualityGateLoadingStepTest { | |||
private static final String PROJECT_KEY = "project key"; | |||
private static final ReportComponent PROJECT_ALONE = ReportComponent.builder(Component.Type.PROJECT, 1).setKey(PROJECT_KEY).build(); | |||
public class LoadQualityGateStepTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); | |||
@Rule | |||
public MutableQualityGateHolderRule mutableQualityGateHolder = new MutableQualityGateHolderRule(); | |||
private ConfigurationRepository settingsRepository = mock(ConfigurationRepository.class); | |||
private QualityGateService qualityGateService = mock(QualityGateService.class); | |||
private LoadQualityGateStep underTest = new LoadQualityGateStep(treeRootHolder, settingsRepository, qualityGateService, mutableQualityGateHolder); | |||
private LoadQualityGateStep underTest = new LoadQualityGateStep(settingsRepository, qualityGateService, mutableQualityGateHolder); | |||
@Test | |||
public void execute_sets_default_QualityGate_when_project_has_no_settings() { | |||
ReportComponent root = ReportComponent.builder(Component.Type.PROJECT, 1).setKey(PROJECT_KEY).addChildren(ReportComponent.builder(Component.Type.FILE, 2).build()).build(); | |||
treeRootHolder.setRoot(root); | |||
when(settingsRepository.getConfiguration(root)).thenReturn(new MapSettings().asConfig()); | |||
when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().asConfig()); | |||
underTest.execute(); | |||
verifyNoQualityGate(); | |||
// verify only project is processed | |||
verify(settingsRepository).getConfiguration(root); | |||
verify(settingsRepository).getConfiguration(); | |||
verifyNoMoreInteractions(settingsRepository); | |||
} | |||
@Test | |||
public void execute_sets_default_QualityGate_when_property_value_is_not_a_long() { | |||
expectedException.expect(VisitException.class); | |||
expectedException.expectCause( | |||
hasType(IllegalStateException.class) | |||
.andMessage(format("Unsupported value (%s) in property sonar.qualitygate", "10 sds"))); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage(format("Unsupported value (%s) in property sonar.qualitygate", "10 sds")); | |||
treeRootHolder.setRoot(PROJECT_ALONE); | |||
when(settingsRepository.getConfiguration(PROJECT_ALONE)).thenReturn(new MapSettings().setProperty("sonar.qualitygate", "10 sds").asConfig()); | |||
when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().setProperty("sonar.qualitygate", "10 sds").asConfig()); | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void execute_sets_default_QualityGate_if_it_can_not_be_found_by_service() { | |||
treeRootHolder.setRoot(PROJECT_ALONE); | |||
when(settingsRepository.getConfiguration(PROJECT_ALONE)).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig()); | |||
when(qualityGateService.findById(10)).thenReturn(Optional.<QualityGate>absent()); | |||
when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig()); | |||
when(qualityGateService.findById(10)).thenReturn(Optional.absent()); | |||
underTest.execute(); | |||
@@ -101,10 +85,9 @@ public class QualityGateLoadingStepTest { | |||
@Test | |||
public void execute_sets_QualityGate_if_it_can_be_found_by_service() { | |||
QualityGate qualityGate = new QualityGate(465, "name", Collections.<Condition>emptyList()); | |||
QualityGate qualityGate = new QualityGate(465, "name", Collections.emptyList()); | |||
treeRootHolder.setRoot(PROJECT_ALONE); | |||
when(settingsRepository.getConfiguration(PROJECT_ALONE)).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig()); | |||
when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().setProperty("sonar.qualitygate", 10).asConfig()); | |||
when(qualityGateService.findById(10)).thenReturn(Optional.of(qualityGate)); | |||
underTest.execute(); |
@@ -23,7 +23,6 @@ import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.ce.queue.CeTask; | |||
@@ -31,35 +30,30 @@ import org.sonar.core.platform.PluginInfo; | |||
import org.sonar.core.platform.PluginRepository; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Organization; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.ScannerPlugin; | |||
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.BranchLoader; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import org.sonar.server.organization.BillingValidations; | |||
import org.sonar.server.organization.BillingValidations.BillingValidationsException; | |||
import org.sonar.server.organization.BillingValidationsProxy; | |||
import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.organization.TestDefaultOrganizationProvider; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Mockito.doThrow; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
public class LoadReportAnalysisMetadataHolderStepTest { | |||
private static final String PROJECT_KEY = "project_key"; | |||
private static final String BRANCH = "origin/master"; | |||
private static final long ANALYSIS_DATE = 123456789L; | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
@Rule | |||
public BatchReportReaderRule reportReader = new BatchReportReaderRule(); | |||
@Rule | |||
@@ -67,16 +61,16 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private DbClient dbClient = dbTester.getDbClient(); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); | |||
private BillingValidationsProxy billingValidations = mock(BillingValidationsProxy.class); | |||
private DbClient dbClient = db.getDbClient(); | |||
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); | |||
private PluginRepository pluginRepository = mock(PluginRepository.class); | |||
private ComputationStep underTest; | |||
@Before | |||
public void setUp() { | |||
CeTask defaultOrgCeTask = createCeTask(PROJECT_KEY, dbTester.getDefaultOrganization().getUuid()); | |||
CeTask defaultOrgCeTask = createCeTask(PROJECT_KEY, db.getDefaultOrganization().getUuid()); | |||
underTest = createStep(defaultOrgCeTask); | |||
db.components().insertPublicProject(db.getDefaultOrganization(), p -> p.setDbKey(PROJECT_KEY)); | |||
} | |||
@Test | |||
@@ -103,32 +97,6 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
assertThat(analysisMetadataHolder.getAnalysisDate()).isEqualTo(ANALYSIS_DATE); | |||
} | |||
@Test | |||
public void set_branch() { | |||
reportReader.setMetadata( | |||
newBatchReportBuilder() | |||
.setBranch(BRANCH) | |||
.build()); | |||
CeTask ceTask = createCeTask(PROJECT_KEY + ":" + BRANCH, dbTester.getDefaultOrganization().getUuid()); | |||
ComputationStep underTest = createStep(ceTask); | |||
underTest.execute(); | |||
assertThat(analysisMetadataHolder.getBranch()).isEqualTo(BRANCH); | |||
} | |||
@Test | |||
public void set_null_branch_when_nothing_in_the_report() { | |||
reportReader.setMetadata( | |||
newBatchReportBuilder() | |||
.build()); | |||
underTest.execute(); | |||
assertThat(analysisMetadataHolder.getBranch()).isNull(); | |||
} | |||
@Test | |||
public void set_cross_project_duplication_to_true() { | |||
reportReader.setMetadata( | |||
@@ -192,6 +160,7 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
public void execute_fails_with_MessageException_if_projectKey_is_null_in_CE_task() { | |||
CeTask res = mock(CeTask.class); | |||
when(res.getComponentUuid()).thenReturn("prj_uuid"); | |||
when(res.getOrganizationUuid()).thenReturn(defaultOrganizationProvider.get().getUuid()); | |||
reportReader.setMetadata(ScannerReport.Metadata.newBuilder().build()); | |||
ComputationStep underTest = createStep(res); | |||
@@ -235,13 +204,13 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
reportReader.setMetadata( | |||
newBatchReportBuilder() | |||
.build()); | |||
OrganizationDto nonDefaultOrganizationDto = dbTester.organizations().insert(); | |||
OrganizationDto nonDefaultOrganizationDto = db.organizations().insert(); | |||
ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, nonDefaultOrganizationDto.getUuid())); | |||
expectedException.expect(MessageException.class); | |||
expectedException.expectMessage("Report does not specify an OrganizationKey but it has been submitted to another organization (" + | |||
nonDefaultOrganizationDto.getKey() + ") than the default one (" + dbTester.getDefaultOrganization().getKey() + ")"); | |||
nonDefaultOrganizationDto.getKey() + ") than the default one (" + db.getDefaultOrganization().getKey() + ")"); | |||
underTest.execute(); | |||
} | |||
@@ -255,7 +224,7 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
underTest.execute(); | |||
Organization organization = analysisMetadataHolder.getOrganization(); | |||
OrganizationDto defaultOrganization = dbTester.getDefaultOrganization(); | |||
OrganizationDto defaultOrganization = db.getDefaultOrganization(); | |||
assertThat(organization.getUuid()).isEqualTo(defaultOrganization.getUuid()); | |||
assertThat(organization.getKey()).isEqualTo(defaultOrganization.getKey()); | |||
assertThat(organization.getName()).isEqualTo(defaultOrganization.getName()); | |||
@@ -265,13 +234,13 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
public void execute_set_organization_from_ce_task_when_organizationKey_is_set_in_report() { | |||
reportReader.setMetadata( | |||
newBatchReportBuilder() | |||
.setOrganizationKey(dbTester.getDefaultOrganization().getKey()) | |||
.setOrganizationKey(db.getDefaultOrganization().getKey()) | |||
.build()); | |||
underTest.execute(); | |||
Organization organization = analysisMetadataHolder.getOrganization(); | |||
OrganizationDto defaultOrganization = dbTester.getDefaultOrganization(); | |||
OrganizationDto defaultOrganization = db.getDefaultOrganization(); | |||
assertThat(organization.getUuid()).isEqualTo(defaultOrganization.getUuid()); | |||
assertThat(organization.getKey()).isEqualTo(defaultOrganization.getKey()); | |||
assertThat(organization.getName()).isEqualTo(defaultOrganization.getName()); | |||
@@ -279,13 +248,15 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
@Test | |||
public void execute_set_non_default_organization_from_ce_task() { | |||
OrganizationDto nonDefaultOrganizationDto = dbTester.organizations().insert(); | |||
OrganizationDto nonDefaultOrganizationDto = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPublicProject(nonDefaultOrganizationDto); | |||
reportReader.setMetadata( | |||
newBatchReportBuilder() | |||
.setOrganizationKey(nonDefaultOrganizationDto.getKey()) | |||
.setProjectKey(project.getDbKey()) | |||
.build()); | |||
ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, nonDefaultOrganizationDto.getUuid())); | |||
ComputationStep underTest = createStep(createCeTask(project.getDbKey(), nonDefaultOrganizationDto.getUuid())); | |||
underTest.execute(); | |||
@@ -297,15 +268,18 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
@Test | |||
public void execute_ensures_that_report_has_quality_profiles_matching_the_project_organization() { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPublicProject(organization); | |||
ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder(); | |||
metadataBuilder.setOrganizationKey(organization.getKey()); | |||
metadataBuilder | |||
.setOrganizationKey(organization.getKey()) | |||
.setProjectKey(project.getDbKey()); | |||
metadataBuilder.getMutableQprofilesPerLanguage().put("js", ScannerReport.Metadata.QProfile.newBuilder().setKey("p1").setName("Sonar way").setLanguage("js").build()); | |||
reportReader.setMetadata(metadataBuilder.build()); | |||
dbTester.qualityProfiles().insert(organization, p -> p.setLanguage("js").setKee("p1")); | |||
db.qualityProfiles().insert(organization, p -> p.setLanguage("js").setKee("p1")); | |||
ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid())); | |||
ComputationStep underTest = createStep(createCeTask(project.getDbKey(), organization.getUuid())); | |||
// no errors | |||
underTest.execute(); | |||
@@ -313,18 +287,21 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
@Test | |||
public void execute_fails_with_MessageException_when_report_has_quality_profiles_on_other_organizations() { | |||
OrganizationDto organization1 = dbTester.organizations().insert(); | |||
OrganizationDto organization2 = dbTester.organizations().insert(); | |||
OrganizationDto organization1 = db.organizations().insert(); | |||
OrganizationDto organization2 = db.organizations().insert(); | |||
ComponentDto projectInOrg1 = db.components().insertPublicProject(organization1); | |||
ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder(); | |||
metadataBuilder.setOrganizationKey(organization1.getKey()); | |||
metadataBuilder | |||
.setOrganizationKey(organization1.getKey()) | |||
.setProjectKey(projectInOrg1.getDbKey()); | |||
metadataBuilder.getMutableQprofilesPerLanguage().put("js", ScannerReport.Metadata.QProfile.newBuilder().setKey("jsInOrg1").setName("Sonar way").setLanguage("js").build()); | |||
metadataBuilder.getMutableQprofilesPerLanguage().put("php", ScannerReport.Metadata.QProfile.newBuilder().setKey("phpInOrg2").setName("PHP way").setLanguage("php").build()); | |||
reportReader.setMetadata(metadataBuilder.build()); | |||
dbTester.qualityProfiles().insert(organization1, p -> p.setLanguage("js").setKee("jsInOrg1")); | |||
dbTester.qualityProfiles().insert(organization2, p -> p.setLanguage("php").setKee("phpInOrg2")); | |||
db.qualityProfiles().insert(organization1, p -> p.setLanguage("js").setKee("jsInOrg1")); | |||
db.qualityProfiles().insert(organization2, p -> p.setLanguage("php").setKee("phpInOrg2")); | |||
ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization1.getUuid())); | |||
ComputationStep underTest = createStep(createCeTask(projectInOrg1.getDbKey(), organization1.getUuid())); | |||
expectedException.expect(MessageException.class); | |||
expectedException.expectMessage("Quality profiles with following keys don't exist in organization [" + organization1.getKey() + "]: phpInOrg2"); | |||
@@ -334,49 +311,20 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
@Test | |||
public void execute_does_not_fail_when_report_has_a_quality_profile_that_does_not_exist_anymore() { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPublicProject(organization); | |||
ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder(); | |||
metadataBuilder.setOrganizationKey(organization.getKey()); | |||
metadataBuilder | |||
.setOrganizationKey(organization.getKey()) | |||
.setProjectKey(project.getDbKey()); | |||
metadataBuilder.getMutableQprofilesPerLanguage().put("js", ScannerReport.Metadata.QProfile.newBuilder().setKey("p1").setName("Sonar way").setLanguage("js").build()); | |||
reportReader.setMetadata(metadataBuilder.build()); | |||
ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid())); | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void execute_fails_with_MessageException_when_organization_is_not_allowed_to_execute_analysis() { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
reportReader.setMetadata(newBatchReportBuilder() | |||
.setOrganizationKey(organization.getKey()) | |||
.build()); | |||
ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid())); | |||
doThrow(new BillingValidationsException("This organization cannot execute project analysis")).when(billingValidations) | |||
.checkOnProjectAnalysis(any(BillingValidations.Organization.class)); | |||
expectedException.expect(MessageException.class); | |||
expectedException.expectMessage("This organization cannot execute project analysis"); | |||
ComputationStep underTest = createStep(createCeTask(project.getDbKey(), organization.getUuid())); | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void execute_does_no_fails_when_organization_is_allowed_to_execute_analysis() { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
reportReader.setMetadata(newBatchReportBuilder() | |||
.setOrganizationKey(organization.getKey()) | |||
.build()); | |||
ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid())); | |||
underTest.execute(); | |||
ArgumentCaptor<BillingValidations.Organization> argumentCaptor = ArgumentCaptor.forClass(BillingValidations.Organization.class); | |||
verify(billingValidations).checkOnProjectAnalysis(argumentCaptor.capture()); | |||
assertThat(argumentCaptor.getValue().getKey()).isEqualTo(organization.getKey()); | |||
assertThat(argumentCaptor.getValue().getUuid()).isEqualTo(organization.getUuid()); | |||
} | |||
@Test | |||
public void execute_read_plugins_from_report() { | |||
ScannerReport.Metadata.Builder metadataBuilder = newBatchReportBuilder(); | |||
@@ -398,7 +346,8 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
} | |||
private LoadReportAnalysisMetadataHolderStep createStep(CeTask ceTask) { | |||
return new LoadReportAnalysisMetadataHolderStep(ceTask, reportReader, analysisMetadataHolder, defaultOrganizationProvider, dbClient, billingValidations, pluginRepository); | |||
return new LoadReportAnalysisMetadataHolderStep(ceTask, reportReader, analysisMetadataHolder, | |||
defaultOrganizationProvider, dbClient, new BranchLoader(analysisMetadataHolder), pluginRepository); | |||
} | |||
private static ScannerReport.Metadata.Builder newBatchReportBuilder() { |
@@ -28,6 +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.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDisabledComponentsHolder; | |||
@@ -67,6 +68,7 @@ public class PersistComponentsStepTest { | |||
mock(MutableDbIdsRepository.class), | |||
System2.INSTANCE, | |||
mock(MutableDisabledComponentsHolder.class), | |||
mock(AnalysisMetadataHolder.class)).execute(); | |||
mock(AnalysisMetadataHolder.class), | |||
mock(BranchPersisterDelegate.class)).execute(); | |||
} | |||
} |
@@ -134,7 +134,7 @@ public class PurgeDatastoresStepTest extends BaseStepTest { | |||
private void verify_call_purge_method_of_the_purge_task(Component project) { | |||
treeRootHolder.setRoot(project); | |||
when(settingsRepository.getConfiguration(project)).thenReturn(new MapSettings().asConfig()); | |||
when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().asConfig()); | |||
dbIdsRepository.setComponentId(project, PROJECT_ID); | |||
underTest.execute(); |
@@ -22,27 +22,36 @@ package org.sonar.server.computation.task.projectanalysis.step; | |||
import com.google.common.base.Optional; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import java.util.Random; | |||
import java.util.function.Consumer; | |||
import java.util.stream.Stream; | |||
import javax.annotation.Nullable; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.db.DbClient; | |||
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.db.organization.OrganizationDto; | |||
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.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.FileAttributes; | |||
import org.sonar.server.computation.task.projectanalysis.component.MainBranchImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepositoryRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDisabledComponentsHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; | |||
import org.sonar.server.computation.task.step.ComputationStep; | |||
import static org.apache.commons.lang.StringUtils.isEmpty; | |||
import static org.apache.commons.lang.StringUtils.trimToNull; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.guava.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.RETURNS_DEEP_STUBS; | |||
@@ -52,7 +61,6 @@ import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT; | |||
import static org.sonar.db.component.ComponentDto.UUID_PATH_SEPARATOR; | |||
import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.DIRECTORY; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.FILE; | |||
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; | |||
@@ -66,7 +74,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
private static final String ORGANIZATION_UUID = "org1"; | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
@Rule | |||
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); | |||
@Rule | |||
@@ -76,18 +84,19 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
.setOrganizationUuid(ORGANIZATION_UUID); | |||
private System2 system2 = mock(System2.class); | |||
private DbClient dbClient = dbTester.getDbClient(); | |||
private DbClient dbClient = db.getDbClient(); | |||
private Date now; | |||
private MutableDisabledComponentsHolder disabledComponentsHolder = mock(MutableDisabledComponentsHolder.class, RETURNS_DEEP_STUBS); | |||
private PersistComponentsStep underTest; | |||
private BranchPersisterDelegate branchPersister; | |||
@Before | |||
public void setup() throws Exception { | |||
now = DATE_FORMAT.parse("2015-06-02"); | |||
when(system2.now()).thenReturn(now.getTime()); | |||
dbTester.organizations().insertForUuid(ORGANIZATION_UUID); | |||
underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder); | |||
db.organizations().insertForUuid(ORGANIZATION_UUID); | |||
underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder, branchPersister); | |||
} | |||
@Override | |||
@@ -97,7 +106,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
@Test | |||
public void persist_components() { | |||
ComponentDto projectDto = insertProject(); | |||
ComponentDto projectDto = prepareProject(); | |||
Component file = builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java") | |||
.setPath("src/main/java/dir/Foo.java") | |||
.setFileAttributes(new FileAttributes(false, "java", 1)) | |||
@@ -119,9 +128,9 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(4); | |||
ComponentDto moduleDto = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); | |||
ComponentDto moduleDto = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); | |||
assertThat(moduleDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); | |||
assertThat(moduleDto.name()).isEqualTo("Module"); | |||
assertThat(moduleDto.description()).isEqualTo("Module description"); | |||
@@ -137,7 +146,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(moduleDto.getRootUuid()).isEqualTo(projectDto.uuid()); | |||
assertThat(moduleDto.getCreatedAt()).isEqualTo(now); | |||
ComponentDto directoryDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
ComponentDto directoryDto = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
assertThat(directoryDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); | |||
assertThat(directoryDto.name()).isEqualTo("src/main/java/dir"); | |||
assertThat(directoryDto.description()).isNull(); | |||
@@ -153,7 +162,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(directoryDto.getRootUuid()).isEqualTo(moduleDto.uuid()); | |||
assertThat(directoryDto.getCreatedAt()).isEqualTo(now); | |||
ComponentDto fileDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
ComponentDto fileDto = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
assertThat(fileDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); | |||
assertThat(fileDto.name()).isEqualTo("Foo.java"); | |||
assertThat(fileDto.description()).isNull(); | |||
@@ -175,33 +184,113 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(dbIdsRepository.getComponentId(file)).isEqualTo(fileDto.getId()); | |||
} | |||
@Test | |||
public void persist_components_of_existing_branch() { | |||
ComponentDto project = prepareBranch("feature/foo"); | |||
Component file = builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java") | |||
.setPath("src/main/java/dir/Foo.java") | |||
.setFileAttributes(new FileAttributes(false, "java", 1)) | |||
.build(); | |||
Component directory = builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir") | |||
.setPath("src/main/java/dir") | |||
.addChildren(file) | |||
.build(); | |||
Component module = builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) | |||
.setPath("module") | |||
.setName("Module") | |||
.setDescription("Module description") | |||
.addChildren(directory) | |||
.build(); | |||
Component treeRoot = asTreeRoot(project) | |||
.addChildren(module) | |||
.build(); | |||
treeRootHolder.setRoot(treeRoot); | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(4); | |||
ComponentDto moduleDto = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); | |||
assertThat(moduleDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); | |||
assertThat(moduleDto.name()).isEqualTo("Module"); | |||
assertThat(moduleDto.description()).isEqualTo("Module description"); | |||
assertThat(moduleDto.path()).isEqualTo("module"); | |||
assertThat(moduleDto.uuid()).isEqualTo("BCDE"); | |||
assertThat(moduleDto.getUuidPath()).isEqualTo(project.getUuidPath() + project.uuid() + UUID_PATH_SEPARATOR); | |||
assertThat(moduleDto.moduleUuid()).isEqualTo(project.uuid()); | |||
assertThat(moduleDto.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleDto.uuid() + "."); | |||
assertThat(moduleDto.getMainBranchProjectUuid()).isEqualTo(project.uuid()); | |||
assertThat(moduleDto.projectUuid()).isEqualTo(project.uuid()); | |||
assertThat(moduleDto.qualifier()).isEqualTo("BRC"); | |||
assertThat(moduleDto.scope()).isEqualTo("PRJ"); | |||
assertThat(moduleDto.getRootUuid()).isEqualTo(project.uuid()); | |||
assertThat(moduleDto.getCreatedAt()).isEqualTo(now); | |||
ComponentDto directoryDto = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
assertThat(directoryDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); | |||
assertThat(directoryDto.name()).isEqualTo("src/main/java/dir"); | |||
assertThat(directoryDto.description()).isNull(); | |||
assertThat(directoryDto.path()).isEqualTo("src/main/java/dir"); | |||
assertThat(directoryDto.uuid()).isEqualTo("CDEF"); | |||
assertThat(directoryDto.getUuidPath()).isEqualTo(moduleDto.getUuidPath() + moduleDto.uuid() + UUID_PATH_SEPARATOR); | |||
assertThat(directoryDto.moduleUuid()).isEqualTo(moduleDto.uuid()); | |||
assertThat(directoryDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath()); | |||
assertThat(directoryDto.getMainBranchProjectUuid()).isEqualTo(project.uuid()); | |||
assertThat(directoryDto.projectUuid()).isEqualTo(project.uuid()); | |||
assertThat(directoryDto.qualifier()).isEqualTo("DIR"); | |||
assertThat(directoryDto.scope()).isEqualTo("DIR"); | |||
assertThat(directoryDto.getRootUuid()).isEqualTo(moduleDto.uuid()); | |||
assertThat(directoryDto.getCreatedAt()).isEqualTo(now); | |||
ComponentDto fileDto = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
assertThat(fileDto.getOrganizationUuid()).isEqualTo(ORGANIZATION_UUID); | |||
assertThat(fileDto.name()).isEqualTo("Foo.java"); | |||
assertThat(fileDto.description()).isNull(); | |||
assertThat(fileDto.path()).isEqualTo("src/main/java/dir/Foo.java"); | |||
assertThat(fileDto.language()).isEqualTo("java"); | |||
assertThat(fileDto.uuid()).isEqualTo("DEFG"); | |||
assertThat(fileDto.getUuidPath()).isEqualTo(directoryDto.getUuidPath() + directoryDto.uuid() + UUID_PATH_SEPARATOR); | |||
assertThat(fileDto.moduleUuid()).isEqualTo(moduleDto.uuid()); | |||
assertThat(fileDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath()); | |||
assertThat(fileDto.getMainBranchProjectUuid()).isEqualTo(project.uuid()); | |||
assertThat(fileDto.projectUuid()).isEqualTo(project.uuid()); | |||
assertThat(fileDto.qualifier()).isEqualTo("FIL"); | |||
assertThat(fileDto.scope()).isEqualTo("FIL"); | |||
assertThat(fileDto.getRootUuid()).isEqualTo(moduleDto.uuid()); | |||
assertThat(fileDto.getCreatedAt()).isEqualTo(now); | |||
assertThat(dbIdsRepository.getComponentId(module)).isEqualTo(moduleDto.getId()); | |||
assertThat(dbIdsRepository.getComponentId(directory)).isEqualTo(directoryDto.getId()); | |||
assertThat(dbIdsRepository.getComponentId(file)).isEqualTo(fileDto.getId()); | |||
} | |||
@Test | |||
public void persist_file_directly_attached_on_root_directory() { | |||
ComponentDto projectDto = insertProject(); | |||
ComponentDto projectDto = prepareProject(); | |||
treeRootHolder.setRoot( | |||
asTreeRoot(projectDto) | |||
.addChildren( | |||
builder(DIRECTORY, 2).setUuid("CDEF").setKey(PROJECT_KEY + ":/").setPath("/") | |||
builder(DIRECTORY, 2).setUuid("CDEF").setKey(projectDto.getDbKey() + ":/").setPath("/") | |||
.addChildren( | |||
builder(FILE, 3).setUuid("DEFG").setKey(PROJECT_KEY + ":pom.xml").setPath("pom.xml") | |||
builder(FILE, 3).setUuid("DEFG").setKey(projectDto.getDbKey() + ":pom.xml").setPath("pom.xml") | |||
.build()) | |||
.build()) | |||
.build()); | |||
underTest.execute(); | |||
ComponentDto directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "PROJECT_KEY:/").get(); | |||
ComponentDto directory = dbClient.componentDao().selectByKey(db.getSession(), projectDto.getDbKey() + ":/").get(); | |||
assertThat(directory.name()).isEqualTo("/"); | |||
assertThat(directory.path()).isEqualTo("/"); | |||
ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), "PROJECT_KEY:pom.xml").get(); | |||
ComponentDto file = dbClient.componentDao().selectByKey(db.getSession(), projectDto.getDbKey() + ":pom.xml").get(); | |||
assertThat(file.name()).isEqualTo("pom.xml"); | |||
assertThat(file.path()).isEqualTo("pom.xml"); | |||
} | |||
@Test | |||
public void persist_unit_test() { | |||
ComponentDto projectDto = insertProject(); | |||
ComponentDto projectDto = prepareProject(); | |||
treeRootHolder.setRoot( | |||
asTreeRoot(projectDto) | |||
.addChildren( | |||
@@ -217,7 +306,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY + ":src/test/java/dir/FooTest.java").get(); | |||
ComponentDto file = dbClient.componentDao().selectByKey(db.getSession(), PROJECT_KEY + ":src/test/java/dir/FooTest.java").get(); | |||
assertThat(file.name()).isEqualTo("FooTest.java"); | |||
assertThat(file.path()).isEqualTo("src/test/java/dir/FooTest.java"); | |||
assertThat(file.qualifier()).isEqualTo("UTS"); | |||
@@ -227,14 +316,13 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
@Test | |||
public void persist_only_new_components() { | |||
// Project and module already exists | |||
ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); | |||
dbClient.componentDao().insert(dbTester.getSession(), project); | |||
ComponentDto project = prepareProject(); | |||
ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module"); | |||
dbClient.componentDao().insert(dbTester.getSession(), module); | |||
dbTester.getSession().commit(); | |||
dbClient.componentDao().insert(db.getSession(), module); | |||
db.getSession().commit(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) | |||
builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) | |||
.setName("Project") | |||
.addChildren( | |||
builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) | |||
@@ -252,15 +340,15 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(4); | |||
ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get(); | |||
ComponentDto projectReloaded = dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get(); | |||
assertThat(projectReloaded.getId()).isEqualTo(project.getId()); | |||
assertThat(projectReloaded.uuid()).isEqualTo(project.uuid()); | |||
assertThat(projectReloaded.getUuidPath()).isEqualTo(UUID_PATH_OF_ROOT); | |||
assertThat(projectReloaded.getMainBranchProjectUuid()).isNull(); | |||
ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); | |||
ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); | |||
assertThat(moduleReloaded.getId()).isEqualTo(module.getId()); | |||
assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid()); | |||
assertThat(moduleReloaded.getUuidPath()).isEqualTo(module.getUuidPath()); | |||
@@ -270,7 +358,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(moduleReloaded.getRootUuid()).isEqualTo(module.getRootUuid()); | |||
assertThat(moduleReloaded.getMainBranchProjectUuid()).isNull(); | |||
ComponentDto directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
ComponentDto directory = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
assertThat(directory.getUuidPath()).isEqualTo(directory.getUuidPath()); | |||
assertThat(directory.moduleUuid()).isEqualTo(module.uuid()); | |||
assertThat(directory.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); | |||
@@ -278,7 +366,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(directory.getRootUuid()).isEqualTo(module.uuid()); | |||
assertThat(directory.getMainBranchProjectUuid()).isNull(); | |||
ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
ComponentDto file = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
assertThat(file.getUuidPath()).isEqualTo(file.getUuidPath()); | |||
assertThat(file.moduleUuid()).isEqualTo(module.uuid()); | |||
assertThat(file.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); | |||
@@ -289,7 +377,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
@Test | |||
public void compute_root_uuid() { | |||
ComponentDto project = insertProject(); | |||
ComponentDto project = prepareProject(); | |||
treeRootHolder.setRoot( | |||
asTreeRoot(project) | |||
.addChildren( | |||
@@ -312,36 +400,28 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(5); | |||
Optional<ComponentDto> module = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY); | |||
Optional<ComponentDto> module = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY); | |||
assertThat(module).isPresent(); | |||
assertThat(module.get().getRootUuid()).isEqualTo(project.uuid()); | |||
Optional<ComponentDto> subModule1 = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_1_KEY"); | |||
Optional<ComponentDto> subModule1 = dbClient.componentDao().selectByKey(db.getSession(), "SUB_MODULE_1_KEY"); | |||
assertThat(subModule1).isPresent(); | |||
assertThat(subModule1.get().getRootUuid()).isEqualTo(project.uuid()); | |||
Optional<ComponentDto> subModule2 = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_2_KEY"); | |||
Optional<ComponentDto> subModule2 = dbClient.componentDao().selectByKey(db.getSession(), "SUB_MODULE_2_KEY"); | |||
assertThat(subModule2).isPresent(); | |||
assertThat(subModule2.get().getRootUuid()).isEqualTo(project.uuid()); | |||
Optional<ComponentDto> directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_2_KEY:src/main/java/dir"); | |||
Optional<ComponentDto> directory = dbClient.componentDao().selectByKey(db.getSession(), "SUB_MODULE_2_KEY:src/main/java/dir"); | |||
assertThat(directory).isPresent(); | |||
assertThat(directory.get().getRootUuid()).isEqualTo(subModule2.get().uuid()); | |||
} | |||
private ReportComponent.Builder asTreeRoot(ComponentDto project) { | |||
return builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()).setName(project.name()); | |||
} | |||
public ComponentDto insertProject() { | |||
return dbTester.components().insertPrivateProject(dbTester.organizations().insert()); | |||
} | |||
@Test | |||
public void persist_multi_modules() { | |||
ComponentDto project = insertProject(); | |||
ComponentDto project = prepareProject(); | |||
treeRootHolder.setRoot( | |||
asTreeRoot(project) | |||
.setName("Project") | |||
@@ -360,21 +440,21 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(4); | |||
ComponentDto moduleA = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_A").get(); | |||
ComponentDto moduleA = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_A").get(); | |||
assertThat(moduleA.getUuidPath()).isEqualTo(project.getUuidPath() + project.uuid() + UUID_PATH_SEPARATOR); | |||
assertThat(moduleA.moduleUuid()).isEqualTo(project.uuid()); | |||
assertThat(moduleA.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleA.uuid() + "."); | |||
assertThat(moduleA.getRootUuid()).isEqualTo(project.uuid()); | |||
ComponentDto subModuleA = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_A").get(); | |||
ComponentDto subModuleA = dbClient.componentDao().selectByKey(db.getSession(), "SUB_MODULE_A").get(); | |||
assertThat(subModuleA.getUuidPath()).isEqualTo(moduleA.getUuidPath() + moduleA.uuid() + UUID_PATH_SEPARATOR); | |||
assertThat(subModuleA.moduleUuid()).isEqualTo(moduleA.uuid()); | |||
assertThat(subModuleA.moduleUuidPath()).isEqualTo(moduleA.moduleUuidPath() + subModuleA.uuid() + "."); | |||
assertThat(subModuleA.getRootUuid()).isEqualTo(project.uuid()); | |||
ComponentDto moduleB = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B").get(); | |||
ComponentDto moduleB = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_B").get(); | |||
assertThat(moduleB.getUuidPath()).isEqualTo(project.getUuidPath() + project.uuid() + UUID_PATH_SEPARATOR); | |||
assertThat(moduleB.moduleUuid()).isEqualTo(project.uuid()); | |||
assertThat(moduleB.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleB.uuid() + "."); | |||
@@ -383,18 +463,17 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
@Test | |||
public void nothing_to_persist() { | |||
ComponentDto project = newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); | |||
dbClient.componentDao().insert(dbTester.getSession(), project); | |||
ComponentDto project = prepareProject(); | |||
ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module"); | |||
dbClient.componentDao().insert(dbTester.getSession(), module); | |||
dbClient.componentDao().insert(db.getSession(), module); | |||
ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setDbKey("MODULE_KEY:src/main/java/dir"); | |||
ComponentDto file = ComponentTesting.newFileDto(module, directory, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java") | |||
.setDbKey("MODULE_KEY:src/main/java/dir/Foo.java"); | |||
dbClient.componentDao().insert(dbTester.getSession(), directory, file); | |||
dbTester.getSession().commit(); | |||
dbClient.componentDao().insert(db.getSession(), directory, file); | |||
db.getSession().commit(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) | |||
builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) | |||
.setName("Project") | |||
.addChildren( | |||
builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) | |||
@@ -412,13 +491,13 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get().getId()).isEqualTo(project.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get().getId()).isEqualTo(module.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(directory.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(file.getId()); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(4); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get().getId()).isEqualTo(project.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get().getId()).isEqualTo(module.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(directory.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(file.getId()); | |||
ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get(); | |||
ComponentDto projectReloaded = dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get(); | |||
assertThat(projectReloaded.getId()).isEqualTo(project.getId()); | |||
assertThat(projectReloaded.uuid()).isEqualTo(project.uuid()); | |||
assertThat(projectReloaded.moduleUuid()).isEqualTo(project.moduleUuid()); | |||
@@ -426,7 +505,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(projectReloaded.projectUuid()).isEqualTo(project.projectUuid()); | |||
assertThat(projectReloaded.getRootUuid()).isEqualTo(project.getRootUuid()); | |||
ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); | |||
ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); | |||
assertThat(moduleReloaded.getId()).isEqualTo(module.getId()); | |||
assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid()); | |||
assertThat(moduleReloaded.getUuidPath()).isEqualTo(module.getUuidPath()); | |||
@@ -435,7 +514,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(moduleReloaded.projectUuid()).isEqualTo(module.projectUuid()); | |||
assertThat(moduleReloaded.getRootUuid()).isEqualTo(module.getRootUuid()); | |||
ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid()); | |||
assertThat(directoryReloaded.getUuidPath()).isEqualTo(directory.getUuidPath()); | |||
assertThat(directoryReloaded.moduleUuid()).isEqualTo(directory.moduleUuid()); | |||
@@ -445,7 +524,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(directoryReloaded.name()).isEqualTo(directory.name()); | |||
assertThat(directoryReloaded.path()).isEqualTo(directory.path()); | |||
ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
ComponentDto fileReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
assertThat(fileReloaded.uuid()).isEqualTo(file.uuid()); | |||
assertThat(fileReloaded.getUuidPath()).isEqualTo(file.getUuidPath()); | |||
assertThat(fileReloaded.moduleUuid()).isEqualTo(file.moduleUuid()); | |||
@@ -458,14 +537,15 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
@Test | |||
public void update_module_name_and_description() { | |||
ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project").setDescription("Project description"); | |||
dbClient.componentDao().insert(dbTester.getSession(), project); | |||
ComponentDto project = prepareProject(p -> p.setName("Project").setDescription("Project description")); | |||
ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module"); | |||
dbClient.componentDao().insert(dbTester.getSession(), module); | |||
dbTester.getSession().commit(); | |||
dbClient.componentDao().insert(db.getSession(), module); | |||
db.getSession().commit(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) | |||
builder(PROJECT, 1) | |||
.setUuid(project.uuid()) | |||
.setKey(project.getDbKey()) | |||
.setName("New Project") | |||
.setDescription("New project description") | |||
.addChildren( | |||
@@ -480,31 +560,30 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
// functional transaction not finished, "A-fields" are not updated yet | |||
assertNameAndDescription(PROJECT_KEY, "Project", "Project description"); | |||
assertNameAndDescription(project.getDbKey(), "Project", "Project description"); | |||
assertNameAndDescription(MODULE_KEY, "Module", null); | |||
// commit functional transaction -> copies B-fields to A-fields | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), "ABCD"); | |||
assertNameAndDescription(PROJECT_KEY, "New Project", "New project description"); | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); | |||
assertNameAndDescription(project.getDbKey(), "New Project", "New project description"); | |||
assertNameAndDescription(MODULE_KEY, "New Module", "New module description"); | |||
} | |||
private void assertNameAndDescription(String key, String expectedName, String expectedDescription) { | |||
ComponentDto dto = dbClient.componentDao().selectByKey(dbTester.getSession(), key).get(); | |||
ComponentDto dto = dbClient.componentDao().selectByKey(db.getSession(), key).get(); | |||
assertThat(dto.name()).isEqualTo(expectedName); | |||
assertThat(dto.description()).isEqualTo(expectedDescription); | |||
} | |||
@Test | |||
public void update_module_path() { | |||
ComponentDto project = newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); | |||
dbClient.componentDao().insert(dbTester.getSession(), project); | |||
ComponentDto project = prepareProject(); | |||
ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module").setPath("path"); | |||
dbClient.componentDao().insert(dbTester.getSession(), module); | |||
dbTester.getSession().commit(); | |||
dbClient.componentDao().insert(db.getSession(), module); | |||
db.getSession().commit(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) | |||
builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) | |||
.setName("Project") | |||
.addChildren( | |||
builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) | |||
@@ -515,32 +594,31 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get().path()).isEqualTo("path"); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get().path()).isEqualTo("path"); | |||
// commit the functional transaction | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), project.uuid()); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get().path()).isEqualTo("New path"); | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get().path()).isEqualTo("New path"); | |||
} | |||
@Test | |||
public void update_module_uuid_when_moving_a_module() { | |||
ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); | |||
dbClient.componentDao().insert(dbTester.getSession(), project); | |||
ComponentDto project = prepareProject(); | |||
ComponentDto moduleA = ComponentTesting.newModuleDto("EDCB", project) | |||
.setDbKey("MODULE_A") | |||
.setName("Module A"); | |||
ComponentDto moduleB = ComponentTesting.newModuleDto("BCDE", project) | |||
.setDbKey("MODULE_B") | |||
.setName("Module B"); | |||
dbClient.componentDao().insert(dbTester.getSession(), moduleA, moduleB); | |||
dbClient.componentDao().insert(db.getSession(), moduleA, moduleB); | |||
ComponentDto directory = ComponentTesting.newDirectory(moduleB, "src/main/java/dir").setUuid("CDEF").setDbKey("MODULE_B:src/main/java/dir"); | |||
ComponentDto file = ComponentTesting.newFileDto(moduleB, directory, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java") | |||
.setDbKey("MODULE_B:src/main/java/dir/Foo.java"); | |||
dbClient.componentDao().insert(dbTester.getSession(), directory, file); | |||
dbTester.getSession().commit(); | |||
dbClient.componentDao().insert(db.getSession(), directory, file); | |||
db.getSession().commit(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) | |||
builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) | |||
.setName("Project") | |||
.addChildren( | |||
builder(Component.Type.MODULE, 2).setUuid("EDCB").setKey("MODULE_A") | |||
@@ -563,14 +641,14 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
// commit the functional transaction | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), project.uuid()); | |||
dbTester.commit(); | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); | |||
db.commit(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(5); | |||
ComponentDto moduleAreloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_A").get(); | |||
ComponentDto moduleAreloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_A").get(); | |||
ComponentDto moduleBReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B").get(); | |||
ComponentDto moduleBReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_B").get(); | |||
assertThat(moduleBReloaded).isNotNull(); | |||
assertThat(moduleBReloaded.uuid()).isEqualTo(moduleB.uuid()); | |||
assertThat(moduleBReloaded.getUuidPath()).isEqualTo(moduleBReloaded.getUuidPath()); | |||
@@ -579,7 +657,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(moduleBReloaded.projectUuid()).isEqualTo(project.uuid()); | |||
assertThat(moduleBReloaded.getRootUuid()).isEqualTo(project.uuid()); | |||
ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B:src/main/java/dir").get(); | |||
ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_B:src/main/java/dir").get(); | |||
assertThat(directoryReloaded).isNotNull(); | |||
assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid()); | |||
assertThat(directoryReloaded.getUuidPath()).isEqualTo(directoryReloaded.getUuidPath()); | |||
@@ -588,7 +666,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(directoryReloaded.projectUuid()).isEqualTo(project.uuid()); | |||
assertThat(directoryReloaded.getRootUuid()).isEqualTo(moduleBReloaded.uuid()); | |||
ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B:src/main/java/dir/Foo.java").get(); | |||
ComponentDto fileReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_B:src/main/java/dir/Foo.java").get(); | |||
assertThat(fileReloaded).isNotNull(); | |||
assertThat(fileReloaded.uuid()).isEqualTo(file.uuid()); | |||
assertThat(fileReloaded.getUuidPath()).isEqualTo(fileReloaded.getUuidPath()); | |||
@@ -601,31 +679,29 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
@Test | |||
public void do_not_update_created_at_on_existing_component() { | |||
Date oldDate = DateUtils.parseDate("2015-01-01"); | |||
ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project").setCreatedAt(oldDate); | |||
dbClient.componentDao().insert(dbTester.getSession(), project); | |||
ComponentDto project = prepareProject(p -> p.setCreatedAt(oldDate)); | |||
ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module").setPath("path").setCreatedAt(oldDate); | |||
dbClient.componentDao().insert(dbTester.getSession(), module); | |||
dbTester.getSession().commit(); | |||
dbClient.componentDao().insert(db.getSession(), module); | |||
db.getSession().commit(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) | |||
builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) | |||
.build()); | |||
underTest.execute(); | |||
Optional<ComponentDto> projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY); | |||
Optional<ComponentDto> projectReloaded = dbClient.componentDao().selectByUuid(db.getSession(), project.uuid()); | |||
assertThat(projectReloaded.get().getCreatedAt()).isNotEqualTo(now); | |||
} | |||
@Test | |||
public void persist_components_that_were_previously_removed() { | |||
ComponentDto project = newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); | |||
dbClient.componentDao().insert(dbTester.getSession(), project); | |||
ComponentDto project = prepareProject(); | |||
ComponentDto removedModule = ComponentTesting.newModuleDto("BCDE", project) | |||
.setDbKey(MODULE_KEY) | |||
.setName("Module") | |||
.setEnabled(false); | |||
dbClient.componentDao().insert(dbTester.getSession(), removedModule); | |||
dbClient.componentDao().insert(db.getSession(), removedModule); | |||
ComponentDto removedDirectory = ComponentTesting.newDirectory(removedModule, "src/main/java/dir") | |||
.setUuid("CDEF") | |||
.setDbKey("MODULE_KEY:src/main/java/dir") | |||
@@ -635,11 +711,11 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
.setName("Foo.java") | |||
.setDbKey("MODULE_KEY:src/main/java/dir/Foo.java") | |||
.setEnabled(false); | |||
dbClient.componentDao().insert(dbTester.getSession(), removedDirectory, removedFile); | |||
dbTester.getSession().commit(); | |||
dbClient.componentDao().insert(db.getSession(), removedDirectory, removedFile); | |||
db.getSession().commit(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) | |||
builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) | |||
.setName("Project") | |||
.addChildren( | |||
builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) | |||
@@ -657,17 +733,17 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get().getId()).isEqualTo(project.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get().getId()).isEqualTo(removedModule.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(removedDirectory.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(removedFile.getId()); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(4); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get().getId()).isEqualTo(project.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get().getId()).isEqualTo(removedModule.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(removedDirectory.getId()); | |||
assertThat(dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(removedFile.getId()); | |||
assertExistButDisabled(removedModule.getDbKey(), removedDirectory.getDbKey(), removedFile.getDbKey()); | |||
// commit the functional transaction | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), project.uuid()); | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); | |||
ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get(); | |||
ComponentDto projectReloaded = dbClient.componentDao().selectByKey(db.getSession(), project.getDbKey()).get(); | |||
assertThat(projectReloaded.getId()).isEqualTo(project.getId()); | |||
assertThat(projectReloaded.uuid()).isEqualTo(project.uuid()); | |||
assertThat(projectReloaded.getUuidPath()).isEqualTo(project.getUuidPath()); | |||
@@ -677,7 +753,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(projectReloaded.getRootUuid()).isEqualTo(project.getRootUuid()); | |||
assertThat(projectReloaded.isEnabled()).isTrue(); | |||
ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); | |||
ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); | |||
assertThat(moduleReloaded.getId()).isEqualTo(removedModule.getId()); | |||
assertThat(moduleReloaded.uuid()).isEqualTo(removedModule.uuid()); | |||
assertThat(moduleReloaded.getUuidPath()).isEqualTo(removedModule.getUuidPath()); | |||
@@ -687,7 +763,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(moduleReloaded.getRootUuid()).isEqualTo(removedModule.getRootUuid()); | |||
assertThat(moduleReloaded.isEnabled()).isTrue(); | |||
ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir").get(); | |||
assertThat(directoryReloaded.getId()).isEqualTo(removedDirectory.getId()); | |||
assertThat(directoryReloaded.uuid()).isEqualTo(removedDirectory.uuid()); | |||
assertThat(directoryReloaded.getUuidPath()).isEqualTo(removedDirectory.getUuidPath()); | |||
@@ -699,7 +775,7 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
assertThat(directoryReloaded.path()).isEqualTo(removedDirectory.path()); | |||
assertThat(directoryReloaded.isEnabled()).isTrue(); | |||
ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
ComponentDto fileReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
assertThat(fileReloaded.getId()).isEqualTo(fileReloaded.getId()); | |||
assertThat(fileReloaded.uuid()).isEqualTo(removedFile.uuid()); | |||
assertThat(fileReloaded.getUuidPath()).isEqualTo(removedFile.getUuidPath()); | |||
@@ -714,27 +790,26 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
private void assertExistButDisabled(String... keys) { | |||
for (String key : keys) { | |||
ComponentDto dto = dbClient.componentDao().selectByKey(dbTester.getSession(), key).get(); | |||
ComponentDto dto = dbClient.componentDao().selectByKey(db.getSession(), key).get(); | |||
assertThat(dto.isEnabled()).isFalse(); | |||
} | |||
} | |||
@Test | |||
public void update_module_uuid_when_reactivating_removed_component() { | |||
ComponentDto project = newPrivateProjectDto(dbTester.getDefaultOrganization(), "ABCD").setDbKey(PROJECT_KEY).setName("Project"); | |||
dbClient.componentDao().insert(dbTester.getSession(), project); | |||
ComponentDto project = prepareProject(); | |||
ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setDbKey(MODULE_KEY).setName("Module"); | |||
ComponentDto removedModule = ComponentTesting.newModuleDto("EDCD", project).setDbKey("REMOVED_MODULE_KEY").setName("Removed Module").setEnabled(false); | |||
dbClient.componentDao().insert(dbTester.getSession(), module, removedModule); | |||
dbClient.componentDao().insert(db.getSession(), module, removedModule); | |||
ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setDbKey("MODULE_KEY:src/main/java/dir"); | |||
// The file was attached to another module | |||
ComponentDto removedFile = ComponentTesting.newFileDto(removedModule, directory, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java") | |||
.setDbKey("MODULE_KEY:src/main/java/dir/Foo.java").setEnabled(false); | |||
dbClient.componentDao().insert(dbTester.getSession(), directory, removedFile); | |||
dbTester.getSession().commit(); | |||
dbClient.componentDao().insert(db.getSession(), directory, removedFile); | |||
db.getSession().commit(); | |||
treeRootHolder.setRoot( | |||
builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY) | |||
builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()) | |||
.setName("Project") | |||
.addChildren( | |||
builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY) | |||
@@ -753,15 +828,15 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
underTest.execute(); | |||
// commit the functional transaction | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(dbTester.getSession(), project.uuid()); | |||
dbTester.commit(); | |||
dbClient.componentDao().applyBChangesForRootComponentUuid(db.getSession(), project.uuid()); | |||
db.commit(); | |||
// Projects contains 4 components from the report + one removed module | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5); | |||
assertThat(db.countRowsOfTable("projects")).isEqualTo(5); | |||
ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), MODULE_KEY).get(); | |||
ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(db.getSession(), MODULE_KEY).get(); | |||
ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
ComponentDto fileReloaded = dbClient.componentDao().selectByKey(db.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get(); | |||
assertThat(fileReloaded.getId()).isEqualTo(removedFile.getId()); | |||
assertThat(fileReloaded.uuid()).isEqualTo(removedFile.uuid()); | |||
assertThat(fileReloaded.getUuidPath()).isEqualTo(fileReloaded.getUuidPath()); | |||
@@ -775,21 +850,18 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
@Test | |||
public void persists_existing_components_with_visibility_of_root_in_db_out_of_functional_transaction() { | |||
boolean isRootPrivate = new Random().nextBoolean(); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto project = newPrivateProjectDto(organization, "ABCD").setDbKey(PROJECT_KEY).setName("Project").setPrivate(isRootPrivate); | |||
dbTester.components().insertComponent(project); | |||
ComponentDto module = newModuleDto(project).setUuid("BCDE").setDbKey("MODULE").setPrivate(!isRootPrivate); | |||
dbTester.components().insertComponent(module); | |||
dbTester.components().insertComponent(newDirectory(module, "DEFG", "Directory").setDbKey("DIR").setPrivate(isRootPrivate)); | |||
ComponentDto project = prepareProject(p -> p.setPrivate(true)); | |||
ComponentDto module = newModuleDto(project).setPrivate(false); | |||
db.components().insertComponent(module); | |||
ComponentDto dir = db.components().insertComponent(newDirectory(module, "DEFG", "Directory").setDbKey("DIR").setPrivate(true)); | |||
treeRootHolder.setRoot(createSampleProjectComponentTree(project)); | |||
underTest.execute(); | |||
Stream.of("ABCD", "BCDE", "BCDE", "BCDE") | |||
.forEach(uuid -> assertThat(dbClient.componentDao().selectByUuid(dbTester.getSession(), uuid).get().isPrivate()) | |||
Stream.of(project.uuid(), module.uuid(), dir.uuid()) | |||
.forEach(uuid -> assertThat(dbClient.componentDao().selectByUuid(db.getSession(), uuid).get().isPrivate()) | |||
.describedAs("for uuid " + uuid) | |||
.isEqualTo(isRootPrivate)); | |||
.isEqualTo(true)); | |||
} | |||
private ReportComponent createSampleProjectComponentTree(ComponentDto project) { | |||
@@ -813,4 +885,59 @@ public class ReportPersistComponentsStepTest extends BaseStepTest { | |||
.build()) | |||
.build(); | |||
} | |||
private ReportComponent.Builder asTreeRoot(ComponentDto project) { | |||
return builder(PROJECT, 1).setUuid(project.uuid()).setKey(project.getDbKey()).setName(project.name()); | |||
} | |||
private ComponentDto prepareProject(Consumer<ComponentDto>... populators) { | |||
ComponentDto dto = db.components().insertPrivateProject(db.organizations().insert(), populators); | |||
analysisMetadataHolder.setProject(Project.copyOf(dto)); | |||
analysisMetadataHolder.setBranch(new MainBranchImpl(null)); | |||
return dto; | |||
} | |||
private ComponentDto prepareBranch(String branchName, Consumer<ComponentDto>... populators) { | |||
ComponentDto dto = db.components().insertPrivateProject(db.organizations().insert(), populators); | |||
analysisMetadataHolder.setProject(Project.copyOf(dto)); | |||
analysisMetadataHolder.setBranch(new BranchImpl(branchName)); | |||
return dto; | |||
} | |||
private static class BranchImpl implements Branch { | |||
private final String name; | |||
public BranchImpl(String name) { | |||
this.name = name; | |||
} | |||
@Override | |||
public BranchType getType() { | |||
return BranchType.LONG; | |||
} | |||
@Override | |||
public boolean isMain() { | |||
return false; | |||
} | |||
@Override | |||
public java.util.Optional<String> getName() { | |||
return java.util.Optional.ofNullable(name); | |||
} | |||
@Override | |||
public boolean supportsCrossProjectCpd() { | |||
return false; | |||
} | |||
@Override | |||
public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { | |||
String moduleKey = module.getKey(); | |||
if (fileOrDir == null || isEmpty(fileOrDir.getPath())) { | |||
return moduleKey; | |||
} | |||
return ComponentKeys.createEffectiveKey(moduleKey, trimToNull(fileOrDir.getPath())); | |||
} | |||
} | |||
} |
@@ -40,6 +40,8 @@ import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Analysis; | |||
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.component.MainBranchImpl; | |||
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.Component; | |||
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent; | |||
@@ -51,7 +53,7 @@ public class ValidateProjectStepTest { | |||
static long DEFAULT_ANALYSIS_TIME = 1433131200000L; // 2015-06-01 | |||
static final String PROJECT_KEY = "PROJECT_KEY"; | |||
static final String MODULE_KEY = "MODULE_KEY"; | |||
static final String DEFAULT_BRANCH = "origin/master"; | |||
static final Branch DEFAULT_BRANCH = new MainBranchImpl(null); | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
@@ -97,36 +99,6 @@ public class ValidateProjectStepTest { | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void not_fail_on_valid_branch() { | |||
analysisMetadataHolder.setBranch(DEFAULT_BRANCH); | |||
reportReader.putComponent(ScannerReport.Component.newBuilder() | |||
.setRef(1) | |||
.setType(ComponentType.PROJECT) | |||
.setKey(PROJECT_KEY) | |||
.build()); | |||
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY + ":origin/master").build()); | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void fail_on_invalid_branch() { | |||
analysisMetadataHolder.setBranch("bran#ch"); | |||
reportReader.putComponent(ScannerReport.Component.newBuilder() | |||
.setRef(1) | |||
.setType(ComponentType.PROJECT) | |||
.setKey(PROJECT_KEY) | |||
.build()); | |||
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY + ":bran#ch").build()); | |||
thrown.expect(MessageException.class); | |||
thrown.expectMessage("Validation of project failed:\n" + | |||
" o \"bran#ch\" is not a valid branch name. Allowed characters are alphanumeric, '-', '_', '.' and '/'."); | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void fail_on_invalid_key() { | |||
String invalidProjectKey = "Project\\Key"; |
@@ -0,0 +1,80 @@ | |||
/* | |||
* 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.step; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; | |||
import org.sonar.server.computation.task.projectanalysis.analysis.Organization; | |||
import org.sonar.server.organization.BillingValidations; | |||
import org.sonar.server.organization.BillingValidations.BillingValidationsException; | |||
import org.sonar.server.organization.BillingValidationsProxy; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Mockito.doThrow; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; | |||
public class VerifyBillingStepTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private OrganizationDto organization = newOrganizationDto(); | |||
@Rule | |||
public MutableAnalysisMetadataHolderRule analysisMetadata = new MutableAnalysisMetadataHolderRule() | |||
.setOrganization(Organization.from(organization)); | |||
private BillingValidationsProxy validations = mock(BillingValidationsProxy.class); | |||
@Test | |||
public void execute_fails_with_MessageException_when_organization_is_not_allowed_to_execute_analysis() { | |||
doThrow(new BillingValidationsException("This organization cannot execute project analysis")) | |||
.when(validations) | |||
.checkOnProjectAnalysis(any(BillingValidations.Organization.class)); | |||
VerifyBillingStep underTest = new VerifyBillingStep(analysisMetadata, validations); | |||
expectedException.expect(MessageException.class); | |||
expectedException.expectMessage("This organization cannot execute project analysis"); | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void execute_does_no_fail_when_organization_is_allowed_to_execute_analysis() { | |||
ArgumentCaptor<BillingValidations.Organization> orgCaptor = ArgumentCaptor.forClass(BillingValidations.Organization.class); | |||
VerifyBillingStep underTest = new VerifyBillingStep(analysisMetadata, validations); | |||
underTest.execute(); | |||
verify(validations).checkOnProjectAnalysis(orgCaptor.capture()); | |||
BillingValidations.Organization calledOrg = orgCaptor.getValue(); | |||
assertThat(calledOrg.getKey()).isEqualTo(organization.getKey()); | |||
} | |||
} |
@@ -37,6 +37,8 @@ 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.MainBranchImpl; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDbIdsRepositoryRule; | |||
import org.sonar.server.computation.task.projectanalysis.component.MutableDisabledComponentsHolder; | |||
import org.sonar.server.computation.task.projectanalysis.component.ProjectViewAttributes; | |||
@@ -93,6 +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; | |||
@Before | |||
public void setup() throws Exception { | |||
@@ -100,7 +103,8 @@ public class ViewsPersistComponentsStepTest extends BaseStepTest { | |||
when(system2.now()).thenReturn(now.getTime()); | |||
dbTester.organizations().insertForUuid(ORGANIZATION_UUID); | |||
underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder); | |||
analysisMetadataHolder.setBranch(new MainBranchImpl(null)); | |||
underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2, disabledComponentsHolder, analysisMetadataHolder, branchPersister); | |||
} | |||
@Override |
@@ -32,7 +32,6 @@ import org.sonar.api.utils.log.LogTester; | |||
import org.sonar.api.utils.log.LoggerLevel; | |||
import org.sonar.server.computation.task.projectanalysis.component.ConfigurationRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.TestSettingsRepository; | |||
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Matchers.any; | |||
@@ -43,7 +42,6 @@ import static org.mockito.Mockito.verifyZeroInteractions; | |||
import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newCeTaskBuilder; | |||
import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newProjectBuilder; | |||
import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newScannerContextBuilder; | |||
import static org.sonar.server.computation.task.projectanalysis.component.ReportComponent.DUMB_PROJECT; | |||
public class WebhookPostTaskTest { | |||
@@ -53,9 +51,6 @@ public class WebhookPostTaskTest { | |||
@Rule | |||
public LogTester logTester = new LogTester().setLevel(LoggerLevel.DEBUG); | |||
@Rule | |||
public TreeRootHolderRule rootHolder = new TreeRootHolderRule().setRoot(DUMB_PROJECT); | |||
private final MapSettings settings = new MapSettings(); | |||
private final TestWebhookCaller caller = new TestWebhookCaller(); | |||
private final WebhookPayloadFactory payloadFactory = new TestWebhookPayloadFactory(); | |||
@@ -131,7 +126,7 @@ public class WebhookPostTaskTest { | |||
private void execute() { | |||
ConfigurationRepository settingsRepository = new TestSettingsRepository(settings.asConfig()); | |||
WebhookPostTask task = new WebhookPostTask(rootHolder, settingsRepository, payloadFactory, caller, deliveryStorage); | |||
WebhookPostTask task = new WebhookPostTask(settingsRepository, payloadFactory, caller, deliveryStorage); | |||
PostProjectAnalysisTaskTester.of(task) | |||
.at(new Date()) |
@@ -451,7 +451,7 @@ public class PermissionTemplateServiceTest { | |||
} | |||
@Test | |||
public void would_user_have_scann_permission_with_empty_template() { | |||
public void would_user_have_scan_permission_with_empty_template() { | |||
PermissionTemplateDto template = templateDb.insertTemplate(dbTester.getDefaultOrganization()); | |||
dbTester.organizations().setDefaultTemplates(template, null); | |||
@@ -459,7 +459,7 @@ public class PermissionTemplateServiceTest { | |||
} | |||
private void checkWouldUserHaveScanPermission(OrganizationDto organization, @Nullable Integer userId, boolean expectedResult) { | |||
assertThat(underTest.wouldUserHaveScanPermissionWithDefaultTemplate(session, organization.getUuid(), userId, null, "PROJECT_KEY", Qualifiers.PROJECT)) | |||
assertThat(underTest.wouldUserHaveScanPermissionWithDefaultTemplate(session, organization.getUuid(), userId, "PROJECT_KEY", Qualifiers.PROJECT)) | |||
.isEqualTo(expectedResult); | |||
} | |||
@@ -30,6 +30,6 @@ public class ProjectsWsModuleTest { | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new ProjectsWsModule().configure(container); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 14); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 15); | |||
} | |||
} |
@@ -19,9 +19,7 @@ | |||
*/ | |||
package org.sonar.core.config; | |||
import com.google.common.collect.ImmutableList; | |||
import com.google.common.collect.Lists; | |||
import java.util.Arrays; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.PropertyType; | |||
@@ -29,6 +27,7 @@ import org.sonar.api.config.EmailSettings; | |||
import org.sonar.api.config.PropertyDefinition; | |||
import org.sonar.api.resources.Qualifiers; | |||
import static java.util.Arrays.asList; | |||
import static org.sonar.api.PropertyType.BOOLEAN; | |||
import static org.sonar.api.database.DatabaseProperties.PROP_PASSWORD; | |||
@@ -54,7 +53,7 @@ public class CorePropertyDefinitions { | |||
} | |||
public static List<PropertyDefinition> all() { | |||
List<PropertyDefinition> defs = Lists.newArrayList(); | |||
List<PropertyDefinition> defs = new ArrayList<>(); | |||
defs.addAll(IssueExclusionProperties.all()); | |||
defs.addAll(ExclusionProperties.all()); | |||
defs.addAll(SecurityProperties.all()); | |||
@@ -63,8 +62,9 @@ public class CorePropertyDefinitions { | |||
defs.addAll(EmailSettings.definitions()); | |||
defs.addAll(WebhookProperties.all()); | |||
defs.addAll(TelemetryProperties.all()); | |||
defs.addAll(ScannerProperties.all()); | |||
defs.addAll(ImmutableList.of( | |||
defs.addAll(asList( | |||
PropertyDefinition.builder(PROP_PASSWORD) | |||
.type(PropertyType.PASSWORD) | |||
.hidden() | |||
@@ -102,14 +102,6 @@ public class CorePropertyDefinitions { | |||
.category(CoreProperties.CATEGORY_GENERAL) | |||
.hidden() | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.ANALYSIS_MODE) | |||
.name("Analysis mode") | |||
.type(PropertyType.SINGLE_SELECT_LIST) | |||
.options(Arrays.asList(CoreProperties.ANALYSIS_MODE_ANALYSIS, CoreProperties.ANALYSIS_MODE_PREVIEW, CoreProperties.ANALYSIS_MODE_INCREMENTAL)) | |||
.category(CoreProperties.CATEGORY_GENERAL) | |||
.defaultValue(CoreProperties.ANALYSIS_MODE_ANALYSIS) | |||
.hidden() | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.PREVIEW_INCLUDE_PLUGINS) | |||
.name("Plugins accepted for Preview mode") | |||
.description("List of plugin keys. Those plugins will be used during preview analyses.") | |||
@@ -148,20 +140,6 @@ public class CorePropertyDefinitions { | |||
.defaultValue(String.valueOf(false)) | |||
.hidden() | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.SCM_DISABLED_KEY) | |||
.name("Disable the SCM Sensor") | |||
.description("Disable the retrieval of blame information from Source Control Manager") | |||
.category(CoreProperties.CATEGORY_SCM) | |||
.type(BOOLEAN) | |||
.onQualifiers(Qualifiers.PROJECT) | |||
.defaultValue(String.valueOf(false)) | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.SCM_PROVIDER_KEY) | |||
.name("Key of the SCM provider for this project") | |||
.description("Force the provider to be used to get SCM information for this project. By default auto-detection is done. Example: svn, git.") | |||
.category(CoreProperties.CATEGORY_SCM) | |||
.onlyOnQualifiers(Qualifiers.PROJECT) | |||
.build(), | |||
PropertyDefinition.builder(DISABLE_NOTIFICATION_ON_BUILT_IN_QPROFILES) | |||
.name("Avoid quality profiles notification") | |||
.description("Avoid sending email notification on each update of built-in quality profiles to quality profile administrators.") |
@@ -19,20 +19,21 @@ | |||
*/ | |||
package org.sonar.core.config; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.config.PropertyDefinition; | |||
import org.sonar.api.resources.Qualifiers; | |||
import static java.util.Arrays.asList; | |||
public final class PurgeProperties { | |||
private PurgeProperties() { | |||
} | |||
public static List<PropertyDefinition> all() { | |||
return Arrays.asList( | |||
return asList( | |||
PropertyDefinition.builder(PurgeConstants.PROPERTY_CLEAN_DIRECTORY) | |||
.defaultValue("true") | |||
.name("Clean directory/package history") |
@@ -0,0 +1,76 @@ | |||
/* | |||
* 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.core.config; | |||
import java.util.List; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.config.PropertyDefinition; | |||
import org.sonar.api.resources.Qualifiers; | |||
import static java.util.Arrays.asList; | |||
import static org.sonar.api.PropertyType.BOOLEAN; | |||
public class ScannerProperties { | |||
public static final String BRANCH_NAME = "sonar.branch.name"; | |||
public static final String ORGANIZATION = "sonar.organization"; | |||
private ScannerProperties() { | |||
// only static stuff | |||
} | |||
public static List<PropertyDefinition> all() { | |||
return asList( | |||
PropertyDefinition.builder(CoreProperties.ANALYSIS_MODE) | |||
.name("Analysis mode") | |||
.type(PropertyType.SINGLE_SELECT_LIST) | |||
.options(asList(CoreProperties.ANALYSIS_MODE_ANALYSIS, CoreProperties.ANALYSIS_MODE_PREVIEW, CoreProperties.ANALYSIS_MODE_INCREMENTAL)) | |||
.category(CoreProperties.CATEGORY_GENERAL) | |||
.defaultValue(CoreProperties.ANALYSIS_MODE_ANALYSIS) | |||
.hidden() | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.SCM_DISABLED_KEY) | |||
.name("Disable the SCM Sensor") | |||
.description("Disable the retrieval of blame information from Source Control Manager") | |||
.category(CoreProperties.CATEGORY_SCM) | |||
.type(BOOLEAN) | |||
.onQualifiers(Qualifiers.PROJECT) | |||
.defaultValue(String.valueOf(false)) | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.SCM_PROVIDER_KEY) | |||
.name("Key of the SCM provider for this project") | |||
.description("Force the provider to be used to get SCM information for this project. By default auto-detection is done. Example: svn, git.") | |||
.category(CoreProperties.CATEGORY_SCM) | |||
.onlyOnQualifiers(Qualifiers.PROJECT) | |||
.build(), | |||
PropertyDefinition.builder(ORGANIZATION) | |||
.name("Organization key") | |||
.description("Key of the organization that contains the project being analyzed. If unset, then the organization marked as default is used.") | |||
.hidden() | |||
.build(), | |||
PropertyDefinition.builder(BRANCH_NAME) | |||
.name("Optional name of SCM branch") | |||
.description("TODO") | |||
.hidden() | |||
.build() | |||
); | |||
} | |||
} |
@@ -19,13 +19,14 @@ | |||
*/ | |||
package org.sonar.core.config; | |||
import com.google.common.collect.ImmutableList; | |||
import java.util.List; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.config.PropertyDefinition; | |||
import org.sonar.api.config.PropertyFieldDefinition; | |||
import org.sonar.api.resources.Qualifiers; | |||
import static java.util.Arrays.asList; | |||
public class WebhookProperties { | |||
public static final String GLOBAL_KEY = "sonar.webhooks.global"; | |||
@@ -56,7 +57,7 @@ public class WebhookProperties { | |||
} | |||
static List<PropertyDefinition> all() { | |||
return ImmutableList.of( | |||
return asList( | |||
PropertyDefinition.builder(GLOBAL_KEY) | |||
.category(CATEGORY) | |||
.name("Webhooks") |
@@ -55,7 +55,7 @@ public class PluginLoader { | |||
* Defines the base keys (defined by {@link #basePluginKey(PluginInfo, Map)}) of the plugins which are allowed to | |||
* run a full server extensions. | |||
*/ | |||
private static final Set<String> PRIVILEGED_PLUGINS_BASE_KEYS = ImmutableSet.of("views", "devcockpit", "governance", "billing", "developer", "incremental"); | |||
private static final Set<String> PRIVILEGED_PLUGINS_BASE_KEYS = ImmutableSet.of("views", "devcockpit", "governance", "billing", "developer", "incremental", "branch"); | |||
public static final Version COMPATIBILITY_MODE_MAX_VERSION = Version.create("5.2"); | |||
@@ -33,7 +33,7 @@ public class CorePropertyDefinitionsTest { | |||
@Test | |||
public void all() { | |||
List<PropertyDefinition> defs = CorePropertyDefinitions.all(); | |||
assertThat(defs).hasSize(61); | |||
assertThat(defs).hasSize(63); | |||
} | |||
@Test | |||
@@ -44,4 +44,12 @@ public class CorePropertyDefinitionsTest { | |||
assertThat(prop.get().type()).isEqualTo(PropertyType.PASSWORD); | |||
} | |||
@Test | |||
public void all_includes_scanner_properties() { | |||
List<PropertyDefinition> defs = CorePropertyDefinitions.all(); | |||
assertThat(defs.stream() | |||
.filter(def -> def.key().equals(ScannerProperties.BRANCH_NAME)) | |||
.findFirst()).isPresent(); | |||
} | |||
} |
@@ -126,11 +126,6 @@ public interface CoreProperties { | |||
String PROJECT_BRANCH_PROPERTY = "sonar.branch"; | |||
String PROJECT_VERSION_PROPERTY = "sonar.projectVersion"; | |||
/** | |||
* @since 6.3 | |||
*/ | |||
String PROJECT_ORGANIZATION_PROPERTY = "sonar.organization"; | |||
/** | |||
* @since 2.6 | |||
*/ |
@@ -77,14 +77,14 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
if (!container.getComponentByType(AnalysisMode.class).isIssues()) { | |||
Metadata readMetadata = getReportReader().readMetadata(); | |||
int rootComponentRef = readMetadata.getRootComponentRef(); | |||
storeReportComponents(rootComponentRef, null, readMetadata.getBranch()); | |||
storeReportComponents(rootComponentRef, null); | |||
} | |||
storeFs(container); | |||
} | |||
private void storeReportComponents(int componentRef, String parentModuleKey, String branch) { | |||
private void storeReportComponents(int componentRef, String parentModuleKey) { | |||
Component component = getReportReader().readComponent(componentRef); | |||
if (isNotEmpty(component.getKey())) { | |||
reportComponents.put(component.getKey(), component); | |||
@@ -92,7 +92,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
reportComponents.put(parentModuleKey + ":" + component.getPath(), component); | |||
} | |||
for (int childId : component.getChildRefList()) { | |||
storeReportComponents(childId, isNotEmpty(component.getKey()) ? component.getKey() : parentModuleKey, branch); | |||
storeReportComponents(childId, isNotEmpty(component.getKey()) ? component.getKey() : parentModuleKey); | |||
} | |||
} | |||
@@ -174,7 +174,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
* @param lineOffset 0-based offset in file | |||
*/ | |||
public List<TypeOfText> highlightingTypeFor(InputFile file, int line, int lineOffset) { | |||
int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); | |||
int ref = reportComponents.get(file.key()).getRef(); | |||
if (!reader.hasSyntaxHighlighting(ref)) { | |||
return Collections.emptyList(); | |||
} | |||
@@ -205,7 +205,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
*/ | |||
@CheckForNull | |||
public List<ScannerReport.TextRange> symbolReferencesFor(InputFile file, int symbolStartLine, int symbolStartLineOffset) { | |||
int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); | |||
int ref = reportComponents.get(file.key()).getRef(); | |||
try (CloseableIterator<Symbol> symbols = getReportReader().readComponentSymbols(ref)) { | |||
while (symbols.hasNext()) { | |||
Symbol symbol = symbols.next(); | |||
@@ -219,7 +219,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
public List<ScannerReport.Duplication> duplicationsFor(InputFile file) { | |||
List<ScannerReport.Duplication> result = new ArrayList<>(); | |||
int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); | |||
int ref = reportComponents.get(file.key()).getRef(); | |||
try (CloseableIterator<ScannerReport.Duplication> it = getReportReader().readComponentDuplications(ref)) { | |||
while (it.hasNext()) { | |||
result.add(it.next()); | |||
@@ -232,7 +232,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
public List<ScannerReport.CpdTextBlock> duplicationBlocksFor(InputFile file) { | |||
List<ScannerReport.CpdTextBlock> result = new ArrayList<>(); | |||
int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); | |||
int ref = reportComponents.get(file.key()).getRef(); | |||
try (CloseableIterator<ScannerReport.CpdTextBlock> it = getReportReader().readCpdTextBlocks(ref)) { | |||
while (it.hasNext()) { | |||
result.add(it.next()); | |||
@@ -245,7 +245,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
@CheckForNull | |||
public ScannerReport.LineCoverage coverageFor(InputFile file, int line) { | |||
int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef(); | |||
int ref = reportComponents.get(file.key()).getRef(); | |||
try (CloseableIterator<ScannerReport.LineCoverage> it = getReportReader().readComponentCoverage(ref)) { | |||
while (it.hasNext()) { | |||
ScannerReport.LineCoverage coverage = it.next(); | |||
@@ -260,7 +260,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
} | |||
public ScannerReport.Test firstTestExecutionForName(InputFile testFile, String testName) { | |||
int ref = reportComponents.get(((DefaultInputFile) testFile).key()).getRef(); | |||
int ref = reportComponents.get(testFile.key()).getRef(); | |||
try (InputStream inputStream = FileUtils.openInputStream(getReportReader().readTests(ref))) { | |||
ScannerReport.Test test = ScannerReport.Test.parser().parseDelimitedFrom(inputStream); | |||
while (test != null) { | |||
@@ -276,7 +276,7 @@ public class TaskResult implements org.sonar.scanner.mediumtest.ScanTaskObserver | |||
} | |||
public ScannerReport.CoverageDetail coveragePerTestFor(InputFile testFile, String testName) { | |||
int ref = reportComponents.get(((DefaultInputFile) testFile).key()).getRef(); | |||
int ref = reportComponents.get(testFile.key()).getRef(); | |||
try (InputStream inputStream = FileUtils.openInputStream(getReportReader().readCoverageDetails(ref))) { | |||
ScannerReport.CoverageDetail details = ScannerReport.CoverageDetail.parser().parseDelimitedFrom(inputStream); | |||
while (details != null) { |
@@ -20,8 +20,8 @@ | |||
package org.sonar.scanner.report; | |||
import java.util.Map.Entry; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.AnalysisMode; | |||
import java.util.Optional; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.fs.internal.InputModuleHierarchy; | |||
@@ -35,6 +35,9 @@ import org.sonar.scanner.protocol.output.ScannerReportWriter; | |||
import org.sonar.scanner.rule.ModuleQProfiles; | |||
import org.sonar.scanner.rule.QProfile; | |||
import static org.sonar.core.config.ScannerProperties.BRANCH_NAME; | |||
import static org.sonar.core.config.ScannerProperties.ORGANIZATION; | |||
public class MetadataPublisher implements ReportPublisherStep { | |||
private final Configuration settings; | |||
@@ -68,12 +71,10 @@ public class MetadataPublisher implements ReportPublisherStep { | |||
.setRootComponentRef(rootProject.batchId()) | |||
.setIncremental(mode.isIncremental()); | |||
settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).ifPresent(builder::setOrganizationKey); | |||
settings.get(ORGANIZATION).ifPresent(builder::setOrganizationKey); | |||
settings.get(BRANCH_NAME).ifPresent(builder::setBranchName); | |||
Optional.ofNullable(rootDef.getBranch()).ifPresent(builder::setDeprecatedBranch); | |||
String branch = rootDef.getBranch(); | |||
if (branch != null) { | |||
builder.setBranch(branch); | |||
} | |||
for (QProfile qp : qProfiles.findAll()) { | |||
builder.getMutableQprofilesPerLanguage().put(qp.getLanguage(), ScannerReport.Metadata.QProfile.newBuilder() | |||
.setKey(qp.getKey()) |
@@ -35,7 +35,6 @@ import javax.annotation.Nullable; | |||
import okhttp3.HttpUrl; | |||
import org.apache.commons.io.FileUtils; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.ScannerSide; | |||
import org.sonar.api.batch.fs.internal.InputModuleHierarchy; | |||
import org.sonar.api.config.Configuration; | |||
@@ -54,6 +53,7 @@ import org.sonarqube.ws.client.HttpException; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsResponse; | |||
import static org.sonar.core.config.ScannerProperties.ORGANIZATION; | |||
import static org.sonar.core.util.FileUtils.deleteQuietly; | |||
@ScannerSide | |||
@@ -167,7 +167,7 @@ public class ReportPublisher implements Startable { | |||
PostRequest.Part filePart = new PostRequest.Part(MediaTypes.ZIP, report); | |||
PostRequest post = new PostRequest("api/ce/submit") | |||
.setMediaType(MediaTypes.PROTOBUF) | |||
.setParam("organization", settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).orElse(null)) | |||
.setParam("organization", settings.get(ORGANIZATION).orElse(null)) | |||
.setParam("projectKey", moduleHierarchy.root().key()) | |||
.setParam("projectName", moduleHierarchy.root().getOriginalName()) | |||
.setParam("projectBranch", moduleHierarchy.root().getBranch()) | |||
@@ -204,7 +204,7 @@ public class ReportPublisher implements Startable { | |||
Map<String, String> metadata = new LinkedHashMap<>(); | |||
String effectiveKey = moduleHierarchy.root().getKeyWithBranch(); | |||
settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).ifPresent(org -> metadata.put("organization", org)); | |||
settings.get(ORGANIZATION).ifPresent(org -> metadata.put("organization", org)); | |||
metadata.put("projectKey", effectiveKey); | |||
metadata.put("serverUrl", publicUrl); | |||
metadata.put("serverVersion", server.getVersion()); |
@@ -29,7 +29,6 @@ import java.util.Optional; | |||
import java.util.function.BinaryOperator; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.io.IOUtils; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.scanner.bootstrap.ScannerWsClient; | |||
@@ -39,6 +38,7 @@ import org.sonarqube.ws.client.GetRequest; | |||
import static java.util.function.Function.identity; | |||
import static java.util.stream.Collectors.toMap; | |||
import static org.sonar.core.config.ScannerProperties.ORGANIZATION; | |||
import static org.sonar.scanner.util.ScannerUtils.encodeForUrl; | |||
public class DefaultQualityProfileLoader implements QualityProfileLoader { | |||
@@ -82,7 +82,7 @@ public class DefaultQualityProfileLoader implements QualityProfileLoader { | |||
} | |||
private Optional<String> getOrganizationKey() { | |||
return settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY); | |||
return settings.get(ORGANIZATION); | |||
} | |||
private Map<String, QualityProfile> call(String url) { |