Conversation
Discover subprojects in Gradle multi-project builds using a custom init script that emits structured project listings. Supports Groovy and Kotlin DSL variants, gradlew wrapper detection, and workspaceDiscoveryIgnore filtering. Adds **/build/** and **/.gradle/** to default ignore patterns. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add discoverGoWorkspaceModules() for discovering go.mod manifest paths in Go multi-module workspaces via `go work edit -json`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reviewer's GuideAdds Go multi-module workspace discovery based on Sequence diagram for Go workspace (go.work) module discoverysequenceDiagram
participant ExhortApi
participant Operations
participant GoCLI
participant ObjectMapper
participant WorkspaceUtils
ExhortApi->>ExhortApi: discoverWorkspaceManifests(workspaceDir, ignorePatterns)
ExhortApi->>ExhortApi: Files.isRegularFile(workspaceDir.resolve(go.work))
alt go.work exists
ExhortApi->>ExhortApi: discoverGoWorkspaceModules(workspaceDir, ignorePatterns)
ExhortApi->>Operations: getCustomPathOrElse(go)
Operations-->>ExhortApi: goBin
ExhortApi->>Operations: runProcessGetFullOutput(workspaceDir, [goBin, work, edit, -json, goWork], null)
Operations->>GoCLI: Execute go work edit -json
GoCLI-->>Operations: exitCode, stdout
Operations-->>ExhortApi: ProcessExecOutput
ExhortApi->>ExhortApi: check exitCode
alt exitCode != 0
ExhortApi-->>ExhortApi: return emptyList
else exitCode == 0
ExhortApi->>ObjectMapper: readValue(stdout, GoWorkspace)
ObjectMapper-->>ExhortApi: GoWorkspace workspace
ExhortApi->>ExhortApi: iterate workspace.use()
ExhortApi->>ExhortApi: resolve moduleDir and go.mod for each UseEntry
ExhortApi->>ExhortApi: collect existing go.mod paths
ExhortApi->>WorkspaceUtils: filterByIgnorePatterns(workspaceDir, manifests, ignorePatterns)
WorkspaceUtils-->>ExhortApi: filtered manifests
ExhortApi-->>ExhortApi: return manifests to discoverWorkspaceManifests
end
else go.work missing
ExhortApi-->>ExhortApi: Skip Go workspace discovery
end
Class diagram for GoWorkspace and updated ExhortApi workspace discoveryclassDiagram
class ExhortApi {
-static Set DEFAULT_WORKSPACE_DISCOVERY_IGNORE
+Set resolveIgnorePatterns(Set callerPatterns)
+List discoverWorkspaceManifests(Path workspaceDir, Set ignorePatterns)
-List discoverCargoManifests(Path workspaceDir, Set ignorePatterns)
-List discoverGoWorkspaceModules(Path workspaceDir, Set ignorePatterns)
-String resolveGradleBinary(Path startDir)
-List discoverGradleSubprojects(Path workspaceDir, Set ignorePatterns)
-static List parseGradleInitScriptOutput(String raw)
}
class GoWorkspace {
+List use()
}
class GoWorkspace_UseEntry {
+String diskPath()
}
class GradleProject {
+String path()
+String dir()
}
class Operations {
+static String getCustomPathOrElse(String binary)
+static boolean getWrapperPreference(String tool)
+static boolean isWindows()
+static ProcessExecOutput runProcessGetFullOutput(Path workspaceDir, String[] command, Map env)
}
class WorkspaceUtils {
+static List filterByIgnorePatterns(Path workspaceDir, List manifests, Set ignorePatterns)
}
class ObjectMapper {
+GoWorkspace readValue(String json, Class type)
}
class JavaMavenProvider {
+static String traverseForMvnw(String wrapperName, String startPath)
}
%% Relationships
ExhortApi ..> GoWorkspace : uses
ExhortApi ..> GoWorkspace_UseEntry : iterates
GoWorkspace o-- GoWorkspace_UseEntry : contains
ExhortApi ..> GradleProject : uses
ExhortApi ..> Operations : uses
ExhortApi ..> WorkspaceUtils : uses
ExhortApi ..> ObjectMapper : uses
ExhortApi ..> JavaMavenProvider : uses
Operations ..> ProcessExecOutput : returns
Flow diagram for updated workspace manifest discovery orderflowchart TD
start["Start workspace discovery"]
A["discoverWorkspaceManifests(workspaceDir, ignorePatterns)"]
A --> B{Workspace is Rust?}
B -- "Yes" --> B1["discoverCargoManifests"]
B -- "No" --> C{Has Gradle settings.gradle or settings.gradle.kts?}
C -- "Yes" --> C1["discoverGradleSubprojects"]
C -- "No" --> D{Has go.work?}
D -- "Yes" --> D1["discoverGoWorkspaceModules"]
D1 --> D2{Found go.mod manifests?}
D2 -- "Yes" --> returnGo["Return Go manifests"]
D2 -- "No" --> E
D -- "No" --> E["Check for JS workspace (package.json + lock file)"]
E --> E1{Has JS workspace?}
E1 -- "Yes" --> returnJs["Return JS manifests"]
E1 -- "No" --> F["Fallback to other manifest discovery mechanisms"]
B1 --> endRust["Return Cargo manifests"]
C1 --> endGradle["Return Gradle manifests"]
F --> endOther["Return discovered manifests or empty list"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Test Results0 tests 0 ✅ 0s ⏱️ Results for commit 157d3c1. |
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/main/java/io/github/guacsec/trustifyda/impl/ExhortApi.java" line_range="1090-1099" />
<code_context>
+ return List.of();
+ }
+ List<GradleProject> projects = new ArrayList<>();
+ for (String line : raw.split("\n")) {
+ if (!line.startsWith("::DA_PROJECT::")) {
+ continue;
+ }
+ String[] parts = line.split("::");
+ List<String> nonEmpty = new ArrayList<>();
+ for (String part : parts) {
+ if (!part.isEmpty()) {
+ nonEmpty.add(part);
+ }
+ }
+ if (nonEmpty.size() >= 3) {
+ projects.add(new GradleProject(nonEmpty.get(1), nonEmpty.get(2)));
+ }
+ }
</code_context>
<issue_to_address>
**issue:** Handle Windows CRLF and stray whitespace when parsing Gradle output lines.
This logic splits only on "\n" and never trims lines or parts. On Windows, Gradle often emits CRLF, so `line` and `proj.dir()` can include a trailing `\r`, leading to invalid paths and subprojects being skipped. Normalize the input (e.g., `line = line.trim()`) and/or trim each parsed part before creating `GradleProject` so `\r` and extra whitespace don’t end up in paths.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| for (String line : raw.split("\n")) { | ||
| if (!line.startsWith("::DA_PROJECT::")) { | ||
| continue; | ||
| } | ||
| String[] parts = line.split("::"); | ||
| List<String> nonEmpty = new ArrayList<>(); | ||
| for (String part : parts) { | ||
| if (!part.isEmpty()) { | ||
| nonEmpty.add(part); | ||
| } |
There was a problem hiding this comment.
issue: Handle Windows CRLF and stray whitespace when parsing Gradle output lines.
This logic splits only on "\n" and never trims lines or parts. On Windows, Gradle often emits CRLF, so line and proj.dir() can include a trailing \r, leading to invalid paths and subprojects being skipped. Normalize the input (e.g., line = line.trim()) and/or trim each parsed part before creating GradleProject so \r and extra whitespace don’t end up in paths.
Summary
GoWorkspacerecord for deserializinggo work edit -jsonoutputdiscoverGoWorkspaceModules()method inExhortApifor discoveringgo.modmanifest paths in Go multi-module workspacesdiscoverWorkspaceManifests()(between Gradle and JavaScript in the detection order)Test plan
Dependencies
Depends on #444 (Gradle workspace discovery - TC-4262) for the base branch
Jira
TC-4264
🤖 Generated with Claude Code
Summary by Sourcery
Extend workspace manifest discovery to support Go multi-module workspaces and Gradle multi-project builds, while tightening default ignore patterns and adding comprehensive tests for the new discovery logic.
New Features:
Enhancements:
Tests: