Skip to content

Commit 94e374f

Browse files
committed
feat: migrate to PresentableError
1 parent 605814b commit 94e374f

File tree

9 files changed

+124
-56
lines changed

9 files changed

+124
-56
lines changed

src/main/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanel.kt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,10 @@ class SnykToolWindowPanel(
541541
iacResultsCount: Int?,
542542
addHMLPostfix: String
543543
) = when {
544-
getSnykCachedResults(project)?.currentIacError != null -> "$IAC_ROOT_TEXT (error)"
544+
getSnykCachedResults(project)?.currentIacError != null -> {
545+
val errorSuffix = getSnykCachedResults(project)!!.currentSnykCodeError!!.treeNodeSuffix
546+
"$IAC_ROOT_TEXT $errorSuffix"
547+
}
545548
isIacRunning(project) && settings.iacScanEnabled -> "$IAC_ROOT_TEXT (scanning...)"
546549
else ->
547550
iacResultsCount?.let { count ->
@@ -551,7 +554,7 @@ class SnykToolWindowPanel(
551554
count == 0 -> NO_ISSUES_FOUND_TEXT
552555
count > 0 -> ProductType.IAC.getCountText(count, isUniqueCount = true) + addHMLPostfix
553556
count == NODE_NOT_SUPPORTED_STATE -> NO_SUPPORTED_IAC_FILES_FOUND
554-
else -> throw IllegalStateException("ResultsCount is meaningful")
557+
else -> throw IllegalStateException("ResultsCount is not meaningful")
555558
}
556559
}
557560
}
@@ -562,11 +565,7 @@ class SnykToolWindowPanel(
562565
addHMLPostfix: String
563566
) = when {
564567
getSnykCachedResults(project)?.currentSnykCodeError != null -> {
565-
val errorMessage = getSnykCachedResults(project)?.currentSnykCodeError?.message
566-
val errorSuffix = when {
567-
errorMessage?.contains("not enabled", ignoreCase = true) == true -> "(disabled at Snyk)"
568-
else -> "(error)"
569-
}
568+
val errorSuffix = getSnykCachedResults(project)!!.currentSnykCodeError!!.treeNodeSuffix
570569
"$CODE_SECURITY_ROOT_TEXT $errorSuffix"
571570
}
572571
isSnykCodeRunning(project) &&
@@ -579,7 +578,7 @@ class SnykToolWindowPanel(
579578
count == NODE_INITIAL_STATE -> ""
580579
count == 0 -> NO_ISSUES_FOUND_TEXT
581580
count > 0 -> ProductType.CODE_SECURITY.getCountText(count) + addHMLPostfix
582-
else -> throw IllegalStateException("ResultsCount is meaningful")
581+
else -> throw IllegalStateException("ResultsCount is not meaningful")
583582
}
584583
}
585584
}
@@ -591,7 +590,10 @@ class SnykToolWindowPanel(
591590
addHMLPostfix: String
592591
) = when {
593592
isOssRunning(project) && settings.ossScanEnable -> "$OSS_ROOT_TEXT (scanning...)"
594-
realError -> "$OSS_ROOT_TEXT (error)"
593+
realError -> {
594+
val errorSuffix = getSnykCachedResults(project)!!.currentSnykCodeError!!.treeNodeSuffix
595+
"$OSS_ROOT_TEXT $errorSuffix"
596+
}
595597

596598
else ->
597599
ossResultsCount?.let { count ->

src/main/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowScanListener.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ class SnykToolWindowSnykScanListener(
281281
}
282282

283283
val currentOssError = getSnykCachedResults(project)?.currentOssError
284-
val cliErrorMessage = currentOssError?.message
284+
val cliErrorMessage = currentOssError?.error
285285

286286
var ossResultsCountForDisplay = ossResultsCount
287287
if (cliErrorMessage?.contains(NO_OSS_FILES) == true) {

src/main/kotlin/io/snyk/plugin/ui/toolwindow/nodes/root/RootIacIssuesTreeNode.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ class RootIacIssuesTreeNode(
2323
super.getSelectVulnerabilityMessage()
2424
}
2525

26-
override fun getSnykError(): SnykError? = getSnykCachedResults(project)?.currentIacError
26+
override fun getSnykError(): SnykError? = getSnykCachedResults(project)?.currentIacError?.toSnykError()
2727
}

src/main/kotlin/io/snyk/plugin/ui/toolwindow/nodes/root/RootOssTreeNode.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ class RootOssTreeNode(project: Project) : RootTreeNodeBase(SnykToolWindowPanel.O
1616
override fun getSelectVulnerabilityMessage(): String =
1717
originalCliErrorMessage?.let { txtToHtml(it) } ?: super.getSelectVulnerabilityMessage()
1818

19-
override fun getSnykError(): SnykError? = getSnykCachedResults(project)?.currentOssError
19+
override fun getSnykError(): SnykError? = getSnykCachedResults(project)?.currentOssError?.toSnykError()
2020
}

src/main/kotlin/io/snyk/plugin/ui/toolwindow/nodes/root/RootSecurityIssuesTreeNode.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ class RootSecurityIssuesTreeNode(
99
project: Project
1010
) : RootTreeNodeBase(SnykToolWindowPanel.CODE_SECURITY_ROOT_TEXT, project) {
1111

12-
override fun getSnykError(): SnykError? = getSnykCachedResults(project)?.currentSnykCodeError
12+
override fun getSnykError(): SnykError? = getSnykCachedResults(project)?.currentSnykCodeError?.toSnykError(project.basePath ?: "")
1313
}

src/main/kotlin/snyk/common/SnykCachedResults.kt

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import io.snyk.plugin.events.SnykScanListener
1313
import io.snyk.plugin.ui.SnykBalloonNotificationHelper
1414
import io.snyk.plugin.ui.toolwindow.SnykPluginDisposable
1515
import snyk.common.lsp.LsProduct
16+
import snyk.common.lsp.PresentableError
1617
import snyk.common.lsp.ScanIssue
1718
import snyk.common.lsp.SnykScanParams
1819

@@ -40,9 +41,9 @@ class SnykCachedResults(
4041
val currentOSSResultsLS: ConcurrentMap<SnykFile, Set<ScanIssue>> = ConcurrentMap()
4142
val currentIacResultsLS: MutableMap<SnykFile, Set<ScanIssue>> = ConcurrentMap()
4243

43-
var currentOssError: SnykError? = null
44-
var currentIacError: SnykError? = null
45-
var currentSnykCodeError: SnykError? = null
44+
var currentOssError: PresentableError? = null
45+
var currentIacError: PresentableError? = null
46+
var currentSnykCodeError: PresentableError? = null
4647

4748
fun clearCaches() {
4849
currentOssError = null
@@ -75,41 +76,24 @@ class SnykCachedResults(
7576
when (LsProduct.getFor(snykScan.product)) {
7677
LsProduct.OpenSource -> {
7778
currentOSSResultsLS.clear()
78-
currentOssError =
79-
SnykError(
80-
snykScan.cliError?.error ?: snykScan.errorMessage
81-
?: "Failed to run Snyk Open Source Scan",
82-
snykScan.cliError?.path ?: snykScan.folderPath,
83-
snykScan.cliError?.code,
84-
)
79+
currentOssError = snykScan.presentableError
8580
}
8681

8782
LsProduct.Code -> {
8883
currentSnykCodeResultsLS.clear()
89-
currentSnykCodeError =
90-
SnykError(
91-
snykScan.cliError?.error ?: snykScan.errorMessage
92-
?: "Failed to run Snyk Code Scan",
93-
snykScan.cliError?.path ?: snykScan.folderPath,
94-
snykScan.cliError?.code,
95-
)
84+
currentSnykCodeError = snykScan.presentableError
9685
}
9786

9887
LsProduct.InfrastructureAsCode -> {
9988
currentIacResultsLS.clear()
100-
currentIacError =
101-
SnykError(
102-
snykScan.cliError?.error ?: snykScan.errorMessage ?: "Failed to run Snyk IaC Scan",
103-
snykScan.cliError?.path ?: snykScan.folderPath,
104-
snykScan.cliError?.code,
105-
)
89+
currentIacError = snykScan.presentableError
10690
}
10791

10892
LsProduct.Unknown -> Unit
10993
}
11094

111-
val errorMessage = snykScan.errorMessage ?: "Scanning error for project ${project.name}. Data: $snykScan"
112-
if (snykScan.showNotification) {
95+
val errorMessage = snykScan.presentableError?.error ?: "Scanning error for project ${project.name}. Data: $snykScan"
96+
if (snykScan.presentableError?.showNotification == true) {
11397
SnykBalloonNotificationHelper.showError(errorMessage, project)
11498
}
11599
}

src/main/kotlin/snyk/common/lsp/Types.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,29 @@ data class CliError(
2929
val command: String? = null,
3030
)
3131

32+
data class PresentableError(
33+
val code: Int? = null, // Error code
34+
val error: String? = null, // Error message
35+
val path: String? = null, // Path where the error occurred
36+
val command: String? = null, // Command that caused the error
37+
val showNotification: Boolean = false, // ShowNotification is for IDE to decide to display a notification or not
38+
val treeNodeSuffix: String = "" // TreeNodeSuffix is an optional suffix message to be displayed in the tree node in IDEs
39+
) {
40+
fun toSnykError(defaultPath: String = ""): snyk.common.SnykError {
41+
return snyk.common.SnykError(
42+
message = error ?: treeNodeSuffix,
43+
path = path ?: defaultPath,
44+
code = code
45+
)
46+
}
47+
}
48+
3249
// Define the SnykScanParams data class
3350
data class SnykScanParams(
3451
val status: String, // Status (Must map to an LsScanStatus enum)
3552
val product: String, // Product under scan (Must map to an LsProduct)
3653
val folderPath: String, // FolderPath is the root-folder of the current scan
37-
val issues: List<ScanIssue>, // Issues contain the scan results in the common issues model
38-
val errorMessage: String? = null, // Error Message if applicable
39-
val cliError: CliError? = null, // Structured error information if applicable
40-
val showNotification: Boolean
54+
val presentableError: PresentableError? = null // PresentableError structured error object for displaying it to the user
4155
)
4256

4357
data class SnykScanSummaryParams(

src/test/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanelIntegTest.kt

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import org.junit.runners.JUnit4
3232
import snyk.common.SnykError
3333
import snyk.common.UIComponentFinder.getComponentByName
3434
import snyk.common.lsp.LanguageServerWrapper
35+
import snyk.common.lsp.PresentableError
3536
import snyk.common.lsp.SnykScanParams
3637
import snyk.trust.confirmScanningAndSetWorkspaceTrustedStateIfNeeded
3738
import java.awt.Component
@@ -100,8 +101,24 @@ class SnykToolWindowPanelIntegTest : HeavyPlatformTestCase() {
100101
mockkObject(SnykBalloonNotificationHelper)
101102

102103
val snykError =
103-
SnykScanParams("failed", "iac", project.basePath!!, emptyList(), SnykToolWindowPanel.NO_IAC_FILES)
104-
val snykErrorControl = SnykScanParams("failed", "iac", project.basePath!!, emptyList(), "control")
104+
SnykScanParams(
105+
"failed",
106+
"iac",
107+
project.basePath!!,
108+
PresentableError(
109+
error = SnykToolWindowPanel.NO_IAC_FILES,
110+
showNotification = true
111+
)
112+
)
113+
val snykErrorControl = SnykScanParams(
114+
"failed",
115+
"iac",
116+
project.basePath!!,
117+
PresentableError(
118+
error = "control",
119+
showNotification = true
120+
)
121+
)
105122

106123
scanPublisherLS.scanningError(snykErrorControl)
107124
scanPublisherLS.scanningError(snykError)
@@ -139,9 +156,25 @@ class SnykToolWindowPanelIntegTest : HeavyPlatformTestCase() {
139156
setUpOssTest()
140157

141158
val noFilesErrorParams =
142-
SnykScanParams("failed", "oss", project.basePath!!, emptyList(), SnykToolWindowPanel.NO_OSS_FILES)
159+
SnykScanParams(
160+
"failed",
161+
"oss",
162+
project.basePath!!,
163+
PresentableError(
164+
error = SnykToolWindowPanel.NO_OSS_FILES,
165+
showNotification = true
166+
)
167+
)
143168
val controlErrorParams =
144-
SnykScanParams("failed", "oss", project.basePath!!, emptyList(), "control")
169+
SnykScanParams(
170+
"failed",
171+
"oss",
172+
project.basePath!!,
173+
PresentableError(
174+
error = "control",
175+
showNotification = true
176+
)
177+
)
145178

146179
scanPublisherLS.scanningError(noFilesErrorParams)
147180
scanPublisherLS.scanningError(controlErrorParams)
@@ -180,20 +213,36 @@ class SnykToolWindowPanelIntegTest : HeavyPlatformTestCase() {
180213
mockkObject(SnykBalloonNotificationHelper)
181214

182215
val authErrorParams =
183-
SnykScanParams("failed", "oss", project.basePath!!, emptyList(), "auth error")
216+
SnykScanParams(
217+
"failed",
218+
"oss",
219+
project.basePath!!,
220+
PresentableError(
221+
error = "auth error",
222+
showNotification = true
223+
)
224+
)
184225
val controlErrorParams =
185-
SnykScanParams("failed", "oss", project.basePath!!, emptyList(), "control")
226+
SnykScanParams(
227+
"failed",
228+
"oss",
229+
project.basePath!!,
230+
PresentableError(
231+
error = "control",
232+
showNotification = true
233+
)
234+
)
186235

187236
scanPublisherLS.scanningError(controlErrorParams)
188237
scanPublisherLS.scanningError(authErrorParams)
189238

190239
PlatformTestUtil.dispatchAllEventsInIdeEventQueue()
191240

192241
verify(exactly = 1, timeout = 2000) {
193-
SnykBalloonNotificationHelper.showError(controlErrorParams.errorMessage!!, project)
242+
SnykBalloonNotificationHelper.showError(controlErrorParams.presentableError?.error!!, project)
194243
}
195244
verify(exactly = 1, timeout = 2000) {
196-
SnykBalloonNotificationHelper.showError(authErrorParams.errorMessage!!, project)
245+
SnykBalloonNotificationHelper.showError(authErrorParams.presentableError?.error!!, project)
197246
}
198247

199248
assertNull(getSnykCachedResults(project)?.currentOssError)
@@ -209,12 +258,22 @@ class SnykToolWindowPanelIntegTest : HeavyPlatformTestCase() {
209258
@Test
210259
fun `test should display '(error)' in OSS root tree node when result is empty and error occurs`() {
211260
val ossError = SnykError("an error", project.basePath!!)
212-
val ossErrorParams = SnykScanParams("failed", "oss", ossError.path, emptyList(), ossError.message)
261+
val presentableError = PresentableError(
262+
error = ossError.message,
263+
path = ossError.path,
264+
showNotification = true
265+
)
266+
val ossErrorParams = SnykScanParams(
267+
"failed",
268+
"oss",
269+
ossError.path,
270+
presentableError
271+
)
213272

214273
scanPublisherLS.scanningError(ossErrorParams)
215274
PlatformTestUtil.dispatchAllEventsInIdeEventQueue()
216275

217-
assertEquals(ossError, getSnykCachedResults(project)?.currentOssError)
276+
assertEquals(presentableError, getSnykCachedResults(project)?.currentOssError)
218277
assertTrue(getSnykCachedResults(project)?.currentOSSResultsLS?.isEmpty() ?: false)
219278
assertEquals(
220279
SnykToolWindowPanel.OSS_ROOT_TEXT + " (error)",
@@ -244,7 +303,17 @@ class SnykToolWindowPanelIntegTest : HeavyPlatformTestCase() {
244303

245304
// mock IaC results
246305
val iacError = SnykError("fake error", "fake path")
247-
val iacErrorParams = SnykScanParams("failed", "iac", iacError.path, emptyList(), iacError.message)
306+
val presentableError = PresentableError(
307+
error = iacError.message,
308+
path = iacError.path,
309+
showNotification = true
310+
)
311+
val iacErrorParams = SnykScanParams(
312+
"failed",
313+
"iac",
314+
iacError.path,
315+
presentableError
316+
)
248317

249318
// Trigger the callback from Language Server signalling scan failure
250319
scanPublisherLS.scanningError(iacErrorParams)
@@ -253,7 +322,7 @@ class SnykToolWindowPanelIntegTest : HeavyPlatformTestCase() {
253322
verify (exactly = 1, timeout = 2000) {
254323
SnykBalloonNotificationHelper.showError(iacError.message, project)
255324
}
256-
assertEquals(iacError, getSnykCachedResults(project)?.currentIacError)
325+
assertEquals(presentableError, getSnykCachedResults(project)?.currentIacError)
257326

258327
TreeUtil.selectNode(toolWindowPanel.getTree(), toolWindowPanel.getRootIacIssuesTreeNode())
259328

src/test/kotlin/snyk/common/lsp/SnykLanguageClientTest.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@ class SnykLanguageClientTest {
118118
fun `snykScan does not run when disposed`() {
119119
every { applicationMock.isDisposed } returns true
120120
every { projectMock.isDisposed } returns true
121-
val mockIssue = mockk<ScanIssue>()
122-
val param = SnykScanParams("success", "code", "testFolder", listOf(mockIssue))
121+
val param = SnykScanParams("success", "code", "testFolder")
123122

124123
cut.snykScan(param)
125124

0 commit comments

Comments
 (0)