Skip to content

Migrate workflows to Java 25#44604

Open
Thevakumar-Luheerathan wants to merge 13 commits into
masterfrom
java-25-migration
Open

Migrate workflows to Java 25#44604
Thevakumar-Luheerathan wants to merge 13 commits into
masterfrom
java-25-migration

Conversation

@Thevakumar-Luheerathan
Copy link
Copy Markdown
Member

@Thevakumar-Luheerathan Thevakumar-Luheerathan commented May 20, 2026

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues.

Fixes #

Approach

Describe how you are implementing the solutions along with the design details.

Samples

Provide high-level details about the samples related to this feature.

Remarks

List any other known issues, related PRs, TODO items, or any other notes related to the PR.

Check List

  • Read the Contributing Guide
  • Updated Change Log
  • Checked Tooling Support (#)
  • Added necessary tests
    • Unit Tests
    • Spec Conformance Tests
    • Integration Tests
    • Ballerina By Example Tests
  • Increased Test Coverage
  • Added necessary documentation
    • API documentation
    • Module documentation in Module.md files
    • Ballerina By Examples

This pull request upgrades the Ballerina build and CI/tooling environment to Java 25 and modernizes related build configuration to improve compatibility and build reliability.

Key changes

  • Java platform upgrade across CI and build:

    • GitHub Actions workflows updated to use Temurin JDK 25.0.3 (replacing 21.0.3) and GraalVM configured for Java 25.
    • Gradle convention scripts updated to use Java 25 for source/target compatibility.
    • JVM startup flag (--sun-misc-unsafe-memory-access=allow) added to distribution launch scripts to accommodate Java 25 behavior.
  • Build system modernization:

    • Replaced legacy buildDir usages with Gradle’s provider API (layout.buildDirectory) across many Gradle scripts.
    • Bumped Gradle wrapper to 9.5.1.
    • Switched Shadow plugin coordinates to the new provider namespace.
  • Dependency and tooling updates:

    • Updated versions for JaCoCo, OW2 ASM, SpotBugs-related tooling, and several plugins via gradle/libs.versions.toml.
  • Build and test script adjustments:

    • Standardized explicit buildDir variables and updated tasks to use provider-based paths.
    • Added a dedicated benchmark task and simplified related test wiring.
    • Adjusted test code and expectations (order-insensitive checks, normalization fixes, and some tests disabled or gated on platforms) to improve stability.
    • Includes a commit addressing a Windows build failure.
  • Code-quality and configuration updates:

    • Added or expanded SpotBugs exclusion filters across multiple modules to suppress intentional or benign findings.
    • Minor Javadoc and packaging/script tweaks.
  • Repository structural tweaks:

    • settings.gradle now ensures mapped project directories are created at configuration time.

Scope and impact

  • Changes are primarily focused on CI/workflow configuration, Gradle build scripts, test adjustments, and static analysis filters.
  • No public API or exported runtime behavior changes are introduced.

Checklist

  • PR body template checklist remains unchecked (contributing guide, changelog, tooling checks, tests, coverage, and documentation updates not marked complete).

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Upgrades CI workflows to Temurin JDK 25, migrates Gradle scripts to use provider-based buildDirectory/explicit buildDir, bumps multiple tooling/dependencies and the Gradle wrapper, expands SpotBugs exclusions, adds a JVM startup flag, and adjusts tests, settings, and benchmark/build infra.

Changes

Comprehensive Toolchain & Build System Upgrade

Layer / File(s) Summary
Comprehensive upgrade and migration
.github/workflows/*, gradle/**, build.gradle, settings.gradle, distribution/**, tests/**, **/spotbugs-exclude.xml, compiler/.../ProjectConstants.java
Replaces JDK 21 with Temurin JDK 25.0.3 across GitHub Actions workflows, updates GraalVM entries to Java 25/community where present, migrates many Gradle scripts to use layout.buildDirectory (adds explicit buildDir), bumps Gradle wrapper and many dependency/tool versions via gradle/libs.versions.toml, converts several custom Gradle task classes to abstract, expands SpotBugs exclusion rules across modules, adds JVM flag --sun-misc-unsafe-memory-access=allow to startup scripts, tweaks tests (assertions, disabled tests, file-system cleanup and exception handling), refactors benchmark runner into runBenchmark, ensures projectDir mkdirs in settings.gradle, and adjusts packaging/permission handling and maven-resolver assembly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Poem

"I hop through CI and build, a rabbit bright and spry,
Java climbed to twenty-five, I gave the wrapper a try,
Gradle found new pathways, SpotBugs hushes its call,
Benchmarks run in tidy tasks — I nibbled carrots by the wall,
Pipelines hum, tests settle — hooray, a springtime fly! 🥕"

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is entirely a template with all sections empty and no concrete details about the Java 25 migration, approach, samples, or remarks provided. Fill in all required template sections: specify the issue number being fixed, describe the migration approach, provide relevant samples/context, and document any known issues or related items.
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title "Migrate workflows to Java 25" clearly summarizes the main change across multiple workflow files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch java-25-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the build and CI configuration to target Java 25, including Gradle/plugin upgrades and build-script adjustments needed for newer Gradle/SpotBugs behavior.

Changes:

  • Upgrade Gradle wrapper and update the shared Java convention plugin to compile/target Java 25.
  • Update GitHub Actions workflows (Temurin + GraalVM) to run on Java 25.
  • Modernize Gradle scripts around layout.buildDirectory, adjust packaging permissions, and extend SpotBugs exclusions to accommodate new warnings.

Reviewed changes

Copilot reviewed 71 out of 74 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/testerina-integration-test/build.gradle Use layout.buildDirectory-derived build path.
tests/language-server-integration-tests/build.gradle Use layout.buildDirectory-derived build path.
tests/jballerina-integration-test/build.gradle Use layout.buildDirectory-derived build path.
tests/jballerina-debugger-integration-test/src/test/java/org/ballerinalang/debugger/test/adapter/DebugOutputTest.java Make output assertion order-independent for Java 25 runtime behavior.
tests/jballerina-debugger-integration-test/spotbugs-exclude.xml Add SpotBugs suppressions for new warning patterns.
tests/jballerina-debugger-integration-test/build.gradle Use layout.buildDirectory-derived build path.
tests/jballerina-benchmark-test/build.gradle Refactor benchmark execution into dedicated Exec task; adjust test behavior.
tests/ballerina-tools-integration-test/build.gradle Use layout.buildDirectory-derived build path.
tests/ballerina-test-utils/spotbugs-exclude.xml Add SpotBugs suppression for new throws warning.
tests/ballerina-test-utils/build.gradle Migrate Shadow plugin id to com.gradleup.shadow.
tests/bal-tools-integration-tests/build.gradle Use layout.buildDirectory-derived build path.
settings.gradle Add projectDir.mkdirs() calls for many projects/parents.
project-api/test-artifacts/log-creator-pkg-provided-code-modifier/spotbugs-exclude.xml Add SpotBugs suppression for new throws warning.
project-api/test-artifacts/log-creator-pkg-provided-code-generator/spotbugs-exclude.xml Add SpotBugs suppression for new throws warning.
project-api/test-artifacts/log-creator-pkg-provided-code-analyzer/spotbugs-exclude.xml Add SpotBugs suppression for new throws warning.
project-api/test-artifacts/log-creator-in-built-code-modifier/spotbugs-exclude.xml Add SpotBugs suppression for new throws warning.
project-api/test-artifacts/log-creator-in-built-code-generator/spotbugs-exclude.xml Add SpotBugs suppression for new throws warning.
project-api/test-artifacts/log-creator-in-built-code-analyzer/spotbugs-exclude.xml Add SpotBugs suppression for new throws warning.
project-api/test-artifacts/compiler-plugin-with-analyzer-generator-modifier/spotbugs-exclude.xml Add SpotBugs suppression for new throws warning.
project-api/test-artifacts/bal-tool-integration-test-artifacts/build.gradle Use layout.buildDirectory-derived build path.
project-api/test-artifacts/bad-sad-compiler-plugin/spotbugs-exclude.xml New SpotBugs exclude filter for test artifact.
project-api/project-api-test/build.gradle Use layout.buildDirectory-derived build path.
misc/testerina/modules/testerina-core/build.gradle Move off project.buildDir usages to layout.buildDirectory.
misc/maven-resolver/build.gradle Configure Gradle test task to use TestNG.
misc/formatter/modules/formatter-core/build.gradle Use layout.buildDirectory-derived build path.
misc/docerina/build.gradle Use layout.buildDirectory-derived build path.
misc/diagram-util/spotbugs-exclude.xml Add SpotBugs suppression for new stale-thread-write warnings.
misc/diagram-util/build.gradle Use layout.buildDirectory-derived build path.
misc/debug-adapter/modules/debug-adapter-core/spotbugs-exclude.xml Add SpotBugs suppressions for new throws/stale-thread-write warnings.
misc/ballerinalang-data-mapper/src/main/java/org/ballerinalang/datamapper/utils/HttpResponse.java Javadoc cleanup ({@code int} usage).
misc/ballerinalang-data-mapper/build.gradle Use layout.buildDirectory-derived build path.
language-server/modules/langserver-stdlib/build.gradle Move off project.buildDir usages to layout.buildDirectory.
language-server/modules/langserver-core/spotbugs-exclude.xml Expand SpotBugs suppressions for new warning patterns.
language-server/modules/langserver-core/build.gradle Use layout.buildDirectory; update archives name API usage.
language-server/modules/langserver-commons/spotbugs-exclude.xml Expand module-wide SpotBugs suppressions to include throws warnings.
language-server/modules/langserver-commons/build.gradle Use layout.buildDirectory-derived build path.
langlib/lang.test/build.gradle Move off project.buildDir usages to layout.buildDirectory.
gradle/wrapper/gradle-wrapper.properties Upgrade Gradle wrapper version.
gradle/plugins/java-convention/src/main/groovy/javaProjectWithExtBala.gradle Use layout.buildDirectory-derived build path.
gradle/plugins/java-convention/src/main/groovy/javaProject.gradle Set Java compatibility to 25; set SpotBugs tool version; use layout.buildDirectory.
gradle/plugins/java-convention/src/main/groovy/ballerinaStdLibBuildInternal.gradle Gradle 9 compatibility updates (abstract task class, buildDir usage).
gradle/plugins/java-convention/src/main/groovy/ballerinaStdLibBuild.gradle Gradle 9 compatibility updates (abstract task class, buildDir usage).
gradle/plugins/java-convention/src/main/groovy/ballerinaNativeStdLibBuild.gradle Gradle 9 compatibility updates (abstract task class, buildDir usage).
gradle/plugins/java-convention/src/main/groovy/ballerinaLangLibLoad.gradle Use layout.buildDirectory-derived build path.
gradle/plugins/java-convention/src/main/groovy/ballerinaLangLibBuild.gradle Gradle 9 compatibility updates (abstract task class, buildDir usage).
gradle/libs.versions.toml Bump tool/library/plugin versions (SpotBugs, Shadow, JaCoCo, ASM, TestNG, etc.).
distribution/zip/jballerina/build.gradle Use layout.buildDirectory-derived build path.
distribution/zip/jballerina/bin/bal.bat Add JVM flag for Unsafe memory access behavior under Java 25.
distribution/zip/jballerina/bin/bal Add JVM flag for Unsafe memory access behavior under Java 25.
distribution/zip/jballerina-tools/build.gradle Use layout.buildDirectory; adjust copy permissions DSL for Gradle 9.
compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectConstants.java Update embedded tool jar names (JaCoCo/ASM) to new versions.
compiler/ballerina-lang/spotbugs-exclude.xml Expand SpotBugs suppression set to include new throws warning.
cli/central-client/build.gradle Use layout.buildDirectory-derived build path.
cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestNativeImageCommandTest.java Loosen assertion to match changed native-image output text.
cli/ballerina-cli/spotbugs-exclude.xml Add SpotBugs suppressions for throws and stale-thread-write warnings.
cli/ballerina-cli/build.gradle Use layout.buildDirectory-derived build path.
build.gradle Replace subproject.buildDir usages with layout.buildDirectory.
build-config/checkstyle/build.gradle Move off buildDir direct usage to layout.buildDirectory.
ballerina-shell/modules/shell-core/spotbugs-exclude.xml Add SpotBugs suppressions for new throws/stale-thread-write warnings.
ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/base/TestIntegrator.java Normalize REPL output for Java 25 I/O behavior differences.
ballerina-shell/modules/shell-cli/spotbugs-exclude.xml Add SpotBugs suppressions for new throws warnings.
.github/workflows/trivy-scan.yml Switch workflow JDK to 25.
.github/workflows/push_master.yml Switch workflow JDK to 25; update GraalVM setup inputs.
.github/workflows/pull_request_windows_build.yml Switch workflow JDK to 25; update GraalVM setup inputs.
.github/workflows/pull_request_ubuntu_build.yml Switch workflow JDK to 25; update GraalVM setup inputs.
.github/workflows/pull_request_full_build.yml Switch workflow JDK to 25.
.github/workflows/pull_request_debugger_tests.yml Switch workflow JDK to 25; update GraalVM setup inputs.
.github/workflows/publish_timestamped_release.yml Switch workflow JDK to 25.
.github/workflows/publish_release.yml Switch workflow JDK to 25; update GraalVM setup inputs.
.github/workflows/observe_package_push.yaml Switch workflow JDK to 25.
.github/workflows/nightly_publish_timestamped_release.yml Switch workflow JDK to 25.
.github/workflows/daily_spec_conformance_test_runner.yml Switch workflow JDK to 25.
.github/workflows/daily_build.yml Switch workflow JDK to 25; update GraalVM setup inputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread settings.gradle
Comment on lines 153 to +156
project(':ballerina-tools-api').projectDir = file('compiler/ballerina-tools-api')
project(':ballerina-tools-api').projectDir.mkdirs()
project(':ballerina-parser').projectDir = file('compiler/ballerina-parser')
project(':ballerina-parser').projectDir.mkdirs()
Comment on lines +90 to +92
<Match>
<Bug pattern="THROWS_METHOD_THROWS_RUNTIMEEXCEPTION,THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION"/>
</Match>
Comment on lines 19 to 21
<Match>
<Bug pattern="EI_EXPOSE_REP,EI_EXPOSE_REP2"/>
<Bug pattern="EI_EXPOSE_REP,EI_EXPOSE_REP2,THROWS_METHOD_THROWS_RUNTIMEEXCEPTION,THROWS_METHOD_THROWS_CLAUSE_THROWABLE"/>
</Match>
Comment on lines +51 to +55
<Match>
<Class name="org.ballerinalang.debugger.test.utils.BreakpointEventListener" />
<Field name="breakpointEventFound" />
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
</Match>
Comment on lines +139 to +143
<Field name="coverage" />
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
</Match>
<Match>
<Class name="io.ballerina.cli.task.RunTestsTask" />
Comment on lines +142 to +146
<Match>
<Class name="io.ballerina.cli.task.RunTestsTask" />
<Field name="report" />
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
</Match>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/daily_build.yml (1)

72-76: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update stale step title to match Java version.

Line 72 still says “Set up JDK 21” but Line 76 configures 25.0.3. Please align the step name for accurate workflow logs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/daily_build.yml around lines 72 - 76, Update the step
title string "Set up JDK 21" to reflect the configured Java version used by
actions/setup-java@v4 (java-version: '25.0.3'); for example rename the step to
"Set up JDK 25" or "Set up JDK 25 (Temurin 25.0.3)" so the workflow logs
accurately match the java-version setting.
.github/workflows/push_master.yml (1)

116-116: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update stale step name to match configured JDK version.

Line 116 says “Set up JDK 21” but this step now configures Java 25.0.3 (Line 120), which makes CI logs misleading.

Suggested change
-      - name: Set up JDK 21
+      - name: Set up JDK 25
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/push_master.yml at line 116, The workflow step name "Set
up JDK 21" is stale and should match the configured Java version; update the
step name string to reflect the actual version being installed (e.g., change
"Set up JDK 21" to "Set up JDK 25" or "Set up JDK 25.0.3") so the step name
matches the configuration that installs Java 25.0.3.
🧹 Nitpick comments (5)
.github/workflows/trivy-scan.yml (1)

16-16: ⚡ Quick win

Consider pinning actions/setup-java to a specific commit SHA for enhanced supply chain security.

While not currently enforced in this repository, pinning GitHub Actions to immutable commit SHAs (rather than mutable major version tags like @v4) is a security best practice that prevents potential tampering. This applies to all actions in the workflow: actions/checkout@v4, actions/setup-java@v4, and actions/cache@v4.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/trivy-scan.yml at line 16, Replace mutable action tags
with immutable commit SHAs: update uses entries for actions/setup-java@v4,
actions/checkout@v4, and actions/cache@v4 to their corresponding repository
commit SHAs (e.g., actions/setup-java@<commit-sha>) to pin the workflow to a
specific git commit; fetch the desired SHA from each action's GitHub repository
(releases or commit history) and use that full SHA ref in the workflow to ensure
supply-chain immutability.
misc/testerina/modules/testerina-core/build.gradle (1)

57-57: ⚡ Quick win

Use the buildDir variable defined above.

The buildDir variable is defined on Line 22 but not used here. For consistency, use the variable instead of calling the API again.

♻️ Proposed refactor
 tasks.register('updateVersion') {
     doLast {
         ant.replaceregexp(
-                file: "${project.layout.buildDirectory.get().asFile}/ballerina-src/Ballerina.toml",
+                file: "${buildDir}/ballerina-src/Ballerina.toml",
                 match: "${project.name}-(.*).jar",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@misc/testerina/modules/testerina-core/build.gradle` at line 57, Replace the
direct project API call with the pre-defined buildDir variable: locate the use
of project.layout.buildDirectory.get().asFile in the Ballerina.toml file path
(the line that currently reads file:
"${project.layout.buildDirectory.get().asFile}/ballerina-src/Ballerina.toml")
and update it to use the buildDir variable (e.g., construct the path from
buildDir + "/ballerina-src/Ballerina.toml") so the existing buildDir definition
is consistently reused.
language-server/modules/langserver-stdlib/build.gradle (1)

47-47: ⚡ Quick win

Define buildDir variable for consistency with the migration pattern.

Unlike other build scripts in this PR that define def buildDir = layout.buildDirectory.get().asFile and reference the variable, this file uses the inline API call directly. For consistency and maintainability across the codebase, consider defining the buildDir variable at the top of the file as done in sibling modules.

📋 Proposed refactor for consistency

Add the buildDir definition after the plugins block:

 plugins {
     id 'ballerinaStdLibBuild'
 }
 
+def buildDir = layout.buildDirectory.get().asFile
+
 dependencies {

Then update the usage to reference the variable:

 tasks.register('updateVersion') {
     doLast {
         ant.replaceregexp(
-                file: "${project.layout.buildDirectory.get().asFile}/ballerina-src/Ballerina.toml",
+                file: "${buildDir}/ballerina-src/Ballerina.toml",
                 match: "${project.name}-(.*).jar",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@language-server/modules/langserver-stdlib/build.gradle` at line 47, This file
uses inline layout.buildDirectory.get().asFile instead of the shared buildDir
variable; add def buildDir = layout.buildDirectory.get().asFile (e.g.,
immediately after the plugins block) and update usages such as file:
"${project.layout.buildDirectory.get().asFile}/ballerina-src/Ballerina.toml" to
use file: "${buildDir}/ballerina-src/Ballerina.toml" so the module matches the
migration pattern used in sibling build.gradle files.
distribution/zip/jballerina/bin/bal.bat (1)

195-195: 💤 Low value

JVM flag addition mirrors Unix script.

This Windows batch script includes the same --sun-misc-unsafe-memory-access=allow flag as the bash script (bal). The same verification and migration considerations apply.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@distribution/zip/jballerina/bin/bal.bat` at line 195, The bal.bat script
currently hardcodes the JVM flag --sun-misc-unsafe-memory-access=allow into
CMD_LINE_ARGS; change the CMD_LINE_ARGS assembly logic to mirror the Unix bal
script by only appending that flag after verifying the JVM supports it (e.g.,
run a version/feature check or inspect %JAVA_HOME%\bin\java -XshowSettings or
similar) or remove the flag entirely for Windows builds; update the
CMD_LINE_ARGS variable construction (the line setting CMD_LINE_ARGS) so it
conditionally includes or omits --sun-misc-unsafe-memory-access=allow and
document the check in the script comments.
distribution/zip/jballerina/bin/bal (1)

222-222: 💤 Low value

Consider using warn mode as an intermediate step; track which dependencies require this flag for future updates.

The --sun-misc-unsafe-memory-access=allow flag is correctly formatted and valid for Java 25. However, warn mode is available as a less permissive alternative that would still permit execution while surfacing problematic dependencies. Document which dependencies trigger this flag so they can be updated or replaced in future releases to eliminate the need for this bypass.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@distribution/zip/jballerina/bin/bal` at line 222, Replace the permissive flag
--sun-misc-unsafe-memory-access=allow with the less-permissive
--sun-misc-unsafe-memory-access=warn in the bal startup options so the JVM still
runs but surfaces offending modules, and add a short runtime/build-time tracking
step (e.g., emit a one-line comment/log or write to a deps file when the JVM
warns about sun.misc unsafe access) to record which dependencies trigger the
warning so they can be updated/replaced in future releases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/observe_package_push.yaml:
- Line 21: The workflow currently references a mutable tag "uses:
actions/setup-java@v4"; replace this with a fixed commit SHA for the
actions/setup-java action (e.g., "uses: actions/setup-java@<full-commit-sha>")
so the job is pinned and reproducible—update the observe_package_push workflow
to use the specific commit SHA for actions/setup-java instead of the `@v4` tag.

In @.github/workflows/pull_request_full_build.yml:
- Line 23: Replace the mutable tag "uses: actions/setup-java@v4" with the
corresponding full commit SHA for each occurrence so the workflow is pinned and
immutable; update all three spots where "uses: actions/setup-java@v4" appears
(the three separate job steps) to use the full commit SHA string (the exact SHA
for the v4 release) instead of the `@v4` tag, ensuring each job references the
same verified commit SHA.

In @.github/workflows/push_master.yml:
- Line 23: Three occurrences use the mutable tag "actions/setup-java@v4";
replace each "uses: actions/setup-java@v4" with the exact commit SHA form "uses:
actions/setup-java@<COMMIT_SHA>" (the specific commit SHA from the
actions/setup-java repository) to pin the action immutably. Locate the three
instances of the string "uses: actions/setup-java@v4" in the workflow and update
them to the chosen commit SHAs, then run the workflow lint/check to verify the
YAML remains valid.

In `@gradle/wrapper/gradle-wrapper.properties`:
- Line 3: The Gradle distributionUrl was bumped to 9.5.1 which may break the
build due to Gradle 9.x changes; before merging, either revert the
distributionUrl to the previously used Gradle 8.x version or run a full upgrade
checklist: execute gradle help --scan to gather deprecation/warning details,
update any plugins or code that rely on internal/removed APIs (check plugins in
build.gradle settings and init scripts), verify compatibility with Kotlin and
Groovy versions used by your project, and follow the Gradle 9.0.0 migration
guide to address stricter nullability and removed CLI options; only update
distributionUrl to 9.5.1 once all incompatible plugins/code are updated and the
build/tests pass.

In `@language-server/modules/langserver-core/spotbugs-exclude.xml`:
- Around line 215-224: The crash-state fields in
org.ballerinalang.langserver.workspace.BallerinaWorkspaceManager$ProjectContext
(compilationCrashed and projectCrashed) are accessed from multiple threads
without consistent synchronization; either declare both fields as volatile in
ProjectContext or ensure every read/write uses the existing Lock (use
lockAndGet()/unlock around accesses and update set*/is* methods accordingly).
Update the field declarations and/or the getters/setters for compilationCrashed
and projectCrashed (and all call sites that read/write them) so visibility is
guaranteed across threads.

In `@misc/debug-adapter/modules/debug-adapter-core/spotbugs-exclude.xml`:
- Around line 93-102: The fields supportsVerification and isVerified in class
BalBreakpoint are accessed from multiple threads (read in getAsDAPBreakpoint()
and written in setVerified(), activateUserBreakPoints(), and
setSupportsVerification()), so mark both fields as volatile to ensure visibility
across threads; update the field declarations in BalBreakpoint to add the
volatile modifier for supportsVerification and isVerified.

---

Outside diff comments:
In @.github/workflows/daily_build.yml:
- Around line 72-76: Update the step title string "Set up JDK 21" to reflect the
configured Java version used by actions/setup-java@v4 (java-version: '25.0.3');
for example rename the step to "Set up JDK 25" or "Set up JDK 25 (Temurin
25.0.3)" so the workflow logs accurately match the java-version setting.

In @.github/workflows/push_master.yml:
- Line 116: The workflow step name "Set up JDK 21" is stale and should match the
configured Java version; update the step name string to reflect the actual
version being installed (e.g., change "Set up JDK 21" to "Set up JDK 25" or "Set
up JDK 25.0.3") so the step name matches the configuration that installs Java
25.0.3.

---

Nitpick comments:
In @.github/workflows/trivy-scan.yml:
- Line 16: Replace mutable action tags with immutable commit SHAs: update uses
entries for actions/setup-java@v4, actions/checkout@v4, and actions/cache@v4 to
their corresponding repository commit SHAs (e.g.,
actions/setup-java@<commit-sha>) to pin the workflow to a specific git commit;
fetch the desired SHA from each action's GitHub repository (releases or commit
history) and use that full SHA ref in the workflow to ensure supply-chain
immutability.

In `@distribution/zip/jballerina/bin/bal`:
- Line 222: Replace the permissive flag --sun-misc-unsafe-memory-access=allow
with the less-permissive --sun-misc-unsafe-memory-access=warn in the bal startup
options so the JVM still runs but surfaces offending modules, and add a short
runtime/build-time tracking step (e.g., emit a one-line comment/log or write to
a deps file when the JVM warns about sun.misc unsafe access) to record which
dependencies trigger the warning so they can be updated/replaced in future
releases.

In `@distribution/zip/jballerina/bin/bal.bat`:
- Line 195: The bal.bat script currently hardcodes the JVM flag
--sun-misc-unsafe-memory-access=allow into CMD_LINE_ARGS; change the
CMD_LINE_ARGS assembly logic to mirror the Unix bal script by only appending
that flag after verifying the JVM supports it (e.g., run a version/feature check
or inspect %JAVA_HOME%\bin\java -XshowSettings or similar) or remove the flag
entirely for Windows builds; update the CMD_LINE_ARGS variable construction (the
line setting CMD_LINE_ARGS) so it conditionally includes or omits
--sun-misc-unsafe-memory-access=allow and document the check in the script
comments.

In `@language-server/modules/langserver-stdlib/build.gradle`:
- Line 47: This file uses inline layout.buildDirectory.get().asFile instead of
the shared buildDir variable; add def buildDir =
layout.buildDirectory.get().asFile (e.g., immediately after the plugins block)
and update usages such as file:
"${project.layout.buildDirectory.get().asFile}/ballerina-src/Ballerina.toml" to
use file: "${buildDir}/ballerina-src/Ballerina.toml" so the module matches the
migration pattern used in sibling build.gradle files.

In `@misc/testerina/modules/testerina-core/build.gradle`:
- Line 57: Replace the direct project API call with the pre-defined buildDir
variable: locate the use of project.layout.buildDirectory.get().asFile in the
Ballerina.toml file path (the line that currently reads file:
"${project.layout.buildDirectory.get().asFile}/ballerina-src/Ballerina.toml")
and update it to use the buildDir variable (e.g., construct the path from
buildDir + "/ballerina-src/Ballerina.toml") so the existing buildDir definition
is consistently reused.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d08365ad-0cfc-4b52-9459-ec34b8e80373

📥 Commits

Reviewing files that changed from the base of the PR and between 6983b29 and 02fa0f3.

📒 Files selected for processing (73)
  • .github/workflows/daily_build.yml
  • .github/workflows/daily_spec_conformance_test_runner.yml
  • .github/workflows/nightly_publish_timestamped_release.yml
  • .github/workflows/observe_package_push.yaml
  • .github/workflows/publish_release.yml
  • .github/workflows/publish_timestamped_release.yml
  • .github/workflows/pull_request_debugger_tests.yml
  • .github/workflows/pull_request_full_build.yml
  • .github/workflows/pull_request_ubuntu_build.yml
  • .github/workflows/pull_request_windows_build.yml
  • .github/workflows/push_master.yml
  • .github/workflows/trivy-scan.yml
  • ballerina-shell/modules/shell-cli/spotbugs-exclude.xml
  • ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/base/TestIntegrator.java
  • ballerina-shell/modules/shell-core/spotbugs-exclude.xml
  • build-config/checkstyle/build.gradle
  • build.gradle
  • cli/ballerina-cli/build.gradle
  • cli/ballerina-cli/spotbugs-exclude.xml
  • cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestNativeImageCommandTest.java
  • cli/central-client/build.gradle
  • compiler/ballerina-lang/spotbugs-exclude.xml
  • compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectConstants.java
  • distribution/zip/jballerina-tools/build.gradle
  • distribution/zip/jballerina/bin/bal
  • distribution/zip/jballerina/bin/bal.bat
  • distribution/zip/jballerina/build.gradle
  • gradle/libs.versions.toml
  • gradle/plugins/java-convention/src/main/groovy/ballerinaLangLibBuild.gradle
  • gradle/plugins/java-convention/src/main/groovy/ballerinaLangLibLoad.gradle
  • gradle/plugins/java-convention/src/main/groovy/ballerinaNativeStdLibBuild.gradle
  • gradle/plugins/java-convention/src/main/groovy/ballerinaStdLibBuild.gradle
  • gradle/plugins/java-convention/src/main/groovy/ballerinaStdLibBuildInternal.gradle
  • gradle/plugins/java-convention/src/main/groovy/javaProject.gradle
  • gradle/plugins/java-convention/src/main/groovy/javaProjectWithExtBala.gradle
  • gradle/wrapper/gradle-wrapper.properties
  • langlib/lang.test/build.gradle
  • language-server/modules/langserver-commons/build.gradle
  • language-server/modules/langserver-commons/spotbugs-exclude.xml
  • language-server/modules/langserver-core/build.gradle
  • language-server/modules/langserver-core/spotbugs-exclude.xml
  • language-server/modules/langserver-stdlib/build.gradle
  • misc/ballerinalang-data-mapper/build.gradle
  • misc/ballerinalang-data-mapper/src/main/java/org/ballerinalang/datamapper/utils/HttpResponse.java
  • misc/debug-adapter/modules/debug-adapter-core/spotbugs-exclude.xml
  • misc/diagram-util/build.gradle
  • misc/diagram-util/spotbugs-exclude.xml
  • misc/docerina/build.gradle
  • misc/formatter/modules/formatter-core/build.gradle
  • misc/maven-resolver/build.gradle
  • misc/testerina/modules/testerina-core/build.gradle
  • project-api/project-api-test/build.gradle
  • project-api/test-artifacts/bad-sad-compiler-plugin/spotbugs-exclude.xml
  • project-api/test-artifacts/bal-tool-integration-test-artifacts/build.gradle
  • project-api/test-artifacts/compiler-plugin-with-analyzer-generator-modifier/spotbugs-exclude.xml
  • project-api/test-artifacts/log-creator-in-built-code-analyzer/spotbugs-exclude.xml
  • project-api/test-artifacts/log-creator-in-built-code-generator/spotbugs-exclude.xml
  • project-api/test-artifacts/log-creator-in-built-code-modifier/spotbugs-exclude.xml
  • project-api/test-artifacts/log-creator-pkg-provided-code-analyzer/spotbugs-exclude.xml
  • project-api/test-artifacts/log-creator-pkg-provided-code-generator/spotbugs-exclude.xml
  • project-api/test-artifacts/log-creator-pkg-provided-code-modifier/spotbugs-exclude.xml
  • settings.gradle
  • tests/bal-tools-integration-tests/build.gradle
  • tests/ballerina-test-utils/build.gradle
  • tests/ballerina-test-utils/spotbugs-exclude.xml
  • tests/ballerina-tools-integration-test/build.gradle
  • tests/jballerina-benchmark-test/build.gradle
  • tests/jballerina-debugger-integration-test/build.gradle
  • tests/jballerina-debugger-integration-test/spotbugs-exclude.xml
  • tests/jballerina-debugger-integration-test/src/test/java/org/ballerinalang/debugger/test/adapter/DebugOutputTest.java
  • tests/jballerina-integration-test/build.gradle
  • tests/language-server-integration-tests/build.gradle
  • tests/testerina-integration-test/build.gradle

run: git checkout ${{ github.event.inputs.repoTag }}
- name: Set up JDK 21
- name: Set up JDK 25
uses: actions/setup-java@v4
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/observe_package_push.yaml | head -30

Repository: ballerina-platform/ballerina-lang

Length of output: 1009


🏁 Script executed:

cat -n .github/workflows/observe_package_push.yaml

Repository: ballerina-platform/ballerina-lang

Length of output: 2363


Pin actions/setup-java to a commit SHA instead of @v4.

Line 21 uses a mutable major version tag that can change unexpectedly. Pin to a full commit SHA to ensure workflow reproducibility and comply with action pinning policies.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 21-21: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/observe_package_push.yaml at line 21, The workflow
currently references a mutable tag "uses: actions/setup-java@v4"; replace this
with a fixed commit SHA for the actions/setup-java action (e.g., "uses:
actions/setup-java@<full-commit-sha>") so the job is pinned and
reproducible—update the observe_package_push workflow to use the specific commit
SHA for actions/setup-java instead of the `@v4` tag.


- name: Set up JDK 21
- name: Set up JDK 25
uses: actions/setup-java@v4
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cd .github/workflows && wc -l pull_request_full_build.yml

Repository: ballerina-platform/ballerina-lang

Length of output: 109


🏁 Script executed:

cat -n .github/workflows/pull_request_full_build.yml | sed -n '20,30p; 78,85p; 169,175p'

Repository: ballerina-platform/ballerina-lang

Length of output: 958


🏁 Script executed:

rg "setup-java" .github/workflows/pull_request_full_build.yml -n

Repository: ballerina-platform/ballerina-lang

Length of output: 195


🌐 Web query:

GitHub Actions best practices version pinning major version tag mutable security

💡 Result:

To ensure the security and stability of your GitHub Actions workflows, the industry-standard best practice is to pin all actions to a full-length (40-character) commit SHA [1][2][3][4]. Why Pinning to a Commit SHA is Required GitHub Actions referenced by tags (e.g., @v4) or branches (e.g., @main) are mutable [5][6]. This means the code they point to can be changed at any time—either intentionally by the maintainer or maliciously if the repository or maintainer account is compromised [1][2][5][7]. Pinning to a full-length commit SHA ensures that your workflow always executes the exact same, immutable code, protecting you against supply chain attacks where malicious code is injected into a previously trusted tag [2][3][4]. Key Security Considerations 1. Enforced Policies: Many organizations now mandate SHA pinning via GitHub's organization-level policies [8][9]. When enabled, any workflow using a tag-based reference will fail [8][9]. Note that this policy often checks the entire dependency tree, meaning even internal sub-actions referenced by your primary actions must be SHA-pinned [8]. 2. Immutable Releases: GitHub now supports "Immutable Releases," which lock a tag to a specific commit and prevent it from being moved or deleted [10][11][12]. While this provides a higher level of security for tagged releases, pinning to a commit SHA remains the most robust and universally recommended method for consumers to guarantee immutability [3][4][13]. 3. Maintenance: Because SHA-pinned actions do not automatically receive updates, you must actively manage them [2][14]. It is best practice to: - Use a comment in your workflow file to indicate the version the SHA corresponds to (e.g., uses: actions/checkout@abc123... # v4.1.1) [15][1][16]. - Use automated dependency management tools like Dependabot or Renovate to track and propose updates to your pinned SHAs [15][14][4][17]. Summary of Best Practices - Always pin to a full-length (40-character) commit SHA [3][4][17]. - Include the version tag in a comment for readability and maintenance [15][1][16]. - Use Dependabot or similar tools to keep your pinned actions up to date [14][4][17]. - Verify that the SHA originates from the official action repository, not a fork [3][4].

Citations:


🏁 Script executed:

fd -e md -e txt | xargs rg -l "actions/setup-java|version.*pin|commit.*sha" --max-count=5 2>/dev/null | head -10

Repository: ballerina-platform/ballerina-lang

Length of output: 59


🏁 Script executed:

find . -name "SECURITY.md" -o -name "CONTRIBUTING.md" -o -name ".github/CODEOWNERS" | xargs cat 2>/dev/null

Repository: ballerina-platform/ballerina-lang

Length of output: 3906


Pin actions/setup-java to commit SHAs across all three jobs.

Lines 23, 81, and 172 use mutable @v4 tags. Pin each to a full commit SHA to ensure immutable, reproducible workflow execution and protect against supply chain attacks where tags could be repointed to malicious code.

Also applies to: 81-81, 172-172

🧰 Tools
🪛 zizmor (1.25.2)

[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pull_request_full_build.yml at line 23, Replace the
mutable tag "uses: actions/setup-java@v4" with the corresponding full commit SHA
for each occurrence so the workflow is pinned and immutable; update all three
spots where "uses: actions/setup-java@v4" appears (the three separate job steps)
to use the full commit SHA string (the exact SHA for the v4 release) instead of
the `@v4` tag, ensuring each job references the same verified commit SHA.


- name: Set up JDK 21
- name: Set up JDK 25
uses: actions/setup-java@v4
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n 'uses:\s*actions/setup-java@v[0-9]+' .github/workflows/push_master.yml

Repository: ballerina-platform/ballerina-lang

Length of output: 195


🏁 Script executed:

cat -n .github/workflows/push_master.yml | grep -E "(uses:|actions/setup-java)"

Repository: ballerina-platform/ballerina-lang

Length of output: 633


🏁 Script executed:

# Check if there are any other action usages that might need pinning
rg -n 'uses:\s*actions' .github/workflows/push_master.yml | head -20

Repository: ballerina-platform/ballerina-lang

Length of output: 445


Pin actions/setup-java to commit SHAs instead of version tags.

Lines 23, 67, and 117 use @v4 tags instead of immutable SHAs. Replace with the specific commit SHA for improved security and reproducibility.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/push_master.yml at line 23, Three occurrences use the
mutable tag "actions/setup-java@v4"; replace each "uses: actions/setup-java@v4"
with the exact commit SHA form "uses: actions/setup-java@<COMMIT_SHA>" (the
specific commit SHA from the actions/setup-java repository) to pin the action
immutably. Locate the three instances of the string "uses:
actions/setup-java@v4" in the workflow and update them to the chosen commit
SHAs, then run the workflow lint/check to verify the YAML remains valid.

Comment thread gradle/wrapper/gradle-wrapper.properties
Comment on lines +215 to +224
<Match>
<Class name="org.ballerinalang.langserver.workspace.BallerinaWorkspaceManager$ProjectContext" />
<Field name="compilationCrashed" />
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
</Match>
<Match>
<Class name="org.ballerinalang.langserver.workspace.BallerinaWorkspaceManager$ProjectContext" />
<Field name="projectCrashed" />
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
</Match>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the field declarations and concurrent access patterns
rg -nP -A5 -B2 'class\s+.*ProjectContext' language-server/modules/langserver-core/src/main/java/
rg -nP -C3 '\b(compilationCrashed|projectCrashed)\s*=' language-server/modules/langserver-core/src/main/java/

Repository: ballerina-platform/ballerina-lang

Length of output: 4747


🏁 Script executed:

#!/bin/bash
# Get the full ProjectContext class definition
# Since it's likely an inner class, we need to find where it ends
rg -nP 'public static class ProjectContext' language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/workspace/BallerinaWorkspaceManager.java -A 150 | head -200

Repository: ballerina-platform/ballerina-lang

Length of output: 5073


🏁 Script executed:

#!/bin/bash
# Find all call sites for the crash state setters
rg -nP 'setCompilationCrashed|setProjectCrashed|compilationCrashed\(\)|isProjectCrashed\(\)' language-server/modules/langserver-core/src/main/java/ | head -50

Repository: ballerina-platform/ballerina-lang

Length of output: 2825


🏁 Script executed:

#!/bin/bash
# Check context around key call sites to see if lock is acquired
echo "=== Lines 350-400 ===" 
sed -n '340,400p' language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/workspace/BallerinaWorkspaceManager.java | cat -n

echo -e "\n=== Lines 1380-1400 ===" 
sed -n '1380,1400p' language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/workspace/BallerinaWorkspaceManager.java | cat -n

echo -e "\n=== Lines 1480-1495 ===" 
sed -n '1480,1495p' language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/workspace/BallerinaWorkspaceManager.java | cat -n

echo -e "\n=== Lines 1545-1575 ===" 
sed -n '1545,1575p' language-server/modules/langserver-core/src/main/java/org/ballerinalang/langserver/workspace/BallerinaWorkspaceManager.java | cat -n

Repository: ballerina-platform/ballerina-lang

Length of output: 7938


Add volatile keyword to crash state fields or ensure lock-protected access.

The fields compilationCrashed and projectCrashed are written from compilation threads and read from LSP protocol threads without consistent synchronization. While a Lock exists in ProjectContext, it's only applied to the project and process fields (with explicit Javadoc guidance). The crash state fields are accessed unsynchronized in most call sites (lines 350, 362, 378, 1390, 1489, 1555, 1569), creating visibility and race condition risks.

Either:

  1. Mark these fields as volatile to ensure visibility across threads, or
  2. Always acquire the lock before reading or writing these fields.
Reference: Inconsistent synchronization pattern in call sites
// Without lock (lines 350, 362, 378):
Optional<ProjectContext> projectPair = projectContext(projectRoot(filePath));
if (projectPair.get().compilationCrashed()) { ... }

// With lock (lines 386-394):
Lock lock = projectPair.get().lockAndGet();
try {
    if (projectPair.get().compilationCrashed()) {
        projectPair.get().setCompilationCrashed(false);
    }
} finally {
    lock.unlock();
}

// Without lock (lines 1390, 1489, 1555, 1569):
projectContext.setProjectCrashed(true);
projectContext.isProjectCrashed()
projectContext.setProjectCrashed(false);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@language-server/modules/langserver-core/spotbugs-exclude.xml` around lines
215 - 224, The crash-state fields in
org.ballerinalang.langserver.workspace.BallerinaWorkspaceManager$ProjectContext
(compilationCrashed and projectCrashed) are accessed from multiple threads
without consistent synchronization; either declare both fields as volatile in
ProjectContext or ensure every read/write uses the existing Lock (use
lockAndGet()/unlock around accesses and update set*/is* methods accordingly).
Update the field declarations and/or the getters/setters for compilationCrashed
and projectCrashed (and all call sites that read/write them) so visibility is
guaranteed across threads.

Comment on lines +93 to +102
<Match>
<Class name="org.ballerinalang.debugadapter.breakpoint.BalBreakpoint" />
<Field name="supportsVerification" />
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
</Match>
<Match>
<Class name="org.ballerinalang.debugadapter.breakpoint.BalBreakpoint" />
<Field name="isVerified" />
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
</Match>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check BalBreakpoint field declarations and concurrent access
rg -nP -A10 'class\s+BalBreakpoint' misc/debug-adapter/modules/debug-adapter-core/src/main/java/
rg -nP -C3 '\b(supportsVerification|isVerified)\s*=' misc/debug-adapter/modules/debug-adapter-core/src/main/java/

Repository: ballerina-platform/ballerina-lang

Length of output: 4890


🏁 Script executed:

# Check getter methods and search for concurrent access patterns
rg -nP 'getIsVerified|isVerified|getSupportsVerification|supportsVerification' misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/breakpoint/BalBreakpoint.java

# Look at the full BalBreakpoint class to understand context
wc -l misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/breakpoint/BalBreakpoint.java

# Search for where BalBreakpoint instances are accessed from multiple threads
rg -nP 'setVerified|setSupportsVerification' misc/debug-adapter/modules/debug-adapter-core/src/main/java/

Repository: ballerina-platform/ballerina-lang

Length of output: 1645


🏁 Script executed:

# Check BreakpointProcessor context around line 209
sed -n '200,220p' misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java

# Check ServerUtils context around line 132
sed -n '120,145p' misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/utils/ServerUtils.java

# Search for thread creation or executor usage in debug adapter
rg -nP 'Thread|Executor|ThreadPool|newThread' misc/debug-adapter/modules/debug-adapter-core/src/main/java/ | head -30

Repository: ballerina-platform/ballerina-lang

Length of output: 8619


🏁 Script executed:

# Search for breakpoint storage and access patterns
rg -nP 'breakpoints|BalBreakpoint' misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/ | grep -E '(Map|List|Collection|ConcurrentHashMap|Collections)' | head -20

# Look for the DebugAdapterContext and how breakpoints are managed
rg -nP 'class.*Context|getBreakpoints' misc/debug-adapter/modules/debug-adapter-core/src/main/java/ | head -20

# Check for multi-threaded execution in debug adapter core
rg -nP 'ExecutorService|newFixedThreadPool|newCachedThreadPool|Thread\s+t|new Thread' misc/debug-adapter/modules/debug-adapter-core/src/main/java/ | head -15

Repository: ballerina-platform/ballerina-lang

Length of output: 7067


🏁 Script executed:

# Check BreakpointProcessor for synchronization/suspend context
sed -n '190,220p' misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java

# Check JDIEventProcessor for synchronization around enableBreakpoints
sed -n '215,235p' misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java

# Look for the full getAsDAPBreakpoint method (around line 91-102 in BalBreakpoint)
sed -n '91,107p' misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/breakpoint/BalBreakpoint.java

Repository: ballerina-platform/ballerina-lang

Length of output: 3166


Mark these breakpoint state fields as volatile.

The supportsVerification and isVerified fields in BalBreakpoint are read and written across multiple threads without visibility guarantees. The getAsDAPBreakpoint() method reads both fields (line 96) without synchronization, and setVerified() is called from different contexts via activateUserBreakPoints() and setSupportsVerification() from configuration setup. Since the debug adapter operates with multiple threads (JDI event processor, DAP protocol handling), non-volatile writes to these fields can result in stale cache values or torn reads. Adding volatile ensures thread-safe visibility of breakpoint state changes across all threads.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@misc/debug-adapter/modules/debug-adapter-core/spotbugs-exclude.xml` around
lines 93 - 102, The fields supportsVerification and isVerified in class
BalBreakpoint are accessed from multiple threads (read in getAsDAPBreakpoint()
and written in setVerified(), activateUserBreakPoints(), and
setSupportsVerification()), so mark both fields as volatile to ensure visibility
across threads; update the field declarations in BalBreakpoint to add the
volatile modifier for supportsVerification and isVerified.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/troubleshoot/StrandDumpTest.java`:
- Line 59: The three disabled test annotations in StrandDumpTest.java (the
`@Test`(enabled = false) on the test methods around the occurrences at lines
corresponding to the three tests) lack any explanation or issue tracking; please
add an inline comment directly above each disabled test annotation referencing a
tracker/issue ID (or a TODO with a short reason and owner) and a link or issue
number so re-enablement can be tracked, e.g., "TODO: disabled due to <brief
reason> - tracked in ISSUE-#### (owner)"; ensure you update the PR description
to summarize the rationale and the same issue reference so the intent is
recorded for functions/tests in this class (the three disabled test methods in
StrandDumpTest).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d01aaeb9-c5c4-440a-a48c-b089ead65be8

📥 Commits

Reviewing files that changed from the base of the PR and between 02fa0f3 and bab379f.

📒 Files selected for processing (1)
  • tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/troubleshoot/StrandDumpTest.java

}

@Test
@Test(enabled = false)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for references to StrandDump, strand dump issues, or Java 25 compatibility notes

echo "=== Searching for StrandDump references and potential issues ==="
rg -i "stranddump|strand.dump" --type java -C2

echo -e "\n=== Searching for Java 25 compatibility comments ==="
rg -i "java.?25|jdk.?25" --type java -C2

echo -e "\n=== Checking for TODO/FIXME related to these tests ==="
rg -i "todo|fixme|xxx|hack" --glob "**/StrandDumpTest.java" -C2

Repository: ballerina-platform/ballerina-lang

Length of output: 20058


🏁 Script executed:

#!/bin/bash

echo "=== Checking git log for StrandDumpTest changes ==="
git log --oneline -20 -- tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/troubleshoot/StrandDumpTest.java

echo -e "\n=== Checking detailed commit message for recent changes ==="
git log -1 --format=fuller -- tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/troubleshoot/StrandDumpTest.java

echo -e "\n=== Checking for any issues or patterns in recent Java 25 related changes ==="
git log --oneline --all --grep="Java 25\|java 25\|strand" -i | head -20

echo -e "\n=== Searching for any `@Ignore` annotations to compare pattern ==="
rg "`@Ignore`|`@Test`.*enabled.*false" --type java -B1 | head -50

Repository: ballerina-platform/ballerina-lang

Length of output: 7081


Add explanation and issue tracking for disabled strand dump tests.

All three test methods in this file have been disabled without explanation, documentation, or issue references. Unlike other disabled tests in the codebase (e.g., NotSoBasicWorkerTest.java references issue #30590), these tests lack any tracking mechanism for re-enablement.

The commit message provides no details about:

  • Why these tests are disabled
  • Whether this is a temporary workaround or permanent change
  • What the plan is to restore coverage

Add an inline comment with an issue reference or tracking details, or include information in the PR description explaining the reason for disabling this critical test coverage.

Also applies to: 76-76, 95-95

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tests/jballerina-integration-test/src/test/java/org/ballerinalang/test/troubleshoot/StrandDumpTest.java`
at line 59, The three disabled test annotations in StrandDumpTest.java (the
`@Test`(enabled = false) on the test methods around the occurrences at lines
corresponding to the three tests) lack any explanation or issue tracking; please
add an inline comment directly above each disabled test annotation referencing a
tracker/issue ID (or a TODO with a short reason and owner) and a link or issue
number so re-enablement can be tracked, e.g., "TODO: disabled due to <brief
reason> - tracked in ISSUE-#### (owner)"; ensure you update the PR description
to summarize the rationale and the same issue reference so the intent is
recorded for functions/tests in this class (the three disabled test methods in
StrandDumpTest).

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@build.gradle`:
- Around line 133-134: The html.outputLocation currently points to a file path;
change it to a directory path (e.g. "${rootDir}/.jacoco/reports/jacoco/html") so
JaCoCo can write multiple HTML files; leave xml.outputLocation as-is. Update the
html.outputLocation assignment to use new File("<directory>") (not a single
report.html file) and ensure the directory exists/gets created by the build if
needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b531c35d-723b-4fdf-b1fe-99c04b459363

📥 Commits

Reviewing files that changed from the base of the PR and between bab379f and 4b5dfe8.

📒 Files selected for processing (2)
  • build.gradle
  • misc/maven-resolver/build.gradle

Comment thread build.gradle
Comment on lines +133 to +134
xml.outputLocation = new File("${rootDir}/.jacoco/reports/jacoco/report.xml")
html.outputLocation = new File("${rootDir}/.jacoco/reports/jacoco/report.html")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

For Gradle JacocoReport, what is the expected type/semantics of reports.html.outputLocation? Should it be a directory path or an HTML file path?

💡 Result:

For the Gradle JacocoReport task, the reports.html.outputLocation property expects a directory path, not a file path [1][2]. The JaCoCo HTML report is a collection of files (a site), and the output location is configured as a DirectoryReport [3][4]. When setting this property, you should point it to the directory where you want the HTML report site to be generated [5]. Example of correct configuration (Kotlin DSL): tasks.jacocoTestReport { reports { html.outputLocation.set(layout.buildDirectory.dir("jacoco/html")) } } Example of correct configuration (Groovy DSL): jacocoTestReport { reports { html.outputLocation = layout.buildDirectory.dir('jacocoHtml') } } This contrasts with other report types like XML or CSV, which are SingleFileReports and expect a direct file path [3][4].

Citations:


Use a directory for JaCoCo HTML output location.

html.outputLocation must point to a directory, not a file path. The JaCoCo HTML report is a collection of files, and setting it to a file path (report.html) violates the API contract and can cause report publishing/consumption issues.

Proposed fix
-        html.outputLocation = new File("${rootDir}/.jacoco/reports/jacoco/report.html")
+        html.outputLocation = new File("${rootDir}/.jacoco/reports/jacoco/html")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
xml.outputLocation = new File("${rootDir}/.jacoco/reports/jacoco/report.xml")
html.outputLocation = new File("${rootDir}/.jacoco/reports/jacoco/report.html")
xml.outputLocation = new File("${rootDir}/.jacoco/reports/jacoco/report.xml")
html.outputLocation = new File("${rootDir}/.jacoco/reports/jacoco/html")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build.gradle` around lines 133 - 134, The html.outputLocation currently
points to a file path; change it to a directory path (e.g.
"${rootDir}/.jacoco/reports/jacoco/html") so JaCoCo can write multiple HTML
files; leave xml.outputLocation as-is. Update the html.outputLocation assignment
to use new File("<directory>") (not a single report.html file) and ensure the
directory exists/gets created by the build if needed.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/push_master.yml (1)

116-120: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the JDK setup step name to match the configured version.

Line 116 says Set up JDK 21, but Line 120 is 25.0.3. Keeping the label accurate avoids confusion in build logs.

Suggested patch
-      - name: Set up JDK 21
+      - name: Set up JDK 25
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/push_master.yml around lines 116 - 120, Update the
workflow step label so it matches the configured Java version: change the step
name "Set up JDK 21" to reflect the actual java-version '25.0.3' (the step using
actions/setup-java@v4 with with: java-version: '25.0.3') so build logs
accurately describe the JDK being installed.
.github/workflows/daily_build.yml (1)

72-76: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix stale JDK step label.

Line 72 still says Set up JDK 21, but Line 76 installs 25.0.3. This makes CI logs misleading during incident triage.

Suggested patch
-      - name: Set up JDK 21
+      - name: Set up JDK 25
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/daily_build.yml around lines 72 - 76, The workflow step
label "Set up JDK 21" is stale relative to the configured java-version '25.0.3'
for actions/setup-java@v4; update the step name text to accurately reflect the
installed JDK (for example "Set up JDK 25" or "Set up Temurin JDK 25.0.3") so CI
logs show the correct JDK version during runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/daily_build.yml:
- Around line 72-76: The workflow step label "Set up JDK 21" is stale relative
to the configured java-version '25.0.3' for actions/setup-java@v4; update the
step name text to accurately reflect the installed JDK (for example "Set up JDK
25" or "Set up Temurin JDK 25.0.3") so CI logs show the correct JDK version
during runs.

In @.github/workflows/push_master.yml:
- Around line 116-120: Update the workflow step label so it matches the
configured Java version: change the step name "Set up JDK 21" to reflect the
actual java-version '25.0.3' (the step using actions/setup-java@v4 with with:
java-version: '25.0.3') so build logs accurately describe the JDK being
installed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a168e838-dea2-419a-b1c0-8a6430f1e222

📥 Commits

Reviewing files that changed from the base of the PR and between 4b5dfe8 and c111fe9.

📒 Files selected for processing (4)
  • .github/workflows/daily_build.yml
  • .github/workflows/pull_request_ubuntu_build.yml
  • .github/workflows/push_master.yml
  • gradle/libs.versions.toml

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestBuildProject.java (1)

221-258: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Ensure permissions are always restored for the whole test body.

resetPermissions(projectPath) is only guaranteed after entering the inner try block. If an exception occurs before that (for example at Line 250), the test can leak filesystem permissions into later tests.

Proposed fix
-        // 4) Compile the current package — expects RuntimeException on non-Windows
-        PackageCompilation compilation = currentPackage.getCompilation();
-        try {
-            JBallerinaBackend jBallerinaBackend = JBallerinaBackend.from(compilation, JvmTarget.JAVA_21);
-            Assert.fail("Expected RuntimeException when compiling with no write permission");
-        } catch (RuntimeException e) {
-            // expected
-        } finally {
-            resetPermissions(projectPath);
-        }
+        // 4) Compile the current package — expects RuntimeException on non-Windows
+        try {
+            PackageCompilation compilation = currentPackage.getCompilation();
+            try {
+                JBallerinaBackend.from(compilation, JvmTarget.JAVA_21);
+                Assert.fail("Expected RuntimeException when compiling with no write permission");
+            } catch (RuntimeException e) {
+                // expected
+            }
+        } finally {
+            resetPermissions(projectPath);
+        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestBuildProject.java`
around lines 221 - 258, The test testBuildProjectWithNoWritePermission can leak
filesystem permissions because resetPermissions(projectPath) is only in the
inner finally; wrap the entire test logic (from immediately after
setWritable(false, true) through the end) in a single try { ... } finally {
resetPermissions(projectPath); } so resetPermissions is always executed even if
loadBuildProject, currentPackage(), or compilation throw; keep the inner
try/catch that asserts RuntimeException for JBallerinaBackend.from(...) but
move/reset the outer finally to guarantee restoration of projectPath
permissions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestSingleFileProject.java`:
- Around line 220-222: The testSingleFileWithNoReadPermission method currently
does an early return when isWindows() is true, which marks the test as passed;
replace that return with throwing a TestNG skip by using throw new
SkipException("Skipping test on Windows") (or similar message) so the test
reports as SKIPPED; update the if (isWindows()) block to throw SkipException
(the file already imports org.testng.SkipException) and ensure no other logic is
executed afterwards.

---

Outside diff comments:
In
`@project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestBuildProject.java`:
- Around line 221-258: The test testBuildProjectWithNoWritePermission can leak
filesystem permissions because resetPermissions(projectPath) is only in the
inner finally; wrap the entire test logic (from immediately after
setWritable(false, true) through the end) in a single try { ... } finally {
resetPermissions(projectPath); } so resetPermissions is always executed even if
loadBuildProject, currentPackage(), or compilation throw; keep the inner
try/catch that asserts RuntimeException for JBallerinaBackend.from(...) but
move/reset the outer finally to guarantee restoration of projectPath
permissions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2660c35a-d8c5-41c1-963c-d3cee0ce6915

📥 Commits

Reviewing files that changed from the base of the PR and between c111fe9 and 4074254.

📒 Files selected for processing (9)
  • compiler/ballerina-lang/src/test/java/io/ballerina/projects/ProjectUtilsTests.java
  • project-api/project-api-test/src/test/java/io/ballerina/projects/test/BaseTest.java
  • project-api/project-api-test/src/test/java/io/ballerina/projects/test/CustomRepoResolutionTests.java
  • project-api/project-api-test/src/test/java/io/ballerina/projects/test/HierarchicalPackageNameTests.java
  • project-api/project-api-test/src/test/java/io/ballerina/projects/test/PackageResolutionTests.java
  • project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestBalaProject.java
  • project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestBuildProject.java
  • project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestBuildProjectWithGeneratedSources.java
  • project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestSingleFileProject.java

Comment on lines 220 to 222
if (isWindows()) {
throw new SkipException("Skipping tests on Windows");
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In TestNG, what is the reporting/behavior difference between returning early from an @test method and throwing org.testng.SkipException?

💡 Result:

Difference in TestNG reporting/behavior: 1) Returning early from an @Test method - TestNG treats a normal return from a @Test method as “test completed successfully” (assuming no assertion/exception was thrown), so it reports the test as PASS, not SKIP. TestNG does not have a special “skip” notion for a bare early return. 2) Throwing org.testng.SkipException - TestNG treats throwing org.testng.SkipException from a @Test or @Configuration method as a skip, not a failure. The SkipException Javadoc states it is “the root exception for special skip handling” and that in case a @Test or @Configuration throws this exception, “the method will be considered a skip” (subject to SkipException#isSkip behavior). [1] - The SkipException class extends RuntimeException and is explicitly meant for “special skip handling.” [1] Important nuance: SkipException may still interact with TestNG’s “configuration failure policy” - In suites, TestNG has a configfailurepolicy that controls what happens when @Before* fails: default is “skip”, and you can set “continue” to run remaining tests. This affects whether one skipped configuration can cause other tests/configs to be skipped too. [2][3] Practical takeaway - Use “return;” to stop the current test method, but it will still be reported as SUCCESS/PASS. - Use “throw new SkipException(...)” to have TestNG report the method (and potentially dependent subsequent behavior) as SKIPPED. [1] Code sketch (conceptual) - Early return: - inside @Test: if (cond) return; -> not a SKIP; reported as PASS. - Skip: - inside @Test: if (cond) throw new SkipException("..."); -> reported as SKIP. [1]

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestSingleFileProject.java"

# Show the window around the reported lines
nl -ba "$FILE" | sed -n '190,250p'

# Check for SkipException usage/imports
rg -n "SkipException" "$FILE" || true
rg -n "import .*SkipException" "$FILE" || true

# Show the method signature that contains the isWindows() block
# (extract a few lines above the if)
nl -ba "$FILE" | sed -n '205,235p'

Repository: ballerina-platform/ballerina-lang

Length of output: 120


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestSingleFileProject.java"

# Print lines 190-250 with line numbers using python (nl isn't available)
python3 - <<'PY'
import itertools
path = "project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestSingleFileProject.java"
start, end = 190, 250
with open(path, 'r', encoding='utf-8') as f:
    for i, line in enumerate(f, start=1):
        if start <= i <= end:
            print(f"{i:4d}: {line.rstrip()}")
        if i > end:
            break
PY

# Search for SkipException usage/imports
rg -n "SkipException" "$FILE" || true
rg -n "import .*SkipException" "$FILE" || true

# Also show the test method signature around the isWindows() block
python3 - <<'PY'
import re
path = "project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestSingleFileProject.java"
target_line = 221
# Find nearest def line (method signature) above the target line
with open(path, 'r', encoding='utf-8') as f:
    lines = f.readlines()
for i in range(target_line-1, -1, -1):
    if re.search(r'\)\s*\{?\s*$', lines[i]) or re.search(r'\bvoid\s+\w+\s*\(', lines[i]) or re.search(r'\w+\s+\w+\s*\(', lines[i]):
        # print a small window upward for context
        lo = max(0, i-10); hi = min(len(lines), i+20)
        for j in range(lo, hi):
            print(f"{j+1:4d}: {lines[j].rstrip()}")
        break
PY

Repository: ballerina-platform/ballerina-lang

Length of output: 4930


Use TestNG skip instead of returning on Windows.

testSingleFileWithNoReadPermission returns early on Windows (if (isWindows()) { return; }), which makes the test appear as PASS instead of SKIP. Throw org.testng.SkipException instead (the file already imports it).

Suggested fix
         if (isWindows()) {
-            return;
+            throw new SkipException("Skipping tests on Windows");
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isWindows()) {
throw new SkipException("Skipping tests on Windows");
return;
}
if (isWindows()) {
throw new SkipException("Skipping tests on Windows");
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@project-api/project-api-test/src/test/java/io/ballerina/projects/test/TestSingleFileProject.java`
around lines 220 - 222, The testSingleFileWithNoReadPermission method currently
does an early return when isWindows() is true, which marks the test as passed;
replace that return with throwing a TestNG skip by using throw new
SkipException("Skipping test on Windows") (or similar message) so the test
reports as SKIPPED; update the if (isWindows()) block to throw SkipException
(the file already imports org.testng.SkipException) and ensure no other logic is
executed afterwards.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
33 Security Hotspots
E Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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