Skip to content

Commit

Permalink
feat: make progresses cancelable, cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
bastiandoetsch committed Sep 30, 2024
1 parent 92feb30 commit 6fd424c
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 163 deletions.
14 changes: 2 additions & 12 deletions src/main/kotlin/io/snyk/plugin/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ fun isUrlValid(url: String?): Boolean {
}

fun isOssRunning(project: Project): Boolean {
return isProductScanRunning(project, ProductType.OSS, getSnykTaskQueueService(project)?.ossScanProgressIndicator)
return isProductScanRunning(project, ProductType.OSS)
}

private fun isProductScanRunning(project: Project, productType: ProductType): Boolean {
Expand All @@ -178,16 +178,6 @@ private fun isProductScanRunning(
(progressIndicator != null && progressIndicator.isRunning && !progressIndicator.isCanceled)
}

fun cancelOssIndicator(project: Project) {
val indicator = getSnykTaskQueueService(project)?.ossScanProgressIndicator
indicator?.cancel()
}

fun cancelIacIndicator(project: Project) {
val indicator = getSnykTaskQueueService(project)?.iacScanProgressIndicator
indicator?.cancel()
}

fun isSnykCodeRunning(project: Project): Boolean {
return isProductScanRunning(project, ProductType.CODE_SECURITY) || isProductScanRunning(
project,
Expand All @@ -196,7 +186,7 @@ fun isSnykCodeRunning(project: Project): Boolean {
}

fun isIacRunning(project: Project): Boolean {
return isProductScanRunning(project, ProductType.IAC, getSnykTaskQueueService(project)?.iacScanProgressIndicator)
return isProductScanRunning(project, ProductType.IAC)
}

fun isContainerRunning(project: Project): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,5 @@ interface SnykTaskQueueListener {
Topic.create("Snyk Task Queue", SnykTaskQueueListener::class.java)
}

fun stopped(
wasOssRunning: Boolean = false,
wasSnykCodeRunning: Boolean = false,
wasIacRunning: Boolean = false,
wasContainerRunning: Boolean = false
)
fun stopped()
}
73 changes: 5 additions & 68 deletions src/main/kotlin/io/snyk/plugin/services/SnykTaskQueueService.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.snyk.plugin.services

import ai.grazie.nlp.langs.Language
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.logger
Expand All @@ -9,38 +8,29 @@ import com.intellij.openapi.progress.BackgroundTaskQueue
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import io.snyk.plugin.cancelOssIndicator
import io.snyk.plugin.events.SnykCliDownloadListener
import io.snyk.plugin.events.SnykScanListener
import io.snyk.plugin.events.SnykSettingsListener
import io.snyk.plugin.events.SnykTaskQueueListener
import io.snyk.plugin.getContainerService
import io.snyk.plugin.getIacService
import io.snyk.plugin.getSnykCachedResults
import io.snyk.plugin.getSnykCliDownloaderService
import io.snyk.plugin.getSnykToolWindowPanel
import io.snyk.plugin.getSyncPublisher
import io.snyk.plugin.isCliDownloading
import io.snyk.plugin.isCliInstalled
import io.snyk.plugin.isContainerRunning
import io.snyk.plugin.isIacRunning
import io.snyk.plugin.isOssRunning
import io.snyk.plugin.isSnykCodeRunning
import io.snyk.plugin.pluginSettings
import io.snyk.plugin.refreshAnnotationsForOpenFiles
import io.snyk.plugin.ui.SnykBalloonNotificationHelper
import org.jetbrains.annotations.TestOnly
import snyk.common.SnykError
import snyk.common.lsp.LanguageServerWrapper
import snyk.common.lsp.SnykLanguageClient
import snyk.common.lsp.progress.ProgressManager
import snyk.common.lsp.ScanState
import snyk.trust.confirmScanningAndSetWorkspaceTrustedStateIfNeeded

@Service(Service.Level.PROJECT)
class SnykTaskQueueService(val project: Project) {
private val logger = logger<SnykTaskQueueService>()
private val taskQueue = BackgroundTaskQueue(project, "Snyk")
private val taskQueueIac = BackgroundTaskQueue(project, "Snyk: Iac")
private val taskQueueContainer = BackgroundTaskQueue(project, "Snyk: Container")

private val settings
Expand All @@ -55,12 +45,6 @@ class SnykTaskQueueService(val project: Project) {
private val taskQueuePublisher
get() = getSyncPublisher(project, SnykTaskQueueListener.TASK_QUEUE_TOPIC)

var ossScanProgressIndicator: ProgressIndicator? = null
private set

var iacScanProgressIndicator: ProgressIndicator? = null
private set

var containerScanProgressIndicator: ProgressIndicator? = null
private set

Expand Down Expand Up @@ -94,7 +78,7 @@ class SnykTaskQueueService(val project: Project) {
}

fun scan() {
taskQueue.run(object : Task.Backgroundable(project, "Snyk: initializing...", true) {
taskQueue.run(object : Task.Backgroundable(project, "Snyk: triggering scan", true) {
override fun run(indicator: ProgressIndicator) {
if (!confirmScanningAndSetWorkspaceTrustedStateIfNeeded(project)) return

Expand Down Expand Up @@ -141,7 +125,7 @@ class SnykTaskQueueService(val project: Project) {

if (indicator.isCanceled) {
logger.debug("cancel container scan")
taskQueuePublisher?.stopped(wasContainerRunning = true)
taskQueuePublisher?.stopped()
} else {
if (containerResult.isSuccessful()) {
logger.debug("Container result: ->")
Expand All @@ -159,49 +143,6 @@ class SnykTaskQueueService(val project: Project) {
})
}

private fun scheduleIacScan() {
taskQueueIac.run(object : Task.Backgroundable(project, "Snyk Infrastructure as Code is scanning", true) {
override fun run(indicator: ProgressIndicator) {
if (!isCliInstalled()) return
val snykCachedResults = getSnykCachedResults(project) ?: return
if (snykCachedResults.currentIacResult?.iacScanNeeded == false) return
logger.debug("Starting IaC scan")
iacScanProgressIndicator = indicator
scanPublisher?.scanningStarted()

snykCachedResults.currentIacResult = null
val iacResult = try {
getIacService(project)?.scan()
} finally {
iacScanProgressIndicator = null
}
if (iacResult == null || project.isDisposed) return

if (indicator.isCanceled) {
logger.debug("cancel IaC scan")
taskQueuePublisher?.stopped(wasIacRunning = true)
} else {
if (iacResult.isSuccessful()) {
logger.debug("IaC result: ->")
iacResult.allCliIssues?.forEach {
logger.debug(" ${it.targetFile}, ${it.infrastructureAsCodeIssues.size} issues")
}
scanPublisher?.scanningIacFinished(iacResult)
} else {
val error = iacResult.getFirstError()
if (error == null) {
SnykError("unknown IaC error", project.basePath ?: "")
} else {
scanPublisher?.scanningIacError(error)
}
}
}
logger.debug("IaC scan completed")
refreshAnnotationsForOpenFiles(project)
}
})
}

fun downloadLatestRelease(force: Boolean = false) {
// abort even before submitting a task
if (project.isDisposed || ApplicationManager.getApplication().isDisposed) return
Expand Down Expand Up @@ -236,18 +177,14 @@ class SnykTaskQueueService(val project: Project) {

fun stopScan() {
val languageServerWrapper = LanguageServerWrapper.getInstance()
val wasOssRunning = isOssRunning(project)
val wasSnykCodeRunning = isSnykCodeRunning(project)
val wasIacRunning = isIacRunning(project)

if (languageServerWrapper.isInitialized) {
languageServerWrapper.languageClient.progressManager.cancelProgresses()
ScanState.scanInProgress.clear()
}

val wasContainerRunning = containerScanProgressIndicator?.isRunning == true
containerScanProgressIndicator?.cancel()

taskQueuePublisher?.stopped(wasOssRunning, wasSnykCodeRunning, wasIacRunning, wasContainerRunning)
taskQueuePublisher?.stopped()
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,7 @@ class SnykToolWindow(private val project: Project) : SimpleToolWindowPanel(false

project.messageBus.connect(this)
.subscribe(SnykTaskQueueListener.TASK_QUEUE_TOPIC, object : SnykTaskQueueListener {
override fun stopped(
wasOssRunning: Boolean,
wasSnykCodeRunning: Boolean,
wasIacRunning: Boolean,
wasContainerRunning: Boolean
) = updateActionsPresentation()
override fun stopped() = updateActionsPresentation()
})
}

Expand Down
33 changes: 20 additions & 13 deletions src/main/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,16 @@ class SnykToolWindowPanel(
SnykResultsFilteringListener.SNYK_FILTERING_TOPIC,
object : SnykResultsFilteringListener {
override fun filtersChanged() {
val codeResultsLS =
val codeSecurityResultsLS =
getSnykCachedResultsForProduct(project, ProductType.CODE_SECURITY) ?: return
ApplicationManager.getApplication().invokeLater {
scanListenerLS.displaySnykCodeResults(codeResultsLS)
scanListenerLS.displaySnykCodeResults(codeSecurityResultsLS)
}

val codeQualityResultsLS =
getSnykCachedResultsForProduct(project, ProductType.CODE_QUALITY) ?: return
ApplicationManager.getApplication().invokeLater {
scanListenerLS.displaySnykCodeResults(codeQualityResultsLS)
}

val ossResultsLS =
Expand All @@ -281,6 +287,12 @@ class SnykToolWindowPanel(
scanListenerLS.displayOssResults(ossResultsLS)
}

val iacResultsLS =
getSnykCachedResultsForProduct(project, ProductType.IAC) ?: return
ApplicationManager.getApplication().invokeLater {
scanListenerLS.displayIacResults(iacResultsLS)
}

val snykCachedResults = getSnykCachedResults(project) ?: return
ApplicationManager.getApplication().invokeLater {
snykCachedResults.currentIacResult?.let { displayIacResults(it) }
Expand Down Expand Up @@ -324,18 +336,13 @@ class SnykToolWindowPanel(
.subscribe(
SnykTaskQueueListener.TASK_QUEUE_TOPIC,
object : SnykTaskQueueListener {
override fun stopped(
wasOssRunning: Boolean,
wasSnykCodeRunning: Boolean,
wasIacRunning: Boolean,
wasContainerRunning: Boolean,
) = ApplicationManager.getApplication().invokeLater {
override fun stopped() = ApplicationManager.getApplication().invokeLater {
updateTreeRootNodesPresentation(
ossResultsCount = if (wasOssRunning) NODE_INITIAL_STATE else null,
securityIssuesCount = if (wasSnykCodeRunning) NODE_INITIAL_STATE else null,
qualityIssuesCount = if (wasSnykCodeRunning) NODE_INITIAL_STATE else null,
iacResultsCount = if (wasIacRunning) NODE_INITIAL_STATE else null,
containerResultsCount = if (wasContainerRunning) NODE_INITIAL_STATE else null,
ossResultsCount = NODE_INITIAL_STATE,
securityIssuesCount = NODE_INITIAL_STATE,
qualityIssuesCount = NODE_INITIAL_STATE,
iacResultsCount = NODE_INITIAL_STATE,
containerResultsCount = NODE_INITIAL_STATE,
)
displayEmptyDescription()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.ui.tree.TreeUtil
import io.snyk.plugin.Severity
import io.snyk.plugin.SnykFile
import io.snyk.plugin.cancelIacIndicator
import io.snyk.plugin.cancelOssIndicator
import io.snyk.plugin.events.SnykScanListenerLS
import io.snyk.plugin.getSnykCachedResults
import io.snyk.plugin.pluginSettings
Expand Down Expand Up @@ -84,7 +82,6 @@ class SnykToolWindowSnykScanListenerLS(

override fun scanningOssFinished() {
if (disposed) return
cancelOssIndicator(project)
ApplicationManager.getApplication().invokeLater {
this.rootOssIssuesTreeNode.userObject = "$OSS_ROOT_TEXT (scanning finished)"
this.snykToolWindowPanel.triggerSelectionListeners = false
Expand All @@ -97,7 +94,6 @@ class SnykToolWindowSnykScanListenerLS(

override fun scanningIacFinished() {
if (disposed) return
cancelIacIndicator(project)
ApplicationManager.getApplication().invokeLater {
this.rootIacIssuesTreeNode.userObject = "$IAC_ROOT_TEXT (scanning finished)"
this.snykToolWindowPanel.triggerSelectionListeners = false
Expand Down Expand Up @@ -173,36 +169,35 @@ class SnykToolWindowSnykScanListenerLS(
)
}

fun displayOssResults(snykResults: Map<SnykFile, List<ScanIssue>>) {
private fun displayResults(snykResults: Map<SnykFile, List<ScanIssue>>, enabledInSettings: Boolean, filterTree: Boolean, rootNode: DefaultMutableTreeNode) {
if (disposed) return
if (getSnykCachedResults(project)?.currentOssError != null) return

val settings = pluginSettings()
if (getSnykCachedResults(project)?.currentIacError != null) return

displayIssues(
enabledInSettings = settings.ossScanEnable,
filterTree = settings.treeFiltering.ossResults,
enabledInSettings = enabledInSettings,
filterTree = filterTree,
snykResults = snykResults,
rootNode = this.rootOssIssuesTreeNode,
ossResultsCount = snykResults.values.flatten().distinct().size,
rootNode = rootNode,
iacResultsCount = snykResults.values.flatten().distinct().size,
fixableIssuesCount = snykResults.values.flatten().count { it.additionalData.isUpgradable }
)
}

fun displayOssResults(snykResults: Map<SnykFile, List<ScanIssue>>) {
if (disposed) return
if (getSnykCachedResults(project)?.currentOssError != null) return

val settings = pluginSettings()

displayResults(snykResults, settings.ossScanEnable, settings.treeFiltering.ossResults, this.rootOssIssuesTreeNode)
}

fun displayIacResults(snykResults: Map<SnykFile, List<ScanIssue>>) {
if (disposed) return
if (getSnykCachedResults(project)?.currentIacError != null) return

val settings = pluginSettings()

displayIssues(
enabledInSettings = settings.iacScanEnabled,
filterTree = settings.treeFiltering.iacResults,
snykResults = snykResults,
rootNode = this.rootIacIssuesTreeNode,
iacResultsCount = snykResults.values.flatten().distinct().size,
fixableIssuesCount = snykResults.values.flatten().count { it.additionalData.isUpgradable }
)
displayResults(snykResults, settings.iacScanEnabled, settings.treeFiltering.iacResults, this.rootIacIssuesTreeNode)
}

private fun displayIssues(
Expand Down
Loading

0 comments on commit 6fd424c

Please sign in to comment.