import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.scm.ScmProvider;
-import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.rule.ModuleQProfiles;
import org.sonar.scanner.rule.QProfile;
+import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scm.ScmConfiguration;
private static final Logger LOG = Loggers.get(MetadataPublisher.class);
- private final Configuration settings;
+ private final ScanProperties properties;
private final ModuleQProfiles qProfiles;
private final ProjectAnalysisInfo projectAnalysisInfo;
private final InputModuleHierarchy moduleHierarchy;
@Nullable
private final ScmConfiguration scmConfiguration;
- public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, Configuration settings,
+ public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties,
ModuleQProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration,
@Nullable ScmConfiguration scmConfiguration) {
this.projectAnalysisInfo = projectAnalysisInfo;
this.moduleHierarchy = moduleHierarchy;
- this.settings = settings;
+ this.properties = properties;
this.qProfiles = qProfiles;
this.cpdSettings = cpdSettings;
this.pluginRepository = pluginRepository;
this.scmConfiguration = scmConfiguration;
}
- public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, Configuration settings,
+ public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties,
ModuleQProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration) {
- this(projectAnalysisInfo, moduleHierarchy, settings, qProfiles, cpdSettings, pluginRepository, branchConfiguration, null);
+ this(projectAnalysisInfo, moduleHierarchy, properties, qProfiles, cpdSettings, pluginRepository, branchConfiguration, null);
}
@Override
.setCrossProjectDuplicationActivated(cpdSettings.isCrossProjectDuplicationEnabled())
.setRootComponentRef(rootProject.batchId());
- settings.get(ORGANIZATION).ifPresent(builder::setOrganizationKey);
+ properties.organizationKey().ifPresent(builder::setOrganizationKey);
if (branchConfiguration.branchName() != null) {
addBranchInformation(builder);
import org.picocontainer.Startable;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
-import org.sonar.api.config.Configuration;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.TempFolder;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
import org.sonar.scanner.bootstrap.ScannerWsClient;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
+import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonarqube.ws.Ce;
import org.sonarqube.ws.MediaTypes;
import static java.net.URLEncoder.encode;
import static org.apache.commons.lang.StringUtils.EMPTY;
import static org.apache.commons.lang.StringUtils.isBlank;
-import static org.sonar.core.config.ScannerProperties.BRANCH_NAME;
-import static org.sonar.core.config.ScannerProperties.ORGANIZATION;
import static org.sonar.core.util.FileUtils.deleteQuietly;
import static org.sonar.scanner.scan.branch.BranchType.LONG;
import static org.sonar.scanner.scan.branch.BranchType.PULL_REQUEST;
public class ReportPublisher implements Startable {
private static final Logger LOG = Loggers.get(ReportPublisher.class);
-
- public static final String KEEP_REPORT_PROP_KEY = "sonar.scanner.keepReport";
- public static final String VERBOSE_KEY = "sonar.verbose";
- public static final String METADATA_DUMP_FILENAME = "report-task.txt";
private static final String CHARACTERISTIC = "characteristic";
-
private static final String DASHBOARD = "dashboard";
private static final String BRANCH = "branch";
private static final String ID = "id";
private static final String RESOLVED = "resolved";
- private final Configuration settings;
private final ScannerWsClient wsClient;
private final AnalysisContextReportPublisher contextPublisher;
private final InputModuleHierarchy moduleHierarchy;
private final ReportPublisherStep[] publishers;
private final Server server;
private final BranchConfiguration branchConfiguration;
+ private final ScanProperties properties;
private Path reportDir;
private ScannerReportWriter writer;
- public ReportPublisher(Configuration settings, ScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher,
+ public ReportPublisher(ScanProperties properties, ScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher,
InputModuleHierarchy moduleHierarchy, GlobalAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers, BranchConfiguration branchConfiguration) {
- this.settings = settings;
this.wsClient = wsClient;
this.server = server;
this.contextPublisher = contextPublisher;
this.temp = temp;
this.publishers = publishers;
this.branchConfiguration = branchConfiguration;
+ this.properties = properties;
}
@Override
@Override
public void stop() {
- if (!shouldKeepReport()) {
+ if (!properties.shouldKeepReport()) {
deleteQuietly(reportDir);
}
}
String taskId = null;
if (!analysisMode.isIssues()) {
File report = generateReportFile();
- if (shouldKeepReport()) {
+ if (properties.shouldKeepReport()) {
LOG.info("Analysis report generated in " + reportDir);
}
if (!analysisMode.isMediumTest()) {
logSuccess(taskId);
}
- private boolean shouldKeepReport() {
- return settings.getBoolean(KEEP_REPORT_PROP_KEY).orElse(false) || settings.getBoolean(VERBOSE_KEY).orElse(false);
- }
-
private File generateReportFile() {
try {
long startTime = System.currentTimeMillis();
PostRequest.Part filePart = new PostRequest.Part(MediaTypes.ZIP, report);
PostRequest post = new PostRequest("api/ce/submit")
.setMediaType(MediaTypes.PROTOBUF)
- .setParam("organization", settings.get(ORGANIZATION).orElse(null))
+ .setParam("organization", properties.organizationKey().orElse(null))
.setParam("projectKey", moduleHierarchy.root().key())
.setParam("projectName", moduleHierarchy.root().getOriginalName())
.setParam("projectBranch", moduleHierarchy.root().getBranch())
Map<String, String> metadata = new LinkedHashMap<>();
String effectiveKey = moduleHierarchy.root().getKeyWithBranch();
- settings.get(ORGANIZATION).ifPresent(org -> metadata.put("organization", org));
+ properties.organizationKey().ifPresent(org -> metadata.put("organization", org));
metadata.put("projectKey", effectiveKey);
metadata.put("serverUrl", server.getPublicRootUrl());
metadata.put("serverVersion", server.getVersion());
- settings.get(BRANCH_NAME).ifPresent(branch -> metadata.put(BRANCH, branch));
+ properties.branch().ifPresent(branch -> metadata.put("branch", branch));
URL dashboardUrl = buildDashboardUrl(server.getPublicRootUrl(), effectiveKey);
metadata.put("dashboardUrl", dashboardUrl.toExternalForm());
}
private static String encoded(@Nullable String queryParameter) {
- if (isBlank(queryParameter)){
+ if (isBlank(queryParameter)) {
return EMPTY;
}
try {
}
private void dumpMetadata(Map<String, String> metadata) {
- Path file = moduleHierarchy.root().getWorkDir().resolve(METADATA_DUMP_FILENAME);
- try (Writer output = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
- for (Map.Entry<String, String> entry : metadata.entrySet()) {
- output.write(entry.getKey());
- output.write("=");
- output.write(entry.getValue());
- output.write("\n");
+ Path file = properties.metadataFilePath();
+ try {
+ Files.createDirectories(file.getParent());
+ try (Writer output = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
+ for (Map.Entry<String, String> entry : metadata.entrySet()) {
+ output.write(entry.getKey());
+ output.write("=");
+ output.write(entry.getValue());
+ output.write("\n");
+ }
}
LOG.debug("Report metadata written to {}", file);
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.function.BinaryOperator;
import javax.annotation.Nullable;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.config.Configuration;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.scan.ScanProperties;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
import org.sonarqube.ws.client.GetRequest;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
-import static org.sonar.core.config.ScannerProperties.ORGANIZATION;
import static org.sonar.scanner.util.ScannerUtils.encodeForUrl;
public class DefaultQualityProfileLoader implements QualityProfileLoader {
private static final String WS_URL = "/api/qualityprofiles/search.protobuf";
- private final Configuration settings;
private final ScannerWsClient wsClient;
+ private final ScanProperties properties;
- public DefaultQualityProfileLoader(Configuration settings, ScannerWsClient wsClient) {
- this.settings = settings;
+ public DefaultQualityProfileLoader(ScanProperties properties, ScannerWsClient wsClient) {
+ this.properties = properties;
this.wsClient = wsClient;
}
}
private List<QualityProfile> loadAndOverrideIfNeeded(@Nullable String profileName, StringBuilder url) {
- getOrganizationKey().ifPresent(k -> url.append("&organization=").append(encodeForUrl(k)));
+ properties.organizationKey().ifPresent(k -> url.append("&organization=").append(encodeForUrl(k)));
Map<String, QualityProfile> result = call(url.toString());
if (profileName != null) {
StringBuilder urlForName = new StringBuilder(WS_URL + "?profileName=");
urlForName.append(encodeForUrl(profileName));
- getOrganizationKey().ifPresent(k -> urlForName.append("&organization=").append(encodeForUrl(k)));
+ properties.organizationKey().ifPresent(k -> urlForName.append("&organization=").append(encodeForUrl(k)));
result.putAll(call(urlForName.toString()));
}
if (result.isEmpty()) {
return new ArrayList<>(result.values());
}
- private Optional<String> getOrganizationKey() {
- return settings.get(ORGANIZATION);
- }
-
private Map<String, QualityProfile> call(String url) {
GetRequest getRequest = new GetRequest(url);
- InputStream is = wsClient.call(getRequest).contentStream();
- SearchWsResponse profiles;
-
- try {
- profiles = SearchWsResponse.parseFrom(is);
+ try (InputStream is = wsClient.call(getRequest).contentStream()) {
+ SearchWsResponse profiles = SearchWsResponse.parseFrom(is);
+ List<QualityProfile> profilesList = profiles.getProfilesList();
+ return profilesList.stream().collect(toMap(QualityProfile::getLanguage, identity(), throwingMerger(), LinkedHashMap::new));
} catch (IOException e) {
throw new IllegalStateException("Failed to load quality profiles", e);
- } finally {
- IOUtils.closeQuietly(is);
}
- List<QualityProfile> profilesList = profiles.getProfilesList();
- return profilesList.stream()
- .collect(toMap(QualityProfile::getLanguage, identity(), throwingMerger(), LinkedHashMap::new));
}
private static <T> BinaryOperator<T> throwingMerger() {
add(
props,
ProjectReactorBuilder.class,
+ ScanProperties.class,
WorkDirectoriesInitializer.class,
new MutableProjectReactorProvider(),
ProjectBuildersExecutor.class,
SensorStrategy.class,
MutableProjectSettings.class,
+ ScannerProperties.class,
new ProjectSettingsProvider(),
// Report
protected void doAfterStart() {
GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class);
InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class);
+ ScanProperties properties = getComponentByType(ScanProperties.class);
+ properties.validate();
LOG.info("Project key: {}", tree.root().key());
LOG.info("Project base dir: {}", tree.root().getBaseDir());
- String organization = props.property("sonar.organization");
- if (StringUtils.isNotEmpty(organization)) {
- LOG.info("Organization key: {}", organization);
- }
+ properties.organizationKey().ifPresent(k -> LOG.info("Organization key: {}", k));
+
String branch = tree.root().definition().getBranch();
if (branch != null) {
LOG.info("Branch key: {}", branch);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 org.sonar.scanner.scan;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.utils.MessageException;
+
+import static org.sonar.core.config.ScannerProperties.BRANCH_NAME;
+import static org.sonar.core.config.ScannerProperties.ORGANIZATION;
+
+/**
+ * Properties that can be passed to the scanners and are not exposed in SonarQube.
+ */
+@ScannerSide
+public class ScanProperties {
+ public static final String METADATA_FILE_PATH_KEY = "sonar.scanner.metadataFilePath";
+ public static final String KEEP_REPORT_PROP_KEY = "sonar.scanner.keepReport";
+ public static final String VERBOSE_KEY = "sonar.verbose";
+ public static final String METADATA_DUMP_FILENAME = "report-task.txt";
+ public static final String SONAR_REPORT_EXPORT_PATH = "sonar.report.export.path";
+ public static final String PRELOAD_FILE_METADATA_KEY = "sonar.preloadFileMetadata";
+ public static final String FORCE_RELOAD_KEY = "sonar.scm.forceReloadAll";
+
+ private final Configuration configuration;
+ private final InputModuleHierarchy moduleHierarchy;
+
+ public ScanProperties(Configuration configuration, InputModuleHierarchy moduleHierarchy) {
+ this.configuration = configuration;
+ this.moduleHierarchy = moduleHierarchy;
+ }
+
+ public boolean shouldKeepReport() {
+ return configuration.getBoolean(KEEP_REPORT_PROP_KEY).orElse(false) || configuration.getBoolean(VERBOSE_KEY).orElse(false);
+ }
+
+ public boolean preloadFileMetadata() {
+ return configuration.getBoolean(PRELOAD_FILE_METADATA_KEY).orElse(false);
+ }
+
+ public Optional<String> organizationKey() {
+ return configuration.get(ORGANIZATION);
+ }
+
+ public Optional<String> branch() {
+ return configuration.get(BRANCH_NAME);
+ }
+
+ public Path metadataFilePath() {
+ Optional<String> metadataFilePath = configuration.get(METADATA_FILE_PATH_KEY);
+ if (metadataFilePath.isPresent()) {
+ Path metadataPath = Paths.get(metadataFilePath.get());
+ if (!metadataPath.isAbsolute()) {
+ throw MessageException.of(String.format("Property '%s' must point to an absolute path: %s", METADATA_FILE_PATH_KEY, metadataFilePath.get()));
+ }
+ return moduleHierarchy.root().getBaseDir().resolve(metadataPath);
+ } else {
+ return moduleHierarchy.root().getWorkDir().resolve(METADATA_DUMP_FILENAME);
+ }
+ }
+
+ /**
+ * This should be called in the beginning of the analysis to fail fast
+ */
+ public void validate() {
+ metadataFilePath();
+ }
+}
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.api.config.Configuration;
import org.sonar.api.utils.PathUtils;
+import org.sonar.scanner.scan.ScanProperties;
public class InputFileBuilder {
- public static final String PRELOAD_FILE_METADATA_KEY = "sonar.preloadFileMetadata";
private final String moduleKey;
private final Path moduleBaseDir;
private final BatchIdGenerator idGenerator;
private final SensorStrategy sensorStrategy;
public InputFileBuilder(DefaultInputModule module, MetadataGenerator metadataGenerator,
- BatchIdGenerator idGenerator, Configuration settings, ModuleFileSystemInitializer moduleFileSystemInitializer, InputModuleHierarchy hierarchy, SensorStrategy sensorStrategy) {
+ BatchIdGenerator idGenerator, ScanProperties properties, ModuleFileSystemInitializer moduleFileSystemInitializer, InputModuleHierarchy hierarchy,
+ SensorStrategy sensorStrategy) {
this.sensorStrategy = sensorStrategy;
this.projectBaseDir = hierarchy.root().getBaseDir();
this.moduleFileSystemInitializer = moduleFileSystemInitializer;
this.moduleBaseDir = module.getBaseDir();
this.metadataGenerator = metadataGenerator;
this.idGenerator = idGenerator;
- this.preloadMetadata = settings.getBoolean(PRELOAD_FILE_METADATA_KEY).orElse(false);
+ this.preloadMetadata = properties.preloadFileMetadata();
}
DefaultInputFile create(InputFile.Type type, Path absolutePath, @Nullable String language) {
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.batch.bootstrapper.LogOutput;
+import org.sonar.core.config.ScannerProperties;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
import org.sonar.scanner.issue.tracking.ServerLineHashesLoader;
import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue;
import org.sonar.scanner.rule.ActiveRulesLoader;
import org.sonar.scanner.rule.LoadedActiveRule;
import org.sonar.scanner.rule.RulesLoader;
+import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.branch.BranchConfigurationLoader;
import org.sonar.scanner.scan.branch.BranchType;
}
registerCoreMetrics();
globalProperties.put(GlobalAnalysisMode.MEDIUM_TEST_ENABLED, "true");
- globalProperties.put(ReportPublisher.KEEP_REPORT_PROP_KEY, "true");
+ globalProperties.put(ScanProperties.KEEP_REPORT_PROP_KEY, "true");
globalProperties.put("sonar.userHome", userHome.toString());
}
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.rule.ModuleQProfiles;
import org.sonar.scanner.rule.QProfile;
+import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.branch.BranchType;
import org.sonar.scanner.scm.ScmConfiguration;
private DefaultInputModule rootModule;
private MetadataPublisher underTest;
- private MapSettings settings;
- private ModuleQProfiles qProfiles;
- private ProjectAnalysisInfo projectAnalysisInfo;
- private CpdSettings cpdSettings;
+ private ScanProperties properties = mock(ScanProperties.class);
+ private ModuleQProfiles qProfiles = mock(ModuleQProfiles.class);
+ private ProjectAnalysisInfo projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
+ private CpdSettings cpdSettings = mock(CpdSettings.class);
private InputModuleHierarchy inputModuleHierarchy;
- private ScannerPluginRepository pluginRepository;
+ private ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
private BranchConfiguration branches;
private ScmConfiguration scmConfiguration;
- private ScmProvider scmProvider;
+ private ScmProvider scmProvider = mock(ScmProvider.class);
@Before
public void prepare() throws IOException {
- projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
- cpdSettings = mock(CpdSettings.class);
when(projectAnalysisInfo.analysisDate()).thenReturn(new Date(1234567L));
- settings = new MapSettings();
- qProfiles = mock(ModuleQProfiles.class);
- pluginRepository = mock(ScannerPluginRepository.class);
-
- scmProvider = mock(ScmProvider.class);
when(scmProvider.relativePathFromScmRoot(any(Path.class))).thenReturn(Paths.get("dummy/path"));
when(scmProvider.revisionId(any(Path.class))).thenReturn("dummy-sha1");
branches = mock(BranchConfiguration.class);
scmConfiguration = mock(ScmConfiguration.class);
when(scmConfiguration.provider()).thenReturn(scmProvider);
- underTest = new MetadataPublisher(projectAnalysisInfo, inputModuleHierarchy, settings.asConfig(), qProfiles, cpdSettings,
+ underTest = new MetadataPublisher(projectAnalysisInfo, inputModuleHierarchy, properties, qProfiles, cpdSettings,
pluginRepository, branches, scmConfiguration);
}
@Test
public void write_metadata() throws Exception {
- settings.setProperty(CoreProperties.CPD_CROSS_PROJECT, "true");
Date date = new Date();
when(qProfiles.findAll()).thenReturn(asList(new QProfile("q1", "Q1", "java", date)));
when(pluginRepository.getPluginsByKey()).thenReturn(ImmutableMap.of(
@Test
public void write_project_branch() throws Exception {
when(cpdSettings.isCrossProjectDuplicationEnabled()).thenReturn(false);
- settings.setProperty(CoreProperties.CPD_CROSS_PROJECT, "true");
- settings.setProperty(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch");
ProjectDefinition projectDef = ProjectDefinition.create()
.setKey("foo")
@Test
public void write_project_organization() throws Exception {
- settings.setProperty(ScannerProperties.ORGANIZATION, "SonarSource");
+ when(properties.organizationKey()).thenReturn(Optional.of("SonarSource"));
File outputDir = temp.newFolder();
ScannerReportWriter writer = new ScannerReportWriter(outputDir);
ScannerReportReader reader = new ScannerReportReader(outputDir);
ScannerReport.Metadata metadata = reader.readMetadata();
- assertThat(metadata.getOrganizationKey()).isEqualTo("SonarSource");
+ assertThat(properties.organizationKey()).isEqualTo(Optional.of("SonarSource"));
}
@Test
*/
package org.sonar.scanner.report;
-import java.io.File;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.core.config.CorePropertyDefinitions;
-import org.sonar.core.config.ScannerProperties;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonarqube.ws.Ce;
import org.sonarqube.ws.client.HttpException;
import static org.apache.commons.io.FileUtils.readFileToString;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public ExpectedException exception = ExpectedException.none();
GlobalAnalysisMode mode = mock(GlobalAnalysisMode.class);
- MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all()));
- ScannerWsClient wsClient;
+ ScanProperties properties = mock(ScanProperties.class);
+ ScannerWsClient wsClient = mock(ScannerWsClient.class, Mockito.RETURNS_DEEP_STUBS);
Server server = mock(Server.class);
InputModuleHierarchy moduleHierarchy = mock(InputModuleHierarchy.class);
DefaultInputModule root;
AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);
BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
+ ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ new ReportPublisherStep[0], branchConfiguration);
@Before
public void setUp() throws IOException {
- wsClient = mock(ScannerWsClient.class, Mockito.RETURNS_DEEP_STUBS);
root = new DefaultInputModule(ProjectDefinition.create().setKey("org.sonarsource.sonarqube:sonarqube").setBaseDir(temp.newFolder()).setWorkDir(temp.getRoot()));
when(moduleHierarchy.root()).thenReturn(root);
when(server.getPublicRootUrl()).thenReturn("https://localhost");
when(server.getVersion()).thenReturn("6.4");
+ when(properties.metadataFilePath()).thenReturn(temp.newFolder().toPath()
+ .resolve("folder")
+ .resolve("report-task.txt"));
}
@Test
public void log_and_dump_information_about_report_uploading() throws IOException {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode,
- mock(TempFolder.class), new ReportPublisherStep[0], branchConfiguration);
- settings.setProperty(ScannerProperties.ORGANIZATION, "MyOrg");
-
+ when(properties.organizationKey()).thenReturn(Optional.of("MyOrg"));
underTest.logSuccess("TASK-123");
assertThat(logTester.logs(LoggerLevel.INFO))
.contains("Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report")
.contains("More about the report processing at https://localhost/api/ce/task?id=TASK-123");
- File detailsFile = new File(temp.getRoot(), "report-task.txt");
- assertThat(readFileToString(detailsFile)).isEqualTo(
+ assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
"organization=MyOrg\n" +
"projectKey=org.sonarsource.sonarqube:sonarqube\n" +
"serverUrl=https://localhost\n" +
@Test
public void parse_upload_error_message() throws IOException {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode,
- mock(TempFolder.class), new ReportPublisherStep[0], branchConfiguration);
HttpException ex = new HttpException("url", 404, "{\"errors\":[{\"msg\":\"Organization with key 'MyOrg' does not exist\"}]}");
WsResponse response = mock(WsResponse.class);
when(response.failIfNotSuccessful()).thenThrow(ex);
@Test
public void log_public_url_if_defined_for_main_branch() throws IOException {
when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
- new ReportPublisherStep[0], branchConfiguration);
underTest.logSuccess("TASK-123");
.contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard?id=org.sonarsource.sonarqube%3Asonarqube")
.contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
- File detailsFile = new File(temp.getRoot(), "report-task.txt");
- assertThat(readFileToString(detailsFile)).isEqualTo(
+ assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
"projectKey=org.sonarsource.sonarqube:sonarqube\n" +
"serverUrl=https://publicserver/sonarqube\n" +
"serverVersion=6.4\n" +
when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
when(branchConfiguration.branchType()).thenReturn(LONG);
when(branchConfiguration.branchName()).thenReturn("branch-6.7");
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
new ReportPublisherStep[0], branchConfiguration);
underTest.logSuccess("TASK-123");
.contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard?id=org.sonarsource.sonarqube%3Asonarqube&branch=branch-6.7")
.contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
- File detailsFile = new File(temp.getRoot(), "report-task.txt");
- assertThat(readFileToString(detailsFile)).isEqualTo(
+ assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
"projectKey=org.sonarsource.sonarqube:sonarqube\n" +
"serverUrl=https://publicserver/sonarqube\n" +
"serverVersion=6.4\n" +
when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
when(branchConfiguration.branchType()).thenReturn(SHORT);
when(branchConfiguration.branchName()).thenReturn("branch-6.7");
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
new ReportPublisherStep[0], branchConfiguration);
underTest.logSuccess("TASK-123");
.contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard?id=org.sonarsource.sonarqube%3Asonarqube&branch=branch-6.7&resolved=false")
.contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
- File detailsFile = new File(temp.getRoot(), "report-task.txt");
- assertThat(readFileToString(detailsFile)).isEqualTo(
+ assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
"projectKey=org.sonarsource.sonarqube:sonarqube\n" +
"serverUrl=https://publicserver/sonarqube\n" +
"serverVersion=6.4\n" +
when(branchConfiguration.branchType()).thenReturn(PULL_REQUEST);
when(branchConfiguration.pullRequestKey()).thenReturn("105");
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
new ReportPublisherStep[0], branchConfiguration);
underTest.logSuccess("TASK-123");
.contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/project/issues?id=org.sonarsource.sonarqube%3Asonarqube&pullRequest=105&resolved=false")
.contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
- File detailsFile = new File(temp.getRoot(), "report-task.txt");
- assertThat(readFileToString(detailsFile)).isEqualTo(
+ assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
"projectKey=org.sonarsource.sonarqube:sonarqube\n" +
"serverUrl=https://publicserver/sonarqube\n" +
"serverVersion=6.4\n" +
@Test
public void fail_if_public_url_malformed() {
when(server.getPublicRootUrl()).thenReturn("invalid");
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
- new ReportPublisherStep[0], branchConfiguration);
exception.expect(MessageException.class);
exception.expectMessage("Failed to parse public URL set in SonarQube server: invalid");
}
@Test
- public void log_but_not_dump_information_when_report_is_not_uploaded() {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
- new ReportPublisherStep[0], branchConfiguration);
-
+ public void log_but_not_dump_information_when_report_is_not_uploaded() throws IOException {
underTest.logSuccess(/* report not uploaded, no server task */null);
assertThat(logTester.logs(LoggerLevel.INFO))
.contains("ANALYSIS SUCCESSFUL")
.doesNotContain("dashboard/index");
- File detailsFile = new File(temp.getRoot(), ReportPublisher.METADATA_DUMP_FILENAME);
- assertThat(detailsFile).doesNotExist();
+ assertThat(properties.metadataFilePath()).doesNotExist();
+ }
+
+ @Test
+ public void log_and_dump_information_to_custom_path() throws IOException {
+ underTest.logSuccess("TASK-123");
+
+ assertThat(properties.metadataFilePath()).exists();
+ assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Report metadata written to " + properties.metadataFilePath());
}
@Test
public void should_not_delete_report_if_property_is_set() throws IOException {
- settings.setProperty("sonar.scanner.keepReport", true);
+ when(properties.shouldKeepReport()).thenReturn(true);
Path reportDir = temp.getRoot().toPath().resolve("scanner-report");
Files.createDirectory(reportDir);
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
- new ReportPublisherStep[0], branchConfiguration);
underTest.start();
underTest.stop();
public void should_delete_report_by_default() throws IOException {
Path reportDir = temp.getRoot().toPath().resolve("scanner-report");
Files.createDirectory(reportDir);
- ReportPublisher job = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
- new ReportPublisherStep[0],
- branchConfiguration);
- job.start();
- job.stop();
+ underTest.start();
+ underTest.stop();
assertThat(reportDir).doesNotExist();
}
@Test
public void test_ws_parameters() throws Exception {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
- new ReportPublisherStep[0], branchConfiguration);
-
- settings.setProperty(ScannerProperties.ORGANIZATION, "MyOrg");
+ when(properties.organizationKey()).thenReturn(Optional.of("MyOrg"));
WsResponse response = mock(WsResponse.class);
verify(wsClient).call(capture.capture());
WsRequest wsRequest = capture.getValue();
- assertThat(wsRequest.getParams()).containsOnly(
- entry("organization", "MyOrg"),
- entry("projectKey", "org.sonarsource.sonarqube:sonarqube"));
+ assertThat(wsRequest.getParameters().getKeys()).containsOnly("organization", "projectKey");
+ assertThat(wsRequest.getParameters().getValue("organization")).isEqualTo("MyOrg");
+ assertThat(wsRequest.getParameters().getValue("projectKey")).isEqualTo("org.sonarsource.sonarqube:sonarqube");
}
@Test
public void test_send_branches_characteristics() throws Exception {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
- new ReportPublisherStep[0], branchConfiguration);
-
String orgName = "MyOrg";
- settings.setProperty(ScannerProperties.ORGANIZATION, orgName);
+ when(properties.organizationKey()).thenReturn(Optional.of(orgName));
String branchName = "feature";
when(branchConfiguration.branchName()).thenReturn(branchName);
@Test
public void send_pull_request_characteristic() throws Exception {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
- new ReportPublisherStep[0], branchConfiguration);
-
String orgName = "MyOrg";
- settings.setProperty(ScannerProperties.ORGANIZATION, orgName);
+ when(properties.organizationKey()).thenReturn(Optional.of(orgName));
String branchName = "feature";
String pullRequestId = "pr-123";
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.WsTestUtil;
import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.scan.ScanProperties;
import org.sonarqube.ws.Qualityprofiles;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
public class DefaultQualityProfileLoaderTest {
@Rule
public ExpectedException exception = ExpectedException.none();
private ScannerWsClient wsClient = mock(ScannerWsClient.class);
- private MapSettings settings = new MapSettings();
- private DefaultQualityProfileLoader underTest = new DefaultQualityProfileLoader(settings.asConfig(), wsClient);
+ private ScanProperties properties = mock(ScanProperties.class);
+ private DefaultQualityProfileLoader underTest = new DefaultQualityProfileLoader(properties, wsClient);
@Test
public void load_gets_profiles_for_specified_project_and_profile_name() throws IOException {
@Test
public void load_sets_organization_parameter_if_defined_in_settings() throws IOException {
- settings.setProperty("sonar.organization", "my-org");
+ when(properties.organizationKey()).thenReturn(Optional.of("my-org"));
prepareCallWithResults();
underTest.load("foo", null);
verifyCalledPath("/api/qualityprofiles/search.protobuf?projectKey=foo&organization=my-org");
@Test
public void loadDefault_sets_organization_parameter_if_defined_in_settings() throws IOException {
- settings.setProperty("sonar.organization", "my-org");
+ when(properties.organizationKey()).thenReturn(Optional.of("my-org"));
WsTestUtil.mockStream(wsClient, "/api/qualityprofiles/search.protobuf?defaults=true&organization=my-org", createStreamOfProfiles("qp"));
WsTestUtil.mockStream(wsClient, "/api/qualityprofiles/search.protobuf?profileName=foo&organization=my-org", createStreamOfProfiles("qp"));
underTest.loadDefault("foo");
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 org.sonar.scanner.scan;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.MessageException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ScanPropertiesTest {
+ private MapSettings settings = new MapSettings();
+ private InputModuleHierarchy inputModuleHierarchy = mock(InputModuleHierarchy.class);
+ private ScanProperties underTest = new ScanProperties(settings.asConfig(), inputModuleHierarchy);
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ @Before
+ public void setUp() throws IOException {
+ DefaultInputModule root = mock(DefaultInputModule.class);
+ when(root.getBaseDir()).thenReturn(temp.newFolder().toPath());
+ when(root.getWorkDir()).thenReturn(temp.newFolder().toPath());
+ when(inputModuleHierarchy.root()).thenReturn(root);
+ }
+
+ @Test
+ public void defaults_if_no_setting_defined() {
+ assertThat(underTest.branch()).isEmpty();
+ assertThat(underTest.organizationKey()).isEmpty();
+ assertThat(underTest.preloadFileMetadata()).isFalse();
+ assertThat(underTest.shouldKeepReport()).isFalse();
+ assertThat(underTest.metadataFilePath()).isEqualTo(inputModuleHierarchy.root().getWorkDir().resolve("report-task.txt"));
+ underTest.validate();
+ }
+
+ @Test
+ public void should_define_organization_key() {
+ settings.setProperty("sonar.organization", "org");
+ assertThat(underTest.organizationKey()).isEqualTo(Optional.of("org"));
+ }
+
+ @Test
+ public void should_define_branch_name() {
+ settings.setProperty("sonar.branch.name", "name");
+ assertThat(underTest.branch()).isEqualTo(Optional.of("name"));
+ }
+
+ @Test
+ public void should_define_preload_file_metadata() {
+ settings.setProperty("sonar.preloadFileMetadata", "true");
+ assertThat(underTest.preloadFileMetadata()).isTrue();
+ }
+
+ @Test
+ public void should_define_keep_report() {
+ settings.setProperty("sonar.scanner.keepReport", "true");
+ assertThat(underTest.shouldKeepReport()).isTrue();
+ }
+
+ @Test
+ public void should_define_metadata_file_path() throws IOException {
+ Path path = temp.newFolder().toPath().resolve("report");
+ settings.setProperty("sonar.scanner.metadataFilePath", path.toString());
+ assertThat(underTest.metadataFilePath()).isEqualTo(path);
+ }
+
+ @Test
+ public void validate_fails_if_metadata_file_location_is_not_absolute() {
+ settings.setProperty("sonar.scanner.metadataFilePath", "relative");
+
+ exception.expect(MessageException.class);
+ exception.expectMessage("Property 'sonar.scanner.metadataFilePath' must point to an absolute path: relative");
+ underTest.validate();
+
+ }
+}
import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.scanner.scan.DefaultInputModuleHierarchy;
+import org.sonar.scanner.scan.ScanProperties;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
MetadataGenerator metadataGenerator = mock(MetadataGenerator.class);
BatchIdGenerator idGenerator = new BatchIdGenerator();
- MapSettings settings = new MapSettings();
+ ScanProperties properties = mock(ScanProperties.class);
ModuleFileSystemInitializer moduleFileSystemInitializer = mock(ModuleFileSystemInitializer.class);
when(moduleFileSystemInitializer.defaultEncoding()).thenReturn(StandardCharsets.UTF_8);
sensorStrategy = new SensorStrategy();
- builder = new InputFileBuilder(module, metadataGenerator, idGenerator, settings.asConfig(), moduleFileSystemInitializer, new DefaultInputModuleHierarchy(root),
+ builder = new InputFileBuilder(module, metadataGenerator, idGenerator, properties, moduleFileSystemInitializer, new DefaultInputModuleHierarchy(root),
sensorStrategy);
}