From 9c38ed460e4b4cb01e7ed977f52424cdfd4a747e Mon Sep 17 00:00:00 2001 From: Janos Gyerik Date: Tue, 11 Sep 2018 16:27:55 +0200 Subject: [PATCH] SONAR-11241 Provide API for SCM plugins to register analysis warnings --- .../api/notifications/AnalysisWarnings.java | 37 +++++++ .../DefaultAnalysisWarnings.java | 73 ++++++++++++++ .../scanner/notifications/package-info.java | 23 +++++ .../scanner/scan/ProjectScanContainer.java | 3 + .../DefaultAnalysisWarningsTest.java | 98 +++++++++++++++++++ 5 files changed, 234 insertions(+) create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/notifications/AnalysisWarnings.java create mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/notifications/DefaultAnalysisWarnings.java create mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/notifications/package-info.java create mode 100644 sonar-scanner-engine/src/test/java/org/sonar/scanner/notifications/DefaultAnalysisWarningsTest.java diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/notifications/AnalysisWarnings.java b/sonar-plugin-api/src/main/java/org/sonar/api/notifications/AnalysisWarnings.java new file mode 100644 index 00000000000..636e8ced40b --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/notifications/AnalysisWarnings.java @@ -0,0 +1,37 @@ +/* + * 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.api.notifications; + +import org.sonar.api.batch.ScannerSide; + +/** + * Record user-friendly warnings that will be visible on SonarQube + * to users with browse access to the project. + * + * @since 7.4 + */ +@ScannerSide +public interface AnalysisWarnings { + + /** + * Add a single message, if it was not already added. + */ + void addUnique(String text); +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/notifications/DefaultAnalysisWarnings.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/notifications/DefaultAnalysisWarnings.java new file mode 100644 index 00000000000..a7b944d649b --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/notifications/DefaultAnalysisWarnings.java @@ -0,0 +1,73 @@ +/* + * 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.notifications; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.concurrent.Immutable; +import org.sonar.api.notifications.AnalysisWarnings; +import org.sonar.api.utils.System2; + +import static com.google.common.base.Preconditions.checkArgument; + +public class DefaultAnalysisWarnings implements AnalysisWarnings { + private final System2 system2; + + private final List messages = new ArrayList<>(); + private final Set seen = new HashSet<>(); + + public DefaultAnalysisWarnings(System2 system2) { + this.system2 = system2; + } + + @Override + public void addUnique(String text) { + if (this.seen.add(text)) { + this.messages.add(new Message(text, system2.now())); + } + } + + public List warnings() { + return Collections.unmodifiableList(messages); + } + + @Immutable + public static class Message { + private final String text; + private final long timestamp; + + Message(String text, long timestamp) { + checkArgument(!text.isEmpty(), "Text can't be empty"); + this.text = text; + this.timestamp = timestamp; + } + + public String getText() { + return text; + } + + public long getTimestamp() { + return timestamp; + } + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/notifications/package-info.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/notifications/package-info.java new file mode 100644 index 00000000000..ca7459190f4 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/notifications/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.scanner.notifications; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java index b2c105c2722..3e47377c768 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java @@ -55,6 +55,7 @@ import org.sonar.scanner.issue.tracking.LocalIssueTracking; import org.sonar.scanner.issue.tracking.ServerIssueRepository; import org.sonar.scanner.issue.tracking.ServerLineHashesLoader; import org.sonar.scanner.mediumtest.ScanTaskObservers; +import org.sonar.scanner.notifications.DefaultAnalysisWarnings; import org.sonar.scanner.report.ActiveRulesPublisher; import org.sonar.scanner.report.AnalysisContextReportPublisher; import org.sonar.scanner.report.ChangedLinesPublisher; @@ -189,6 +190,8 @@ public class ProjectScanContainer extends ComponentContainer { ContextPropertiesCache.class, ContextPropertiesPublisher.class, + DefaultAnalysisWarnings.class, + SensorStrategy.class, MutableProjectSettings.class, diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/notifications/DefaultAnalysisWarningsTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/notifications/DefaultAnalysisWarningsTest.java new file mode 100644 index 00000000000..c7cbc949178 --- /dev/null +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/notifications/DefaultAnalysisWarningsTest.java @@ -0,0 +1,98 @@ +/* + * 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.notifications; + +import org.junit.Test; +import org.sonar.api.utils.System2; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DefaultAnalysisWarningsTest { + + private final System2 system2 = mock(System2.class); + private final DefaultAnalysisWarnings underTest = new DefaultAnalysisWarnings(system2); + + @Test + public void addUnique_adds_messages_with_timestamp() { + String warning1 = "dummy warning 1"; + long timestamp1 = 1L; + String warning2 = "dummy warning 2"; + long timestamp2 = 2L; + + when(system2.now()) + .thenReturn(timestamp1) + .thenReturn(timestamp2); + + underTest.addUnique(warning1); + underTest.addUnique(warning2); + + assertThat(underTest.warnings()) + .extracting(DefaultAnalysisWarnings.Message::getText, DefaultAnalysisWarnings.Message::getTimestamp) + .containsExactly(tuple(warning1, timestamp1), tuple(warning2, timestamp2)); + } + + @Test + public void addUnique_adds_same_message_once() { + String warning = "dummy warning"; + + underTest.addUnique(warning); + underTest.addUnique(warning); + assertThat(underTest.warnings()) + .extracting(DefaultAnalysisWarnings.Message::getText) + .isEqualTo(singletonList(warning)); + } + + @Test(expected = IllegalArgumentException.class) + public void addUnique_fails_with_IAE_when_message_is_empty() { + underTest.addUnique(""); + } + + @Test + public void addUnique_preserves_order_and_takes_first_unique_item() { + String warning1 = "dummy warning 1"; + long timestamp1 = 1L; + String warning2 = "dummy warning 2"; + long timestamp2 = 2L; + String warning3 = "dummy warning 3"; + long timestamp3 = 3L; + + when(system2.now()) + .thenReturn(timestamp1) + .thenReturn(timestamp2) + .thenReturn(timestamp3); + + underTest.addUnique(warning1); + underTest.addUnique(warning2); + underTest.addUnique(warning3); + underTest.addUnique(warning2); + + assertThat(underTest.warnings()) + .extracting(DefaultAnalysisWarnings.Message::getText, DefaultAnalysisWarnings.Message::getTimestamp) + .containsExactly( + tuple(warning1, timestamp1), + tuple(warning2, timestamp2), + tuple(warning3, timestamp3) + ); + } +} -- 2.39.5