Skip to content

Commit dc893f5

Browse files
Merge main into feature/dev-execution
2 parents 86e993e + 8a1d250 commit dc893f5

File tree

4 files changed

+437
-15
lines changed

4 files changed

+437
-15
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Amazon Q /test: Fixed an issue which incorrectly caused payload size exceeded exception when collecting project payload files"
4+
}

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/sessionconfig/CodeTestSessionConfig.kt

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import software.aws.toolkits.core.utils.createTemporaryZipFile
1818
import software.aws.toolkits.core.utils.debug
1919
import software.aws.toolkits.core.utils.getLogger
2020
import software.aws.toolkits.core.utils.putNextEntry
21-
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
2221
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.sessionconfig.Payload
2322
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.sessionconfig.PayloadContext
2423
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.sessionconfig.PayloadMetadata
@@ -33,6 +32,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmi
3332
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.CODE_SCAN_CREATE_PAYLOAD_TIMEOUT_IN_SECONDS
3433
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.DEFAULT_CODE_SCAN_TIMEOUT_IN_SECONDS
3534
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.DEFAULT_PAYLOAD_LIMIT_IN_BYTES
35+
import software.aws.toolkits.jetbrains.services.codewhisperer.util.GitIgnoreFilteringUtil
3636
import software.aws.toolkits.jetbrains.services.codewhisperer.util.isWithin
3737
import software.aws.toolkits.resources.message
3838
import java.io.File
@@ -53,8 +53,6 @@ class CodeTestSessionConfig(
5353
project.guessProjectDir() ?: error("Cannot guess base directory for project ${project.name}")
5454
}
5555

56-
private val featureDevSessionContext = FeatureDevSessionContext(project)
57-
5856
val fileIndex = ProjectRootManager.getInstance(project).fileIndex
5957

6058
/**
@@ -186,15 +184,16 @@ class CodeTestSessionConfig(
186184

187185
moduleLoop@ for (module in project.modules) {
188186
val changeListManager = ChangeListManager.getInstance(module.project)
189-
if (module.guessModuleDir() != null) {
190-
stack.push(module.guessModuleDir())
187+
module.guessModuleDir()?.let { moduleDir ->
188+
val gitIgnoreFilteringUtil = GitIgnoreFilteringUtil(moduleDir)
189+
stack.push(moduleDir)
191190
while (stack.isNotEmpty()) {
192191
val current = stack.pop()
193192

194193
if (!current.isDirectory) {
195194
if (current.isFile && current.path != selectedFile?.path &&
196195
!changeListManager.isIgnoredFile(current) &&
197-
runBlocking { !featureDevSessionContext.ignoreFile(current) } &&
196+
runBlocking { !gitIgnoreFilteringUtil.ignoreFile(current) } &&
198197
runReadAction { !fileIndex.isInLibrarySource(current) }
199198
) {
200199
if (willExceedPayloadLimit(currentTotalFileSize, current.length)) {
@@ -217,7 +216,7 @@ class CodeTestSessionConfig(
217216
} else {
218217
// Directory case: only traverse if not ignored
219218
if (!changeListManager.isIgnoredFile(current) &&
220-
runBlocking { !featureDevSessionContext.ignoreFile(current) } &&
219+
runBlocking { !gitIgnoreFilteringUtil.ignoreFile(current) } &&
221220
!traversedDirectories.contains(current) && current.isValid &&
222221
runReadAction { !fileIndex.isInLibrarySource(current) }
223222
) {
@@ -242,21 +241,14 @@ class CodeTestSessionConfig(
242241
return PayloadMetadata(files, currentTotalFileSize, currentTotalLines, maxCountLanguage.toTelemetryType())
243242
}
244243

245-
fun getPath(root: String, relativePath: String = ""): Path? = try {
246-
Path.of(root, relativePath).normalize()
247-
} catch (e: Exception) {
248-
LOG.debug { "Cannot find file at path $relativePath relative to the root $root" }
249-
null
250-
}
251-
252244
fun getRelativePath(): Path? = try {
253245
selectedFile?.path?.let { Path.of(projectRoot.path).relativize(Path.of(it)).normalize() }
254246
} catch (e: Exception) {
255247
LOG.debug { "Cannot calculate relative path of $selectedFile with respect to $projectRoot" }
256248
null
257249
}
258250

259-
fun File.toVirtualFile() = LocalFileSystem.getInstance().findFileByIoFile(this)
251+
private fun File.toVirtualFile() = LocalFileSystem.getInstance().findFileByIoFile(this)
260252

261253
companion object {
262254
private val LOG = getLogger<CodeTestSessionConfig>()
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.codewhisperer.util
5+
6+
import com.intellij.openapi.vfs.VfsUtil
7+
import com.intellij.openapi.vfs.VirtualFile
8+
import kotlinx.coroutines.async
9+
import kotlinx.coroutines.withContext
10+
import kotlin.coroutines.coroutineContext
11+
12+
class GitIgnoreFilteringUtil(private val moduleDir: VirtualFile) {
13+
private var ignorePatternsWithGitIgnore = emptyList<Regex>()
14+
private val additionalGitIgnoreRules = setOf(
15+
".aws-sam",
16+
".gem",
17+
".git",
18+
".gitignore",
19+
".gradle",
20+
".hg",
21+
".idea",
22+
".project",
23+
".rvm",
24+
".svn",
25+
"*.zip",
26+
"*.bin",
27+
"*.png",
28+
"*.jpg",
29+
"*.svg",
30+
"*.pyc",
31+
"license.txt",
32+
"License.txt",
33+
"LICENSE.txt",
34+
"license.md",
35+
"License.md",
36+
"LICENSE.md",
37+
"node_modules",
38+
"build",
39+
"dist",
40+
"annotation-generated-src",
41+
"annotation-generated-tst"
42+
)
43+
44+
init {
45+
ignorePatternsWithGitIgnore = try {
46+
buildList {
47+
addAll(additionalGitIgnoreRules.map { convertGitIgnorePatternToRegex(it) })
48+
addAll(parseGitIgnore())
49+
}.mapNotNull { pattern ->
50+
runCatching { Regex(pattern) }.getOrNull()
51+
}
52+
} catch (e: Exception) {
53+
emptyList()
54+
}
55+
}
56+
57+
private fun parseGitIgnore(): Set<String> {
58+
val gitignoreFile = moduleDir.findChild(".gitignore")
59+
return gitignoreFile?.let {
60+
if (it.isValid && it.exists()) {
61+
it.inputStream.bufferedReader().readLines()
62+
.filter { line ->
63+
line.isNotBlank() && !line.startsWith("#")
64+
}
65+
.map { pattern ->
66+
convertGitIgnorePatternToRegex(pattern.trim())
67+
}
68+
.toSet()
69+
} else {
70+
emptySet()
71+
}
72+
}.orEmpty()
73+
}
74+
75+
// gitignore patterns are not regex, method update needed.
76+
private fun convertGitIgnorePatternToRegex(pattern: String): String = pattern
77+
.replace(".", "\\.")
78+
.replace("*", ".*")
79+
.let { if (it.endsWith("/")) "$it.*" else "$it/.*" } // Add a trailing /* to all patterns. (we add a trailing / to all files when matching)
80+
81+
suspend fun ignoreFile(file: VirtualFile): Boolean {
82+
// this method reads like something a JS dev would write and doesn't do what the author thinks
83+
val deferredResults = ignorePatternsWithGitIgnore.map { pattern ->
84+
withContext(coroutineContext) {
85+
// avoid partial match (pattern.containsMatchIn) since it causes us matching files
86+
// against folder patterns. (e.g. settings.gradle ignored by .gradle rule!)
87+
// we convert the glob rules to regex, add a trailing /* to all rules and then match
88+
// entries against them by adding a trailing /.
89+
// TODO: Add unit tests for gitignore matching
90+
val relative = getRelativePath(file)
91+
async { pattern.matches("$relative/") }
92+
}
93+
}
94+
95+
// this will serially iterate over and block
96+
// ideally we race the results https://github.com/Kotlin/kotlinx.coroutines/issues/2867
97+
// i.e. Promise.any(...)
98+
return deferredResults.any { it.await() }
99+
}
100+
101+
private fun getRelativePath(file: VirtualFile): String = VfsUtil.getRelativePath(file, moduleDir).orEmpty()
102+
}

0 commit comments

Comments
 (0)