Browse Source

SONAR-6823 WS batch/project with protobuf and new behaviors

tags/5.2-RC1
Teryk Bellahsene 8 years ago
parent
commit
5af4d8ed1f
21 changed files with 2710 additions and 678 deletions
  1. 84
    8
      server/sonar-server/src/main/java/org/sonar/server/batch/ProjectAction.java
  2. 42
    164
      server/sonar-server/src/main/java/org/sonar/server/batch/ProjectDataLoader.java
  3. 5
    5
      server/sonar-server/src/main/java/org/sonar/server/batch/ProjectDataQuery.java
  4. 13
    0
      server/sonar-server/src/main/java/org/sonar/server/ws/WsUtils.java
  5. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/batch/ProjectActionTest.java
  6. 41
    324
      server/sonar-server/src/test/java/org/sonar/server/batch/ProjectDataLoaderMediumTest.java
  7. 9
    5
      sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/FileData.java
  8. 16
    21
      sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectRepositories.java
  9. 0
    95
      sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectRepositoriesTest.java
  10. 2
    22
      sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/input/ProjectRepositoriesTest/testToJson.json
  11. 3
    14
      sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java
  12. 5
    6
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/cache/CacheSyncTest.java
  13. 1
    1
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java
  14. 2
    2
      sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectSettingsLoaderTest.java
  15. 5
    6
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/StatusDetectionTest.java
  16. 10
    0
      sonar-db/src/main/java/org/sonar/db/component/FilePathWithHashDto.java
  17. 2
    2
      sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml
  18. 3
    0
      sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java
  19. 2
    2
      sonar-db/src/test/resources/org/sonar/db/component/ComponentDaoTest/select_module_files_tree.xml
  20. 2417
    0
      sonar-ws/src/main/gen-java/org/sonarqube/ws/WsBatch.java
  21. 47
    0
      sonar-ws/src/main/protobuf/ws-batch.proto

+ 84
- 8
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectAction.java View File

@@ -20,12 +20,16 @@

package org.sonar.server.batch;

import org.apache.commons.io.IOUtils;
import java.util.HashMap;
import java.util.Map;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.batch.protocol.input.FileData;
import org.sonar.batch.protocol.input.ProjectRepositories;
import org.sonar.server.plugins.MimeTypes;
import org.sonarqube.ws.WsBatch.WsProjectResponse;

import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class ProjectAction implements BatchWsAction {

@@ -66,13 +70,85 @@ public class ProjectAction implements BatchWsAction {
}

@Override
public void handle(Request request, Response response) throws Exception {
public void handle(Request wsRequest, Response wsResponse) throws Exception {
ProjectRepositories data = projectDataLoader.load(ProjectDataQuery.create()
.setModuleKey(request.mandatoryParam(PARAM_KEY))
.setProfileName(request.param(PARAM_PROFILE))
.setPreview(request.mandatoryParamAsBoolean(PARAM_PREVIEW)));
response.stream().setMediaType(MimeTypes.JSON);
IOUtils.write(data.toJson(), response.stream().output());
.setModuleKey(wsRequest.mandatoryParam(PARAM_KEY))
.setProfileName(wsRequest.param(PARAM_PROFILE))
.setIssuesMode(wsRequest.mandatoryParamAsBoolean(PARAM_PREVIEW)));

WsProjectResponse projectResponse = buildResponse(data);
writeProtobuf(projectResponse, wsRequest, wsResponse);
}

private static WsProjectResponse buildResponse(ProjectRepositories data) {
WsProjectResponse.Builder response = WsProjectResponse.newBuilder();
setLastAnalysisDate(response, data);
response.setTimestamp(data.timestamp());
response.getMutableFileDataByModuleAndPatch()
.putAll(buildFileDataByModuleAndPatch(data));
response.getMutableSettingsByModule()
.putAll(buildSettingsByModule(data));

return response.build();
}

private static void setLastAnalysisDate(WsProjectResponse.Builder response, ProjectRepositories data) {
if (data.lastAnalysisDate() != null) {
response.setLastAnalysisDate(data.lastAnalysisDate().getTime());
}
}

private static Map<String, WsProjectResponse.FileDataByPath> buildFileDataByModuleAndPatch(ProjectRepositories data) {
Map<String, WsProjectResponse.FileDataByPath> fileDataByModuleAndPathResponse = new HashMap<>();
for (Map.Entry<String, Map<String, FileData>> moduleAndFileDataByPathEntry : data.fileDataByModuleAndPath().entrySet()) {
fileDataByModuleAndPathResponse.put(
moduleAndFileDataByPathEntry.getKey(),
buildFileDataByPath(moduleAndFileDataByPathEntry.getValue()));
}

return fileDataByModuleAndPathResponse;
}

private static WsProjectResponse.FileDataByPath buildFileDataByPath(Map<String, FileData> fileDataByPath) {
WsProjectResponse.FileDataByPath.Builder response = WsProjectResponse.FileDataByPath.newBuilder();
Map<String, WsProjectResponse.FileData> fileDataByPathResponse = response.getMutableFileDataByPath();

for (Map.Entry<String, FileData> pathFileDataEntry : fileDataByPath.entrySet()) {
fileDataByPathResponse.put(
pathFileDataEntry.getKey(),
toFileDataResponse(pathFileDataEntry.getValue()));
}

return response.build();
}

private static Map<String, WsProjectResponse.Settings> buildSettingsByModule(ProjectRepositories data) {
Map<String, WsProjectResponse.Settings> settingsByModuleResponse = new HashMap<>();
for (Map.Entry<String, Map<String, String>> moduleSettingsEntry : data.settings().entrySet()) {
settingsByModuleResponse.put(
moduleSettingsEntry.getKey(),
toSettingsResponse(moduleSettingsEntry.getValue())
);
}

return settingsByModuleResponse;
}

private static WsProjectResponse.Settings toSettingsResponse(Map<String, String> settings) {
WsProjectResponse.Settings.Builder settingsResponse = WsProjectResponse.Settings
.newBuilder();
settingsResponse
.getMutableSettings()
.putAll(settings);

return settingsResponse.build();
}

private static WsProjectResponse.FileData toFileDataResponse(FileData fileData) {
return WsProjectResponse.FileData.newBuilder()
.setHash(fileData.hash())
.setRevision(fileData.revision())
.build();
}

}

+ 42
- 164
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectDataLoader.java View File

@@ -20,20 +20,13 @@

package org.sonar.server.batch;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -41,28 +34,19 @@ import org.sonar.api.web.UserRole;
import org.sonar.batch.protocol.input.FileData;
import org.sonar.batch.protocol.input.ProjectRepositories;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.util.UtcDateUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.FilePathWithHashDto;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.qualityprofile.ActiveRule;
import org.sonar.server.qualityprofile.QProfileFactory;
import org.sonar.server.qualityprofile.QProfileLoader;
import org.sonar.server.rule.Rule;
import org.sonar.server.rule.RuleService;
import org.sonar.server.rule.index.RuleNormalizer;
import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.search.QueryContext;
import org.sonar.server.search.Result;
import org.sonar.server.user.UserSession;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static java.lang.String.format;
import static org.sonar.server.ws.WsUtils.checkFound;

@ServerSide
public class ProjectDataLoader {
@@ -70,73 +54,60 @@ public class ProjectDataLoader {
private static final Logger LOG = Loggers.get(ProjectDataLoader.class);

private final DbClient dbClient;
private final QProfileFactory qProfileFactory;
private final QProfileLoader qProfileLoader;
private final RuleService ruleService;
private final Languages languages;
private final UserSession userSession;

public ProjectDataLoader(DbClient dbClient, QProfileFactory qProfileFactory, QProfileLoader qProfileLoader, RuleService ruleService,
Languages languages, UserSession userSession) {
public ProjectDataLoader(DbClient dbClient, UserSession userSession) {
this.dbClient = dbClient;
this.qProfileFactory = qProfileFactory;
this.qProfileLoader = qProfileLoader;
this.ruleService = ruleService;
this.languages = languages;
this.userSession = userSession;
}

public ProjectRepositories load(ProjectDataQuery query) {
boolean hasScanPerm = userSession.hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
checkPermission(query.isPreview());
checkPermission(query.isIssuesMode());

DbSession session = dbClient.openSession(false);
try {
ProjectRepositories ref = new ProjectRepositories();
String projectKey = query.getModuleKey();
Optional<ComponentDto> moduleOptional = dbClient.componentDao().selectByKey(session, query.getModuleKey());
// Current project/module can be null when analysing a new project
if (moduleOptional.isPresent()) {
ComponentDto module = moduleOptional.get();
// Scan permission is enough to analyze all projects but preview permission is limited to projects user can access
if (query.isPreview() && !userSession.hasProjectPermissionByUuid(UserRole.USER, module.projectUuid())) {
throw new ForbiddenException("You're not authorized to access to project '" + module.name() + "', please contact your SonarQube administrator.");
}
ProjectRepositories data = new ProjectRepositories();
ComponentDto module = checkFound(dbClient.componentDao().selectByKey(session, query.getModuleKey()),
format("Project or module with key '%s' is not found", query.getModuleKey()));

ComponentDto project = getProject(module, session);
if (!project.key().equals(module.key())) {
addSettings(ref, module.getKey(), getSettingsFromParents(module, hasScanPerm, session));
projectKey = project.key();
}
// Scan permission is enough to analyze all projects but preview permission is limited to projects user can access
if (query.isIssuesMode() && !userSession.hasProjectPermissionByUuid(UserRole.USER, module.projectUuid())) {
throw new ForbiddenException("You're not authorized to access to project '" + module.name() + "', please contact your SonarQube administrator.");
}

ComponentDto project = getProject(module, session);
if (!project.key().equals(module.key())) {
addSettings(data, module.getKey(), getSettingsFromParents(module, hasScanPerm, session));
}

List<ComponentDto> modulesTree = dbClient.componentDao().selectEnabledDescendantModules(session, module.uuid());
Map<String, String> moduleUuidsByKey = moduleUuidsByKey(module, modulesTree);
Map<String, Long> moduleIdsByKey = moduleIdsByKey(module, modulesTree);
List<ComponentDto> modulesTree = dbClient.componentDao().selectEnabledDescendantModules(session, module.uuid());
Map<String, String> moduleUuidsByKey = moduleUuidsByKey(modulesTree);
Map<String, Long> moduleIdsByKey = moduleIdsByKey(modulesTree);

List<PropertyDto> modulesTreeSettings = dbClient.propertiesDao().selectEnabledDescendantModuleProperties(module.uuid(), session);
TreeModuleSettings treeModuleSettings = new TreeModuleSettings(moduleUuidsByKey, moduleIdsByKey, modulesTree, modulesTreeSettings, module);
List<PropertyDto> modulesTreeSettings = dbClient.propertiesDao().selectEnabledDescendantModuleProperties(module.uuid(), session);
TreeModuleSettings treeModuleSettings = new TreeModuleSettings(moduleUuidsByKey, moduleIdsByKey, modulesTree, modulesTreeSettings);

addSettingsToChildrenModules(ref, query.getModuleKey(), Maps.<String, String>newHashMap(), treeModuleSettings, hasScanPerm, session);
List<FilePathWithHashDto> files = module.isRootProject() ? dbClient.componentDao().selectEnabledFilesFromProject(session, module.uuid())
: dbClient.componentDao().selectEnabledDescendantFiles(session, module.uuid());
addFileData(session, ref, modulesTree, files);
addSettingsToChildrenModules(data, query.getModuleKey(), Maps.<String, String>newHashMap(), treeModuleSettings, hasScanPerm);
List<FilePathWithHashDto> files = searchFilesWithHashAndRevision(session, module);
addFileData(data, modulesTree, files);

// FIXME need real value but actually only used to know if there is a previous analysis in local issue tracking mode so any value is
// ok
ref.setLastAnalysisDate(new Date());
} else {
ref.setLastAnalysisDate(null);
}
// FIXME need real value but actually only used to know if there is a previous analysis in local issue tracking mode so any value is
// ok
data.setLastAnalysisDate(new Date());

addProfiles(ref, projectKey, query.getProfileName(), session);
addActiveRules(ref);
addManualRules(ref);
return ref;
return data;
} finally {
MyBatis.closeQuietly(session);
}
}

private List<FilePathWithHashDto> searchFilesWithHashAndRevision(DbSession session, ComponentDto module) {
return module.isRootProject() ?
dbClient.componentDao().selectEnabledFilesFromProject(session, module.uuid())
: dbClient.componentDao().selectEnabledDescendantFiles(session, module.uuid());
}

private ComponentDto getProject(ComponentDto module, DbSession session) {
if (!module.isRootProject()) {
return dbClient.componentDao().selectOrFailByUuid(session, module.projectUuid());
@@ -169,7 +140,7 @@ public class ProjectDataLoader {
}

private void addSettingsToChildrenModules(ProjectRepositories ref, String moduleKey, Map<String, String> parentProperties, TreeModuleSettings treeModuleSettings,
boolean hasScanPerm, DbSession session) {
boolean hasScanPerm) {
Map<String, String> currentParentProperties = newHashMap();
currentParentProperties.putAll(parentProperties);
currentParentProperties.putAll(getPropertiesMap(treeModuleSettings.findModuleSettings(moduleKey), hasScanPerm));
@@ -177,7 +148,7 @@ public class ProjectDataLoader {

for (ComponentDto childModule : treeModuleSettings.findChildrenModule(moduleKey)) {
addSettings(ref, childModule.getKey(), currentParentProperties);
addSettingsToChildrenModules(ref, childModule.getKey(), currentParentProperties, treeModuleSettings, hasScanPerm, session);
addSettingsToChildrenModules(ref, childModule.getKey(), currentParentProperties, treeModuleSettings, hasScanPerm);
}
}

@@ -203,99 +174,15 @@ public class ProjectDataLoader {
return !key.contains(".secured") || hasScanPerm;
}

private void addProfiles(ProjectRepositories ref, @Nullable String projectKey, @Nullable String profileName, DbSession session) {
for (Language language : languages.all()) {
String languageKey = language.getKey();
QualityProfileDto qualityProfileDto = getProfile(languageKey, projectKey, profileName, session);
ref.addQProfile(new org.sonar.batch.protocol.input.QProfile(
qualityProfileDto.getKey(),
qualityProfileDto.getName(),
qualityProfileDto.getLanguage(),
UtcDateUtils.parseDateTime(qualityProfileDto.getRulesUpdatedAt())));
}
}

/**
* First try to find a quality profile matching the given name (if provided) and current language
* If no profile found, try to find the quality profile set on the project (if provided)
* If still no profile found, try to find the default profile of the language
* <p/>
* Never return null because a default profile should always be set on each language
*/
private QualityProfileDto getProfile(String languageKey, @Nullable String projectKey, @Nullable String profileName, DbSession session) {
QualityProfileDto qualityProfileDto = profileName != null ? qProfileFactory.getByNameAndLanguage(session, profileName, languageKey) : null;
if (qualityProfileDto == null && projectKey != null) {
qualityProfileDto = qProfileFactory.getByProjectAndLanguage(session, projectKey, languageKey);
}
qualityProfileDto = qualityProfileDto != null ? qualityProfileDto : qProfileFactory.getDefault(session, languageKey);
if (qualityProfileDto != null) {
return qualityProfileDto;
} else {
throw new IllegalStateException(String.format("No quality profile can been found on language '%s' for project '%s'", languageKey, projectKey));
}
}

private void addActiveRules(ProjectRepositories ref) {
for (org.sonar.batch.protocol.input.QProfile qProfile : ref.qProfiles()) {
// Load all rules of the profile language (only needed fields are loaded)
Map<RuleKey, Rule> languageRules = ruleByRuleKey(ruleService.search(new RuleQuery().setLanguages(newArrayList(qProfile.language())),
new QueryContext(userSession).setLimit(100).setFieldsToReturn(newArrayList(
RuleNormalizer.RuleField.KEY.field(), RuleNormalizer.RuleField.NAME.field(), RuleNormalizer.RuleField.INTERNAL_KEY.field(),
RuleNormalizer.RuleField.TEMPLATE_KEY.field())).setScroll(true))
.scroll());
for (Iterator<ActiveRule> activeRuleIterator = qProfileLoader.findActiveRulesByProfile(qProfile.key()); activeRuleIterator.hasNext();) {
ActiveRule activeRule = activeRuleIterator.next();
Rule rule = languageRules.get(activeRule.key().ruleKey());
if (rule == null) {
// It should never happen, but we need some log in case it happens
LOG.warn("Rule could not be found on active rule '{}'", activeRule.key());
} else {
RuleKey templateKey = rule.templateKey();
org.sonar.batch.protocol.input.ActiveRule inputActiveRule = new org.sonar.batch.protocol.input.ActiveRule(
activeRule.key().ruleKey().repository(),
activeRule.key().ruleKey().rule(),
templateKey != null ? templateKey.rule() : null,
rule.name(),
activeRule.severity(),
rule.internalKey(),
qProfile.language());
for (Map.Entry<String, String> entry : activeRule.params().entrySet()) {
inputActiveRule.addParam(entry.getKey(), entry.getValue());
}
ref.addActiveRule(inputActiveRule);
}
}
}
}

private Map<RuleKey, Rule> ruleByRuleKey(Iterator<Rule> rules) {
return Maps.uniqueIndex(rules, MatchRuleKey.INSTANCE);
}

private void addManualRules(ProjectRepositories ref) {
Result<Rule> ruleSearchResult = ruleService.search(new RuleQuery().setRepositories(newArrayList(RuleKey.MANUAL_REPOSITORY_KEY)), new QueryContext(userSession).setScroll(true)
.setFieldsToReturn(newArrayList(RuleNormalizer.RuleField.KEY.field(), RuleNormalizer.RuleField.NAME.field())));
Iterator<Rule> rules = ruleSearchResult.scroll();
while (rules.hasNext()) {
Rule rule = rules.next();
ref.addActiveRule(new org.sonar.batch.protocol.input.ActiveRule(
RuleKey.MANUAL_REPOSITORY_KEY,
rule.key().rule(),
null, rule.name(),
null, null, null));
}
}

private static void addFileData(DbSession session, ProjectRepositories ref, List<ComponentDto> moduleChildren, List<FilePathWithHashDto> files) {
private static void addFileData(ProjectRepositories data, List<ComponentDto> moduleChildren, List<FilePathWithHashDto> files) {
Map<String, String> moduleKeysByUuid = newHashMap();
for (ComponentDto module : moduleChildren) {
moduleKeysByUuid.put(module.uuid(), module.key());
}

for (FilePathWithHashDto file : files) {
// TODO should query E/S to know if blame is missing on this file
FileData fileData = new FileData(file.getSrcHash(), true);
ref.addFileData(moduleKeysByUuid.get(file.getModuleUuid()), file.getPath(), fileData);
FileData fileData = new FileData(file.getSrcHash(), file.getRevision());
data.addFileData(moduleKeysByUuid.get(file.getModuleUuid()), file.getPath(), fileData);
}
}

@@ -314,7 +201,7 @@ public class ProjectDataLoader {
}
}

private static Map<String, String> moduleUuidsByKey(ComponentDto module, List<ComponentDto> moduleChildren) {
private static Map<String, String> moduleUuidsByKey(List<ComponentDto> moduleChildren) {
Map<String, String> moduleUuidsByKey = newHashMap();
for (ComponentDto componentDto : moduleChildren) {
moduleUuidsByKey.put(componentDto.key(), componentDto.uuid());
@@ -322,7 +209,7 @@ public class ProjectDataLoader {
return moduleUuidsByKey;
}

private static Map<String, Long> moduleIdsByKey(ComponentDto module, List<ComponentDto> moduleChildren) {
private static Map<String, Long> moduleIdsByKey(List<ComponentDto> moduleChildren) {
Map<String, Long> moduleIdsByKey = newHashMap();
for (ComponentDto componentDto : moduleChildren) {
moduleIdsByKey.put(componentDto.key(), componentDto.getId());
@@ -338,7 +225,7 @@ public class ProjectDataLoader {
private Multimap<String, ComponentDto> moduleChildrenByModuleUuid;

private TreeModuleSettings(Map<String, String> moduleUuidsByKey, Map<String, Long> moduleIdsByKey, List<ComponentDto> moduleChildren,
List<PropertyDto> moduleChildrenSettings, ComponentDto module) {
List<PropertyDto> moduleChildrenSettings) {
this.moduleIdsByKey = moduleIdsByKey;
this.moduleUuidsByKey = moduleUuidsByKey;
propertiesByModuleId = ArrayListMultimap.create();
@@ -366,13 +253,4 @@ public class ProjectDataLoader {
return newArrayList(moduleChildrenByModuleUuid.get(moduleUuid));
}
}

private enum MatchRuleKey implements Function<Rule, RuleKey> {
INSTANCE;

@Override
public RuleKey apply(@Nullable Rule input) {
return input != null ? input.key() : null;
}
}
}

+ 5
- 5
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectDataQuery.java View File

@@ -27,18 +27,18 @@ public class ProjectDataQuery {

private String projectOrModuleKey;
private String profileName;
private boolean preview;
private boolean issuesMode;

private ProjectDataQuery() {
// No direct call
}

public boolean isPreview() {
return preview;
public boolean isIssuesMode() {
return issuesMode;
}

public ProjectDataQuery setPreview(boolean preview) {
this.preview = preview;
public ProjectDataQuery setIssuesMode(boolean issuesMode) {
this.issuesMode = issuesMode;
return this;
}


+ 13
- 0
server/sonar-server/src/main/java/org/sonar/server/ws/WsUtils.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.server.ws;

import com.google.common.base.Optional;
import com.google.protobuf.Message;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@@ -74,4 +75,16 @@ public class WsUtils {

return value;
}

/**
* @throws NotFoundException if the value is not present
* @return the value
*/
public static <T> T checkFound(Optional<T> value, String message) {
if (!value.isPresent()) {
throw new NotFoundException(message);
}

return value.get();
}
}

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectActionTest.java View File

@@ -59,7 +59,7 @@ public class ProjectActionTest {

assertThat(queryArgumentCaptor.getValue().getModuleKey()).isEqualTo(projectKey);
assertThat(queryArgumentCaptor.getValue().getProfileName()).isEqualTo("Default");
assertThat(queryArgumentCaptor.getValue().isPreview()).isFalse();
assertThat(queryArgumentCaptor.getValue().isIssuesMode()).isFalse();
}

}

+ 41
- 324
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectDataLoaderMediumTest.java View File

@@ -22,43 +22,30 @@ package org.sonar.server.batch;

import com.google.common.collect.ImmutableMap;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.web.UserRole;
import org.sonar.batch.protocol.input.ActiveRule;
import org.sonar.batch.protocol.input.FileData;
import org.sonar.batch.protocol.input.ProjectRepositories;
import org.sonar.batch.protocol.input.QProfile;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.db.source.FileSourceDao;
import org.sonar.db.source.FileSourceDto;
import org.sonar.db.source.FileSourceDto.Type;
import org.sonar.server.db.DbClient;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.qualityprofile.QProfileName;
import org.sonar.server.qualityprofile.RuleActivation;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.tester.UserSessionRule;

import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.sonar.api.utils.DateUtils.formatDateTime;
@@ -98,10 +85,10 @@ public class ProjectDataLoaderMediumTest {
// Project properties
tester.get(DbClient.class).propertiesDao().insertProperty(
dbSession, new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId())
);
);
tester.get(DbClient.class).propertiesDao().insertProperty(
dbSession, new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId())
);
);
dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
@@ -109,7 +96,7 @@ public class ProjectDataLoaderMediumTest {
assertThat(projectSettings).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john"
));
));
}

@Test
@@ -122,17 +109,17 @@ public class ProjectDataLoaderMediumTest {
// Project properties
tester.get(DbClient.class).propertiesDao().insertProperty(
dbSession, new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId())
);
);
tester.get(DbClient.class).propertiesDao().insertProperty(
dbSession, new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId())
);
);
dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()).setPreview(true));
ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()).setIssuesMode(true));
Map<String, String> projectSettings = ref.settings(project.key());
assertThat(projectSettings).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR"
));
));
}

@Test
@@ -163,12 +150,12 @@ public class ProjectDataLoaderMediumTest {
assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john"
));
));
assertThat(ref.settings(module.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR-SERVER",
"sonar.jira.login.secured", "john",
"sonar.coverage.exclusions", "**/*.java"
));
));
}

@Test
@@ -195,11 +182,11 @@ public class ProjectDataLoaderMediumTest {
assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john"
));
));
assertThat(ref.settings(module.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john"
));
));
}

@Test
@@ -237,17 +224,17 @@ public class ProjectDataLoaderMediumTest {
assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john"
));
));
assertThat(ref.settings(module.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR-SERVER",
"sonar.jira.login.secured", "john",
"sonar.coverage.exclusions", "**/*.java"
));
));
assertThat(ref.settings(subModule.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR-SERVER-DAO",
"sonar.jira.login.secured", "john",
"sonar.coverage.exclusions", "**/*.java"
));
));
}

@Test
@@ -265,9 +252,11 @@ public class ProjectDataLoaderMediumTest {
tester.get(DbClient.class).componentDao().insert(dbSession, module1);

// Module 1 properties
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER").setResourceId(module1.getId()));
tester.get(DbClient.class).propertiesDao()
.insertProperty(dbSession, new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER").setResourceId(module1.getId()));
// This property should not be found on the other module
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(module1.getId()));
tester.get(DbClient.class).propertiesDao()
.insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(module1.getId()));

ComponentDto module2 = ComponentTesting.newModuleDto(project);
tester.get(DbClient.class).componentDao().insert(dbSession, module2);
@@ -282,16 +271,16 @@ public class ProjectDataLoaderMediumTest {
assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john"
));
));
assertThat(ref.settings(module1.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR-SERVER",
"sonar.jira.login.secured", "john",
"sonar.coverage.exclusions", "**/*.java"
));
));
assertThat(ref.settings(module2.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR-APPLICATION",
"sonar.jira.login.secured", "john"
));
));
}

@Test
@@ -312,7 +301,7 @@ public class ProjectDataLoaderMediumTest {
assertThat(ref.settings(project.key())).isEqualTo(ImmutableMap.of(
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john"
));
));
}

@Test
@@ -334,7 +323,8 @@ public class ProjectDataLoaderMediumTest {
// Sub module properties
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(subModule.getId()));
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(subModule.getId()));
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(subModule.getId()));
tester.get(DbClient.class).propertiesDao()
.insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(subModule.getId()));

dbSession.commit();

@@ -345,7 +335,7 @@ public class ProjectDataLoaderMediumTest {
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john",
"sonar.coverage.exclusions", "**/*.java"
));
));
}

@Test
@@ -368,7 +358,8 @@ public class ProjectDataLoaderMediumTest {
tester.get(DbClient.class).componentDao().insert(dbSession, subModule);

// Sub module properties
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(subModule.getId()));
tester.get(DbClient.class).propertiesDao()
.insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(subModule.getId()));

dbSession.commit();

@@ -379,7 +370,7 @@ public class ProjectDataLoaderMediumTest {
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john",
"sonar.coverage.exclusions", "**/*.java"
));
));
}

@Test
@@ -391,7 +382,8 @@ public class ProjectDataLoaderMediumTest {
// Project properties
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR").setResourceId(project.getId()));
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()));
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(project.getId()));
tester.get(DbClient.class).propertiesDao()
.insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(project.getId()));

ComponentDto module = ComponentTesting.newModuleDto(project);
tester.get(DbClient.class).componentDao().insert(dbSession, module);
@@ -411,7 +403,7 @@ public class ProjectDataLoaderMediumTest {
"sonar.jira.project.key", "SONAR",
"sonar.jira.login.secured", "john",
"sonar.coverage.exclusions", "**/*.java"
));
));
}

@Test
@@ -422,7 +414,8 @@ public class ProjectDataLoaderMediumTest {

// Project properties
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(project.getId()));
tester.get(DbClient.class).propertiesDao().insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(project.getId()));
tester.get(DbClient.class).propertiesDao()
.insertProperty(dbSession, new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java").setResourceId(project.getId()));

ComponentDto module = ComponentTesting.newModuleDto(project);
tester.get(DbClient.class).componentDao().insert(dbSession, module);
@@ -444,285 +437,7 @@ public class ProjectDataLoaderMediumTest {
"sonar.jira.project.key", "SONAR-SERVER",
"sonar.jira.login.secured", "john",
"sonar.coverage.exclusions", "**/*.java"
));
}

@Test
public void return_quality_profile_from_project_profile() {
Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");

ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);

QualityProfileDto profileDto = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(
formatDateTime(ruleUpdatedAt));
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
tester.get(DbClient.class).qualityProfileDao().insertProjectProfileAssociation(project.uuid(), profileDto.getKee(), dbSession);

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
List<QProfile> profiles = newArrayList(ref.qProfiles());
assertThat(profiles).hasSize(1);
assertThat(profiles.get(0).key()).isEqualTo("abcd");
assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
assertThat(profiles.get(0).language()).isEqualTo("xoo");
assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
}

@Test
public void return_quality_profile_from_default_profile() {
Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");

ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);

QualityProfileDto profileDto = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(
formatDateTime(ruleUpdatedAt)).setDefault(true);
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
List<QProfile> profiles = newArrayList(ref.qProfiles());
assertThat(profiles).hasSize(1);
assertThat(profiles.get(0).key()).isEqualTo("abcd");
assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
assertThat(profiles.get(0).language()).isEqualTo("xoo");
assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
}

@Test
public void return_quality_profile_from_given_profile_name() {
Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");

ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);

QualityProfileDto profileDto = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(
formatDateTime(ruleUpdatedAt)).setDefault(true);
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()).setProfileName("SonarQube way"));
List<QProfile> profiles = newArrayList(ref.qProfiles());
assertThat(profiles).hasSize(1);
assertThat(profiles.get(0).key()).isEqualTo("abcd");
assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
assertThat(profiles.get(0).language()).isEqualTo("xoo");
assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
}

@Test
public void return_quality_profiles_even_when_project_does_not_exists() {
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");

QualityProfileDto profileDto = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(
formatDateTime(ruleUpdatedAt)).setDefault(true);
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey("project"));
List<QProfile> profiles = newArrayList(ref.qProfiles());
assertThat(profiles).hasSize(1);
assertThat(profiles.get(0).key()).isEqualTo("abcd");
assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
assertThat(profiles.get(0).language()).isEqualTo("xoo");
assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
}

@Test
public void return_provisioned_project_profile() {
Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");

// No snapshot attached on the project -> provisioned project
ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);

QualityProfileDto profileDto = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(
formatDateTime(ruleUpdatedAt));
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
tester.get(DbClient.class).qualityProfileDao().insertProjectProfileAssociation(project.uuid(), profileDto.getKee(), dbSession);

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
List<QProfile> profiles = newArrayList(ref.qProfiles());
assertThat(profiles).hasSize(1);
assertThat(profiles.get(0).key()).isEqualTo("abcd");
assertThat(profiles.get(0).name()).isEqualTo("SonarQube way");
assertThat(profiles.get(0).language()).isEqualTo("xoo");
assertThat(profiles.get(0).rulesUpdatedAt()).isEqualTo(ruleUpdatedAt);
}

@Test
public void fail_when_no_quality_profile_for_a_language() {
ComponentDto project = ComponentTesting.newProjectDto().setKey("org.codehaus.sonar:sonar");
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);
dbSession.commit();

try {
loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("No quality profile can been found on language 'xoo' for project 'org.codehaus.sonar:sonar'");
}
}

@Test
public void return_active_rules() {
ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);

QualityProfileDto profileDto = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(
formatDateTime(DateUtils.parseDateTime("2014-01-14T13:00:00+0100"))).setDefault(true);
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);

RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
RuleDto rule = RuleTesting.newDto(ruleKey).setName("Avoid Cycle").setConfigKey("squid-1").setLanguage(ServerTester.Xoo.KEY);
tester.get(DbClient.class).deprecatedRuleDao().insert(dbSession, rule);
tester.get(DbClient.class).deprecatedRuleDao().insertRuleParam(dbSession, rule, RuleParamDto.createFor(rule)
.setName("max").setDefaultValue("10").setType(RuleParamType.INTEGER.type()));

RuleActivation activation = new RuleActivation(ruleKey);
activation.setSeverity(Severity.MINOR);
activation.setParameter("max", "2");
tester.get(RuleActivator.class).activate(dbSession, activation, profileDto.getKey());

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
List<ActiveRule> activeRules = newArrayList(ref.activeRules());
assertThat(activeRules).hasSize(1);
assertThat(activeRules.get(0).repositoryKey()).isEqualTo("squid");
assertThat(activeRules.get(0).ruleKey()).isEqualTo("AvoidCycle");
assertThat(activeRules.get(0).name()).isEqualTo("Avoid Cycle");
assertThat(activeRules.get(0).language()).isEqualTo("xoo");
assertThat(activeRules.get(0).severity()).isEqualTo("MINOR");
assertThat(activeRules.get(0).internalKey()).isEqualTo("squid-1");
assertThat(activeRules.get(0).params()).isEqualTo(ImmutableMap.of("max", "2"));
}

@Test
public void return_only_active_rules_from_project_profile() {
ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);

RuleKey ruleKey1 = RuleKey.of("squid", "AvoidCycle");
RuleKey ruleKey2 = RuleKey.of("squid", "AvoidNPE");
tester.get(DbClient.class).deprecatedRuleDao().insert(dbSession,
RuleTesting.newDto(ruleKey1).setName("Avoid Cycle").setLanguage(ServerTester.Xoo.KEY),
RuleTesting.newDto(ruleKey2).setName("Avoid NPE").setLanguage(ServerTester.Xoo.KEY)
);

QualityProfileDto profileDto1 = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd");
QualityProfileDto profileDto2 = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "Another profile"), "efgh");
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto1, profileDto2);

// The first profile is the profile used but the project
tester.get(DbClient.class).qualityProfileDao().insertProjectProfileAssociation(project.uuid(), profileDto1.getKee(), dbSession);

tester.get(RuleActivator.class).activate(dbSession, new RuleActivation(ruleKey1).setSeverity(Severity.MINOR), profileDto1.getKey());

// Active rule from 2nd profile
tester.get(RuleActivator.class).activate(dbSession, new RuleActivation(ruleKey1).setSeverity(Severity.BLOCKER), profileDto2.getKey());
tester.get(RuleActivator.class).activate(dbSession, new RuleActivation(ruleKey2).setSeverity(Severity.BLOCKER), profileDto2.getKey());

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
List<ActiveRule> activeRules = newArrayList(ref.activeRules());
assertThat(activeRules).hasSize(1);
assertThat(activeRules.get(0).repositoryKey()).isEqualTo("squid");
assertThat(activeRules.get(0).ruleKey()).isEqualTo("AvoidCycle");
assertThat(activeRules.get(0).name()).isEqualTo("Avoid Cycle");
assertThat(activeRules.get(0).language()).isEqualTo("xoo");
assertThat(activeRules.get(0).severity()).isEqualTo("MINOR");
}

@Test
public void return_more_than_10_active_rules() {
ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);

QualityProfileDto profileDto = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd")
.setRulesUpdatedAt(formatDateTime(DateUtils.parseDateTime("2014-01-14T13:00:00+0100"))).setDefault(true);
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);

for (int i = 0; i < 20; i++) {
RuleKey ruleKey = RuleKey.of("squid", "Rule" + i);
tester.get(DbClient.class).deprecatedRuleDao().insert(dbSession, RuleTesting.newDto(ruleKey).setName("Rule" + i).setLanguage(ServerTester.Xoo.KEY));
tester.get(RuleActivator.class).activate(dbSession, new RuleActivation(ruleKey).setSeverity(Severity.MINOR), profileDto.getKey());
}

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
assertThat(ref.activeRules()).hasSize(20);
}

@Test
public void return_custom_rule() {
Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100");

ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);

QualityProfileDto profileDto = newQProfileDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt(
formatDateTime(ruleUpdatedAt)).setDefault(true);
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);

RuleKey ruleKey = RuleKey.of("squid", "ArchitecturalConstraint");
RuleDto templateRule = RuleTesting.newTemplateRule(ruleKey).setName("Architectural Constraint").setLanguage(ServerTester.Xoo.KEY);
tester.get(DbClient.class).deprecatedRuleDao().insert(dbSession, templateRule);

RuleDto customRule = RuleTesting.newCustomRule(templateRule);
tester.get(DbClient.class).deprecatedRuleDao().insert(dbSession, customRule);
tester.get(RuleActivator.class).activate(dbSession, new RuleActivation(customRule.getKey()).setSeverity(Severity.MINOR), profileDto.getKey());

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
List<ActiveRule> activeRules = newArrayList(ref.activeRules());
assertThat(activeRules).hasSize(1);
assertThat(activeRules.get(0).repositoryKey()).isEqualTo("squid");
assertThat(activeRules.get(0).ruleKey()).startsWith("ArchitecturalConstraint_");
assertThat(activeRules.get(0).templateRuleKey()).isEqualTo("ArchitecturalConstraint");
assertThat(activeRules.get(0).language()).isEqualTo("xoo");
assertThat(activeRules.get(0).severity()).isEqualTo("MINOR");
}

@Test
public void return_manual_rules() {
ComponentDto project = ComponentTesting.newProjectDto();
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
tester.get(DbClient.class).componentDao().insert(dbSession, project);
addDefaultProfile();

RuleDto rule = RuleTesting.newManualRule("manualRuleKey").setName("Name manualRuleKey");
tester.get(DbClient.class).deprecatedRuleDao().insert(dbSession, rule);

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(project.key()));
List<ActiveRule> activeRules = newArrayList(ref.activeRules());
assertThat(activeRules).extracting("repositoryKey").containsOnly(RuleKey.MANUAL_REPOSITORY_KEY);
assertThat(activeRules).extracting("ruleKey").containsOnly("manualRuleKey");
assertThat(activeRules).extracting("name").containsOnly("Name manualRuleKey");
assertThat(activeRules).extracting("language").containsNull();
assertThat(activeRules).extracting("severity").containsNull();
));
}

@Test
@@ -750,7 +465,7 @@ public class ProjectDataLoaderMediumTest {
dbSession.commit();

try {
loader.load(ProjectDataQuery.create().setModuleKey(project.key()).setPreview(false));
loader.load(ProjectDataQuery.create().setModuleKey(project.key()).setIssuesMode(false));
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage(
@@ -814,7 +529,7 @@ public class ProjectDataLoaderMediumTest {
// File on project
ComponentDto projectFile = ComponentTesting.newFileDto(project, "projectFile");
tester.get(DbClient.class).componentDao().insert(dbSession, projectFile);
tester.get(FileSourceDao.class).insert(newFileSourceDto(projectFile).setSrcHash("123456"));
tester.get(FileSourceDao.class).insert(newFileSourceDto(projectFile).setSrcHash("123456").setRevision("987654321"));

ComponentDto module = ComponentTesting.newModuleDto(project);
userSessionRule.login("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
@@ -823,12 +538,13 @@ public class ProjectDataLoaderMediumTest {
// File on module
ComponentDto moduleFile = ComponentTesting.newFileDto(module, "moduleFile");
tester.get(DbClient.class).componentDao().insert(dbSession, moduleFile);
tester.get(FileSourceDao.class).insert(newFileSourceDto(moduleFile).setSrcHash("789456"));
tester.get(FileSourceDao.class).insert(newFileSourceDto(moduleFile).setSrcHash("789456").setRevision("123456789"));

dbSession.commit();

ProjectRepositories ref = loader.load(ProjectDataQuery.create().setModuleKey(module.key()));
assertThat(ref.fileData(module.key(), moduleFile.path()).hash()).isEqualTo("789456");
assertThat(ref.fileData(module.key(), moduleFile.path()).revision()).isEqualTo("123456789");
assertThat(ref.fileData(project.key(), projectFile.path())).isNull();
}

@@ -838,16 +554,17 @@ public class ProjectDataLoaderMediumTest {
tester.get(DbClient.class).qualityProfileDao().insert(dbSession, profileDto);
}

private FileSourceDto newFileSourceDto(ComponentDto file) {
private static FileSourceDto newFileSourceDto(ComponentDto file) {
return new FileSourceDto()
.setFileUuid(file.uuid())
.setProjectUuid(file.projectUuid())
//.setSourceData(",,,,,,,,,,,,,,,unchanged&#13;&#10;,,,,,,,,,,,,,,,content&#13;&#10;")
// .setSourceData(",,,,,,,,,,,,,,,unchanged&#13;&#10;,,,,,,,,,,,,,,,content&#13;&#10;")
.setDataHash("0263047cd758c68c27683625f072f010")
.setLineHashes("8d7b3d6b83c0a517eac07e1aac94b773")
.setCreatedAt(System.currentTimeMillis())
.setUpdatedAt(System.currentTimeMillis())
.setDataType(Type.SOURCE)
.setRevision("123456789")
.setSrcHash("123456");
}


+ 9
- 5
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/FileData.java View File

@@ -25,11 +25,11 @@ import javax.annotation.Nullable;
public class FileData {

private final String hash;
private final boolean needBlame;
private final String revision;

public FileData(@Nullable String hash, boolean needBlame) {
public FileData(@Nullable String hash, @Nullable String revision) {
this.hash = hash;
this.needBlame = needBlame;
this.revision = revision;
}

@CheckForNull
@@ -37,8 +37,12 @@ public class FileData {
return hash;
}

public boolean needBlame() {
return needBlame;
@CheckForNull
public String revision() {
return revision;
}

public boolean needBlame() {
return false;
}
}

+ 16
- 21
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/ProjectRepositories.java View File

@@ -36,8 +36,6 @@ import org.sonar.batch.protocol.GsonHelper;
public class ProjectRepositories {

private long timestamp;
private Map<String, QProfile> qprofilesByLanguage = new HashMap<>();
private Collection<ActiveRule> activeRules = new ArrayList<>();
private Map<String, Map<String, String>> settingsByModule = new HashMap<>();
private Map<String, Map<String, FileData>> fileDataByModuleAndPath = new HashMap<>();
private Date lastAnalysisDate;
@@ -45,7 +43,7 @@ public class ProjectRepositories {
public Map<String, String> settings(String moduleKey) {
return settingsByModule.containsKey(moduleKey) ? settingsByModule.get(moduleKey) : Collections.<String, String>emptyMap();
}
public Map<String, Map<String, String>> settings() {
return settingsByModule;
}
@@ -60,24 +58,6 @@ public class ProjectRepositories {
return this;
}

public Collection<QProfile> qProfiles() {
return qprofilesByLanguage.values();
}

public ProjectRepositories addQProfile(QProfile qProfile) {
qprofilesByLanguage.put(qProfile.language(), qProfile);
return this;
}

public Collection<ActiveRule> activeRules() {
return activeRules;
}

public ProjectRepositories addActiveRule(ActiveRule activeRule) {
activeRules.add(activeRule);
return this;
}

public Map<String, Map<String, FileData>> fileDataByModuleAndPath() {
return fileDataByModuleAndPath;
}
@@ -126,4 +106,19 @@ public class ProjectRepositories {
return GsonHelper.create().fromJson(json, ProjectRepositories.class);
}

public Collection<QProfile> qProfiles() {
return new ArrayList<>();
}

public Collection<ActiveRule> activeRules() {
return new ArrayList<>();
}

public void addQProfile(QProfile qProfile) {
// do nothing
}

public void addActiveRule(ActiveRule activeRule) {
// do nothing
}
}

+ 0
- 95
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectRepositoriesTest.java View File

@@ -1,95 +0,0 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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.batch.protocol.input;

import org.junit.Test;
import org.sonar.test.JsonAssert;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;

import static org.assertj.core.api.Assertions.assertThat;

public class ProjectRepositoriesTest {

public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

@Test
public void testToJson() throws Exception {
ProjectRepositories ref = new ProjectRepositories();
assertThat(ref.settings("foo")).isEmpty();

ref.addQProfile(new QProfile("squid-java", "Java", "java", DATE_FORMAT.parse("2013-01-01T12:00:00+0100")));
HashMap<String, String> settings = new HashMap<>();
settings.put("prop1", "value1");
ref.addSettings("foo", settings);
settings = new HashMap<>();
settings.put("prop2", "value2");
ref.addSettings("foo", settings);
ref.settings("foo").put("prop", "value");
ActiveRule activeRule = new ActiveRule("repo", "rule", "templateRule", "Rule", "MAJOR", "rule", "java");
activeRule.addParam("param1", "value1");
ref.addActiveRule(activeRule);
ref.setLastAnalysisDate(DATE_FORMAT.parse("2014-05-18T15:50:45+0100"));
ref.setTimestamp(10);
ref.addFileData("foo", "src/main/java/Foo.java", new FileData("xyz", true));
ref.addFileData("foo", "src/main/java/Foo2.java", new FileData("xyz", false));

JsonAssert.assertJson(ref.toJson())
.isSimilarTo(getClass().getResource("ProjectRepositoriesTest/testToJson.json"));
}

@Test
public void testFromJson() throws ParseException {
ProjectRepositories ref = ProjectRepositories
.fromJson("{timestamp:1,"
+ "qprofilesByLanguage:{java:{key:\"squid-java\",name:Java,language:java,rulesUpdatedAt:\"2013-01-01T12:00:00+0100\"}},"
+ "activeRules:[{repositoryKey:repo,ruleKey:rule,templateRuleKey:templateRule,name:Rule,severity:MAJOR,internalKey:rule1,language:java,params:{param1:value1}}],"
+ "settingsByModule:{foo:{prop:value}},"
+ "fileDataByModuleAndPath:{foo:{\"src/main/java/Foo.java\":{hash:xyz,needBlame:true,scmLastCommitDatetimesByLine:\"1\u003d12345,2\u003d3456\",scmRevisionsByLine:\"1\u003d345,2\u003d345\",scmAuthorsByLine:\"1\u003dhenryju,2\u003dgaudin\"}}},"
+ "lastAnalysisDate:\"2014-10-31T00:00:00+0100\"}");

assertThat(ref.timestamp()).isEqualTo(1);

ActiveRule activeRule = ref.activeRules().iterator().next();
assertThat(activeRule.ruleKey()).isEqualTo("rule");
assertThat(activeRule.repositoryKey()).isEqualTo("repo");
assertThat(activeRule.templateRuleKey()).isEqualTo("templateRule");
assertThat(activeRule.name()).isEqualTo("Rule");
assertThat(activeRule.severity()).isEqualTo("MAJOR");
assertThat(activeRule.internalKey()).isEqualTo("rule1");
assertThat(activeRule.language()).isEqualTo("java");
assertThat(activeRule.params()).containsEntry("param1", "value1");
assertThat(activeRule.param("param1")).isEqualTo("value1");
QProfile qProfile = ref.qProfiles().iterator().next();
assertThat(qProfile.key()).isEqualTo("squid-java");
assertThat(qProfile.name()).isEqualTo("Java");
assertThat(qProfile.rulesUpdatedAt().getTime()).isEqualTo(DATE_FORMAT.parse("2013-01-01T12:00:00+0100").getTime());
assertThat(ref.settings("foo")).containsEntry("prop", "value");

assertThat(ref.fileData("foo2", "src/main/java/Foo3.java")).isNull();

assertThat(ref.fileData("foo", "src/main/java/Foo.java").hash()).isEqualTo("xyz");
assertThat(ref.fileData("foo", "src/main/java/Foo.java").needBlame()).isTrue();

assertThat(ref.lastAnalysisDate().getTime()).isEqualTo(DATE_FORMAT.parse("2014-10-31T00:00:00+0100").getTime());
}
}

+ 2
- 22
sonar-batch-protocol/src/test/resources/org/sonar/batch/protocol/input/ProjectRepositoriesTest/testToJson.json View File

@@ -1,25 +1,5 @@
{
"timestamp": 10,
"qprofilesByLanguage": {
"java": {
"key": "squid-java",
"name": "Java",
"language": "java",
"rulesUpdatedAt": "2013-01-01T12:00:00+0100"
}
},
"activeRules": [
{
"repositoryKey": "repo",
"ruleKey": "rule",
"templateRuleKey": "templateRule",
"name": "Rule",
"severity": "MAJOR",
"internalKey": "rule",
"language": "java",
"params": {"param1": "value1"}
}
],
"settingsByModule": {
"foo": {
"prop1": "value1",
@@ -31,11 +11,11 @@
"foo": {
"src/main/java/Foo.java": {
"hash": "xyz",
"needBlame": true,
"needBlame": true
},
"src/main/java/Foo2.java": {
"hash": "xyz",
"needBlame": false,
"needBlame": false
}
}
},

+ 3
- 14
sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java View File

@@ -19,17 +19,13 @@
*/
package org.sonar.batch.repository;

import org.sonar.batch.cache.WSLoaderResult;

import org.sonar.batch.analysis.DefaultAnalysisMode;
import org.sonar.batch.cache.WSLoader;

import javax.annotation.Nullable;

import org.apache.commons.lang.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.analysis.DefaultAnalysisMode;
import org.sonar.batch.cache.WSLoader;
import org.sonar.batch.cache.WSLoaderResult;
import org.sonar.batch.protocol.input.ProjectRepositories;
import org.sonar.batch.rule.ModuleQProfiles;
import org.sonar.batch.util.BatchUtils;
@@ -58,7 +54,6 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
url += "&preview=" + analysisMode.isIssues();

ProjectRepositories projectRepositories = load(url, fromCache);
validateProjectRepositories(projectRepositories);
return projectRepositories;
}

@@ -69,10 +64,4 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
}
return ProjectRepositories.fromJson(result.get());
}

private static void validateProjectRepositories(ProjectRepositories projectRepositories) {
if (projectRepositories.qProfiles().isEmpty()) {
throw MessageException.of("No quality profiles has been found this project, you probably don't have any language plugin suitable for this analysis.");
}
}
}

+ 5
- 6
sonar-batch/src/test/java/org/sonar/batch/mediumtest/cache/CacheSyncTest.java View File

@@ -20,6 +20,7 @@
package org.sonar.batch.mediumtest.cache;

import com.google.common.collect.ImmutableMap;
import java.util.Date;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
@@ -31,8 +32,6 @@ import org.sonar.batch.protocol.input.FileData;
import org.sonar.xoo.XooPlugin;
import org.sonar.xoo.rule.XooRulesDefinition;

import java.util.Date;

public class CacheSyncTest {
@Rule
public ExpectedException exception = ExpectedException.none();
@@ -49,7 +48,7 @@ public class CacheSyncTest {

@Test
public void testSyncFirstTime() {
FileData file1 = new FileData("hash", true);
FileData file1 = new FileData("hash", "123456789");

tester = BatchMediumTester.builder()
.bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES))
@@ -64,10 +63,10 @@ public class CacheSyncTest {
tester.start();
tester.syncProject("test-project");
}
@Test
public void testNonAssociated() {
FileData file1 = new FileData("hash", true);
FileData file1 = new FileData("hash", "123456789");

tester = BatchMediumTester.builder()
.bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES))
@@ -85,7 +84,7 @@ public class CacheSyncTest {

@Test
public void testNoQProfile() {
FileData file1 = new FileData("hash", true);
FileData file1 = new FileData("hash", "123456789");

tester = BatchMediumTester.builder()
.bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES))

+ 1
- 1
sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java View File

@@ -55,7 +55,7 @@ public class ScmMediumTest {
public BatchMediumTester tester = BatchMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
.addFileData("com.foo.project", "src/sample2.xoo", new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), false))
.addFileData("com.foo.project", "src/sample2.xoo", new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
.build();

@Before

+ 2
- 2
sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectSettingsLoaderTest.java View File

@@ -54,8 +54,8 @@ public class DefaultProjectSettingsLoaderTest {
projectRepositories = new ProjectRepositories();
projectRepositories.setLastAnalysisDate(new Date(1000));

f1 = new FileData("hash1", true);
f2 = new FileData("hash2", true);
f1 = new FileData("hash1", "123456789");
f2 = new FileData("hash2", "123456789");
projectRepositories.addFileData("module1", "file1", f1);
projectRepositories.addFileData("module1", "file2", f2);


+ 5
- 6
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/StatusDetectionTest.java View File

@@ -19,15 +19,14 @@
*/
package org.sonar.batch.scan.filesystem;

import com.google.common.collect.ImmutableTable;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;

import org.sonar.batch.repository.ProjectSettingsRepo;
import org.junit.Test;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.batch.protocol.input.FileData;
import org.sonar.batch.repository.ProjectSettingsRepo;

import static org.assertj.core.api.Assertions.assertThat;

public class StatusDetectionTest {
@@ -45,8 +44,8 @@ public class StatusDetectionTest {
private static Table<String, String, FileData> createTable() {
Table<String, String, FileData> t = HashBasedTable.create();

t.put("foo", "src/Foo.java", new FileData("ABCDE", true));
t.put("foo", "src/Bar.java", new FileData("FGHIJ", true));
t.put("foo", "src/Foo.java", new FileData("ABCDE", "12345789"));
t.put("foo", "src/Bar.java", new FileData("FGHIJ", "123456789"));

return t;
}

+ 10
- 0
sonar-db/src/main/java/org/sonar/db/component/FilePathWithHashDto.java View File

@@ -26,6 +26,7 @@ public class FilePathWithHashDto {
private String moduleUuid;
private String path;
private String srcHash;
private String revision;

public String getSrcHash() {
return srcHash;
@@ -51,6 +52,14 @@ public class FilePathWithHashDto {
this.path = path;
}

public String getRevision() {
return revision;
}

public void setRevision(String revision) {
this.revision = revision;
}

public String getUuid() {
return uuid;
}
@@ -58,4 +67,5 @@ public class FilePathWithHashDto {
public void setUuid(String uuid) {
this.uuid = uuid;
}

}

+ 2
- 2
sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml View File

@@ -191,7 +191,7 @@
</sql>

<select id="selectEnabledFilesFromProject" parameterType="map" resultType="FilePathWithHash">
SELECT p.uuid, p.path, p.module_uuid as moduleUuid, fs.src_hash as srcHash
SELECT p.uuid, p.path, p.module_uuid as moduleUuid, fs.src_hash as srcHash, fs.revision
FROM projects p
INNER JOIN file_sources fs ON fs.file_uuid=p.uuid and fs.data_type='SOURCE'
<where>
@@ -202,7 +202,7 @@
</select>

<select id="selectDescendantFiles" parameterType="map" resultType="FilePathWithHash">
SELECT p.uuid, p.path, p.module_uuid as moduleUuid, fs.src_hash as srcHash
SELECT p.uuid, p.path, p.module_uuid as moduleUuid, fs.src_hash as srcHash, fs.revision
FROM projects p
INNER JOIN file_sources fs ON fs.file_uuid=p.uuid and fs.data_type='SOURCE'
<include refid="modulesTreeQuery"/>

+ 3
- 0
sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java View File

@@ -384,6 +384,7 @@ public class ComponentDaoTest {
assertThat(files).extracting("moduleUuid").containsOnly("EFGH", "FGHI");
assertThat(files).extracting("srcHash").containsOnly("srcEFGHI", "srcHIJK");
assertThat(files).extracting("path").containsOnly("src/org/struts/pom.xml", "src/org/struts/RequestContext.java");
assertThat(files).extracting("revision").containsOnly("123456789");

// From module
files = underTest.selectEnabledDescendantFiles(dbSession, "EFGH");
@@ -391,6 +392,7 @@ public class ComponentDaoTest {
assertThat(files).extracting("moduleUuid").containsOnly("EFGH", "FGHI");
assertThat(files).extracting("srcHash").containsOnly("srcEFGHI", "srcHIJK");
assertThat(files).extracting("path").containsOnly("src/org/struts/pom.xml", "src/org/struts/RequestContext.java");
assertThat(files).extracting("revision").containsOnly("123456789");

// From sub module
files = underTest.selectEnabledDescendantFiles(dbSession, "FGHI");
@@ -398,6 +400,7 @@ public class ComponentDaoTest {
assertThat(files).extracting("moduleUuid").containsOnly("FGHI");
assertThat(files).extracting("srcHash").containsOnly("srcHIJK");
assertThat(files).extracting("path").containsOnly("src/org/struts/RequestContext.java");
assertThat(files).extracting("revision").containsOnly("123456789");

// From directory
assertThat(underTest.selectEnabledDescendantFiles(dbSession, "GHIJ")).isEmpty();

+ 2
- 2
sonar-db/src/test/resources/org/sonar/db/component/ComponentDaoTest/select_module_files_tree.xml View File

@@ -23,7 +23,7 @@
binary_data=",,,,,,,,,,,,,,,unchanged&#13;&#10;,,,,,,,,,,,,,,,content&#13;&#10;"
line_hashes="lineEFGHI"
data_hash="dataEFGHI"
src_hash="srcEFGHI"
src_hash="srcEFGHI" revision="123456789"
created_at="1412952242000" updated_at="1412952242000" data_type="SOURCE"/>

<!-- sub module -->
@@ -50,7 +50,7 @@
binary_data=",,,,,,,,,,,,,,,unchanged&#13;&#10;,,,,,,,,,,,,,,,content&#13;&#10;"
line_hashes="lineHIJK"
data_hash="dataHIJK"
src_hash="srcHIJK"
src_hash="srcHIJK" revision="123456789"
created_at="1412952242000" updated_at="1412952242000" data_type="SOURCE"/>

</dataset>

+ 2417
- 0
sonar-ws/src/main/gen-java/org/sonarqube/ws/WsBatch.java
File diff suppressed because it is too large
View File


+ 47
- 0
sonar-ws/src/main/protobuf/ws-batch.proto View File

@@ -0,0 +1,47 @@
// SonarQube, open source software quality management tool.
// Copyright (C) 2008-2015 SonarSource
// mailto:contact AT sonarsource DOT com
//
// SonarQube 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.
//
// SonarQube 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.

syntax = "proto2";

package sonarqube.ws.batch;

option java_package = "org.sonarqube.ws";
option java_outer_classname = "WsBatch";

option optimize_for = SPEED;

// WS api/batch/project
message WsProjectResponse {
optional int64 timestamp = 1;
map<string, Settings> settingsByModule = 2;
map<string, FileDataByPath> fileDataByModuleAndPatch = 3;
optional int64 lastAnalysisDate = 4;

message Settings {
map<string,string> settings = 1;
}

message FileDataByPath {
map<string, FileData> FileDataByPath = 1;
}

message FileData {
optional string hash = 1;
optional string revision = 2;
}
}

Loading…
Cancel
Save