From: Julien HENRY Date: Wed, 28 Jan 2015 17:10:05 +0000 (+0100) Subject: SONAR-5927 Improve permission checking and error reporting X-Git-Tag: latest-silver-master-#65~39 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b9b8790a3f75f9693f710fb19ed920d07a88c925;p=sonarqube.git SONAR-5927 Improve permission checking and error reporting --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java index a4e93028652..d8849f19400 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java @@ -27,6 +27,7 @@ import org.sonar.api.ServerComponent; import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; import org.sonar.api.rule.RuleKey; +import org.sonar.api.web.UserRole; import org.sonar.batch.protocol.input.FileData; import org.sonar.batch.protocol.input.ProjectRepositories; import org.sonar.core.UtcDateUtils; @@ -53,6 +54,7 @@ import org.sonar.server.user.UserSession; import javax.annotation.Nullable; import java.util.Collections; +import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -88,6 +90,9 @@ public class ProjectRepositoryLoader implements ServerComponent { ComponentDto module = dbClient.componentDao().getNullableByKey(session, query.getModuleKey()); // Current project/module can be null when analysing a new project if (module != null) { + UserSession.get().checkComponentPermission(UserRole.USER, query.getModuleKey(), + "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(ref, module.getKey(), getSettingsFromParents(module, hasScanPerm, session)); @@ -103,6 +108,12 @@ public class ProjectRepositoryLoader implements ServerComponent { addSettingsToChildrenModules(ref, query.getModuleKey(), Maps.newHashMap(), treeModuleSettings, hasScanPerm, session); addFileData(session, ref, modulesTree, module.uuid()); + + // 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); } addProfiles(ref, projectKey, query.getProfileName(), session); @@ -265,9 +276,12 @@ public class ProjectRepositoryLoader implements ServerComponent { throw new ForbiddenException("You're not authorized to execute any SonarQube analysis. Please contact your SonarQube administrator."); } if (!preview && !hasScanPerm) { - throw new ForbiddenException("You're only authorized to execute a local (dry run) SonarQube analysis without pushing the results to the SonarQube server. " + + throw new ForbiddenException("You're only authorized to execute a local (preview) SonarQube analysis without pushing the results to the SonarQube server. " + "Please contact your SonarQube administrator."); } + if (preview && !hasPreviewPerm) { + throw new ForbiddenException("You're not authorized to execute a preview analysis. Please contact your SonarQube administrator."); + } } private Map moduleUuidsByKey(ComponentDto module, List moduleChildren) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java index cdaf45cc962..2c2275ba836 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java @@ -36,7 +36,13 @@ import org.sonar.server.platform.Platform; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; @@ -66,7 +72,8 @@ public class UserSession { List projectPermissions = newArrayList(); UserSession() { - // Do not forget that when forceAuthentication is set to true, the Anyone group should not be set (but this will be check when authentication will be done in Java) + // Do not forget that when forceAuthentication is set to true, the Anyone group should not be set (but this will be check when + // authentication will be done in Java) userGroups = newHashSet(DefaultGroups.ANYONE); } @@ -135,8 +142,12 @@ public class UserSession { * Ensures that user implies the specified global permission. If not a {@link org.sonar.server.exceptions.ForbiddenException} is thrown. */ public UserSession checkGlobalPermission(String globalPermission) { + return checkGlobalPermission(globalPermission, null); + } + + public UserSession checkGlobalPermission(String globalPermission, @Nullable String errorMessage) { if (!hasGlobalPermission(globalPermission)) { - throw new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE); + throw new ForbiddenException(errorMessage != null ? errorMessage : INSUFFICIENT_PRIVILEGES_MESSAGE); } return this; } @@ -187,7 +198,6 @@ public class UserSession { return projectKeyByPermission.get(permission).contains(projectKey); } - /** * Does the user have the given project permission ? */ @@ -206,8 +216,12 @@ public class UserSession { * Ensures that user implies the specified project permission on a component. If not a {@link org.sonar.server.exceptions.ForbiddenException} is thrown. */ public UserSession checkComponentPermission(String projectPermission, String componentKey) { + return checkComponentPermission(projectPermission, componentKey, INSUFFICIENT_PRIVILEGES_MESSAGE); + } + + public UserSession checkComponentPermission(String projectPermission, String componentKey, @Nullable String errorMessage) { if (!hasComponentPermission(projectPermission, componentKey)) { - throw new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE); + throw new ForbiddenException(errorMessage); } return this; } diff --git a/server/sonar-server/src/test/java/org/sonar/server/batch/ProjectRepositoryLoaderMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/batch/ProjectRepositoryLoaderMediumTest.java index 7f282681b09..aa7a7c4d208 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/batch/ProjectRepositoryLoaderMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/batch/ProjectRepositoryLoaderMediumTest.java @@ -29,6 +29,7 @@ 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; @@ -84,9 +85,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_project_settings() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -109,9 +109,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void not_returned_secured_settings_with_only_preview_permission() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -133,9 +132,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_project_with_module_settings() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -170,9 +168,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_project_with_module_settings_inherited_from_project() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -202,9 +199,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_project_with_module_with_sub_module() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -251,9 +247,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_project_with_two_modules() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -296,10 +291,9 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_provisioned_project_settings() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - // No snapshot attached on the project -> provisioned project ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -318,7 +312,6 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_sub_module_settings() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); ComponentDto project = ComponentTesting.newProjectDto(); tester.get(DbClient.class).componentDao().insert(dbSession, project); @@ -330,6 +323,7 @@ public class ProjectRepositoryLoaderMediumTest { // No module properties ComponentDto subModule = ComponentTesting.newModuleDto(module); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), subModule.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, subModule); // Sub module properties @@ -351,8 +345,6 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_sub_module_settings_including_settings_from_parent_modules() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -367,6 +359,7 @@ public class ProjectRepositoryLoaderMediumTest { tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.login.secured").setValue("john").setResourceId(module.getId()), dbSession); ComponentDto subModule = ComponentTesting.newModuleDto(module); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), subModule.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, subModule); // Sub module properties @@ -386,8 +379,6 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_sub_module_settings_only_inherited_from_project() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -402,6 +393,7 @@ public class ProjectRepositoryLoaderMediumTest { // No module property ComponentDto subModule = ComponentTesting.newModuleDto(module); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), subModule.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, subModule); // No sub module property @@ -419,8 +411,6 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_sub_module_settings_inherited_from_project_and_module() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -436,6 +426,7 @@ public class ProjectRepositoryLoaderMediumTest { tester.get(DbClient.class).propertiesDao().setProperty(new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR-SERVER").setResourceId(module.getId()), dbSession); ComponentDto subModule = ComponentTesting.newModuleDto(module); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), subModule.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, subModule); // No sub module property @@ -453,10 +444,10 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_quality_profile_from_project_profile() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100"); ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt( @@ -477,10 +468,10 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_quality_profile_from_default_profile() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100"); ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt( @@ -501,10 +492,10 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_quality_profile_from_given_profile_name() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100"); ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt( @@ -546,11 +537,11 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_provisioned_project_profile() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100"); // No snapshot attached on the project -> provisioned project ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt( @@ -571,9 +562,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void fail_when_no_quality_profile_for_a_language() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto().setKey("org.codehaus.sonar:sonar"); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); dbSession.commit(); @@ -587,10 +577,10 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_active_rules() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); Date ruleUpdatedAt = DateUtils.parseDateTime("2014-01-14T13:00:00+0100"); ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor(ServerTester.Xoo.KEY, "SonarQube way"), "abcd").setRulesUpdatedAt( @@ -625,9 +615,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_manual_rules() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -674,16 +663,15 @@ public class ProjectRepositoryLoaderMediumTest { fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage( - "You're only authorized to execute a local (dry run) SonarQube analysis without pushing the results to the SonarQube server. " + + "You're only authorized to execute a local (preview) SonarQube analysis without pushing the results to the SonarQube server. " + "Please contact your SonarQube administrator."); } } @Test public void return_file_data_from_single_project() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -701,9 +689,8 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_file_data_from_multi_modules() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), project.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -729,8 +716,6 @@ public class ProjectRepositoryLoaderMediumTest { @Test public void return_file_data_from_module() throws Exception { - MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); - ComponentDto project = ComponentTesting.newProjectDto(); tester.get(DbClient.class).componentDao().insert(dbSession, project); addDefaultProfile(); @@ -741,6 +726,7 @@ public class ProjectRepositoryLoaderMediumTest { tester.get(FileSourceDao.class).insert(newFileSourceDto(projectFile).setSrcHash("123456")); ComponentDto module = ComponentTesting.newModuleDto(project); + MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION).addComponentPermission(UserRole.USER, project.getKey(), module.getKey()); tester.get(DbClient.class).componentDao().insert(dbSession, module); // File on module diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java index 11114ec0dc8..f0c22e52c68 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java @@ -21,6 +21,8 @@ package org.sonar.batch.issue.tracking; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.BatchComponent; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.DefaultInputFile; @@ -35,6 +37,7 @@ import org.sonar.api.rule.RuleKey; import org.sonar.batch.index.BatchResource; import org.sonar.batch.index.ResourceCache; import org.sonar.batch.issue.IssueCache; +import org.sonar.batch.protocol.input.ProjectRepositories; import org.sonar.batch.scan.LastLineHashes; import org.sonar.batch.scan.filesystem.InputPathCache; import org.sonar.core.issue.IssueUpdater; @@ -45,6 +48,8 @@ import java.util.Collection; public class LocalIssueTracking implements BatchComponent { + private static final Logger LOG = LoggerFactory.getLogger(LocalIssueTracking.class); + private final IssueCache issueCache; private final IssueTracking tracking; private final LastLineHashes lastLineHashes; @@ -55,10 +60,11 @@ public class LocalIssueTracking implements BatchComponent { private final InputPathCache inputPathCache; private final ResourceCache resourceCache; private final PreviousIssueRepository previousIssueCache; + private final ProjectRepositories projectRepositories; public LocalIssueTracking(ResourceCache resourceCache, IssueCache issueCache, IssueTracking tracking, LastLineHashes lastLineHashes, IssueWorkflow workflow, IssueUpdater updater, - ActiveRules activeRules, InputPathCache inputPathCache, PreviousIssueRepository previousIssueCache) { + ActiveRules activeRules, InputPathCache inputPathCache, PreviousIssueRepository previousIssueCache, ProjectRepositories projectRepositories) { this.resourceCache = resourceCache; this.issueCache = issueCache; this.tracking = tracking; @@ -67,11 +73,17 @@ public class LocalIssueTracking implements BatchComponent { this.updater = updater; this.inputPathCache = inputPathCache; this.previousIssueCache = previousIssueCache; + this.projectRepositories = projectRepositories; this.changeContext = IssueChangeContext.createScan(((Project) resourceCache.getRoot().resource()).getAnalysisDate()); this.activeRules = activeRules; } public void execute() { + if (projectRepositories.lastAnalysisDate() == null) { + LOG.debug("No previous analysis, skipping issue tracking"); + return; + } + previousIssueCache.load(); for (BatchResource component : resourceCache.all()) {