Skip to content

feat(batch): add batch workspace analysis action and settings UI#253

Open
a-oren wants to merge 3 commits intoredhat-developer:mainfrom
a-oren:TC-3865
Open

feat(batch): add batch workspace analysis action and settings UI#253
a-oren wants to merge 3 commits intoredhat-developer:mainfrom
a-oren:TC-3865

Conversation

@a-oren
Copy link
Copy Markdown

@a-oren a-oren commented Apr 19, 2026

Summary

  • Add "Batch Workspace Analysis Report" action that analyzes all packages in a JS/TS monorepo or Cargo workspace from the project root
  • Add batch-specific settings (concurrency, continueOnError, metadata) to the settings UI
  • Validate workspace layout before calling the API, showing a warning dialog for unsupported projects
  • Upgrade trustify-da-java-client to 0.0.16-SNAPSHOT, Java target to 21, and Mockito to 5.x

Test plan

  • Build and unit tests pass (JAVA_HOME=/usr/lib/jvm/java-21-openjdk ./gradlew build)
  • Tested batch analysis on pnpm monorepo workspace (test-workspace) — report opens with vulnerabilities
  • Tested on plain Java/Maven project (test-plain-java) — shows warning dialog instead of cryptic error
  • Tested on workspace without lock file (test-no-lockfile) — shows warning dialog
  • Tested invalid concurrency setting ("abc") — Java client falls back to default (10)
  • Verified batch settings persist correctly in ApiSettingsState

Implements TC-3865

🤖 Generated with Claude Code

Add a new "Batch Workspace Analysis Report" action that triggers batch
stack analysis on all packages in a JS/TS monorepo or Cargo workspace
from the project root. The action validates workspace layout before
calling the API and shows a warning dialog for unsupported projects.

Includes batch-specific settings (concurrency, continueOnError, metadata)
in the settings UI, a dedicated setBatchRequestProperties() method in
ApiService, and tests for both the API delegation and settings defaults.

Upgrades trustify-da-java-client to 0.0.16-SNAPSHOT for the batch API,
Java target to 21 for bytecode compatibility, and Mockito to 5.x for
Java 21 support.

Implements TC-3865

Assisted-by: Claude Code
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add batch workspace analysis action with settings UI and Java 21 support

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add batch workspace analysis action for JS/TS monorepos and Cargo workspaces
• Implement batch-specific settings UI (concurrency, continueOnError, metadata)
• Add workspace layout validation with user-friendly warning dialogs
• Upgrade Java target to 21, trustify-da-java-client to 0.0.16-SNAPSHOT, Mockito to 5.x
Diagram
flowchart LR
  A["SaBatchAction"] -->|validates workspace| B["isSupportedWorkspace"]
  A -->|calls| C["ApiService.getBatchStackAnalysis"]
  C -->|sets properties| D["setBatchRequestProperties"]
  D -->|reads| E["ApiSettingsState batch settings"]
  C -->|delegates to| F["ExhortApi.stackAnalysisBatchHtml"]
  F -->|returns| G["HTML Report"]
  A -->|displays| H["AnalyticsReportUtils.openCustomEditor"]
  I["ApiSettingsComponent"] -->|manages UI| E
  J["ApiSettingsConfigurable"] -->|persists| E
Loading

Grey Divider

File Changes

1. src/main/java/org/jboss/tools/intellij/exhort/ApiService.java ✨ Enhancement +91/-0

Add batch stack analysis API delegation method

src/main/java/org/jboss/tools/intellij/exhort/ApiService.java


2. src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java ✨ Enhancement +157/-0

New batch workspace analysis action with validation

src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java


3. src/main/java/org/jboss/tools/intellij/settings/ApiSettingsComponent.java ✨ Enhancement +45/-0

Add batch analysis settings UI components

src/main/java/org/jboss/tools/intellij/settings/ApiSettingsComponent.java


View more (7)
4. src/main/java/org/jboss/tools/intellij/settings/ApiSettingsConfigurable.java ✨ Enhancement +9/-0

Persist batch settings in configuration

src/main/java/org/jboss/tools/intellij/settings/ApiSettingsConfigurable.java


5. src/main/java/org/jboss/tools/intellij/settings/ApiSettingsState.java ✨ Enhancement +4/-0

Add batch settings fields with defaults

src/main/java/org/jboss/tools/intellij/settings/ApiSettingsState.java


6. src/test/java/org/jboss/tools/intellij/exhort/ApiServiceBatchTest.java 🧪 Tests +171/-0

Test batch API delegation and exclusion patterns

src/test/java/org/jboss/tools/intellij/exhort/ApiServiceBatchTest.java


7. src/test/java/org/jboss/tools/intellij/stackanalysis/SaBatchActionTest.java 🧪 Tests +78/-0

Test batch settings defaults and persistence

src/test/java/org/jboss/tools/intellij/stackanalysis/SaBatchActionTest.java


8. build.gradle.kts Dependencies +2/-2

Upgrade Java target to version 21

build.gradle.kts


9. gradle/libs.versions.toml Dependencies +2/-2

Upgrade trustify-da-java-client and Mockito versions

gradle/libs.versions.toml


10. src/main/resources/META-INF/plugin.xml ⚙️ Configuration changes +11/-0

Register batch workspace analysis action

src/main/resources/META-INF/plugin.xml


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 19, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (5)

Grey Divider


Action required

1. Java target set to 21 📎 Requirement gap ⚙ Maintainability
Description
The build configuration changes the project source/target compatibility to Java 21, which violates
the repository convention requirement to target Java 17.
Code

build.gradle.kts[R17-18]

+    sourceCompatibility = JavaVersion.VERSION_21
+    targetCompatibility = JavaVersion.VERSION_21
Evidence
Project conventions require Java 17, but the PR updates Gradle to compile/target Java 21.

Follow project conventions: Java 17, Gradle Kotlin DSL, JUnit 4
build.gradle.kts[17-18]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The project is configured to build with Java 21, but the repository convention requires Java 17.

## Issue Context
This PR changed Gradle `sourceCompatibility`/`targetCompatibility` to `VERSION_21`.

## Fix Focus Areas
- build.gradle.kts[17-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Batch errors use dialogs📎 Requirement gap ◔ Observability
Description
Batch analysis failures and workspace-detection issues are shown via Messages.show*Dialog instead
of IDE notifications, which can reduce visibility and consistency with other plugin messaging.
Code

src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[R118-123]

+                } catch (RuntimeException ex) {
+                    logger.error(ex);
+                    ApplicationManager.getApplication().invokeLater(() ->
+                            Messages.showErrorDialog(project,
+                                    "Batch analysis failed: " + ex.getLocalizedMessage(),
+                                    "Error"));
Evidence
The compliance requirement calls for IDE notifications, but the code uses modal dialogs
(Messages.showErrorDialog/Messages.showWarningDialog) for error/warning reporting paths.

Report batch analysis errors via IDE notifications
src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[69-75]
src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[118-123]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Batch analysis error/warning reporting uses `Messages.show*Dialog` instead of IntelliJ notifications.

## Issue Context
Compliance requires surfacing batch analysis errors via IDE notifications.

## Fix Focus Areas
- src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[63-75]
- src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[118-123]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Global property race 🐞 Bug ☼ Reliability
Description
ApiService.setBatchRequestProperties mutates JVM-wide System properties from a project-scoped
service, so concurrent analyses (or multiple open projects) can overwrite each other’s
token/tool-path/batch settings mid-request. This can lead to incorrect analysis behavior (wrong
backend settings, wrong tool paths) and hard-to-debug cross-project interference.
Code

src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[R310-366]

+    void setBatchRequestProperties() {
+        String ideName = ApplicationInfo.getInstance().getFullApplicationName();
+        PluginDescriptor pluginDescriptor = PluginManagerCore.getPlugin(PluginId.getId("org.jboss.tools.intellij.analytics"));
+        if (pluginDescriptor != null) {
+            String pluginName = pluginDescriptor.getName() + " " + pluginDescriptor.getVersion();
+            System.setProperty("TRUST_DA_SOURCE", ideName + " / " + pluginName);
+        } else {
+            System.setProperty("TRUST_DA_SOURCE", ideName);
+        }
+
+        ApiSettingsState settings = ApiSettingsState.getInstance();
+        System.setProperty("TRUST_DA_TOKEN", settings.rhdaToken);
+
+        setBackendUrl();
+
+        if (settings.batchConcurrency != null && !settings.batchConcurrency.isBlank()) {
+            System.setProperty("TRUSTIFY_DA_BATCH_CONCURRENCY", settings.batchConcurrency);
+        } else {
+            System.setProperty("TRUSTIFY_DA_BATCH_CONCURRENCY", "10");
+        }
+        System.setProperty("TRUSTIFY_DA_CONTINUE_ON_ERROR", String.valueOf(settings.batchContinueOnError));
+        System.setProperty("TRUSTIFY_DA_BATCH_METADATA", String.valueOf(settings.batchMetadata));
+
+        // Set tool paths needed for batch analysis
+        if (settings.npmPath != null && !settings.npmPath.isBlank()) {
+            System.setProperty("TRUSTIFY_DA_NPM_PATH", settings.npmPath);
+        } else {
+            System.clearProperty("TRUSTIFY_DA_NPM_PATH");
+        }
+        if (settings.yarnPath != null && !settings.yarnPath.isBlank()) {
+            System.setProperty("TRUSTIFY_DA_YARN_PATH", settings.yarnPath);
+        } else {
+            System.clearProperty("TRUSTIFY_DA_YARN_PATH");
+        }
+        if (settings.nodePath != null && !settings.nodePath.isBlank()) {
+            System.setProperty("NODE_HOME", settings.nodePath);
+        } else {
+            System.clearProperty("NODE_HOME");
+        }
+        if (settings.pnpmPath != null && !settings.pnpmPath.isBlank()) {
+            System.setProperty("TRUSTIFY_DA_PNPM_PATH", settings.pnpmPath);
+        } else {
+            System.clearProperty("TRUSTIFY_DA_PNPM_PATH");
+        }
+        if (settings.cargoPath != null && !settings.cargoPath.isBlank()) {
+            System.setProperty("TRUSTIFY_DA_CARGO_PATH", settings.cargoPath);
+        } else {
+            System.clearProperty("TRUSTIFY_DA_CARGO_PATH");
+        }
+
+        Optional<String> proxyUrlOpt = getProxyUrl();
+        if (proxyUrlOpt.isPresent()) {
+            System.setProperty("TRUSTIFY_DA_PROXY_URL", proxyUrlOpt.get());
+        } else {
+            System.clearProperty("TRUSTIFY_DA_PROXY_URL");
+        }
+    }
Evidence
ApiService is a PROJECT-level service, but setBatchRequestProperties uses
System.setProperty/clearProperty (process-global) to configure requests; this makes configuration
non-isolated and subject to interleaving across threads/projects. The same pattern is used for
non-batch analysis too, increasing the likelihood of cross-call contamination when batch analysis is
introduced.

src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[40-45]
src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[102-121]
src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[310-366]
src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[159-208]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ApiService` is `@Service(PROJECT)` but configures the Trustify client via JVM-global `System.setProperty/clearProperty`. This is vulnerable to races/interleaving when multiple analyses run concurrently (or multiple projects are open), causing one analysis to run with another analysis' configuration.

## Issue Context
This PR introduces `setBatchRequestProperties()` which sets additional global keys (batch concurrency, continueOnError, metadata). The existing stack/component analysis already uses the same global-property pattern, so batch analysis increases the surface area for cross-call contamination.

## Fix Focus Areas
- Implement a small utility to (a) snapshot relevant System properties, (b) set required properties, (c) perform the API call, (d) restore the snapshot in a `finally` block.
- Serialize property mutations + API invocation with a static lock to prevent interleaving.
- Apply the same mechanism to both `setRequestProperties(...)` call sites and the new batch call path.

### Focus areas (paths/lines)
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[71-122]
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[159-308]
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[310-366]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. SaBatchAction ignores selected directory 📎 Requirement gap ≡ Correctness
Description
The batch action always uses project.getBasePath() as the workspace root and does not consider a
user-selected directory, which can lead to analyzing the wrong root in multi-root or subdirectory
workflows.
Code

src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[R61-68]

+        String basePath = project.getBasePath();
+        if (basePath == null) {
+            Messages.showErrorDialog(project, "Cannot determine project base path.", "Error");
+            return;
+        }
+
+        Path baseDirPath = Path.of(basePath);
+        if (!isSupportedWorkspace(baseDirPath)) {
Evidence
The compliance requirement expects workspace root detection from the project base path or selected
directory, but the implementation only uses the project base path.

Implement SaBatchAction to detect workspace root from project base path or selected directory
src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[61-68]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`SaBatchAction` determines the workspace root only from `project.getBasePath()` and does not use the selected directory when the action is invoked from context menus.

## Issue Context
The action is added to `ProjectViewPopupMenu`, so users may expect the selection to drive the workspace root.

## Fix Focus Areas
- src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[55-77]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Ignore patterns not comma-joined 📎 Requirement gap ≡ Correctness
Description
Manifest exclusion patterns are passed as a List/Set to the Java client without conversion to
the required comma-separated workspace discovery ignore format, risking incorrect ignore behavior if
the client expects the property-based value.
Code

src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[R109-111]

+            Set<String> ignorePatternsSet = new HashSet<>(ignorePatterns);
+            var htmlContent = exhortApi.stackAnalysisBatchHtml(Path.of(workspacePath), ignorePatternsSet);
+            var tmpFile = Files.createTempFile("exhort_batch_", ".html");
Evidence
The checklist requires converting parsed patterns into a comma-separated workspace discovery ignore
setting, but the PR forwards patterns as a Set argument to stackAnalysisBatchHtml and does not
show any comma-separated formatting step.

Propagate manifest exclusion patterns as workspace discovery ignore setting
src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[86-90]
src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[109-111]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The batch flow does not convert parsed exclusion patterns into the required comma-separated workspace discovery ignore value.

## Issue Context
`SaBatchAction` obtains parsed patterns from `ManifestExclusionManager.getExclusionPatterns()` and forwards them, while compliance expects comma-separated formatting consistent with the documented ignore setting behavior.

## Fix Focus Areas
- src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[85-91]
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[102-112]
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[310-366]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Batch settings tests lack persistence 📎 Requirement gap ☼ Reliability
Description
The added tests only verify in-memory field defaults and mutation on a new ApiSettingsState
instance and do not validate persistence/loading via the IntelliJ PersistentStateComponent
mechanism.
Code

src/test/java/org/jboss/tools/intellij/stackanalysis/SaBatchActionTest.java[R39-54]

+    /** Verifies that batch settings fields can be modified and retain their values. */
+    @Test
+    public void testBatchSettingsPersistence() {
+        // Given
+        ApiSettingsState settings = new ApiSettingsState();
+
+        // When modifying settings
+        settings.batchConcurrency = "5";
+        settings.batchContinueOnError = false;
+        settings.batchMetadata = false;
+
+        // Then values should be retained
+        assertEquals("5", settings.batchConcurrency);
+        assertFalse(settings.batchContinueOnError);
+        assertFalse(settings.batchMetadata);
+    }
Evidence
The compliance requirement is for persistence/loading coverage, but the test merely sets fields on
an instance and asserts values without any save/load/serialization step.

Add and pass unit tests for batch settings persistence/loading
src/test/java/org/jboss/tools/intellij/stackanalysis/SaBatchActionTest.java[39-54]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Current tests do not verify that `ApiSettingsState` batch fields are persisted and reloaded through the IntelliJ state mechanism.

## Issue Context
The existing test only checks defaults and in-memory mutation.

## Fix Focus Areas
- src/test/java/org/jboss/tools/intellij/stackanalysis/SaBatchActionTest.java[27-54]
- src/main/java/org/jboss/tools/intellij/settings/ApiSettingsState.java[68-71]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
7. No mocked SaBatchAction flow test 📎 Requirement gap ☼ Reliability
Description
There are no tests that execute SaBatchAction with a mocked ApiService to verify workspace root
detection, settings/ignore propagation, and report-open flow under success/error conditions.
Code

src/test/java/org/jboss/tools/intellij/stackanalysis/SaBatchActionTest.java[R25-78]

+public class SaBatchActionTest {
+
+    /** Verifies that batch settings fields have correct default values. */
+    @Test
+    public void testBatchSettingsDefaults() {
+        // Given a fresh ApiSettingsState
+        ApiSettingsState settings = new ApiSettingsState();
+
+        // Then defaults should be set correctly
+        assertEquals("Default batch concurrency should be 10", "10", settings.batchConcurrency);
+        assertTrue("Default continueOnError should be true", settings.batchContinueOnError);
+        assertTrue("Default batchMetadata should be true", settings.batchMetadata);
+    }
+
+    /** Verifies that batch settings fields can be modified and retain their values. */
+    @Test
+    public void testBatchSettingsPersistence() {
+        // Given
+        ApiSettingsState settings = new ApiSettingsState();
+
+        // When modifying settings
+        settings.batchConcurrency = "5";
+        settings.batchContinueOnError = false;
+        settings.batchMetadata = false;
+
+        // Then values should be retained
+        assertEquals("5", settings.batchConcurrency);
+        assertFalse(settings.batchContinueOnError);
+        assertFalse(settings.batchMetadata);
+    }
+
+    /** Verifies that exclusion patterns from ManifestExclusionManager are properly parseable. */
+    @Test
+    public void testExclusionPatternConversion() {
+        // Given patterns in the settings format (newline-separated)
+        String patterns = "**/node_modules/**\n**/dist/**\n# comment\n  \n**/build/**";
+
+        // When splitting and filtering (same logic as ManifestExclusionManager.parsePatterns)
+        String[] lines = patterns.split("[\\n\\r]+");
+        java.util.List<String> parsed = new java.util.ArrayList<>();
+        for (String line : lines) {
+            String trimmed = line.trim();
+            if (!trimmed.isEmpty() && !trimmed.startsWith("#")) {
+                parsed.add(trimmed);
+            }
+        }
+
+        // Then comments and blank lines should be filtered out
+        assertEquals(3, parsed.size());
+        assertEquals("**/node_modules/**", parsed.get(0));
+        assertEquals("**/dist/**", parsed.get(1));
+        assertEquals("**/build/**", parsed.get(2));
+    }
+}
Evidence
The only SaBatchAction-related test file contains settings/parsing assertions and does not mock
ApiService or invoke SaBatchAction.actionPerformed to validate behavior.

Add and pass tests for SaBatchAction using a mocked ApiService
src/test/java/org/jboss/tools/intellij/stackanalysis/SaBatchActionTest.java[25-78]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Missing unit tests for `SaBatchAction` that use a mocked `ApiService` to verify invocation, propagation, and success/error flows.

## Issue Context
The current tests do not cover the action execution path.

## Fix Focus Areas
- src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java[55-127]
- src/test/java/org/jboss/tools/intellij/stackanalysis/SaBatchActionTest.java[25-78]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Interrupt flag not restored 🐞 Bug ☼ Reliability
Description
ApiService.getBatchStackAnalysis catches InterruptedException from CompletableFuture.get() and
rethrows RuntimeException without restoring the thread interrupt status. This can break
cancellation/shutdown semantics and cause background threads to keep running when they should stop.
Code

src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[R117-121]

+        } catch (IOException | InterruptedException | ExecutionException exc) {
+            telemetryMsg.error(exc);
+            telemetryMsg.send();
+            throw new RuntimeException(exc);
+        }
Evidence
The batch analysis implementation calls htmlContent.get() and catches InterruptedException in a
multi-catch, but does not call Thread.currentThread().interrupt() before rethrowing. The existing
getStackAnalysis method shows the same pattern, indicating this is an established bug now
duplicated into the new batch path.

src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[71-92]
src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[102-121]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`getBatchStackAnalysis` (and the existing `getStackAnalysis`) swallow `InterruptedException` by wrapping it in `RuntimeException` without restoring the interrupt flag. This loses the interruption signal and can cause incorrect cancellation behavior.

## Issue Context
`CompletableFuture.get()` throws `InterruptedException` when the thread is interrupted. Best practice is to restore the interrupt status (`Thread.currentThread().interrupt()`) before propagating.

## Fix Focus Areas
- Split the catch blocks (or add a conditional) so that when `exc` is an `InterruptedException`, you call `Thread.currentThread().interrupt()` before handling telemetry + throwing.
- Apply the same fix to both `getBatchStackAnalysis` and `getStackAnalysis` to avoid inconsistent behavior.

### Focus areas (paths/lines)
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[71-92]
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[102-121]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread build.gradle.kts
Comment on lines +17 to +18
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Java target set to 21 📎 Requirement gap ⚙ Maintainability

The build configuration changes the project source/target compatibility to Java 21, which violates
the repository convention requirement to target Java 17.
Agent Prompt
## Issue description
The project is configured to build with Java 21, but the repository convention requires Java 17.

## Issue Context
This PR changed Gradle `sourceCompatibility`/`targetCompatibility` to `VERSION_21`.

## Fix Focus Areas
- build.gradle.kts[17-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is required because trustify-da-java-client 0.0.16-SNAPSHOT is compiled with maven.compiler.release=21 (upgraded in guacsec/trustify-da-java-client#390). Building with Java 17 fails with class file has wrong version 65.0, should be 61.0. We need to match the client's Java target to use the batch API.

Comment thread src/main/java/org/jboss/tools/intellij/stackanalysis/SaBatchAction.java Outdated
Comment on lines +310 to +366
void setBatchRequestProperties() {
String ideName = ApplicationInfo.getInstance().getFullApplicationName();
PluginDescriptor pluginDescriptor = PluginManagerCore.getPlugin(PluginId.getId("org.jboss.tools.intellij.analytics"));
if (pluginDescriptor != null) {
String pluginName = pluginDescriptor.getName() + " " + pluginDescriptor.getVersion();
System.setProperty("TRUST_DA_SOURCE", ideName + " / " + pluginName);
} else {
System.setProperty("TRUST_DA_SOURCE", ideName);
}

ApiSettingsState settings = ApiSettingsState.getInstance();
System.setProperty("TRUST_DA_TOKEN", settings.rhdaToken);

setBackendUrl();

if (settings.batchConcurrency != null && !settings.batchConcurrency.isBlank()) {
System.setProperty("TRUSTIFY_DA_BATCH_CONCURRENCY", settings.batchConcurrency);
} else {
System.setProperty("TRUSTIFY_DA_BATCH_CONCURRENCY", "10");
}
System.setProperty("TRUSTIFY_DA_CONTINUE_ON_ERROR", String.valueOf(settings.batchContinueOnError));
System.setProperty("TRUSTIFY_DA_BATCH_METADATA", String.valueOf(settings.batchMetadata));

// Set tool paths needed for batch analysis
if (settings.npmPath != null && !settings.npmPath.isBlank()) {
System.setProperty("TRUSTIFY_DA_NPM_PATH", settings.npmPath);
} else {
System.clearProperty("TRUSTIFY_DA_NPM_PATH");
}
if (settings.yarnPath != null && !settings.yarnPath.isBlank()) {
System.setProperty("TRUSTIFY_DA_YARN_PATH", settings.yarnPath);
} else {
System.clearProperty("TRUSTIFY_DA_YARN_PATH");
}
if (settings.nodePath != null && !settings.nodePath.isBlank()) {
System.setProperty("NODE_HOME", settings.nodePath);
} else {
System.clearProperty("NODE_HOME");
}
if (settings.pnpmPath != null && !settings.pnpmPath.isBlank()) {
System.setProperty("TRUSTIFY_DA_PNPM_PATH", settings.pnpmPath);
} else {
System.clearProperty("TRUSTIFY_DA_PNPM_PATH");
}
if (settings.cargoPath != null && !settings.cargoPath.isBlank()) {
System.setProperty("TRUSTIFY_DA_CARGO_PATH", settings.cargoPath);
} else {
System.clearProperty("TRUSTIFY_DA_CARGO_PATH");
}

Optional<String> proxyUrlOpt = getProxyUrl();
if (proxyUrlOpt.isPresent()) {
System.setProperty("TRUSTIFY_DA_PROXY_URL", proxyUrlOpt.get());
} else {
System.clearProperty("TRUSTIFY_DA_PROXY_URL");
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Global property race 🐞 Bug ☼ Reliability

ApiService.setBatchRequestProperties mutates JVM-wide System properties from a project-scoped
service, so concurrent analyses (or multiple open projects) can overwrite each other’s
token/tool-path/batch settings mid-request. This can lead to incorrect analysis behavior (wrong
backend settings, wrong tool paths) and hard-to-debug cross-project interference.
Agent Prompt
## Issue description
`ApiService` is `@Service(PROJECT)` but configures the Trustify client via JVM-global `System.setProperty/clearProperty`. This is vulnerable to races/interleaving when multiple analyses run concurrently (or multiple projects are open), causing one analysis to run with another analysis' configuration.

## Issue Context
This PR introduces `setBatchRequestProperties()` which sets additional global keys (batch concurrency, continueOnError, metadata). The existing stack/component analysis already uses the same global-property pattern, so batch analysis increases the surface area for cross-call contamination.

## Fix Focus Areas
- Implement a small utility to (a) snapshot relevant System properties, (b) set required properties, (c) perform the API call, (d) restore the snapshot in a `finally` block.
- Serialize property mutations + API invocation with a static lock to prevent interleaving.
- Apply the same mechanism to both `setRequestProperties(...)` call sites and the new batch call path.

### Focus areas (paths/lines)
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[71-122]
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[159-308]
- src/main/java/org/jboss/tools/intellij/exhort/ApiService.java[310-366]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global System.setProperty pattern is pre-existing- setRequestProperties() (used by stack and component analysis) has the same thread-safety concern. setBatchRequestProperties() follows the established convention.

a-oren added 2 commits April 19, 2026 16:54
Replace Messages.showErrorDialog and Messages.showWarningDialog with
NotificationGroupManager notifications using the existing "Red Hat
Dependency Analytics" notification group, matching the pattern used in
ReportFileManager.

Implements TC-3865

Assisted-by: Claude Code
Add batch analysis feature and settings documentation to README.md,
batch telemetry events to USAGE_DATA.md, and batch analysis quick start
entry to plugin.xml description.

Implements TC-3865

Assisted-by: Claude Code
@sonarqubecloud
Copy link
Copy Markdown

@ruromero ruromero self-requested a review April 20, 2026 12:16
Copy link
Copy Markdown
Collaborator

@ruromero ruromero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only one refactoring comment, the rest looks good

}
}

void setBatchRequestProperties() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method shares most of the code with setRequestProperties
Actually this one leaves out the Java, Gradle, Maven, and other properties. It is true that this is not supported it's not a problem to configure the properties in the same way.
The only difference is the concurrency which can also be configured in both cases (stack and batchStack).
The image.ApiService has the same duplication logic. I don't see any problem in configuring all the properties in a common place unless you see any contradiction.

The 3 methods are doing the same:

  • Setup the plugin descriptor
  • Configure the backend
  • Set System properties based on user settings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants