aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Vinot <antoine.vinot@sonarsource.com>2022-08-19 17:05:25 +0200
committersonartech <sonartech@sonarsource.com>2022-08-30 20:03:14 +0000
commitf6f59ecbf8e15e3b251bb0a44a0846b5acca7ea4 (patch)
treef3514b1b4e3134efef821fb3563fb5e05178a91d
parentad1024286aff2d16a3b3aa5f926613d596348f91 (diff)
downloadsonarqube-f6f59ecbf8e15e3b251bb0a44a0846b5acca7ea4.tar.gz
sonarqube-f6f59ecbf8e15e3b251bb0a44a0846b5acca7ea4.zip
SONAR-17210 - Update Github Scanning Alerts on status changes
-rw-r--r--server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubBinding.java90
-rw-r--r--server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/scanning/alert/GithubScanningAlertState.java40
-rw-r--r--server/sonar-webserver-api/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListener.java6
-rw-r--r--server/sonar-webserver-api/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java50
4 files changed, 171 insertions, 15 deletions
diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubBinding.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubBinding.java
index 7a8513153e7..d136e221917 100644
--- a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubBinding.java
+++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/GithubBinding.java
@@ -22,7 +22,7 @@ package org.sonar.alm.client.github;
import com.google.gson.annotations.SerializedName;
import java.util.List;
-import static org.sonar.alm.client.github.GithubApplicationClient.*;
+import static org.sonar.alm.client.github.GithubApplicationClient.Repository;
public class GithubBinding {
@@ -154,4 +154,92 @@ public class GithubBinding {
this.htmlUrl, this.defaultBranch);
}
}
+
+ public static class GsonGithubCodeScanningAlert {
+ @SerializedName("number")
+ long id;
+ @SerializedName("state")
+ GithubCodeScanningAlertState state;
+ @SerializedName("dismissed_reason")
+ String dismissedReason;
+ @SerializedName("dismissed_comment")
+ String dismissedComment;
+ @SerializedName("most_recent_instance")
+ GithubCodeScanningAlertInstance mostRecentInstance;
+
+ public GsonGithubCodeScanningAlert() {
+ // even if empty constructor is not required for Gson, it is strongly
+ // recommended:
+ // http://stackoverflow.com/a/18645370/229031
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public GithubCodeScanningAlertState getState() {
+ return state;
+ }
+
+ public String getDismissedReason() {
+ return dismissedReason;
+ }
+
+ public String getDismissedComment() {
+ return dismissedComment;
+ }
+
+ public GithubCodeScanningAlertInstance getInstance() {
+ return mostRecentInstance;
+ }
+
+ public String getMessageText() {
+ return getInstance().getMessageText();
+ }
+ }
+
+ public static class GithubCodeScanningAlertInstance {
+ @SerializedName("state")
+ GithubCodeScanningAlertState state;
+ @SerializedName("message")
+ Message message;
+
+ public GithubCodeScanningAlertInstance() {
+ // even if empty constructor is not required for Gson, it is strongly
+ // recommended:
+ // http://stackoverflow.com/a/18645370/229031
+ }
+
+ public Message getMessage() {
+ return message;
+ }
+
+ public String getMessageText() {
+ return getMessage().getText();
+ }
+ }
+
+ public enum GithubCodeScanningAlertState {
+ @SerializedName("open")
+ OPEN,
+ @SerializedName("fixed")
+ FIXED,
+ @SerializedName("dismissed")
+ DISMISSED;
+ }
+
+ public static class Message {
+ @SerializedName("text")
+ String text;
+
+ public Message() {
+ // even if empty constructor is not required for Gson, it is strongly
+ // recommended:
+ // http://stackoverflow.com/a/18645370/229031
+ }
+
+ public String getText() {
+ return text;
+ }
+ }
}
diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/scanning/alert/GithubScanningAlertState.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/scanning/alert/GithubScanningAlertState.java
new file mode 100644
index 00000000000..625799d34fd
--- /dev/null
+++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/scanning/alert/GithubScanningAlertState.java
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.alm.client.github.scanning.alert;
+
+import com.google.gson.annotations.SerializedName;
+import javax.annotation.Nullable;
+
+public class GithubScanningAlertState {
+ protected static final String GH_OPEN = "open";
+ protected static final String GH_DISMISSED = "dismissed";
+ protected static final String GH_WONTFIX = "won't fix";
+ protected static final String GH_FALSE_POSITIVE = "false positive";
+
+ @SerializedName("state")
+ private String state;
+ @SerializedName("dismissed_reason")
+ private String dismissedReason;
+
+ public GithubScanningAlertState(String state, @Nullable String dismissedReason) {
+ this.state = state;
+ this.dismissedReason = dismissedReason;
+ }
+}
diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListener.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListener.java
index efe2d11a4a1..149e623c64c 100644
--- a/server/sonar-webserver-api/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListener.java
+++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListener.java
@@ -24,6 +24,8 @@ import java.util.Set;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ServerSide;
+import static org.sonar.api.rules.RuleType.VULNERABILITY;
+
@ServerSide
public interface QGChangeEventListener {
/**
@@ -47,6 +49,10 @@ public interface QGChangeEventListener {
default boolean isNotClosed() {
return !Status.CLOSED_STATUSES.contains(getStatus());
}
+
+ default boolean isVulnerability() {
+ return getType() == VULNERABILITY;
+ }
}
enum Status {
diff --git a/server/sonar-webserver-api/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java b/server/sonar-webserver-api/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java
index cd83615d99b..e5215ae5f31 100644
--- a/server/sonar-webserver-api/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java
+++ b/server/sonar-webserver-api/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java
@@ -64,20 +64,20 @@ public class QGChangeEventListenersImplTest {
@Rule
public LogTester logTester = new LogTester();
- private QGChangeEventListener listener1 = mock(QGChangeEventListener.class);
- private QGChangeEventListener listener2 = mock(QGChangeEventListener.class);
- private QGChangeEventListener listener3 = mock(QGChangeEventListener.class);
- private List<QGChangeEventListener> listeners = Arrays.asList(listener1, listener2, listener3);
+ private final QGChangeEventListener listener1 = mock(QGChangeEventListener.class);
+ private final QGChangeEventListener listener2 = mock(QGChangeEventListener.class);
+ private final QGChangeEventListener listener3 = mock(QGChangeEventListener.class);
+ private final List<QGChangeEventListener> listeners = Arrays.asList(listener1, listener2, listener3);
- private String project1Uuid = RandomStringUtils.randomAlphabetic(6);
- private BranchDto project1 = newBranchDto(project1Uuid);
- private DefaultIssue component1Issue = newDefaultIssue(project1Uuid);
- private List<DefaultIssue> oneIssueOnComponent1 = singletonList(component1Issue);
- private QGChangeEvent component1QGChangeEvent = newQGChangeEvent(project1);
+ private final String project1Uuid = RandomStringUtils.randomAlphabetic(6);
+ private final BranchDto project1 = newBranchDto(project1Uuid);
+ private final DefaultIssue component1Issue = newDefaultIssue(project1Uuid);
+ private final List<DefaultIssue> oneIssueOnComponent1 = singletonList(component1Issue);
+ private final QGChangeEvent component1QGChangeEvent = newQGChangeEvent(project1);
- private InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
+ private final InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
- private QGChangeEventListenersImpl underTest = new QGChangeEventListenersImpl(new QGChangeEventListener[] {listener1, listener2, listener3});
+ private final QGChangeEventListenersImpl underTest = new QGChangeEventListenersImpl(new QGChangeEventListener[] {listener1, listener2, listener3});
@Test
public void broadcastOnIssueChange_has_no_effect_when_issues_are_empty() {
@@ -149,9 +149,9 @@ public class QGChangeEventListenersImplTest {
List<String> traceLogs = logTester.logs(LoggerLevel.TRACE);
assertThat(traceLogs).hasSize(3)
.containsOnly(
- "calling onChange() on listener " + listener1.getClass().getName() + " for events " + component1QGChangeEvent.toString() + "...",
- "calling onChange() on listener " + listener2.getClass().getName() + " for events " + component1QGChangeEvent.toString() + "...",
- "calling onChange() on listener " + listener3.getClass().getName() + " for events " + component1QGChangeEvent.toString() + "...");
+ "calling onChange() on listener " + listener1.getClass().getName() + " for events " + component1QGChangeEvent + "...",
+ "calling onChange() on listener " + listener2.getClass().getName() + " for events " + component1QGChangeEvent + "...",
+ "calling onChange() on listener " + listener3.getClass().getName() + " for events " + component1QGChangeEvent + "...");
}
@Test
@@ -253,6 +253,28 @@ public class QGChangeEventListenersImplTest {
}
@Test
+ public void isVulnerability_returns_true_if_issue_is_of_type_vulnerability() {
+ DefaultIssue defaultIssue = new DefaultIssue();
+ defaultIssue.setStatus(Issue.STATUS_OPEN);
+ defaultIssue.setType(RuleType.VULNERABILITY);
+
+ ChangedIssue changedIssue = new ChangedIssueImpl(defaultIssue);
+
+ assertThat(changedIssue.isVulnerability()).isTrue();
+ }
+
+ @Test
+ public void isVulnerability_returns_false_if_issue_is_not_of_type_vulnerability() {
+ DefaultIssue defaultIssue = new DefaultIssue();
+ defaultIssue.setStatus(Issue.STATUS_OPEN);
+ defaultIssue.setType(RuleType.BUG);
+
+ ChangedIssue changedIssue = new ChangedIssueImpl(defaultIssue);
+
+ assertThat(changedIssue.isVulnerability()).isFalse();
+ }
+
+ @Test
public void test_status_mapping() {
assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_OPEN))).isEqualTo(QGChangeEventListener.Status.OPEN);
assertThat(ChangedIssueImpl.statusOf(new DefaultIssue().setStatus(Issue.STATUS_REOPENED))).isEqualTo(QGChangeEventListener.Status.REOPENED);