-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add language server and report analytics via ls [HEAD-911] (#458)
* feat: integrate language server into jetbrains and prepare report analytics * feat: add oss scan data, clean up a bit * fix: detekt newline finding * fix: erroneous rename * refactor: move report Analytics to AnalyticsScanListener * feat: add tests for language server wrapper * feat: add test for initialization options * feat: add test for event mapping * refactor: remove unused var, introduce listener object * feat: add tests for scanListener * feat: ensure feature doesn't break UX
- Loading branch information
1 parent
6293e59
commit 3bb216f
Showing
11 changed files
with
629 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
src/main/kotlin/io/snyk/plugin/analytics/AnalyticsScanListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package io.snyk.plugin.analytics | ||
|
||
import com.intellij.openapi.components.Service | ||
import com.intellij.openapi.project.Project | ||
import io.snyk.plugin.events.SnykScanListener | ||
import io.snyk.plugin.getSnykTaskQueueService | ||
import io.snyk.plugin.snykcode.SnykCodeResults | ||
import snyk.common.SnykError | ||
import snyk.common.lsp.commands.ScanDoneEvent | ||
import snyk.container.ContainerResult | ||
import snyk.iac.IacResult | ||
import snyk.oss.OssResult | ||
|
||
@Service(Service.Level.PROJECT) | ||
class AnalyticsScanListener(val project: Project) { | ||
fun getScanDoneEvent( | ||
duration: Long, product: String, critical: Int, high: Int, medium: Int, low: Int | ||
): ScanDoneEvent { | ||
return ScanDoneEvent( | ||
ScanDoneEvent.Data( | ||
attributes = ScanDoneEvent.Attributes( | ||
scanType = product, | ||
uniqueIssueCount = ScanDoneEvent.UniqueIssueCount( | ||
critical = critical, | ||
high = high, | ||
medium = medium, | ||
low = low | ||
), | ||
durationMs = "$duration", | ||
) | ||
) | ||
) | ||
} | ||
|
||
val snykScanListener = object : SnykScanListener { | ||
var start: Long = 0 | ||
|
||
override fun scanningStarted() { | ||
start = System.currentTimeMillis() | ||
} | ||
|
||
override fun scanningOssFinished(ossResult: OssResult) { | ||
val scanDoneEvent = getScanDoneEvent( | ||
System.currentTimeMillis() - start, | ||
"Snyk Open Source", | ||
ossResult.criticalSeveritiesCount(), | ||
ossResult.highSeveritiesCount(), | ||
ossResult.mediumSeveritiesCount(), | ||
ossResult.lowSeveritiesCount() | ||
) | ||
getSnykTaskQueueService(project)?.ls?.sendReportAnalyticsCommand(scanDoneEvent) | ||
} | ||
|
||
override fun scanningSnykCodeFinished(snykCodeResults: SnykCodeResults?) { | ||
val duration = System.currentTimeMillis() - start | ||
val product = "Snyk Code" | ||
val scanDoneEvent = if (snykCodeResults != null) { | ||
getScanDoneEvent( | ||
duration, | ||
product, | ||
snykCodeResults.totalCriticalCount, | ||
snykCodeResults.totalErrorsCount, | ||
snykCodeResults.totalWarnsCount, | ||
snykCodeResults.totalInfosCount, | ||
) | ||
} else { | ||
getScanDoneEvent(duration, product, 0, 0, 0, 0) | ||
} | ||
getSnykTaskQueueService(project)?.ls?.sendReportAnalyticsCommand(scanDoneEvent) | ||
} | ||
|
||
override fun scanningIacFinished(iacResult: IacResult) { | ||
val scanDoneEvent = getScanDoneEvent( | ||
System.currentTimeMillis() - start, | ||
"Snyk IaC", | ||
iacResult.criticalSeveritiesCount(), | ||
iacResult.highSeveritiesCount(), | ||
iacResult.mediumSeveritiesCount(), | ||
iacResult.lowSeveritiesCount() | ||
) | ||
getSnykTaskQueueService(project)?.ls?.sendReportAnalyticsCommand(scanDoneEvent) | ||
} | ||
|
||
override fun scanningContainerFinished(containerResult: ContainerResult) { | ||
val scanDoneEvent = getScanDoneEvent( | ||
System.currentTimeMillis() - start, | ||
"Snyk Container", | ||
containerResult.criticalSeveritiesCount(), | ||
containerResult.highSeveritiesCount(), | ||
containerResult.mediumSeveritiesCount(), | ||
containerResult.lowSeveritiesCount() | ||
) | ||
getSnykTaskQueueService(project)?.ls?.sendReportAnalyticsCommand(scanDoneEvent) | ||
} | ||
|
||
override fun scanningOssError(snykError: SnykError) { | ||
// do nothing | ||
} | ||
|
||
override fun scanningIacError(snykError: SnykError) { | ||
// do nothing | ||
} | ||
|
||
override fun scanningSnykCodeError(snykError: SnykError) { | ||
// do nothing | ||
} | ||
|
||
override fun scanningContainerError(snykError: SnykError) { | ||
// do nothing | ||
} | ||
} | ||
|
||
fun initScanListener() = project.messageBus.connect().subscribe( | ||
SnykScanListener.SNYK_SCAN_TOPIC, | ||
snykScanListener, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
@file:Suppress("unused") | ||
|
||
package snyk.common.lsp | ||
|
||
import com.google.gson.annotations.SerializedName | ||
import io.snyk.plugin.pluginSettings | ||
import org.apache.commons.lang.SystemUtils | ||
import snyk.pluginInfo | ||
|
||
data class LanguageServerSettings( | ||
@SerializedName("activateSnykOpenSource") val activateSnykOpenSource: String? = "false", | ||
@SerializedName("activateSnykCode") val activateSnykCode: String? = "false", | ||
@SerializedName("activateSnykIac") val activateSnykIac: String? = "false", | ||
@SerializedName("insecure") val insecure: String?, | ||
@SerializedName("endpoint") val endpoint: String?, | ||
@SerializedName("additionalParams") val additionalParams: String? = null, | ||
@SerializedName("additionalEnv") val additionalEnv: String? = null, | ||
@SerializedName("path") val path: String? = null, | ||
@SerializedName("sendErrorReports") val sendErrorReports: String? = "false", | ||
@SerializedName("organization") val organization: String? = null, | ||
@SerializedName("enableTelemetry") val enableTelemetry: String? = "false", | ||
@SerializedName("manageBinariesAutomatically") val manageBinariesAutomatically: String? = "false", | ||
@SerializedName("cliPath") val cliPath: String?, | ||
@SerializedName("token") val token: String?, | ||
@SerializedName("integrationName") val integrationName: String? = pluginInfo.integrationName, | ||
@SerializedName("integrationVersion") val integrationVersion: String? = pluginInfo.integrationVersion, | ||
@SerializedName("automaticAuthentication") val automaticAuthentication: String? = "false", | ||
@SerializedName("deviceId") val deviceId: String? = pluginSettings().userAnonymousId, | ||
@SerializedName("filterSeverity") val filterSeverity: SeverityFilter? = null, | ||
@SerializedName("enableTrustedFoldersFeature") val enableTrustedFoldersFeature: String? = "false", | ||
@SerializedName("trustedFolders") val trustedFolders: List<String>? = emptyList(), | ||
@SerializedName("activateSnykCodeSecurity") val activateSnykCodeSecurity: String? = "false", | ||
@SerializedName("activateSnykCodeQuality") val activateSnykCodeQuality: String? = "false", | ||
@SerializedName("osPlatform") val osPlatform: String? = SystemUtils.OS_NAME, | ||
@SerializedName("osArch") val osArch: String? = SystemUtils.OS_ARCH, | ||
@SerializedName("runtimeVersion") val runtimeVersion: String? = SystemUtils.JAVA_VERSION, | ||
@SerializedName("runtimeName") val runtimeName: String? = SystemUtils.JAVA_RUNTIME_NAME, | ||
@SerializedName("scanningMode") val scanningMode: String? = null, | ||
@SerializedName("authenticationMethod") val authenticationMethod: AuthenticationMethod? = null, | ||
@SerializedName("snykCodeApi") val snykCodeApi: String? = null, | ||
@SerializedName("enableSnykLearnCodeActions") val enableSnykLearnCodeActions: String? = null, | ||
@SerializedName("enableAnalytics") val enableAnalytics: Boolean = false // TODO: enable when service ready | ||
) | ||
|
||
data class SeverityFilter( | ||
@SerializedName("critical") val critical: Boolean?, | ||
@SerializedName("high") val high: Boolean?, | ||
@SerializedName("medium") val medium: Boolean?, | ||
@SerializedName("low") val low: Boolean? | ||
) | ||
|
||
enum class AuthenticationMethod { | ||
@SerializedName("token") | ||
TokenAuthentication, | ||
|
||
@SerializedName("oauth") | ||
OAuthAuthentication | ||
} |
Oops, something went wrong.