aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Schwarz <daniel.schwarz@sonarsource.com>2017-02-06 12:42:34 +0100
committerDaniel Schwarz <bartfastiel@users.noreply.github.com>2017-02-13 11:08:03 +0100
commite7c02f7fec37c6c7c16af8759d313ad81d807ffa (patch)
treedc258730e1b2c9eebb65598a2d9ccaa8468e83da
parente6ef4e2eb6e853e0edd6a58f05cb3e6c99e7bc58 (diff)
downloadsonarqube-e7c02f7fec37c6c7c16af8759d313ad81d807ffa.tar.gz
sonarqube-e7c02f7fec37c6c7c16af8759d313ad81d807ffa.zip
SONAR-8736 it test for issue creation date
-rw-r--r--it/it-projects/issue/creationDateSampleChanged/sonar-project.properties5
-rw-r--r--it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndModified.xoo7
-rw-r--r--it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndModified.xoo.scm8
-rw-r--r--it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndUnmodified.xoo7
-rw-r--r--it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndUnmodified.xoo.scm8
-rw-r--r--it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/OnlyInChanged.xoo7
-rw-r--r--it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/OnlyInChanged.xoo.scm8
-rw-r--r--it/it-projects/issue/creationDateSampleInitial/sonar-project.properties5
-rw-r--r--it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndModified.xoo7
-rw-r--r--it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndModified.xoo.scm8
-rw-r--r--it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndUnmodified.xoo7
-rw-r--r--it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndUnmodified.xoo.scm8
-rw-r--r--it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/OnlyInInitial.xoo7
-rw-r--r--it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/OnlyInInitial.xoo.scm8
-rw-r--r--it/it-tests/src/test/java/it/issue/IssueCreationDateTest.java379
-rw-r--r--it/it-tests/src/test/resources/issue/IssueCreationDateTest/no-rules.xml6
-rw-r--r--it/it-tests/src/test/resources/issue/IssueCreationDateTest/one-rule.xml11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java4
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java4
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java8
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java6
21 files changed, 514 insertions, 4 deletions
diff --git a/it/it-projects/issue/creationDateSampleChanged/sonar-project.properties b/it/it-projects/issue/creationDateSampleChanged/sonar-project.properties
new file mode 100644
index 00000000000..3a25a96024f
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleChanged/sonar-project.properties
@@ -0,0 +1,5 @@
+sonar.projectKey=creation-date-sample
+sonar.projectName=Creation date sample
+sonar.projectVersion=SNAPSHOT
+sonar.sources=src/main/xoo
+sonar.language=xoo
diff --git a/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndModified.xoo b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndModified.xoo
new file mode 100644
index 00000000000..2e3e81d8300
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndModified.xoo
@@ -0,0 +1,7 @@
+/**/package sample;
+/**/
+/**/public class ForeverAndModified {
+/**/
+/**/ private String myMethod() {
+/**/ }
+/**/}
diff --git a/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndModified.xoo.scm b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndModified.xoo.scm
new file mode 100644
index 00000000000..f8c205d4d68
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndModified.xoo.scm
@@ -0,0 +1,8 @@
+2,jhenry,2004-01-01T00:00:00+0000
+2,jhenry,2004-01-01T00:00:00+0000
+2,jhenry,2004-01-01T00:00:00+0000
+2,jhenry,2004-01-01T00:00:00+0000
+2,jhenry,2004-01-01T00:00:00+0000
+2,jhenry,2004-01-01T00:00:00+0000
+2,jhenry,2004-01-01T00:00:00+0000
+2,jhenry,2004-01-01T00:00:00+0000
diff --git a/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndUnmodified.xoo b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndUnmodified.xoo
new file mode 100644
index 00000000000..3d80cf8da75
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndUnmodified.xoo
@@ -0,0 +1,7 @@
+package sample;
+
+public class ForeverAndUnmodified {
+
+ private String myMethod() {
+ }
+}
diff --git a/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndUnmodified.xoo.scm b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndUnmodified.xoo.scm
new file mode 100644
index 00000000000..3272e3e6ed8
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/ForeverAndUnmodified.xoo.scm
@@ -0,0 +1,8 @@
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
diff --git a/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/OnlyInChanged.xoo b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/OnlyInChanged.xoo
new file mode 100644
index 00000000000..0a96b5c9ddb
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/OnlyInChanged.xoo
@@ -0,0 +1,7 @@
+/**/package sample;
+/**/
+/**/public class OnlyInChanged {
+/**/
+/**/ private String anotherMethod() {
+/**/ }
+/**/}
diff --git a/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/OnlyInChanged.xoo.scm b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/OnlyInChanged.xoo.scm
new file mode 100644
index 00000000000..59c11db6b3b
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleChanged/src/main/xoo/sample/OnlyInChanged.xoo.scm
@@ -0,0 +1,8 @@
+1,jhenry,2005-01-01T00:00:00+0000
+1,jhenry,2005-01-01T00:00:00+0000
+1,jhenry,2005-01-01T00:00:00+0000
+1,jhenry,2005-01-01T00:00:00+0000
+1,jhenry,2005-01-01T00:00:00+0000
+1,jhenry,2005-01-01T00:00:00+0000
+1,jhenry,2005-01-01T00:00:00+0000
+1,jhenry,2005-01-01T00:00:00+0000
diff --git a/it/it-projects/issue/creationDateSampleInitial/sonar-project.properties b/it/it-projects/issue/creationDateSampleInitial/sonar-project.properties
new file mode 100644
index 00000000000..3a25a96024f
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleInitial/sonar-project.properties
@@ -0,0 +1,5 @@
+sonar.projectKey=creation-date-sample
+sonar.projectName=Creation date sample
+sonar.projectVersion=SNAPSHOT
+sonar.sources=src/main/xoo
+sonar.language=xoo
diff --git a/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndModified.xoo b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndModified.xoo
new file mode 100644
index 00000000000..4b6e8b8d818
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndModified.xoo
@@ -0,0 +1,7 @@
+package sample;
+
+public class ForeverAndModified {
+
+ private String myMethod() {
+ }
+}
diff --git a/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndModified.xoo.scm b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndModified.xoo.scm
new file mode 100644
index 00000000000..654a775e4ef
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndModified.xoo.scm
@@ -0,0 +1,8 @@
+1,jhenry,2003-01-01T00:00:00+0000
+1,jhenry,2003-01-01T00:00:00+0000
+1,jhenry,2003-01-01T00:00:00+0000
+1,jhenry,2003-01-01T00:00:00+0000
+1,jhenry,2003-01-01T00:00:00+0000
+1,jhenry,2003-01-01T00:00:00+0000
+1,jhenry,2003-01-01T00:00:00+0000
+1,jhenry,2003-01-01T00:00:00+0000
diff --git a/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndUnmodified.xoo b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndUnmodified.xoo
new file mode 100644
index 00000000000..3d80cf8da75
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndUnmodified.xoo
@@ -0,0 +1,7 @@
+package sample;
+
+public class ForeverAndUnmodified {
+
+ private String myMethod() {
+ }
+}
diff --git a/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndUnmodified.xoo.scm b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndUnmodified.xoo.scm
new file mode 100644
index 00000000000..3272e3e6ed8
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/ForeverAndUnmodified.xoo.scm
@@ -0,0 +1,8 @@
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
+1,jhenry,2002-01-01T00:00:00+0000
diff --git a/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/OnlyInInitial.xoo b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/OnlyInInitial.xoo
new file mode 100644
index 00000000000..969fc44abfe
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/OnlyInInitial.xoo
@@ -0,0 +1,7 @@
+package sample;
+
+public class IsBuggyThenChangesAndBecomesClean {
+
+ private String myMethod() {
+ }
+}
diff --git a/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/OnlyInInitial.xoo.scm b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/OnlyInInitial.xoo.scm
new file mode 100644
index 00000000000..65099dbec9b
--- /dev/null
+++ b/it/it-projects/issue/creationDateSampleInitial/src/main/xoo/sample/OnlyInInitial.xoo.scm
@@ -0,0 +1,8 @@
+1,jhenry,2001-01-01T00:00:00+0000
+1,jhenry,2001-01-01T00:00:00+0000
+1,jhenry,2001-01-01T00:00:00+0000
+1,jhenry,2001-01-01T00:00:00+0000
+1,jhenry,2001-01-01T00:00:00+0000
+1,jhenry,2001-01-01T00:00:00+0000
+1,jhenry,2001-01-01T00:00:00+0000
+1,jhenry,2001-01-01T00:00:00+0000
diff --git a/it/it-tests/src/test/java/it/issue/IssueCreationDateTest.java b/it/it-tests/src/test/java/it/issue/IssueCreationDateTest.java
new file mode 100644
index 00000000000..0caa3db8687
--- /dev/null
+++ b/it/it-tests/src/test/java/it/issue/IssueCreationDateTest.java
@@ -0,0 +1,379 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package it.issue;
+
+import com.sonar.orchestrator.build.SonarScanner;
+import com.sonar.orchestrator.container.Server;
+import com.sonar.orchestrator.locator.FileLocation;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.wsclient.issue.Issue;
+import org.sonar.wsclient.issue.IssueQuery;
+import org.sonarqube.ws.ProjectAnalyses;
+import org.sonarqube.ws.client.projectanalysis.SearchRequest;
+import util.ItUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static util.ItUtils.projectDir;
+
+/**
+ * @see <a href="https://jira.sonarsource.com/browse/MMF-567">MMF-567</a>
+ */
+public class IssueCreationDateTest extends AbstractIssueTest {
+
+ private static final String ISSUE_STATUS_OPEN = "OPEN";
+
+ private static final String LANGUAGE_XOO = "xoo";
+
+ private static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
+ private static final String DATE_FORMAT = "yyyy-MM-dd";
+
+ private static final String SAMPLE_PROJECT_KEY = "creation-date-sample";
+ private static final String SAMPLE_PROJECT_NAME = "Creation date sample";
+ private static final String SAMPLE_QUALITY_PROFILE_NAME = "creation-date-quality-profile";
+ private static final String SAMPLE_EXPLICIT_DATE_1 = todayMinusDays(2);
+ private static final String SAMPLE_EXPLICIT_DATE_2 = todayMinusDays(1);
+
+ private Server server = ORCHESTRATOR.getServer();
+
+ @Before
+ public void resetData() {
+ ORCHESTRATOR.resetData();
+ server.provisionProject(SAMPLE_PROJECT_KEY, SAMPLE_PROJECT_NAME);
+ }
+
+ @Test
+ public void should_use_scm_date_for_new_issues_if_scm_is_available() {
+ analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDate(Component.OnlyInInitial, IssueCreationDate.OnlyInInitial_R1);
+ assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1);
+ assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1);
+ }
+
+ @Test
+ public void should_use_analysis_date_for_new_issues_if_scm_is_not_available() {
+ analysis(QProfile.ONE_RULE, SourceCode.INITIAL);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDates(COMPONENTS_OF_SOURCE_INITIAL, IssueCreationDate.FIRST_ANALYSIS);
+ }
+
+ @Test
+ public void use_explicit_project_date_if_scm_is_not_available() {
+ analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.EXPLICIT_DATE_1);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDates(COMPONENTS_OF_SOURCE_INITIAL, IssueCreationDate.EXPLICIT_DATE_1);
+ }
+
+ @Test
+ public void use_scm_date_even_if_explicit_project_date_is_set() {
+ analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_1);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDate(Component.OnlyInInitial, IssueCreationDate.OnlyInInitial_R1);
+ assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1);
+ assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1);
+ }
+
+ @Test
+ public void no_rules_no_issues_if_scm_is_available() {
+ analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM);
+
+ assertNoIssue();
+ }
+
+ @Test
+ public void no_rules_no_issues_if_scm_is_not_available() {
+ analysis(QProfile.NO_RULES, SourceCode.INITIAL);
+
+ assertNoIssue();
+ }
+
+ @Test
+ public void use_scm_date_for_issues_raised_by_new_rules_if_scm_is_newly_available() {
+ analysis(QProfile.NO_RULES, SourceCode.INITIAL);
+ analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2);
+ assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1);
+ assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1);
+ }
+
+ @Test
+ public void use_scm_date_for_issues_raised_by_new_rules_if_scm_is_available_and_ever_has_been_available() {
+ analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM);
+ analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2);
+ assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1);
+ assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1);
+ }
+
+ @Test
+ public void use_analysis_date_for_issues_raised_by_new_rules_if_scm_is_not_available() {
+ analysis(QProfile.NO_RULES, SourceCode.INITIAL);
+ analysis(QProfile.ONE_RULE, SourceCode.CHANGED);
+
+ assertNumberOfIssues(3);
+ Stream.of(COMPONENTS_OF_SOURCE_CHANGED)
+ .forEach(component -> {
+ assertIssueCreationDate(component, IssueCreationDate.LATEST_ANALYSIS);
+ });
+ }
+
+ @Test
+ public void keep_the_date_of_an_existing_issue_even_if_the_blame_information_changes() {
+ analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM);
+ analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1);
+ assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1);
+
+ // this file is new to the second analysis
+ assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.LATEST_ANALYSIS);
+ }
+
+ @Test
+ public void ignore_explicit_date_for_issues_related_to_new_rules_if_scm_is_available() {
+ analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_1);
+ analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_2);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2);
+ assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1);
+ assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1);
+ }
+
+ @Test
+ public void use_explicit_date_for_issues_related_to_new_rules_if_scm_is_not_available() {
+ analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.EXPLICIT_DATE_1);
+ analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.EXPLICIT_DATE_2);
+
+ assertNumberOfIssues(3);
+ assertIssueCreationDates(COMPONENTS_OF_SOURCE_CHANGED, IssueCreationDate.EXPLICIT_DATE_2);
+ }
+
+ private void analysis(QProfile qProfile, SourceCode sourceCode, ScannerFeature... scm) {
+ server.restoreProfile(FileLocation.ofClasspath(qProfile.path));
+ server.associateProjectToQualityProfile(SAMPLE_PROJECT_KEY, LANGUAGE_XOO, SAMPLE_QUALITY_PROFILE_NAME);
+
+ SonarScanner scanner = SonarScanner.create(projectDir(sourceCode.path));
+ Arrays.stream(scm).forEach(s -> s.configure(scanner));
+ ORCHESTRATOR.executeBuild(scanner);
+ }
+
+ private static void assertNoIssue() {
+ assertNumberOfIssues(0);
+ }
+
+ private static void assertNumberOfIssues(int number) {
+ assertThat(getIssues(issueQuery())).hasSize(number);
+ }
+
+ private static void assertIssueCreationDate(Component component, IssueCreationDate expectedDate) {
+ assertIssueCreationDates(new Component[] {component}, expectedDate);
+ }
+
+ private static void assertIssueCreationDates(Component[] components, IssueCreationDate expectedDate) {
+ String[] keys = Arrays.stream(components).map(Component::getKey).toArray(String[]::new);
+ List<Issue> issues = getIssues(issueQuery().components(keys));
+ Date[] dates = Arrays.stream(components).map(x -> expectedDate.getDate()).toArray(Date[]::new);
+
+ assertThat(issues)
+ .extracting(Issue::creationDate)
+ .containsExactly(dates);
+ }
+
+ private static List<Issue> getIssues(IssueQuery query) {
+ return issueClient().find(query).list();
+ }
+
+ private static IssueQuery issueQuery() {
+ return IssueQuery.create().statuses(ISSUE_STATUS_OPEN);
+ }
+
+ private static Date dateTimeParse(String expectedDate) {
+ try {
+ return new SimpleDateFormat(DATETIME_FORMAT).parse(expectedDate);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static Date dateParse(String expectedDate) {
+ try {
+ return new SimpleDateFormat(DATE_FORMAT).parse(expectedDate);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static String todayMinusDays(int numberOfDays) {
+ return DateTimeFormatter.ofPattern(DATE_FORMAT).format(LocalDate.now().atStartOfDay().minusDays(numberOfDays));
+ }
+
+ private enum SourceCode {
+ INITIAL("issue/creationDateSampleInitial"),
+ CHANGED("issue/creationDateSampleChanged"),
+ ;
+
+ private final String path;
+
+ private SourceCode(String path) {
+ this.path = path;
+ }
+ }
+
+ private enum Component {
+ OnlyInInitial("creation-date-sample:src/main/xoo/sample/OnlyInInitial.xoo"),
+ ForeverAndModified("creation-date-sample:src/main/xoo/sample/ForeverAndModified.xoo"),
+ ForeverAndUnmodified("creation-date-sample:src/main/xoo/sample/ForeverAndUnmodified.xoo"),
+ OnlyInChanged("creation-date-sample:src/main/xoo/sample/OnlyInChanged.xoo"),
+ ;
+ private final String key;
+
+ private Component(String key) {
+ this.key = key;
+ }
+
+ public String getKey() {
+ return key;
+ }
+ }
+
+ private static final Component[] COMPONENTS_OF_SOURCE_INITIAL = {Component.OnlyInInitial, Component.ForeverAndModified, Component.ForeverAndUnmodified};
+ private static final Component[] COMPONENTS_OF_SOURCE_CHANGED = {Component.ForeverAndModified, Component.ForeverAndUnmodified, Component.OnlyInChanged};
+
+ private enum QProfile {
+ ONE_RULE("/issue/IssueCreationDateTest/one-rule.xml"),
+ NO_RULES("/issue/IssueCreationDateTest/no-rules.xml"),
+ ;
+
+ private final String path;
+
+ private QProfile(String path) {
+ this.path = path;
+ }
+ }
+
+ private enum ScannerFeature {
+ SCM {
+ @Override
+ void configure(SonarScanner scanner) {
+ scanner
+ .setProperty("sonar.scm.provider", "xoo")
+ .setProperty("sonar.scm.disabled", "false");
+ }
+ },
+ EXPLICIT_DATE_1 {
+ @Override
+ void configure(SonarScanner scanner) {
+ scanner
+ .setProperty("sonar.projectDate", SAMPLE_EXPLICIT_DATE_1);
+ }
+ },
+ EXPLICIT_DATE_2 {
+ @Override
+ void configure(SonarScanner scanner) {
+ scanner
+ .setProperty("sonar.projectDate", SAMPLE_EXPLICIT_DATE_2);
+ }
+ },
+ ;
+
+ void configure(SonarScanner scanner) {
+ }
+ }
+
+ private enum IssueCreationDate {
+ OnlyInInitial_R1(dateTimeParse("2001-01-01T00:00:00+0000")),
+ ForeverAndUnmodified_R1(dateTimeParse("2002-01-01T00:00:00+0000")),
+ ForeverAndModified_R1(dateTimeParse("2003-01-01T00:00:00+0000")),
+ ForeverAndModified_R2(dateTimeParse("2004-01-01T00:00:00+0000")),
+ OnlyInChanged_R1(dateTimeParse("2005-01-01T00:00:00+0000")),
+ EXPLICIT_DATE_1(dateParse(SAMPLE_EXPLICIT_DATE_1)),
+ EXPLICIT_DATE_2(dateParse(SAMPLE_EXPLICIT_DATE_2)),
+ FIRST_ANALYSIS {
+ @Override
+ Date getDate() {
+ return getAnalysisDate(l -> {
+ if (l.isEmpty()) {
+ return Optional.empty();
+ }
+ return Optional.of(l.get(l.size() - 1));
+ });
+ }
+ },
+ LATEST_ANALYSIS {
+ @Override
+ Date getDate() {
+ return getAnalysisDate(l -> {
+ if (l.size() > 0) {
+ return Optional.of(l.get(0));
+ }
+ return Optional.empty();
+ });
+ }
+ },
+ ;
+
+ private final Date date;
+
+ private IssueCreationDate() {
+ this.date = null;
+ }
+
+ private IssueCreationDate(Date date) {
+ this.date = date;
+ }
+
+ Date getDate() {
+ return date;
+ }
+
+ private static Date getAnalysisDate(Function<List<ProjectAnalyses.Analysis>, Optional<ProjectAnalyses.Analysis>> chooseItem) {
+ return Optional.of(
+ ItUtils.newWsClient(ORCHESTRATOR)
+ .projectAnanlysis()
+ .search(SearchRequest.builder().setProject(SAMPLE_PROJECT_KEY).build())
+ .getAnalysesList())
+ .flatMap(chooseItem)
+ .map(ProjectAnalyses.Analysis::getDate)
+ .map(IssueCreationDateTest::dateTimeParse)
+ .orElseThrow(() -> new IllegalStateException("There is no analysis"));
+ }
+ }
+}
diff --git a/it/it-tests/src/test/resources/issue/IssueCreationDateTest/no-rules.xml b/it/it-tests/src/test/resources/issue/IssueCreationDateTest/no-rules.xml
new file mode 100644
index 00000000000..62ec52d9d10
--- /dev/null
+++ b/it/it-tests/src/test/resources/issue/IssueCreationDateTest/no-rules.xml
@@ -0,0 +1,6 @@
+<profile>
+ <name>creation-date-quality-profile</name>
+ <language>xoo</language>
+ <rules>
+ </rules>
+</profile>
diff --git a/it/it-tests/src/test/resources/issue/IssueCreationDateTest/one-rule.xml b/it/it-tests/src/test/resources/issue/IssueCreationDateTest/one-rule.xml
new file mode 100644
index 00000000000..c1d7d44f02c
--- /dev/null
+++ b/it/it-tests/src/test/resources/issue/IssueCreationDateTest/one-rule.xml
@@ -0,0 +1,11 @@
+<profile>
+ <name>creation-date-quality-profile</name>
+ <language>xoo</language>
+ <rules>
+ <rule>
+ <repositoryKey>xoo</repositoryKey>
+ <key>OneIssuePerFile</key>
+ <priority>MAJOR</priority>
+ </rule>
+ </rules>
+</profile>
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java
index 253f3636cff..26137cbe6a8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculator.java
@@ -1,7 +1,7 @@
/*
* SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java
index c66decbf774..1e2ffcfd40d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java
@@ -1,7 +1,7 @@
/*
* SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
index a905aee8f20..6f80e6b66e5 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
@@ -27,6 +27,7 @@ import org.sonarqube.ws.client.measure.MeasuresService;
import org.sonarqube.ws.client.organization.OrganizationService;
import org.sonarqube.ws.client.permission.PermissionsService;
import org.sonarqube.ws.client.project.ProjectsService;
+import org.sonarqube.ws.client.projectanalysis.ProjectAnalysisService;
import org.sonarqube.ws.client.projectlinks.ProjectLinksService;
import org.sonarqube.ws.client.qualitygate.QualityGatesService;
import org.sonarqube.ws.client.qualityprofile.QualityProfilesService;
@@ -65,6 +66,7 @@ class DefaultWsClient implements WsClient {
private final SettingsService settingsService;
private final RootsService rootsService;
private final WebhooksService webhooksService;
+ private final ProjectAnalysisService projectAnalysisService;
DefaultWsClient(WsConnector wsConnector) {
this.wsConnector = wsConnector;
@@ -86,6 +88,7 @@ class DefaultWsClient implements WsClient {
this.settingsService = new SettingsService(wsConnector);
this.rootsService = new RootsService(wsConnector);
this.webhooksService = new WebhooksService(wsConnector);
+ this.projectAnalysisService = new ProjectAnalysisService(wsConnector);
}
@Override
@@ -182,4 +185,9 @@ class DefaultWsClient implements WsClient {
public WebhooksService webhooks() {
return webhooksService;
}
+
+ @Override
+ public ProjectAnalysisService projectAnanlysis() {
+ return projectAnalysisService;
+ }
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
index 4a1cb95a0ba..9220614689f 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
@@ -27,6 +27,7 @@ import org.sonarqube.ws.client.measure.MeasuresService;
import org.sonarqube.ws.client.organization.OrganizationService;
import org.sonarqube.ws.client.permission.PermissionsService;
import org.sonarqube.ws.client.project.ProjectsService;
+import org.sonarqube.ws.client.projectanalysis.ProjectAnalysisService;
import org.sonarqube.ws.client.projectlinks.ProjectLinksService;
import org.sonarqube.ws.client.qualitygate.QualityGatesService;
import org.sonarqube.ws.client.qualityprofile.QualityProfilesService;
@@ -109,4 +110,9 @@ public interface WsClient {
* @since 6.2
*/
WebhooksService webhooks();
+
+ /**
+ * @since 6.3
+ */
+ ProjectAnalysisService projectAnanlysis();
}