return new File(dir, "metadata.pb");
}
+ public File analysisLog() {
+ return new File(dir, "analysis.log");
+ }
+
public File activeRules() {
return new File(dir, "activerules.pb");
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.report;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.StandardOpenOption;
+import java.util.Map;
+import org.sonar.api.batch.AnalysisMode;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.config.Settings;
+import org.sonar.batch.bootstrap.BatchPluginRepository;
+import org.sonar.batch.protocol.output.BatchReportWriter;
+import org.sonar.core.platform.PluginInfo;
+
+@BatchSide
+public class AnalysisContextReportPublisher {
+
+ private final BatchPluginRepository pluginRepo;
+ private final AnalysisMode mode;
+
+ private BatchReportWriter writer;
+
+ public AnalysisContextReportPublisher(AnalysisMode mode, BatchPluginRepository pluginRepo) {
+ this.mode = mode;
+ this.pluginRepo = pluginRepo;
+ }
+
+ public void init(BatchReportWriter writer) {
+ if (mode.isIssues()) {
+ return;
+ }
+ this.writer = writer;
+ File analysisLog = writer.getFileStructure().analysisLog();
+ try (BufferedWriter fileWriter = Files.newBufferedWriter(analysisLog.toPath(), StandardCharsets.UTF_8)) {
+ fileWriter.append("Environement variables:\n");
+ for (Map.Entry<String, String> env : System.getenv().entrySet()) {
+ fileWriter.append(String.format(" - %s=%s", env.getKey(), env.getValue())).append('\n');
+ }
+ fileWriter.write("System properties:\n");
+ for (Map.Entry<Object, Object> env : System.getProperties().entrySet()) {
+ fileWriter.append(String.format(" - %s=%s", env.getKey(), env.getValue())).append('\n');
+ }
+ fileWriter.write("SonarQube plugins:\n");
+ for (PluginInfo p : pluginRepo.getPluginInfos()) {
+ fileWriter.append(String.format(" - %s %s (%s)", p.getName(), p.getVersion(), p.getKey())).append('\n');
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to write analysis log", e);
+ }
+ }
+
+ public void dumpSettings(ProjectDefinition moduleDefinition, Settings settings) {
+ if (mode.isIssues()) {
+ return;
+ }
+ File analysisLog = writer.getFileStructure().analysisLog();
+ try (BufferedWriter fileWriter = Files.newBufferedWriter(analysisLog.toPath(), StandardCharsets.UTF_8, StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
+ fileWriter.append(String.format("Settings for module: %s", moduleDefinition.getKey())).append('\n');
+ for (Map.Entry<String, String> prop : settings.getProperties().entrySet()) {
+ fileWriter.append(String.format(" - %s=%s", prop.getKey(), sensitive(prop.getKey()) ? "******" : prop.getValue())).append('\n');
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to write analysis log", e);
+ }
+ }
+
+ private static boolean sensitive(String key) {
+ return key.contains(".password") || key.contains(".secured");
+ }
+}
*/
package org.sonar.batch.report;
-import org.sonar.batch.analysis.DefaultAnalysisMode;
-
-import org.sonar.batch.util.BatchUtils;
import com.github.kevinsawicki.http.HttpRequest;
import com.google.common.annotations.VisibleForTesting;
-
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Date;
-
import org.apache.commons.io.FileUtils;
import org.picocontainer.Startable;
import org.slf4j.Logger;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.ZipUtils;
+import org.sonar.batch.analysis.DefaultAnalysisMode;
import org.sonar.batch.bootstrap.ServerClient;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.scan.ImmutableProjectReactor;
+import org.sonar.batch.util.BatchUtils;
+
import static java.lang.String.format;
@BatchSide
private final ImmutableProjectReactor projectReactor;
private final DefaultAnalysisMode analysisMode;
private final TempFolder temp;
+ private final AnalysisContextReportPublisher contextPublisher;
private ReportPublisherStep[] publishers;
private File reportDir;
private BatchReportWriter writer;
- public ReportPublisher(Settings settings, ServerClient serverClient, Server server,
+ public ReportPublisher(Settings settings, ServerClient serverClient, Server server, AnalysisContextReportPublisher contextPublisher,
ImmutableProjectReactor projectReactor, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers) {
this.serverClient = serverClient;
this.server = server;
+ this.contextPublisher = contextPublisher;
this.projectReactor = projectReactor;
this.settings = settings;
this.analysisMode = analysisMode;
public void start() {
reportDir = new File(projectReactor.getRoot().getWorkDir(), "batch-report");
writer = new BatchReportWriter(reportDir);
+ contextPublisher.init(writer);
}
@Override
package org.sonar.batch.scan;
import java.util.Collection;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import javax.annotation.CheckForNull;
import org.sonar.api.batch.BatchSide;
public class ImmutableProjectReactor {
private ProjectDefinition root;
- private Map<String, ProjectDefinition> byKey = new HashMap<>();
+ private Map<String, ProjectDefinition> byKey = new LinkedHashMap<>();
public ImmutableProjectReactor(ProjectDefinition root) {
if (root.getParent() != null) {
*/
package org.sonar.batch.scan;
-import org.sonar.batch.repository.ProjectSettingsRepo;
-
-import org.sonar.batch.analysis.DefaultAnalysisMode;
import com.google.common.collect.Lists;
-
import java.util.List;
-
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.config.Settings;
import org.sonar.api.utils.MessageException;
+import org.sonar.batch.analysis.DefaultAnalysisMode;
import org.sonar.batch.bootstrap.GlobalSettings;
+import org.sonar.batch.report.AnalysisContextReportPublisher;
+import org.sonar.batch.repository.ProjectSettingsRepo;
/**
* @since 2.12
public class ModuleSettings extends Settings {
private final ProjectSettingsRepo projectSettingsRepo;
- private DefaultAnalysisMode analysisMode;
+ private final DefaultAnalysisMode analysisMode;
public ModuleSettings(GlobalSettings batchSettings, ProjectDefinition moduleDefinition, ProjectSettingsRepo projectSettingsRepo,
- DefaultAnalysisMode analysisMode) {
+ DefaultAnalysisMode analysisMode, AnalysisContextReportPublisher contextReportPublisher) {
super(batchSettings.getDefinitions());
this.projectSettingsRepo = projectSettingsRepo;
this.analysisMode = analysisMode;
getEncryption().setPathToSecretKey(batchSettings.getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH));
init(moduleDefinition, batchSettings);
+ contextReportPublisher.dumpSettings(moduleDefinition, this);
}
private ModuleSettings init(ProjectDefinition moduleDefinition, GlobalSettings batchSettings) {
import org.sonar.batch.phases.PhasesTimeProfiler;
import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
import org.sonar.batch.report.ActiveRulesPublisher;
+import org.sonar.batch.report.AnalysisContextReportPublisher;
import org.sonar.batch.report.ComponentsPublisher;
import org.sonar.batch.report.CoveragePublisher;
import org.sonar.batch.report.DuplicationsPublisher;
// Report
ReportPublisher.class,
+ AnalysisContextReportPublisher.class,
MetadataPublisher.class,
ActiveRulesPublisher.class,
ComponentsPublisher.class,
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.report;
+
+import java.util.Arrays;
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.AnalysisMode;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.config.Settings;
+import org.sonar.batch.bootstrap.BatchPluginRepository;
+import org.sonar.batch.protocol.output.BatchReportWriter;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.updatecenter.common.Version;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AnalysisContextReportPublisherTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private BatchPluginRepository pluginRepo = mock(BatchPluginRepository.class);
+ private AnalysisContextReportPublisher publisher;
+ private AnalysisMode analysisMode = mock(AnalysisMode.class);
+
+ @Before
+ public void prepare() throws Exception {
+ publisher = new AnalysisContextReportPublisher(analysisMode, pluginRepo);
+ }
+
+ @Test
+ public void shouldDumpPlugins() throws Exception {
+ when(pluginRepo.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("xoo").setName("Xoo").setVersion(Version.create("1.0"))));
+
+ BatchReportWriter writer = new BatchReportWriter(temp.newFolder());
+ publisher.init(writer);
+
+ assertThat(writer.getFileStructure().analysisLog()).exists();
+ assertThat(FileUtils.readFileToString(writer.getFileStructure().analysisLog())).contains("Xoo 1.0 (xoo)");
+ }
+
+ @Test
+ public void shouldNotDumpInIssuesMode() throws Exception {
+ when(analysisMode.isIssues()).thenReturn(true);
+
+ BatchReportWriter writer = new BatchReportWriter(temp.newFolder());
+ publisher.init(writer);
+ publisher.dumpSettings(ProjectDefinition.create().setProperty("sonar.projectKey", "foo"), new Settings());
+
+ assertThat(writer.getFileStructure().analysisLog()).doesNotExist();
+ }
+
+ @Test
+ public void shouldNotDumpSensitiveProperties() throws Exception {
+ BatchReportWriter writer = new BatchReportWriter(temp.newFolder());
+ publisher.init(writer);
+
+ assertThat(writer.getFileStructure().analysisLog()).exists();
+
+ Settings settings = new Settings();
+ settings.setProperty("sonar.projectKey", "foo");
+ settings.setProperty("sonar.password", "azerty");
+ settings.setProperty("sonar.cpp.license.secured", "AZERTY");
+ publisher.dumpSettings(ProjectDefinition.create().setProperty("sonar.projectKey", "foo"), settings);
+
+ assertThat(FileUtils.readFileToString(writer.getFileStructure().analysisLog())).contains("sonar.projectKey=foo", "sonar.password=******", "sonar.cpp.license.secured=******");
+ }
+}
*/
package org.sonar.batch.report;
-import org.sonar.batch.analysis.DefaultAnalysisMode;
-
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.sonar.api.config.Settings;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.TempFolder;
+import org.sonar.batch.analysis.DefaultAnalysisMode;
import org.sonar.batch.bootstrap.ServerClient;
import org.sonar.batch.scan.ImmutableProjectReactor;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public void should_log_successful_analysis() {
Settings settings = new Settings();
settings.setProperty(CoreProperties.SERVER_BASE_URL, "http://myserver/");
- ReportPublisher job = new ReportPublisher(settings, mock(ServerClient.class), mock(Server.class), reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher job = new ReportPublisher(settings, mock(ServerClient.class), mock(Server.class), mock(AnalysisContextReportPublisher.class), reactor, mode,
+ mock(TempFolder.class), new ReportPublisherStep[0]);
Logger logger = mock(Logger.class);
job.logSuccess(logger);
public void should_log_successful_issues_analysis() {
Settings settings = new Settings();
when(mode.isIssues()).thenReturn(true);
- ReportPublisher job = new ReportPublisher(settings, mock(ServerClient.class), mock(Server.class), reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher job = new ReportPublisher(settings, mock(ServerClient.class), mock(Server.class), mock(AnalysisContextReportPublisher.class), reactor, mode,
+ mock(TempFolder.class), new ReportPublisherStep[0]);
Logger logger = mock(Logger.class);
job.logSuccess(logger);
package org.sonar.batch.scan;
import com.google.common.collect.HashBasedTable;
-
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
+import java.util.List;
+import java.util.Map;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.batch.analysis.DefaultAnalysisMode;
import org.sonar.batch.bootstrap.GlobalSettings;
import org.sonar.batch.protocol.input.FileData;
+import org.sonar.batch.report.AnalysisContextReportPublisher;
import org.sonar.batch.repository.ProjectSettingsRepo;
-import java.util.List;
-import java.util.Map;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
when(batchSettings.getDefinitions()).thenReturn(new PropertyDefinitions());
when(batchSettings.getProperties()).thenReturn(ImmutableMap.of(
"overridding", "batch",
- "on-batch", "true"
- ));
+ "on-batch", "true"));
ProjectSettingsRepo projSettingsRepo = createSettings("struts-core", ImmutableMap.of("on-module", "true", "overridding", "module"));
ProjectDefinition module = ProjectDefinition.create().setKey("struts-core");
- ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode);
+ ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode, mock(AnalysisContextReportPublisher.class));
assertThat(moduleSettings.getString("overridding")).isEqualTo("module");
assertThat(moduleSettings.getString("on-batch")).isEqualTo("true");
GlobalSettings batchSettings = mock(GlobalSettings.class);
when(batchSettings.getDefinitions()).thenReturn(new PropertyDefinitions());
when(batchSettings.getProperties()).thenReturn(ImmutableMap.of(
- "sonar.foo.secured", "bar"
- ));
+ "sonar.foo.secured", "bar"));
ProjectSettingsRepo projSettingsRepo = createSettings("struts-core", ImmutableMap.of("sonar.foo.license.secured", "bar2"));
ProjectDefinition module = ProjectDefinition.create().setKey("struts-core");
- ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode);
+ ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode, mock(AnalysisContextReportPublisher.class));
assertThat(moduleSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2");
assertThat(moduleSettings.getString("sonar.foo.secured")).isEqualTo("bar");
GlobalSettings batchSettings = mock(GlobalSettings.class);
when(batchSettings.getDefinitions()).thenReturn(new PropertyDefinitions());
when(batchSettings.getProperties()).thenReturn(ImmutableMap.of(
- "sonar.foo.secured", "bar"
- ));
+ "sonar.foo.secured", "bar"));
ProjectSettingsRepo projSettingsRepo = createSettings("struts-core", ImmutableMap.of("sonar.foo.license.secured", "bar2"));
ProjectDefinition module = ProjectDefinition.create().setKey("struts-core");
- ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode);
+ ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode, mock(AnalysisContextReportPublisher.class));
assertThat(moduleSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2");
thrown.expect(MessageException.class);
thrown
- .expectMessage("Access to the secured property 'sonar.foo.secured' is not possible in issues mode. The SonarQube plugin which requires this property must be deactivated in issues mode.");
+ .expectMessage(
+ "Access to the secured property 'sonar.foo.secured' is not possible in issues mode. The SonarQube plugin which requires this property must be deactivated in issues mode.");
moduleSettings.getString("sonar.foo.secured");
}
}