aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2015-06-19 17:02:11 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2015-06-19 17:03:40 +0200
commit1770cc66b96a2185edcd5bacd04ac154e3dfefe1 (patch)
treee003f35e9db2d27150b2c876ef59681197551c8f /server
parent63757eaa2a0095f2c47f76cf640436391d4f865f (diff)
downloadsonarqube-1770cc66b96a2185edcd5bacd04ac154e3dfefe1.tar.gz
sonarqube-1770cc66b96a2185edcd5bacd04ac154e3dfefe1.zip
SONAR-6635 Check analysis date is after latest analysis
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java30
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/ValidateProjectStepTest.java73
2 files changed, 89 insertions, 14 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java
index 58c1292fb63..37382a8e8eb 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java
@@ -24,6 +24,7 @@ import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.FluentIterable;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
@@ -35,6 +36,7 @@ import org.sonar.api.utils.MessageException;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.component.ComponentKeys;
+import org.sonar.core.component.SnapshotDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.computation.batch.BatchReportReader;
@@ -43,6 +45,8 @@ import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+
/**
* Validate project and modules. It will fail in the following cases :
* <ol>
@@ -121,9 +125,10 @@ public class ValidateProjectStep implements ComputationStep {
ComponentDto baseProject = loadBaseComponent(rawProjectKey);
validateWhenProvisioningEnforced(baseProject, rawProjectKey);
validateProjectKey(baseProject, rawProjectKey);
+ validateAnalysisDate(baseProject);
}
- private void validateWhenProvisioningEnforced(@Nullable ComponentDto baseProject, String rawProjectKey){
+ private void validateWhenProvisioningEnforced(@Nullable ComponentDto baseProject, String rawProjectKey) {
if (baseProject == null) {
if (preventAutomaticProjectCreation) {
validationMessages.add(String.format("Unable to scan non-existing project '%s'", rawProjectKey));
@@ -131,16 +136,29 @@ public class ValidateProjectStep implements ComputationStep {
}
}
- private void validateProjectKey(@Nullable ComponentDto baseProject, String rawProjectKey){
+ private void validateProjectKey(@Nullable ComponentDto baseProject, String rawProjectKey) {
if (baseProject != null && !baseProject.projectUuid().equals(baseProject.uuid())) {
// Project key is already used as a module of another project
ComponentDto anotherBaseProject = componentDao.selectByUuid(session, baseProject.projectUuid());
validationMessages.add(String.format("The project \"%s\" is already defined in SonarQube but as a module of project \"%s\". "
- + "If you really want to stop directly analysing project \"%s\", please first delete it from SonarQube and then relaunch the analysis of project \"%s\".",
+ + "If you really want to stop directly analysing project \"%s\", please first delete it from SonarQube and then relaunch the analysis of project \"%s\".",
rawProjectKey, anotherBaseProject.key(), anotherBaseProject.key(), rawProjectKey));
}
}
+ private void validateAnalysisDate(@Nullable ComponentDto baseProject) {
+ if (baseProject != null) {
+ SnapshotDto snapshotDto = dbClient.snapshotDao().selectLastSnapshotByComponentId(session, baseProject.getId());
+ long currentAnalysisDate = reportReader.readMetadata().getAnalysisDate();
+ Long lastAnalysisDate = snapshotDto != null ? snapshotDto.getCreatedAt() : null;
+ if (lastAnalysisDate != null && currentAnalysisDate <= snapshotDto.getCreatedAt()) {
+ validationMessages.add(String.format("Date of analysis cannot be older than the date of the last known analysis on this project. Value: \"%s\". " +
+ "Latest analysis: \"%s\". It's only possible to rebuild the past in a chronological order.",
+ formatDateTime(new Date(currentAnalysisDate)), formatDateTime(new Date(lastAnalysisDate))));
+ }
+ }
+ }
+
@Override
public void visitModule(Component rawModule) {
String rawProjectKey = rawProject.getKey();
@@ -156,16 +174,16 @@ public class ValidateProjectStep implements ComputationStep {
validateModuleKeyIsNotAlreadyUsedInAnotherProject(baseModule, rawModuleKey);
}
- private void validateModuleIsNotAlreadyUsedAsProject(ComponentDto baseModule, String rawProjectKey, String rawModuleKey){
+ private void validateModuleIsNotAlreadyUsedAsProject(ComponentDto baseModule, String rawProjectKey, String rawModuleKey) {
if (baseModule.projectUuid().equals(baseModule.uuid())) {
// module is actually a project
validationMessages.add(String.format("The project \"%s\" is already defined in SonarQube but not as a module of project \"%s\". "
- + "If you really want to stop directly analysing project \"%s\", please first delete it from SonarQube and then relaunch the analysis of project \"%s\".",
+ + "If you really want to stop directly analysing project \"%s\", please first delete it from SonarQube and then relaunch the analysis of project \"%s\".",
rawModuleKey, rawProjectKey, rawModuleKey, rawProjectKey));
}
}
- private void validateModuleKeyIsNotAlreadyUsedInAnotherProject(ComponentDto baseModule, String rawModuleKey){
+ private void validateModuleKeyIsNotAlreadyUsedInAnotherProject(ComponentDto baseModule, String rawModuleKey) {
if (!baseModule.projectUuid().equals(baseModule.uuid()) && !baseModule.projectUuid().equals(rawProject.getUuid())) {
ComponentDto projectModule = componentDao.selectByUuid(session, baseModule.projectUuid());
validationMessages.add(String.format("Module \"%s\" is already part of project \"%s\"", rawModuleKey, projectModule.key()));
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ValidateProjectStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ValidateProjectStepTest.java
index cbfab26eab7..feca62fff9d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ValidateProjectStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ValidateProjectStepTest.java
@@ -25,6 +25,7 @@ import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import org.junit.rules.ExpectedException;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
@@ -35,15 +36,20 @@ import org.sonar.core.component.ComponentDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.SnapshotTesting;
import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.component.db.SnapshotDao;
import org.sonar.server.computation.batch.BatchReportReaderRule;
import org.sonar.server.computation.batch.TreeRootHolderRule;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
+import org.sonar.test.DbTests;
+@Category(DbTests.class)
public class ValidateProjectStepTest {
+ private static long DEFAULT_ANALYSIS_TIME = 1433131200000L; // 2015-06-01
private static final String PROJECT_KEY = "PROJECT_KEY";
private static final String MODULE_KEY = "MODULE_KEY";
@@ -67,7 +73,7 @@ public class ValidateProjectStepTest {
@Before
public void setUp() throws Exception {
dbTester.truncateTables();
- dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao());
+ dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao(), new SnapshotDao());
dbSession = dbClient.openSession(false);
settings = new Settings();
@@ -81,7 +87,7 @@ public class ValidateProjectStepTest {
@Test
public void not_fail_if_provisioning_enforced_and_project_exists() throws Exception {
- reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -101,7 +107,7 @@ public class ValidateProjectStepTest {
thrown.expect(MessageException.class);
thrown.expectMessage("Unable to scan non-existing project '" + PROJECT_KEY + "'");
- reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -116,7 +122,7 @@ public class ValidateProjectStepTest {
@Test
public void fail_if_provisioning_not_enforced_and_project_does_not_exists() throws Exception {
- reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -132,6 +138,7 @@ public class ValidateProjectStepTest {
@Test
public void not_fail_on_valid_branch() throws Exception {
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+ .setAnalysisDate(DEFAULT_ANALYSIS_TIME)
.setBranch("origin/master")
.build());
reportReader.putComponent(BatchReport.Component.newBuilder()
@@ -151,6 +158,7 @@ public class ValidateProjectStepTest {
" o \"bran#ch\" is not a valid branch name. Allowed characters are alphanumeric, '-', '_', '.' and '/'.");
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+ .setAnalysisDate(DEFAULT_ANALYSIS_TIME)
.setBranch("bran#ch")
.build());
reportReader.putComponent(BatchReport.Component.newBuilder()
@@ -172,7 +180,7 @@ public class ValidateProjectStepTest {
" o \"Project\\Key\" is not a valid project or module key. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.\n" +
" o \"Module$Key\" is not a valid project or module key. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit");
- reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -199,7 +207,7 @@ public class ValidateProjectStepTest {
"If you really want to stop directly analysing project \"" + MODULE_KEY + "\", please first delete it from SonarQube and then relaunch the analysis of project \""
+ PROJECT_KEY + "\".");
- reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -230,7 +238,7 @@ public class ValidateProjectStepTest {
thrown.expectMessage("Validation of project failed:\n" +
" o Module \"" + MODULE_KEY + "\" is already part of project \"" + anotherProjectKey + "\"");
- reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -266,7 +274,7 @@ public class ValidateProjectStepTest {
"If you really want to stop directly analysing project \"" + anotherProjectKey + "\", please first delete it from SonarQube and then relaunch the analysis of project \""
+ PROJECT_KEY + "\".");
- reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -291,4 +299,53 @@ public class ValidateProjectStepTest {
sut.execute();
}
+
+ @Test
+ public void not_fail_if_analysis_date_is_after_last_analysis() throws Exception {
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+ .setAnalysisDate(DEFAULT_ANALYSIS_TIME) // 2015-06-01
+ .build());
+ reportReader.putComponent(BatchReport.Component.newBuilder()
+ .setRef(1)
+ .setType(Constants.ComponentType.PROJECT)
+ .setKey(PROJECT_KEY)
+ .addChildRef(2)
+ .build());
+
+ ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY);
+ dbClient.componentDao().insert(dbSession, project);
+ dbClient.snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project).setCreatedAt(1420088400000L)); // 2015-01-01
+ dbSession.commit();
+
+ treeRootHolder.setRoot(DumbComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
+
+ sut.execute();
+ }
+
+ @Test
+ public void fail_if_analysis_date_is_before_last_analysis() throws Exception {
+ thrown.expect(MessageException.class);
+ thrown.expectMessage("Validation of project failed:");
+ thrown.expectMessage("Date of analysis cannot be older than the date of the last known analysis on this project. Value: ");
+ thrown.expectMessage("Latest analysis: ");
+
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+ .setAnalysisDate(1420088400000L) // 2015-01-01
+ .build());
+ reportReader.putComponent(BatchReport.Component.newBuilder()
+ .setRef(1)
+ .setType(Constants.ComponentType.PROJECT)
+ .setKey(PROJECT_KEY)
+ .addChildRef(2)
+ .build());
+
+ ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY);
+ dbClient.componentDao().insert(dbSession, project);
+ dbClient.snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project).setCreatedAt(1433131200000L)); // 2015-06-01
+ dbSession.commit();
+
+ treeRootHolder.setRoot(DumbComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
+
+ sut.execute();
+ }
}