Skip to content

Commit 748ef2c

Browse files
SLCORE-1526 allow clients to record dependency risk interaction telemetry
1 parent 4b5a95c commit 748ef2c

File tree

12 files changed

+136
-26
lines changed

12 files changed

+136
-26
lines changed

API_CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
* Allow changing status of SCA issues via `org.sonarsource.sonarlint.core.rpc.protocol.backend.sca.ScaRpcService.changeStatus`.
66
* Required parameters are `configScopeId`, `issueId` and `transition`.
77
* If transition is `ACCEPT`, `FIXED`, or `SAFE`, a `comment` field is mandatory
8+
* Allow clients to open dependency risk (SCA issues) in browser
9+
* Introduce `org.sonarsource.sonarlint.core.rpc.protocol.backend.sca.ScaRpcService.openDependencyRiskInBrowser` that accepts `configScopeId` and `dependencyRiskKey` (UUID) parameters
10+
* Allow clients to record interactions with dependency risks (SCA issues) in telemetry
11+
* Introduce `org.sonarsource.sonarlint.core.rpc.protocol.backend.telemetry.TelemetryRpcService.dependencyRiskInvestigatedLocally` method
12+
* Introduce `org.sonarsource.sonarlint.core.rpc.protocol.backend.telemetry.TelemetryRpcService.dependencyRiskInvestigatedRemotely` method
813
* Add a new `org.sonarsource.sonarlint.core.rpc.protocol.backend.sca.ScaRpcService.getDependencyRiskDetails`.
914

1015
# 10.26

backend/core/src/main/java/org/sonarsource/sonarlint/core/sca/ScaService.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,8 @@ public class ScaService {
5555
private final SonarLintRpcClient client;
5656
private final TelemetryService telemetryService;
5757

58-
public ScaService(ConfigurationRepository configurationRepository, ConnectionConfigurationRepository connectionRepository,
59-
StorageService storageService, SonarQubeClientManager sonarQubeClientManager,
60-
SonarProjectBranchTrackingService branchTrackingService, SonarLintRpcClient client, TelemetryService telemetryService) {
58+
public ScaService(ConfigurationRepository configurationRepository, ConnectionConfigurationRepository connectionRepository, StorageService storageService,
59+
SonarQubeClientManager sonarQubeClientManager, SonarProjectBranchTrackingService branchTrackingService, SonarLintRpcClient client, TelemetryService telemetryService) {
6160
this.configurationRepository = configurationRepository;
6261
this.connectionRepository = connectionRepository;
6362
this.storageService = storageService;
@@ -170,17 +169,17 @@ public void openDependencyRiskInBrowser(String configurationScopeId, String depe
170169

171170
client.openUrlInBrowser(new OpenUrlInBrowserParams(url));
172171

173-
// TODO: Add SCA-specific telemetry method when available
174-
// telemetryService.dependencyRiskOpenedInBrowser();
172+
telemetryService.dependencyRiskInvestigatedRemotely();
175173
}
176174

177-
static String buildScaBrowseUrl(String projectKey, String branch, String dependencyKey, EndpointParams endpointParams) {
178-
var relativePath = "/dependency-risks/"
179-
+ UrlUtils.urlEncode(dependencyKey)
180-
+ "/what?id="
181-
+ UrlUtils.urlEncode(projectKey)
182-
+ "&branch="
183-
+ UrlUtils.urlEncode(branch);
175+
static String buildScaBrowseUrl(String projectKey, String branch, UUID dependencyKey, EndpointParams endpointParams) {
176+
var relativePath = new StringBuilder("/dependency-risks/")
177+
.append(UrlUtils.urlEncode(dependencyKey.toString()))
178+
.append("/what?id=")
179+
.append(UrlUtils.urlEncode(projectKey))
180+
.append("&branch=")
181+
.append(UrlUtils.urlEncode(branch))
182+
.toString();
184183

185184
return ServerApiHelper.concat(endpointParams.getBaseUrl(), relativePath);
186185
}

backend/core/src/main/java/org/sonarsource/sonarlint/core/telemetry/TelemetryService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,14 @@ public void issueInvestigatedLocally() {
258258
updateTelemetry(TelemetryLocalStorage::incrementIssueInvestigatedLocallyCount);
259259
}
260260

261+
public void dependencyRiskInvestigatedRemotely() {
262+
updateTelemetry(TelemetryLocalStorage::incrementDependencyRiskInvestigatedRemotelyCount);
263+
}
264+
265+
public void dependencyRiskInvestigatedLocally() {
266+
updateTelemetry(TelemetryLocalStorage::incrementDependencyRiskInvestigatedLocallyCount);
267+
}
268+
261269
public void findingsFiltered(String filterType) {
262270
updateTelemetry(localStorage -> localStorage.findingsFiltered(filterType));
263271
}

backend/core/src/test/java/org/sonarsource/sonarlint/core/sca/ScaServiceTests.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package org.sonarsource.sonarlint.core.sca;
2121

22+
import java.util.UUID;
2223
import org.junit.jupiter.api.Test;
2324
import org.sonarsource.sonarlint.core.serverapi.EndpointParams;
2425

@@ -28,8 +29,8 @@ class ScaServiceTests {
2829

2930
@Test
3031
void testBuildSonarQubeServerScaUrl() {
31-
assertThat(ScaService.buildScaBrowseUrl("myProject", "myBranch", "dependencyKey", new EndpointParams("http://foo.com", "", false, null)))
32-
.isEqualTo("http://foo.com/dependency-risks/dependencyKey/what?id=myProject&branch=myBranch");
32+
var dependencyKey = UUID.randomUUID();
33+
assertThat(ScaService.buildScaBrowseUrl("myProject", "myBranch", dependencyKey, new EndpointParams("http://foo.com", "", false, null)))
34+
.isEqualTo(String.format("http://foo.com/dependency-risks/%s/what?id=myProject&branch=myBranch", dependencyKey));
3335
}
34-
35-
}
36+
}

backend/rpc-impl/src/main/java/org/sonarsource/sonarlint/core/rpc/impl/TelemetryRpcServiceDelegate.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,16 @@ public void issueInvestigatedLocally() {
149149
notify(() -> getBean(TelemetryService.class).issueInvestigatedLocally());
150150
}
151151

152+
@Override
153+
public void dependencyRiskInvestigatedLocally() {
154+
notify(() -> getBean(TelemetryService.class).dependencyRiskInvestigatedLocally());
155+
}
156+
157+
@Override
158+
public void dependencyRiskInvestigatedRemotely() {
159+
notify(() -> getBean(TelemetryService.class).dependencyRiskInvestigatedRemotely());
160+
}
161+
152162
@Override
153163
public void findingsFiltered(FindingsFilteredParams params) {
154164
notify(() -> getBean(TelemetryService.class).findingsFiltered(params.getFilterType()));

backend/telemetry/src/main/java/org/sonarsource/sonarlint/core/telemetry/TelemetryLocalStorage.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public class TelemetryLocalStorage {
8585
private int hotspotInvestigatedLocallyCount;
8686
private int hotspotInvestigatedRemotelyCount;
8787
private int issueInvestigatedLocallyCount;
88+
private int dependencyRiskInvestigatedRemotelyCount;
89+
private int dependencyRiskInvestigatedLocallyCount;
8890

8991
TelemetryLocalStorage() {
9092
enabled = true;
@@ -240,6 +242,8 @@ void clearAfterPing() {
240242
issuesFixedCount = 0;
241243
biggestNumberOfFilesInConfigScope = 0;
242244
calledToolsByName.clear();
245+
dependencyRiskInvestigatedLocallyCount = 0;
246+
dependencyRiskInvestigatedRemotelyCount = 0;
243247
}
244248

245249
public long numUseDays() {
@@ -563,6 +567,16 @@ public void incrementIssueInvestigatedLocallyCount() {
563567
issueInvestigatedLocallyCount++;
564568
}
565569

570+
public void incrementDependencyRiskInvestigatedRemotelyCount() {
571+
markSonarLintAsUsedToday();
572+
dependencyRiskInvestigatedRemotelyCount++;
573+
}
574+
575+
public void incrementDependencyRiskInvestigatedLocallyCount() {
576+
markSonarLintAsUsedToday();
577+
dependencyRiskInvestigatedLocallyCount++;
578+
}
579+
566580
public int getHotspotInvestigatedRemotelyCount() {
567581
return hotspotInvestigatedRemotelyCount;
568582
}
@@ -582,4 +596,12 @@ public int getTaintInvestigatedLocallyCount() {
582596
public int getIssueInvestigatedLocallyCount() {
583597
return issueInvestigatedLocallyCount;
584598
}
599+
600+
public int getDependencyRiskInvestigatedRemotelyCount() {
601+
return dependencyRiskInvestigatedRemotelyCount;
602+
}
603+
604+
public int getDependencyRiskInvestigatedLocallyCount() {
605+
return dependencyRiskInvestigatedLocallyCount;
606+
}
585607
}

backend/telemetry/src/main/java/org/sonarsource/sonarlint/core/telemetry/measures/payload/TelemetryMeasuresBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ private void addFindingInvestigationMeasures(ArrayList<TelemetryMeasuresValue> v
8080
values.add(new TelemetryMeasuresValue("findings_investigation.hotspots_locally", String.valueOf(storage.getHotspotInvestigatedLocallyCount()), INTEGER, DAILY));
8181
values.add(new TelemetryMeasuresValue("findings_investigation.hotspots_remotely", String.valueOf(storage.getHotspotInvestigatedRemotelyCount()), INTEGER, DAILY));
8282
values.add(new TelemetryMeasuresValue("findings_investigation.issues_locally", String.valueOf(storage.getIssueInvestigatedLocallyCount()), INTEGER, DAILY));
83+
values.add(new TelemetryMeasuresValue("findings_investigation.dependency_risks_locally", String.valueOf(storage.getDependencyRiskInvestigatedLocallyCount()), INTEGER, DAILY));
84+
values.add(new TelemetryMeasuresValue("findings_investigation.dependency_risks_remotely",
85+
String.valueOf(storage.getDependencyRiskInvestigatedRemotelyCount()), INTEGER, DAILY));
8386
}
8487

8588
private void addConnectedModeMeasures(ArrayList<TelemetryMeasuresValue> values) {

backend/telemetry/src/test/java/org/sonarsource/sonarlint/core/telemetry/TelemetryLocalStorageTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,35 @@ void should_clear_findings_filtered_counters() {
250250
data.clearAfterPing();
251251
assertThat(data.getFindingsFilteredCountersByType()).isEmpty();
252252
}
253+
254+
@Test
255+
void should_track_dependency_risk_investigated() {
256+
var data = new TelemetryLocalStorage();
257+
assertThat(data.getDependencyRiskInvestigatedRemotelyCount()).isZero();
258+
assertThat(data.getDependencyRiskInvestigatedLocallyCount()).isZero();
259+
260+
data.incrementDependencyRiskInvestigatedRemotelyCount();
261+
data.incrementDependencyRiskInvestigatedLocallyCount();
262+
assertThat(data.getDependencyRiskInvestigatedRemotelyCount()).isEqualTo(1);
263+
assertThat(data.getDependencyRiskInvestigatedLocallyCount()).isEqualTo(1);
264+
265+
data.incrementDependencyRiskInvestigatedRemotelyCount();
266+
data.incrementDependencyRiskInvestigatedLocallyCount();
267+
assertThat(data.getDependencyRiskInvestigatedRemotelyCount()).isEqualTo(2);
268+
assertThat(data.getDependencyRiskInvestigatedLocallyCount()).isEqualTo(2);
269+
}
270+
271+
@Test
272+
void should_clear_dependency_risk_investigated_counts_after_ping() {
273+
var data = new TelemetryLocalStorage();
274+
275+
data.incrementDependencyRiskInvestigatedRemotelyCount();
276+
data.incrementDependencyRiskInvestigatedLocallyCount();
277+
assertThat(data.getDependencyRiskInvestigatedRemotelyCount()).isEqualTo(1);
278+
assertThat(data.getDependencyRiskInvestigatedLocallyCount()).isEqualTo(1);
279+
280+
data.clearAfterPing();
281+
assertThat(data.getDependencyRiskInvestigatedRemotelyCount()).isZero();
282+
assertThat(data.getDependencyRiskInvestigatedLocallyCount()).isZero();
283+
}
253284
}

medium-tests/src/test/java/mediumtest/TelemetryMediumTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,26 @@ void it_should_accumulate_investigated_taint_vulnerabilities(SonarLintTestHarnes
338338
.containsExactly(3, 2));
339339
}
340340

341+
@SonarLintTest
342+
void it_should_accumulate_investigated_dependency_risks(SonarLintTestHarness harness) {
343+
var backend = setupClientAndBackend(harness);
344+
345+
backend.getTelemetryService().dependencyRiskInvestigatedRemotely();
346+
backend.getTelemetryService().dependencyRiskInvestigatedLocally();
347+
348+
await().untilAsserted(() -> assertThat(backend.telemetryFileContent())
349+
.extracting(TelemetryLocalStorage::getDependencyRiskInvestigatedRemotelyCount, TelemetryLocalStorage::getDependencyRiskInvestigatedLocallyCount)
350+
.containsExactly(1, 1));
351+
352+
backend.getTelemetryService().dependencyRiskInvestigatedRemotely();
353+
backend.getTelemetryService().dependencyRiskInvestigatedLocally();
354+
backend.getTelemetryService().dependencyRiskInvestigatedLocally();
355+
356+
await().untilAsserted(() -> assertThat(backend.telemetryFileContent())
357+
.extracting(TelemetryLocalStorage::getDependencyRiskInvestigatedRemotelyCount, TelemetryLocalStorage::getDependencyRiskInvestigatedLocallyCount)
358+
.containsExactly(2, 3));
359+
}
360+
341361
@SonarLintTest
342362
void it_should_accumulate_clicked_dev_notifications(SonarLintTestHarness harness) {
343363
var backend = setupClientAndBackend(harness);

medium-tests/src/test/java/mediumtest/sca/OpenDependencyRiskInBrowserMediumTests.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,19 @@
2626
import org.sonarsource.sonarlint.core.test.utils.junit5.SonarLintTest;
2727
import org.sonarsource.sonarlint.core.test.utils.junit5.SonarLintTestHarness;
2828

29+
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.awaitility.Awaitility.await;
2931
import static org.mockito.ArgumentMatchers.any;
3032
import static org.mockito.Mockito.timeout;
3133
import static org.mockito.Mockito.verify;
3234
import static org.sonarsource.sonarlint.core.serverapi.UrlUtils.urlEncode;
3335

3436
class OpenDependencyRiskInBrowserMediumTests {
35-
public static final String CONNECTION_ID = "connectionId";
36-
public static final String SCOPE_ID = "scopeId";
37-
public static final String PROJECT_KEY = "projectKey";
38-
public static final String DEPENDENCY_KEY = UUID.randomUUID().toString();
39-
public static final String BRANCH_NAME = "master";
37+
static final String CONNECTION_ID = "connectionId";
38+
static final String SCOPE_ID = "scopeId";
39+
static final String PROJECT_KEY = "projectKey";
40+
static final UUID DEPENDENCY_KEY = UUID.randomUUID();
41+
static final String BRANCH_NAME = "master";
4042

4143
@SonarLintTest
4244
void it_should_open_dependency_risk_in_sonarqube(SonarLintTestHarness harness) throws IOException {
@@ -51,9 +53,10 @@ void it_should_open_dependency_risk_in_sonarqube(SonarLintTestHarness harness) t
5153
SCOPE_ID, DEPENDENCY_KEY));
5254

5355
var expectedUrl = String.format("http://localhost:12345/dependency-risks/%s/what?id=%s&branch=%s",
54-
urlEncode(DEPENDENCY_KEY), urlEncode(PROJECT_KEY), urlEncode(BRANCH_NAME));
56+
urlEncode(DEPENDENCY_KEY.toString()), urlEncode(PROJECT_KEY), urlEncode(BRANCH_NAME));
5557

5658
verify(fakeClient, timeout(5000)).openUrlInBrowser(new URL(expectedUrl));
59+
await().untilAsserted(() -> assertThat(backend.telemetryFileContent().getDependencyRiskInvestigatedRemotelyCount()).isEqualTo(1));
5760
}
5861

5962
@SonarLintTest
@@ -68,4 +71,4 @@ void it_should_not_open_dependency_risk_if_unbound(SonarLintTestHarness harness)
6871

6972
verify(fakeClient, timeout(5000).times(0)).openUrlInBrowser(any(URL.class));
7073
}
71-
}
74+
}

0 commit comments

Comments
 (0)