and pass it in scanner report as Metadata.codePeriodVersion propertytags/7.7
@@ -146,6 +146,7 @@ public interface CoreProperties { | |||
@Deprecated | |||
String PROJECT_BRANCH_PROPERTY = "sonar.branch"; | |||
String PROJECT_VERSION_PROPERTY = "sonar.projectVersion"; | |||
String CODE_PERIOD_VERSION_PROPERTY = "sonar.codePeriodVersion"; | |||
/** | |||
* @since 2.6 |
@@ -22,7 +22,8 @@ package org.sonar.scanner; | |||
import java.time.Clock; | |||
import java.util.Date; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import java.util.function.Predicate; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.Configuration; | |||
@@ -30,6 +31,8 @@ import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.MessageException; | |||
import static java.lang.String.format; | |||
import static org.sonar.api.CoreProperties.CODE_PERIOD_VERSION_PROPERTY; | |||
import static org.sonar.api.CoreProperties.PROJECT_VERSION_PROPERTY; | |||
/** | |||
* @since 6.3 | |||
@@ -42,19 +45,23 @@ public class ProjectInfo implements Startable { | |||
private Date analysisDate; | |||
private String projectVersion; | |||
private String codePeriodVersion; | |||
public ProjectInfo(Configuration settings, Clock clock) { | |||
this.settings = settings; | |||
this.clock = clock; | |||
} | |||
public Date analysisDate() { | |||
public Date getAnalysisDate() { | |||
return analysisDate; | |||
} | |||
@CheckForNull | |||
public String projectVersion() { | |||
return projectVersion; | |||
public Optional<String> getProjectVersion() { | |||
return Optional.ofNullable(projectVersion); | |||
} | |||
public Optional<String> getCodePeriodVersion() { | |||
return Optional.ofNullable(codePeriodVersion); | |||
} | |||
private Date loadAnalysisDate() { | |||
@@ -76,23 +83,27 @@ public class ProjectInfo implements Startable { | |||
} | |||
} | |||
@CheckForNull | |||
private String loadProjectVersion() { | |||
return settings.get(CoreProperties.PROJECT_VERSION_PROPERTY) | |||
.filter(version -> { | |||
if (version.length() > 100) { | |||
throw MessageException.of(format("\"%s\" is not a valid project version. " + | |||
"The maximum length for version numbers is 100 characters.", version)); | |||
} | |||
return true; | |||
}) | |||
.orElse(null); | |||
} | |||
@Override | |||
public void start() { | |||
this.analysisDate = loadAnalysisDate(); | |||
this.projectVersion = loadProjectVersion(); | |||
this.projectVersion = settings.get(PROJECT_VERSION_PROPERTY) | |||
.map(StringUtils::trimToNull) | |||
.filter(validateVersion("project")) | |||
.orElse(null); | |||
this.codePeriodVersion = settings.get(CODE_PERIOD_VERSION_PROPERTY) | |||
.map(StringUtils::trimToNull) | |||
.filter(validateVersion("codePeriod")) | |||
.orElse(projectVersion); | |||
} | |||
private static Predicate<String> validateVersion(String versionLabel) { | |||
return version -> { | |||
if (version.length() > 100) { | |||
throw MessageException.of(format("\"%s\" is not a valid %s version. " + | |||
"The maximum length is 100 characters.", version, versionLabel)); | |||
} | |||
return true; | |||
}; | |||
} | |||
@Override |
@@ -91,7 +91,7 @@ public class DefaultFilterableIssue implements FilterableIssue { | |||
@Override | |||
public Date creationDate() { | |||
return projectInfo.analysisDate(); | |||
return projectInfo.getAnalysisDate(); | |||
} | |||
@Override |
@@ -46,12 +46,12 @@ public class IssueTransition { | |||
private final LocalIssueTracking localIssueTracking; | |||
public IssueTransition(InputComponentStore inputComponentCache, ProjectInfo projectInfo, IssueCache issueCache, ReportPublisher reportPublisher, | |||
@Nullable LocalIssueTracking localIssueTracking) { | |||
@Nullable LocalIssueTracking localIssueTracking) { | |||
this.inputComponentStore = inputComponentCache; | |||
this.issueCache = issueCache; | |||
this.reportPublisher = reportPublisher; | |||
this.localIssueTracking = localIssueTracking; | |||
this.analysisDate = projectInfo.analysisDate(); | |||
this.analysisDate = projectInfo.getAnalysisDate(); | |||
} | |||
public IssueTransition(InputComponentStore inputComponentCache, ProjectInfo projectInfo, IssueCache issueCache, ReportPublisher reportPublisher) { |
@@ -45,7 +45,6 @@ import org.sonar.scanner.scan.branch.BranchConfiguration; | |||
import org.sonar.scanner.scm.ScmConfiguration; | |||
import static java.util.Optional.ofNullable; | |||
import static org.apache.commons.lang.StringUtils.trimToNull; | |||
public class MetadataPublisher implements ReportPublisherStep { | |||
@@ -84,12 +83,13 @@ public class MetadataPublisher implements ReportPublisherStep { | |||
public void publish(ScannerReportWriter writer) { | |||
AbstractProjectOrModule rootProject = moduleHierarchy.root(); | |||
ScannerReport.Metadata.Builder builder = ScannerReport.Metadata.newBuilder() | |||
.setAnalysisDate(projectInfo.analysisDate().getTime()) | |||
.setAnalysisDate(projectInfo.getAnalysisDate().getTime()) | |||
// Here we want key without branch | |||
.setProjectKey(rootProject.key()) | |||
.setCrossProjectDuplicationActivated(cpdSettings.isCrossProjectDuplicationEnabled()) | |||
.setRootComponentRef(rootProject.scannerId()); | |||
ofNullable(trimToNull(projectInfo.projectVersion())).ifPresent(builder::setProjectVersion); | |||
projectInfo.getProjectVersion().ifPresent(builder::setProjectVersion); | |||
projectInfo.getCodePeriodVersion().ifPresent(builder::setCodePeriodVersion); | |||
properties.organizationKey().ifPresent(builder::setOrganizationKey); | |||
@@ -19,15 +19,21 @@ | |||
*/ | |||
package org.sonar.scanner; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.time.Clock; | |||
import java.time.LocalDate; | |||
import java.time.OffsetDateTime; | |||
import java.time.ZoneId; | |||
import java.time.ZoneOffset; | |||
import java.util.Date; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.RandomStringUtils; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.utils.MessageException; | |||
@@ -36,10 +42,11 @@ import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@RunWith(DataProviderRunner.class) | |||
public class ProjectInfoTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private MapSettings settings = new MapSettings(); | |||
private Clock clock = mock(Clock.class); | |||
@@ -53,8 +60,8 @@ public class ProjectInfoTest { | |||
underTest.start(); | |||
assertThat(underTest.analysisDate()).isEqualTo(Date.from(date.toInstant())); | |||
assertThat(underTest.projectVersion()).isEqualTo("version"); | |||
assertThat(underTest.getAnalysisDate()).isEqualTo(Date.from(date.toInstant())); | |||
assertThat(underTest.getProjectVersion()).contains("version"); | |||
} | |||
@Test | |||
@@ -64,16 +71,16 @@ public class ProjectInfoTest { | |||
underTest.start(); | |||
assertThat(underTest.analysisDate()) | |||
assertThat(underTest.getAnalysisDate()) | |||
.isEqualTo(Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant())); | |||
} | |||
@Test | |||
public void emptyDate() { | |||
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, ""); | |||
settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version"); | |||
settings.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, ""); | |||
settings.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version"); | |||
thrown.expect(RuntimeException.class); | |||
expectedException.expect(RuntimeException.class); | |||
underTest.start(); | |||
} | |||
@@ -81,13 +88,65 @@ public class ProjectInfoTest { | |||
@Test | |||
public void fail_with_too_long_version() { | |||
String version = randomAlphabetic(101); | |||
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01"); | |||
settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, version); | |||
settings.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01"); | |||
settings.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, version); | |||
expectedException.expect(MessageException.class); | |||
expectedException.expectMessage("\"" + version + "\" is not a valid project version. " + | |||
"The maximum length is 100 characters."); | |||
underTest.start(); | |||
} | |||
@Test | |||
@UseDataProvider("projectVersions") | |||
public void getCodePeriodVersion_has_value_of_projectVersion_if_property_is_unset(@Nullable String projectVersion) { | |||
settings.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01"); | |||
settings.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, projectVersion); | |||
underTest.start(); | |||
if (projectVersion == null) { | |||
assertThat(underTest.getCodePeriodVersion()).isEmpty(); | |||
} else { | |||
assertThat(underTest.getCodePeriodVersion()).contains(projectVersion); | |||
} | |||
} | |||
thrown.expect(MessageException.class); | |||
thrown.expectMessage("\"" + version +"\" is not a valid project version. " + | |||
"The maximum length for version numbers is 100 characters."); | |||
@Test | |||
@UseDataProvider("projectVersions") | |||
public void getCodePeriodVersion_is_empty_if_property_is_empty(@Nullable String projectVersion) { | |||
settings.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01"); | |||
settings.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, projectVersion); | |||
settings.setProperty(CoreProperties.CODE_PERIOD_VERSION_PROPERTY, ""); | |||
underTest.start(); | |||
if (projectVersion == null) { | |||
assertThat(underTest.getCodePeriodVersion()).isEmpty(); | |||
} else { | |||
assertThat(underTest.getCodePeriodVersion()).contains(projectVersion); | |||
} | |||
} | |||
@Test | |||
@UseDataProvider("projectVersions") | |||
public void getCodePeriodVersion_contains_value_of_property(@Nullable String projectVersion) { | |||
String version = RandomStringUtils.randomAlphabetic(10); | |||
settings.setProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01"); | |||
settings.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, projectVersion); | |||
settings.setProperty(CoreProperties.CODE_PERIOD_VERSION_PROPERTY, version); | |||
underTest.start(); | |||
assertThat(underTest.getCodePeriodVersion()).contains(version); | |||
} | |||
@DataProvider | |||
public static Object[][] projectVersions() { | |||
return new Object[][] { | |||
{null}, | |||
{randomAlphabetic(12)} | |||
}; | |||
} | |||
} |
@@ -72,7 +72,7 @@ public class DefaultFilterableIssueTest { | |||
rawIssue = createIssue(); | |||
issue = new DefaultFilterableIssue(mockedProject, projectInfo, rawIssue, component); | |||
when(projectInfo.analysisDate()).thenReturn(new Date(10_000)); | |||
when(projectInfo.getAnalysisDate()).thenReturn(new Date(10_000)); | |||
when(mockedProject.key()).thenReturn("projectKey"); | |||
assertThat(issue.componentKey()).isEqualTo(component.key()); |
@@ -74,7 +74,7 @@ public class ComponentsPublisherTest { | |||
@Test | |||
public void add_components_to_report() throws Exception { | |||
ProjectInfo projectInfo = mock(ProjectInfo.class); | |||
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
when(projectInfo.getAnalysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
ProjectDefinition rootDef = ProjectDefinition.create() | |||
.setKey("foo") | |||
@@ -138,7 +138,7 @@ public class ComponentsPublisherTest { | |||
@Test | |||
public void should_set_modified_name_with_branch() throws IOException { | |||
ProjectInfo projectInfo = mock(ProjectInfo.class); | |||
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
when(projectInfo.getAnalysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
ProjectDefinition rootDef = ProjectDefinition.create() | |||
.setKey("foo") | |||
@@ -162,7 +162,7 @@ public class ComponentsPublisherTest { | |||
public void publish_unchanged_components_even_in_short_branches() throws IOException { | |||
when(branchConfiguration.isShortOrPullRequest()).thenReturn(true); | |||
ProjectInfo projectInfo = mock(ProjectInfo.class); | |||
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
when(projectInfo.getAnalysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
Path baseDir = temp.newFolder().toPath(); | |||
ProjectDefinition rootDef = ProjectDefinition.create() | |||
@@ -202,7 +202,7 @@ public class ComponentsPublisherTest { | |||
@Test | |||
public void publish_project_without_version_and_name() throws IOException { | |||
ProjectInfo projectInfo = mock(ProjectInfo.class); | |||
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
when(projectInfo.getAnalysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
ProjectDefinition rootDef = ProjectDefinition.create() | |||
.setKey("foo") | |||
@@ -228,7 +228,7 @@ public class ComponentsPublisherTest { | |||
@Test | |||
public void publish_project_with_links_and_branch() throws Exception { | |||
ProjectInfo projectInfo = mock(ProjectInfo.class); | |||
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
when(projectInfo.getAnalysisDate()).thenReturn(DateUtils.parseDate("2012-12-12")); | |||
ProjectDefinition rootDef = ProjectDefinition.create() | |||
.setKey("foo") |
@@ -59,6 +59,7 @@ import org.sonar.scanner.scm.ScmConfiguration; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.emptyMap; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
import static org.mockito.ArgumentMatchers.any; | |||
@@ -85,7 +86,7 @@ public class MetadataPublisherTest { | |||
@Before | |||
public void prepare() throws IOException { | |||
when(projectInfo.analysisDate()).thenReturn(new Date(1234567L)); | |||
when(projectInfo.getAnalysisDate()).thenReturn(new Date(1234567L)); | |||
when(scmProvider.relativePathFromScmRoot(any(Path.class))).thenReturn(Paths.get("dummy/path")); | |||
when(scmProvider.revisionId(any(Path.class))).thenReturn("dummy-sha1"); | |||
@@ -134,6 +135,7 @@ public class MetadataPublisherTest { | |||
assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L); | |||
assertThat(metadata.getProjectKey()).isEqualTo("root"); | |||
assertThat(metadata.getModulesProjectRelativePathByKeyMap()).containsOnly(entry("module", "modulePath"), entry("root", "")); | |||
assertThat(metadata.getProjectVersion()).isEmpty(); | |||
assertThat(metadata.getQprofilesPerLanguageMap()).containsOnly(entry("java", org.sonar.scanner.protocol.output.ScannerReport.Metadata.QProfile.newBuilder() | |||
.setKey("q1") | |||
.setName("Q1") | |||
@@ -189,7 +191,7 @@ public class MetadataPublisherTest { | |||
@Test | |||
@UseDataProvider("projectVersions") | |||
public void write_project_version(@Nullable String projectVersion, String expected) throws Exception { | |||
when(projectInfo.projectVersion()).thenReturn(projectVersion); | |||
when(projectInfo.getProjectVersion()).thenReturn(Optional.ofNullable(projectVersion)); | |||
when(properties.organizationKey()).thenReturn(Optional.of("SonarSource")); | |||
File outputDir = temp.newFolder(); | |||
@@ -204,10 +206,39 @@ public class MetadataPublisherTest { | |||
@DataProvider | |||
public static Object[][] projectVersions() { | |||
String version = randomAlphabetic(15); | |||
return new Object[][] { | |||
{null, ""}, | |||
{"", ""}, | |||
{"5.6.3", "5.6.3"} | |||
{"5.6.3", "5.6.3"}, | |||
{version, version} | |||
}; | |||
} | |||
@Test | |||
@UseDataProvider("codePeriodVersions") | |||
public void write_codePeriod_version(@Nullable String codePeriodVersion, String expected) throws Exception { | |||
when(projectInfo.getCodePeriodVersion()).thenReturn(Optional.ofNullable(codePeriodVersion)); | |||
when(properties.organizationKey()).thenReturn(Optional.of("SonarSource")); | |||
File outputDir = temp.newFolder(); | |||
ScannerReportWriter writer = new ScannerReportWriter(outputDir); | |||
underTest.publish(writer); | |||
ScannerReportReader reader = new ScannerReportReader(outputDir); | |||
ScannerReport.Metadata metadata = reader.readMetadata(); | |||
assertThat(metadata.getCodePeriodVersion()).isEqualTo(expected); | |||
} | |||
@DataProvider | |||
public static Object[][] codePeriodVersions() { | |||
String randomVersion = randomAlphabetic(15); | |||
return new Object[][] { | |||
{null, ""}, | |||
{"", ""}, | |||
{"5.6.3", "5.6.3"}, | |||
{randomVersion, randomVersion} | |||
}; | |||
} | |||
@@ -233,7 +233,7 @@ public class ProjectReactorValidatorTest { | |||
@Test | |||
@UseDataProvider("validVersions") | |||
public void not_fail_with_valid_version(String validVersion) { | |||
when(projectInfo.projectVersion()).thenReturn(validVersion); | |||
when(projectInfo.getProjectVersion()).thenReturn(Optional.ofNullable(validVersion)); | |||
underTest.validate(createProjectReactor("foo")); | |||
} | |||
@@ -241,6 +241,7 @@ public class ProjectReactorValidatorTest { | |||
@DataProvider | |||
public static Object[][] validVersions() { | |||
return new Object[][] { | |||
{null}, | |||
{"1.0"}, | |||
{"2017-10-16"}, | |||
{randomAscii(100)} |
@@ -50,6 +50,7 @@ message Metadata { | |||
map<string, string> modules_project_relative_path_by_key = 15; | |||
string projectVersion = 16; | |||
string codePeriodVersion = 17; | |||
message QProfile { | |||
string key = 1; |