Skip to content

Conversation

akshay1410
Copy link

Improve the PNPM package manager integration to better handle unexpected output and large workspaces.

  • Add defensive parsing for pnpm list and pnpm info JSON results. Instead of failing with exceptions, skip invalid entries and log warnings to aid debugging.

  • Use pnpm list --only-projects --recursive to determine workspace module directories, avoiding reliance on node_modules heuristics.

  • Support the environment variable ORT_PNPM_DEPTH to configure the depth passed to pnpm list. Defaults to "Infinity" if unset.

  • Ensure pnpm install is run with --prod unless dev dependencies are required, reducing unnecessary installs in CI.

  • Improve logging to clarify which scope or project failed resolution and why, making analyzer runs easier to debug.

This makes ORT’s PNPM support more resilient in CI environments where pnpm output may vary between versions or where large monorepos cause performance and stability issues. Returning partial results instead of failing fast allows analysis to complete while still surfacing warnings.

Please ensure that your pull request adheres to our contribution guidelines. Thank you!

@akshay1410 akshay1410 requested a review from a team as a code owner August 25, 2025 22:30
Improve the PNPM package manager integration to better handle
unexpected output and large workspaces.

* Add defensive parsing for `pnpm list` and `pnpm info` JSON results.
  Instead of failing with exceptions, skip invalid entries and log
  warnings to aid debugging.

* Use `pnpm list --only-projects --recursive` to determine workspace
  module directories, avoiding reliance on `node_modules` heuristics.

* Support the environment variable `ORT_PNPM_DEPTH` to configure the
  depth passed to `pnpm list`. Defaults to "Infinity" if unset.

* Ensure `pnpm install` is run with `--prod` unless dev dependencies
  are required, reducing unnecessary installs in CI.

* Improve logging to clarify which scope or project failed resolution
  and why, making analyzer runs easier to debug.

This makes ORT’s PNPM support more resilient in CI environments where
pnpm output may vary between versions or where large monorepos cause
performance and stability issues. Returning partial results instead of
failing fast allows analysis to complete while still surfacing
warnings.

Signed-off-by: kumar10 <[email protected]>
@akshay1410 akshay1410 force-pushed the pnpm-defensive-fixes branch from 46b225d to 56848a2 Compare August 25, 2025 22:46
Copy link

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

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

detekt found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

import org.semver4j.range.RangeList
import org.semver4j.range.RangeListFactory
// pnpm-local ModuleInfo (file is plugins/package-managers/node/src/main/kotlin/pnpm/ModuleInfo.kt)
import org.ossreviewtoolkit.plugins.packagemanagers.node.pnpm.ModuleInfo

Check warning

Code scanning / QDJVMC

Unused import directive Warning

Unused import directive
// ModuleInfoResolver lives in plugins/package-managers/node/src/main/kotlin/ModuleInfoResolver.kt
import org.ossreviewtoolkit.plugins.packagemanagers.node.ModuleInfoResolver

private val logger = LogManager.getLogger("Pnpm")

Check warning

Code scanning / QDJVMC

Unused symbol Warning

Property "logger" is never used

// Expecting an array of project objects; fall back gracefully if not.
val dirs = mutableSetOf<File>()
if (root is ArrayNode) {

Check warning

Code scanning / QDJVMC

Unreachable code Warning

Unreachable code
// Expecting an array of project objects; fall back gracefully if not.
val dirs = mutableSetOf<File>()
if (root is ArrayNode) {
root.forEach { node ->

Check warning

Code scanning / QDJVMC

Unreachable code Warning

Unreachable code
val dirs = mutableSetOf<File>()
if (root is ArrayNode) {
root.forEach { node ->
val pathNode = node.get("path")

Check notice

Code scanning / QDJVMC

Explicit 'get' or 'set' call Note

Explicit 'get' call
else logger.debug { "Skipping non-object element from pnpm list in $pkgDir (scope=$scope): ${elem?.toString()?.take(200)}" }
}
}
else -> if (node.isObject) consolidated.add(node) else logger.debug { "Skipping non-object pnpm list root for $pkgDir (scope=$scope): ${node.toString().take(200)}" }

Check warning

Code scanning / QDJVMC

Unreachable code Warning

Unreachable code
else logger.debug { "Skipping non-object element from pnpm list in $pkgDir (scope=$scope): ${elem?.toString()?.take(200)}" }
}
}
else -> if (node.isObject) consolidated.add(node) else logger.debug { "Skipping non-object pnpm list root for $pkgDir (scope=$scope): ${node.toString().take(200)}" }

Check warning

Code scanning / QDJVMC

Unreachable code Warning

Unreachable code
else logger.debug { "Skipping non-object element from pnpm list in $pkgDir (scope=$scope): ${elem?.toString()?.take(200)}" }
}
}
else -> if (node.isObject) consolidated.add(node) else logger.debug { "Skipping non-object pnpm list root for $pkgDir (scope=$scope): ${node.toString().take(200)}" }

Check warning

Code scanning / QDJVMC

Unreachable code Warning

Unreachable code
try {
val name = jsonNode.get("name")?.asText().orEmpty()
val path = jsonNode.get("path")?.asText().orEmpty()
val version = jsonNode.get("version")?.asText().orEmpty()

Check warning

Code scanning / QDJVMC

Unused variable Warning

Unused variable
}
}

if (moduleInfos.isEmpty()) {

Check warning

Code scanning / QDJVMC

Constant conditions Warning

Condition 'moduleInfos.isEmpty()' is always true
Copy link

codecov bot commented Aug 27, 2025

Codecov Report

❌ Patch coverage is 1.16279% with 85 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.98%. Comparing base (c4a0391) to head (56848a2).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...package-managers/node/src/main/kotlin/pnpm/Pnpm.kt 1.16% 85 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #10771      +/-   ##
============================================
- Coverage     57.38%   56.98%   -0.41%     
+ Complexity     1671     1670       -1     
============================================
  Files           346      346              
  Lines         12759    12832      +73     
  Branches       1209     1228      +19     
============================================
- Hits           7322     7312      -10     
- Misses         4972     5056      +84     
+ Partials        465      464       -1     
Flag Coverage Δ
funTest-non-docker 32.86% <ø> (ø)
test-ubuntu-24.04 41.58% <1.16%> (-0.32%) ⬇️
test-windows-2025 41.56% <1.16%> (-0.32%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

1 participant