Skip to content

Commit 94add88

Browse files
authored
Removing Active Open File Requirement for Project Scans (#4446)
* Removing ActiveFile as requirement for Project Scan. * Adding an Exception for fast fail in case of no supported language files in project scan. * Updated the unsupported files error message.
1 parent 8f2b7b0 commit 94add88

File tree

4 files changed

+42
-26
lines changed

4 files changed

+42
-26
lines changed

plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanException.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ internal fun fileTooLarge(presentableSize: String): Nothing =
2727

2828
internal fun uploadArtifactFailedError(): Nothing =
2929
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.upload_to_s3_failed"))
30+
31+
internal fun noSupportedFilesError(): Nothing =
32+
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.unsupported_language_error"))

plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanManager.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,8 @@ class CodeWhispererCodeScanManager(val project: Project) {
222222
} else {
223223
FileEditorManager.getInstance(project).selectedEditor?.file
224224
}
225-
?: noFileOpenError()
226225
val codeScanSessionConfig = CodeScanSessionConfig.create(file, project, scope)
227-
language = codeScanSessionConfig.getSelectedFile().programmingLanguage()
226+
language = codeScanSessionConfig.getSelectedFile()?.programmingLanguage() ?: CodeWhispererUnknownLanguage.INSTANCE
228227
if (scope == CodeWhispererConstants.CodeAnalysisScope.FILE &&
229228
!language.isAutoFileScanSupported()
230229
) {
@@ -237,6 +236,7 @@ class CodeWhispererCodeScanManager(val project: Project) {
237236
val sessionContext = CodeScanSessionContext(project, codeScanSessionConfig, scope)
238237
val session = CodeWhispererCodeScanSession(sessionContext)
239238
val codeScanResponse = session.run()
239+
language = codeScanSessionConfig.getProgrammingLanguage()
240240
codeScanResponseContext = codeScanResponse.responseContext
241241
codeScanJobId = codeScanResponseContext.codeScanJobId
242242
when (codeScanResponse) {

plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/sessionconfig/CodeScanSessionConfig.kt

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ import software.aws.toolkits.core.utils.getLogger
1818
import software.aws.toolkits.core.utils.putNextEntry
1919
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
2020
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.fileTooLarge
21+
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.noFileOpenError
22+
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.noSupportedFilesError
23+
import software.aws.toolkits.jetbrains.services.codewhisperer.language.CodeWhispererProgrammingLanguage
24+
import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererPlainText
25+
import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererUnknownLanguage
2126
import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmingLanguage
2227
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.CODE_SCAN_CREATE_PAYLOAD_TIMEOUT_IN_SECONDS
2328
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.CodeAnalysisScope
@@ -37,7 +42,7 @@ import java.util.Stack
3742
import kotlin.io.path.relativeTo
3843

3944
class CodeScanSessionConfig(
40-
private val selectedFile: VirtualFile,
45+
private val selectedFile: VirtualFile?,
4146
private val project: Project,
4247
private val scope: CodeAnalysisScope
4348
) {
@@ -69,27 +74,32 @@ class CodeScanSessionConfig(
6974
return exceedsLimit
7075
}
7176

72-
fun getSelectedFile(): VirtualFile = selectedFile
77+
private var programmingLanguage: CodeWhispererProgrammingLanguage = selectedFile?.programmingLanguage() ?: CodeWhispererUnknownLanguage.INSTANCE
78+
79+
fun getProgrammingLanguage(): CodeWhispererProgrammingLanguage = programmingLanguage
80+
81+
fun getSelectedFile(): VirtualFile? = selectedFile
7382

7483
fun createPayload(): Payload {
84+
// Fail fast if the selected file is null for File Scan
85+
if (scope == CodeAnalysisScope.FILE && selectedFile == null) {
86+
noFileOpenError()
87+
}
88+
7589
// Fail fast if the selected file size is greater than the payload limit.
76-
if (selectedFile.length > getPayloadLimitInBytes()) {
90+
if (selectedFile != null && selectedFile.length > getPayloadLimitInBytes()) {
7791
fileTooLarge(getPresentablePayloadLimit())
7892
}
7993

8094
val start = Instant.now().toEpochMilli()
8195

82-
LOG.debug { "Creating payload. File selected as root for the context truncation: ${selectedFile.path}" }
96+
LOG.debug { "Creating payload. File selected as root for the context truncation: ${projectRoot.path}" }
8397

84-
val payloadMetadata = when (selectedFile.path.startsWith(projectRoot.path)) {
85-
true -> when (scope) {
98+
val payloadMetadata = when (selectedFile) {
99+
null -> getProjectPayloadMetadata()
100+
else -> when (scope) {
86101
CodeAnalysisScope.PROJECT -> getProjectPayloadMetadata()
87-
CodeAnalysisScope.FILE -> getFilePayloadMetadata()
88-
}
89-
false -> {
90-
// Set project root as the parent of the selected file.
91-
projectRoot = selectedFile.parent
92-
getFilePayloadMetadata()
102+
CodeAnalysisScope.FILE -> getFilePayloadMetadata(selectedFile)
93103
}
94104
}
95105

@@ -108,13 +118,13 @@ class CodeScanSessionConfig(
108118
return Payload(payloadContext, srcZip)
109119
}
110120

111-
fun getFilePayloadMetadata(): PayloadMetadata =
121+
fun getFilePayloadMetadata(file: VirtualFile): PayloadMetadata =
112122
// Handle the case where the selected file is outside the project root.
113123
PayloadMetadata(
114-
setOf(selectedFile.path),
115-
selectedFile.length,
116-
Files.lines(selectedFile.toNioPath()).count().toLong(),
117-
selectedFile.programmingLanguage().toTelemetryType()
124+
setOf(file.path),
125+
file.length,
126+
Files.lines(file.toNioPath()).count().toLong(),
127+
file.programmingLanguage().toTelemetryType()
118128
)
119129

120130
/**
@@ -137,7 +147,7 @@ class CodeScanSessionConfig(
137147
try {
138148
withTimeout(Duration.ofSeconds(TELEMETRY_TIMEOUT_IN_SECONDS)) {
139149
if (scope == CodeAnalysisScope.FILE) {
140-
totalSize = selectedFile.length
150+
totalSize = selectedFile?.length ?: 0L
141151
} else {
142152
VfsUtil.collectChildrenRecursively(projectRoot).filter {
143153
!it.isDirectory && !it.`is`((VFileProperty.SYMLINK)) && (
@@ -168,7 +178,7 @@ class CodeScanSessionConfig(
168178
val stack = Stack<VirtualFile>()
169179
var currentTotalFileSize = 0L
170180
var currentTotalLines = 0L
171-
val languageCounts = mutableMapOf<CodewhispererLanguage, Int>()
181+
val languageCounts = mutableMapOf<CodeWhispererProgrammingLanguage, Int>()
172182

173183
stack.push(projectRoot)
174184
while (stack.isNotEmpty()) {
@@ -179,8 +189,8 @@ class CodeScanSessionConfig(
179189
if (willExceedPayloadLimit(currentTotalFileSize, current.length)) {
180190
break
181191
} else {
182-
val language = current.programmingLanguage().toTelemetryType()
183-
if (language != CodewhispererLanguage.Plaintext && language != CodewhispererLanguage.Unknown) {
192+
val language = current.programmingLanguage()
193+
if (language != CodeWhispererPlainText.INSTANCE && language != CodeWhispererUnknownLanguage.INSTANCE) {
184194
languageCounts[language] = (languageCounts[language] ?: 0) + 1
185195
}
186196

@@ -202,9 +212,11 @@ class CodeScanSessionConfig(
202212
val maxCountLanguage = languageCounts.filter { it.value == maxCount }.keys.firstOrNull()
203213

204214
if (maxCountLanguage == null) {
205-
return PayloadMetadata(files, currentTotalFileSize, currentTotalLines, CodewhispererLanguage.Unknown)
215+
programmingLanguage = CodeWhispererUnknownLanguage.INSTANCE
216+
noSupportedFilesError()
206217
}
207-
return PayloadMetadata(files, currentTotalFileSize, currentTotalLines, maxCountLanguage)
218+
programmingLanguage = maxCountLanguage
219+
return PayloadMetadata(files, currentTotalFileSize, currentTotalLines, maxCountLanguage.toTelemetryType())
208220
}
209221

210222
fun isProjectTruncated() = isProjectTruncated
@@ -221,7 +233,7 @@ class CodeScanSessionConfig(
221233
companion object {
222234
private val LOG = getLogger<CodeScanSessionConfig>()
223235
private const val TELEMETRY_TIMEOUT_IN_SECONDS: Long = 10
224-
fun create(file: VirtualFile, project: Project, scope: CodeAnalysisScope): CodeScanSessionConfig = CodeScanSessionConfig(file, project, scope)
236+
fun create(file: VirtualFile?, project: Project, scope: CodeAnalysisScope): CodeScanSessionConfig = CodeScanSessionConfig(file, project, scope)
225237
}
226238
}
227239

plugins/toolkit/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,7 @@ codewhisperer.codescan.stop_scan_confirm_message=Are you sure you want to stop o
736736
codewhisperer.codescan.stopping_scan=Stopping Security Scan...
737737
codewhisperer.codescan.suggested_fix_description=Why are we recommending this?
738738
codewhisperer.codescan.suggested_fix_label=Suggested code fix preview
739+
codewhisperer.codescan.unsupported_language_error=Project does not contain valid files to scan
739740
codewhisperer.codescan.upload_to_s3_failed=<html>Amazon Q is unable to upload workspace artifacts to Amazon S3 for security scans. For more information, see the Amazon Q documentation or contact your network or organization administrator.<br/> https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/security_iam_manage-access-with-policies.html</html>
740741
codewhisperer.codescan.view_scanned_files=View {0} scanned files
741742
codewhisperer.credential.login.dialog.exception.cancel_login=Login cancelled

0 commit comments

Comments
 (0)