瀏覽代碼

SONAR-17501 Send push events to SonarLint for branches

tags/9.8.0.63668
Jacek 1 年之前
父節點
當前提交
2dd8147eaf

+ 9
- 7
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/pushevent/PushEventFactory.java 查看文件

@@ -57,7 +57,7 @@ public class PushEventFactory {
this.flowGenerator = flowGenerator;
}

public Optional<PushEventDto> raiseEventOnIssue(DefaultIssue currentIssue) {
public Optional<PushEventDto> raiseEventOnIssue(String projectUuid, DefaultIssue currentIssue) {
var currentIssueComponentUuid = currentIssue.componentUuid();
if (!taintChecker.isTaintVulnerability(currentIssue) || currentIssueComponentUuid == null) {
return Optional.empty();
@@ -65,10 +65,10 @@ public class PushEventFactory {

var component = treeRootHolder.getComponentByUuid(Objects.requireNonNull(currentIssue.componentUuid()));
if (currentIssue.isNew() || currentIssue.isCopied() || isReopened(currentIssue)) {
return Optional.of(raiseTaintVulnerabilityRaisedEvent(component, currentIssue));
return Optional.of(raiseTaintVulnerabilityRaisedEvent(projectUuid, component, currentIssue));
}
if (currentIssue.isBeingClosed()) {
return Optional.of(raiseTaintVulnerabilityClosedEvent(currentIssue));
return Optional.of(raiseTaintVulnerabilityClosedEvent(projectUuid, currentIssue));
}
return Optional.empty();
}
@@ -82,11 +82,12 @@ public class PushEventFactory {
return status != null && status.toString().equals("CLOSED|OPEN");
}

private PushEventDto raiseTaintVulnerabilityRaisedEvent(Component component, DefaultIssue issue) {
private PushEventDto raiseTaintVulnerabilityRaisedEvent(String projectUuid, Component component, DefaultIssue issue) {
TaintVulnerabilityRaised event = prepareEvent(component, issue);
return new PushEventDto()
.setName("TaintVulnerabilityRaised")
.setProjectUuid(treeRootHolder.getRoot().getUuid())
.setProjectUuid(projectUuid)
.setLanguage(issue.language())
.setPayload(serializeEvent(event));
}

@@ -116,11 +117,12 @@ public class PushEventFactory {
return event;
}

private PushEventDto raiseTaintVulnerabilityClosedEvent(DefaultIssue issue) {
private static PushEventDto raiseTaintVulnerabilityClosedEvent(String projectUuid, DefaultIssue issue) {
TaintVulnerabilityClosed event = new TaintVulnerabilityClosed(issue.key(), issue.projectKey());
return new PushEventDto()
.setName("TaintVulnerabilityClosed")
.setProjectUuid(treeRootHolder.getRoot().getUuid())
.setProjectUuid(projectUuid)
.setLanguage(issue.language())
.setPayload(serializeEvent(event));
}


+ 15
- 2
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistPushEventsStep.java 查看文件

@@ -22,6 +22,7 @@ package org.sonar.ce.task.projectanalysis.step;
import java.util.Optional;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
import org.sonar.ce.task.projectanalysis.issue.ProtoIssueCache;
import org.sonar.ce.task.projectanalysis.pushevent.PushEventFactory;
import org.sonar.ce.task.step.ComputationStep;
@@ -38,13 +39,16 @@ public class PersistPushEventsStep implements ComputationStep {
private final DbClient dbClient;
private final ProtoIssueCache protoIssueCache;
private final PushEventFactory pushEventFactory;
private final TreeRootHolder treeRootHolder;

public PersistPushEventsStep(DbClient dbClient,
ProtoIssueCache protoIssueCache,
PushEventFactory pushEventFactory) {
PushEventFactory pushEventFactory,
TreeRootHolder treeRootHolder) {
this.dbClient = dbClient;
this.protoIssueCache = protoIssueCache;
this.pushEventFactory = pushEventFactory;
this.treeRootHolder = treeRootHolder;
}

@Override
@@ -52,10 +56,11 @@ public class PersistPushEventsStep implements ComputationStep {
try (DbSession dbSession = dbClient.openSession(true);
CloseableIterator<DefaultIssue> issues = protoIssueCache.traverse()) {
int batchCounter = 0;
var projectUuid = getProjectUuid(dbSession);

while (issues.hasNext()) {
DefaultIssue currentIssue = issues.next();
Optional<PushEventDto> raisedEvent = pushEventFactory.raiseEventOnIssue(currentIssue);
Optional<PushEventDto> raisedEvent = pushEventFactory.raiseEventOnIssue(projectUuid, currentIssue);

if (raisedEvent.isEmpty()) {
continue;
@@ -72,6 +77,14 @@ public class PersistPushEventsStep implements ComputationStep {
}
}

private String getProjectUuid(DbSession dbSession) {
var branch = dbClient.branchDao().selectByUuid(dbSession, treeRootHolder.getRoot().getUuid());
if (branch.isEmpty()) {
return treeRootHolder.getRoot().getUuid();
}
return branch.get().getProjectUuid();
}

private static int flushIfNeeded(DbSession dbSession, int batchCounter) {
if (batchCounter > MAX_BATCH_SIZE) {
flushSession(dbSession);

+ 17
- 34
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/pushevent/PushEventFactoryTest.java 查看文件

@@ -24,7 +24,6 @@ import java.util.List;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.DateUtils;
@@ -38,7 +37,6 @@ import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.FieldDiffs;
import org.sonar.db.protobuf.DbCommons;
import org.sonar.db.protobuf.DbIssues;
import org.sonar.db.pushevent.PushEventDto;
import org.sonar.server.issue.TaintChecker;

import static org.assertj.core.api.Assertions.assertThat;
@@ -71,11 +69,13 @@ public class PushEventFactoryTest {
DefaultIssue defaultIssue = createDefaultIssue()
.setNew(true);

assertThat(underTest.raiseEventOnIssue(defaultIssue))
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue))
.isNotEmpty()
.hasValueSatisfying(pushEventDto -> {
assertThat(pushEventDto.getName()).isEqualTo("TaintVulnerabilityRaised");
assertThat(pushEventDto.getPayload()).isNotNull();
assertThat(pushEventDto.getLanguage()).isEqualTo("java");
assertThat(pushEventDto.getProjectUuid()).isEqualTo("some-project-uuid");
});

}
@@ -88,7 +88,7 @@ public class PushEventFactoryTest {
.setCopied(false)
.setCurrentChange(new FieldDiffs().setDiff("status", "CLOSED", "OPEN"));

assertThat(underTest.raiseEventOnIssue(defaultIssue))
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue))
.isNotEmpty()
.hasValueSatisfying(pushEventDto -> {
assertThat(pushEventDto.getName()).isEqualTo("TaintVulnerabilityRaised");
@@ -99,12 +99,12 @@ public class PushEventFactoryTest {
@Test
public void skip_event_if_taint_vulnerability_status_change() {
DefaultIssue defaultIssue = createDefaultIssue()
.setChanged(true)
.setNew(false)
.setCopied(false)
.setCurrentChange(new FieldDiffs().setDiff("status", "OPEN", "FIXED"));
.setChanged(true)
.setNew(false)
.setCopied(false)
.setCurrentChange(new FieldDiffs().setDiff("status", "OPEN", "FIXED"));

assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}

@Test
@@ -112,7 +112,7 @@ public class PushEventFactoryTest {
DefaultIssue defaultIssue = createDefaultIssue()
.setCopied(true);

assertThat(underTest.raiseEventOnIssue(defaultIssue))
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue))
.isNotEmpty()
.hasValueSatisfying(pushEventDto -> {
assertThat(pushEventDto.getName()).isEqualTo("TaintVulnerabilityRaised");
@@ -128,7 +128,7 @@ public class PushEventFactoryTest {
.setCopied(false)
.setBeingClosed(true);

assertThat(underTest.raiseEventOnIssue(defaultIssue))
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue))
.isNotEmpty()
.hasValueSatisfying(pushEventDto -> {
assertThat(pushEventDto.getName()).isEqualTo("TaintVulnerabilityClosed");
@@ -147,7 +147,7 @@ public class PushEventFactoryTest {
.setCreationDate(DateUtils.parseDate("2022-01-01"))
.setRuleKey(RuleKey.of("javasecurity", "S123"));

assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}

@Test
@@ -160,7 +160,7 @@ public class PushEventFactoryTest {

when(taintChecker.isTaintVulnerability(any())).thenReturn(false);

assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();

defaultIssue = new DefaultIssue()
.setComponentUuid("issue-component-uuid")
@@ -170,7 +170,7 @@ public class PushEventFactoryTest {
.setType(RuleType.VULNERABILITY)
.setRuleKey(RuleKey.of("weirdrepo", "S123"));

assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}

@Test
@@ -183,7 +183,7 @@ public class PushEventFactoryTest {

when(taintChecker.isTaintVulnerability(any())).thenReturn(false);

assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}

@Test
@@ -196,7 +196,7 @@ public class PushEventFactoryTest {

when(taintChecker.isTaintVulnerability(any())).thenReturn(false);

assertThat(underTest.raiseEventOnIssue(defaultIssue)).isEmpty();
assertThat(underTest.raiseEventOnIssue("some-project-uuid", defaultIssue)).isEmpty();
}

private void buildComponentTree() {
@@ -215,6 +215,7 @@ public class PushEventFactoryTest {
return new DefaultIssue()
.setComponentUuid("issue-component-uuid")
.setType(RuleType.VULNERABILITY)
.setLanguage("java")
.setCreationDate(new Date())
.setLocations(DbIssues.Locations.newBuilder()
.addFlow(DbIssues.Flow.newBuilder()
@@ -230,22 +231,4 @@ public class PushEventFactoryTest {
.setRuleKey(RuleKey.of("javasecurity", "S123"));
}

private static class PushEventMatcher implements ArgumentMatcher<PushEventDto> {

private final PushEventDto left;

static PushEventMatcher eq(PushEventDto left) {
return new PushEventMatcher(left);
}

private PushEventMatcher(PushEventDto left) {
this.left = left;
}

@Override
public boolean matches(PushEventDto right) {
return left.getName().equals(right.getName());
}
}

}

+ 47
- 5
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistPushEventsStepTest.java 查看文件

@@ -31,6 +31,9 @@ import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.System2;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.MutableTreeRootHolderRule;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.sonar.ce.task.projectanalysis.issue.ProtoIssueCache;
import org.sonar.ce.task.projectanalysis.pushevent.PushEventFactory;
import org.sonar.ce.task.step.ComputationStep;
@@ -42,6 +45,8 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@@ -55,14 +60,16 @@ public class PersistPushEventsStepTest {
public final PushEventFactory pushEventFactory = mock(PushEventFactory.class);
@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Rule
public MutableTreeRootHolderRule treeRootHolder = new MutableTreeRootHolderRule();
private ProtoIssueCache protoIssueCache;
private PersistPushEventsStep underTest;

@Before
public void before() throws IOException {
protoIssueCache = new ProtoIssueCache(temp.newFile(), System2.INSTANCE);
underTest = new PersistPushEventsStep(db.getDbClient(), protoIssueCache, pushEventFactory);
buildComponentTree();
underTest = new PersistPushEventsStep(db.getDbClient(), protoIssueCache, pushEventFactory, treeRootHolder);
}

@Test
@@ -83,7 +90,7 @@ public class PersistPushEventsStepTest {
createIssue("key1").setType(RuleType.VULNERABILITY))
.close();

when(pushEventFactory.raiseEventOnIssue(any())).thenThrow(new RuntimeException("I have a bad feelings about this"));
when(pushEventFactory.raiseEventOnIssue(any(), any())).thenThrow(new RuntimeException("I have a bad feelings about this"));

assertThatCode(() -> underTest.execute(mock(ComputationStep.Context.class)))
.doesNotThrowAnyException();
@@ -125,7 +132,30 @@ public class PersistPushEventsStepTest {
.setComponentKey("ck2"))
.close();

when(pushEventFactory.raiseEventOnIssue(any(DefaultIssue.class))).thenReturn(
when(pushEventFactory.raiseEventOnIssue(eq("uuid_1"), any(DefaultIssue.class))).thenReturn(
Optional.of(createPushEvent()),
Optional.of(createPushEvent()));

underTest.execute(mock(ComputationStep.Context.class));

assertThat(db.countSql(db.getSession(), "SELECT count(uuid) FROM push_events")).isEqualTo(2);
}

@Test
public void store_push_events_for_branch() {
var project = db.components().insertPrivateProject();
db.components().insertProjectBranch(project, b -> b.setUuid("uuid_1"));

protoIssueCache.newAppender()
.append(createIssue("key1").setType(RuleType.VULNERABILITY)
.setComponentUuid("cu1")
.setComponentKey("ck1"))
.append(createIssue("key2").setType(RuleType.VULNERABILITY)
.setComponentUuid("cu2")
.setComponentKey("ck2"))
.close();

when(pushEventFactory.raiseEventOnIssue(eq(project.uuid()), any(DefaultIssue.class))).thenReturn(
Optional.of(createPushEvent()),
Optional.of(createPushEvent()));

@@ -144,7 +174,7 @@ public class PersistPushEventsStepTest {
.setComponentUuid("cu" + value)
.setComponentKey("ck" + value);
appender.append(defaultIssue);
when(pushEventFactory.raiseEventOnIssue(defaultIssue)).thenReturn(Optional.of(createPushEvent()));
when(pushEventFactory.raiseEventOnIssue(anyString(), eq(defaultIssue))).thenReturn(Optional.of(createPushEvent()));
});

appender.close();
@@ -169,4 +199,16 @@ public class PersistPushEventsStepTest {
return new PushEventDto().setProjectUuid("project-uuid").setName("event").setPayload("test".getBytes(UTF_8));
}

private void buildComponentTree() {
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1)
.setUuid("uuid_1")
.addChildren(ReportComponent.builder(Component.Type.FILE, 2)
.setUuid("issue-component-uuid")
.build())
.addChildren(ReportComponent.builder(Component.Type.FILE, 3)
.setUuid("location-component-uuid")
.build())
.build());
}

}

Loading…
取消
儲存