[SP-3848] [scanoss.java] Implement CLI scan configuration parameters#37
[SP-3848] [scanoss.java] Implement CLI scan configuration parameters#37descorchator wants to merge 1 commit intomainfrom
Conversation
Implemented by Gepeto Escalante.
📝 WalkthroughWalkthroughThis pull request introduces a multi-tiered scan configuration system enabling CLI, settings file, and per-file snippet tuning of scanning parameters. A new Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant CLI as ScanCommandLine
participant Scanner
participant Settings as ScanossSettings
participant Config as ScanConfig
participant Winnowing
participant ScanApi as ScanApi
User->>CLI: Provide CLI options (min-snippet-hits, skip-headers, etc.)
CLI->>CLI: buildCliScanConfig()
CLI->>Scanner: Scanner.builder()<br/>.cliScanConfig(cliConfig)
Scanner->>Settings: Ensure settings initialized with defaults
Scanner->>Settings: getResolvedScanConfig(cliScanConfig)
Settings->>Settings: Settings.toScanConfig()
Settings->>Config: ScanConfig.resolve(cli, settingsLevel, fileSnippet)
Config->>Config: Apply priority merge:<br/>fileSnippet > settings > cli
Config-->>Settings: Return resolved scanConfig
Settings-->>Scanner: Return resolved scanConfig
Scanner->>Winnowing: builder()<br/>.skipHeaders()<br/>.skipHeadersLimit()
Winnowing-->>Scanner: Configured builder
Scanner->>ScanApi: builder()<br/>.scanConfig(scanConfig)
ScanApi-->>Scanner: Configured builder
Scanner->>Winnowing: Generate WFP (with detectHeaderLines if enabled)
Winnowing-->>Scanner: File fingerprints
Scanner->>ScanApi: POST with config parameters<br/>(min_snippet_hits, ranking, etc.)
ScanApi-->>Scanner: Scan results
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/com/scanoss/settings/ScanConfig.java (1)
144-146: Asymmetric handling ofskipHeadersin merge logic.The
skipHeadersfield is handled differently from other boolean fields: it can only be set totrueby higher-priority layers, but cannot be overridden tofalse. This means if CLI setsskipHeaders=true, a higher-priority settings file cannot disable it.Compare with
honourFileExtsandrankingEnabledwhich useisXxxSet()and can be overridden to eithertrueorfalse.If this is intentional ("once enabled, always enabled"), consider documenting it. Otherwise, consider aligning with other booleans:
♻️ Suggested fix for consistent boolean handling
- if (source.getSkipHeaders() != null && source.getSkipHeaders()) { - target.setSkipHeaders(true); + if (source.getSkipHeaders() != null) { + target.setSkipHeaders(source.getSkipHeaders()); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/scanoss/settings/ScanConfig.java` around lines 144 - 146, The merge logic treats skipHeaders asymmetrically by only allowing it to be set true (using source.getSkipHeaders() and target.setSkipHeaders(true)), preventing higher-priority layers from setting it false; change the code to follow the pattern used by honourFileExts and rankingEnabled: check the source's "isSkipHeadersSet()" (or equivalent isXxxSet method) and, if set, assign the actual value into target via target.setSkipHeaders(source.getSkipHeaders()) so higher-priority layers can set it to true or false; if one-way behavior was intended, add a comment/documentation near getSkipHeaders/isSkipHeadersSet explaining the "once enabled, always enabled" semantics instead of changing code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/test/java/com/scanoss/TestSettings.java`:
- Around line 63-66: The setup silently leaves scanConfigSettingsPath null when
getResource("scanoss-scan-config.json") returns null, causing
testScanConfigFromJson to fail; update the setup in TestSettings so that if
getResource("scanoss-scan-config.json") is null it fails fast (throw an
exception with a clear message) following the same pattern used for the existing
scanoss.json check, or alternatively add the missing test resource file
"scanoss-scan-config.json" under src/test/resources; locate the code that
assigns scanConfigSettingsPath (the block using
getClass().getClassLoader().getResource and Paths.get) and either add the
resource or replace the null branch with an exception to ensure
scanConfigSettingsPath is never null.
---
Nitpick comments:
In `@src/main/java/com/scanoss/settings/ScanConfig.java`:
- Around line 144-146: The merge logic treats skipHeaders asymmetrically by only
allowing it to be set true (using source.getSkipHeaders() and
target.setSkipHeaders(true)), preventing higher-priority layers from setting it
false; change the code to follow the pattern used by honourFileExts and
rankingEnabled: check the source's "isSkipHeadersSet()" (or equivalent isXxxSet
method) and, if set, assign the actual value into target via
target.setSkipHeaders(source.getSkipHeaders()) so higher-priority layers can set
it to true or false; if one-way behavior was intended, add a
comment/documentation near getSkipHeaders/isSkipHeadersSet explaining the "once
enabled, always enabled" semantics instead of changing code.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/main/java/com/scanoss/Scanner.javasrc/main/java/com/scanoss/Winnowing.javasrc/main/java/com/scanoss/cli/ScanCommandLine.javasrc/main/java/com/scanoss/rest/ScanApi.javasrc/main/java/com/scanoss/settings/ScanConfig.javasrc/main/java/com/scanoss/settings/ScanossSettings.javasrc/test/java/com/scanoss/TestSettings.javasrc/test/java/com/scanoss/TestWinnowing.java
| var scanConfigResource = getClass().getClassLoader().getResource("scanoss-scan-config.json"); | ||
| if (scanConfigResource != null) { | ||
| scanConfigSettingsPath = Paths.get(scanConfigResource.toURI()); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if the test resource file exists
echo "=== Searching for scanoss-scan-config.json ==="
fd -t f "scanoss-scan-config.json" src/test/resources 2>&1 || echo "Not found in src/test/resources"
echo ""
echo "=== Checking all test resources ==="
fd -t f . src/test/resources 2>&1 | head -20
echo ""
echo "=== Searching for references to scanoss-scan-config.json ==="
rg "scanoss-scan-config.json" --type javaRepository: scanoss/scanoss.java
Length of output: 398
🏁 Script executed:
#!/bin/bash
# Read the TestSettings.java file to check the actual implementation
echo "=== Reading TestSettings.java ==="
wc -l src/test/java/com/scanoss/TestSettings.java
echo ""
echo "=== Lines 60-70 (context around lines 63-66) ==="
sed -n '60,70p' src/test/java/com/scanoss/TestSettings.java
echo ""
echo "=== Lines 155-165 (context around lines 156-161) ==="
sed -n '155,165p' src/test/java/com/scanoss/TestSettings.javaRepository: scanoss/scanoss.java
Length of output: 1328
🏁 Script executed:
#!/bin/bash
# Check the scanConfigSettingsPath field declaration
echo "=== Searching for scanConfigSettingsPath declaration ==="
rg "scanConfigSettingsPath" src/test/java/com/scanoss/TestSettings.java -B 2 -A 2
echo ""
echo "=== Full `@Before` or `@BeforeEach` setup method ==="
sed -n '50,80p' src/test/java/com/scanoss/TestSettings.javaRepository: scanoss/scanoss.java
Length of output: 2332
🏁 Script executed:
#!/bin/bash
# Check if there are any other files that create this config file
echo "=== Searching for any test setup or creation of scanoss-scan-config.json ==="
rg -r "scanoss-scan-config" --type java --type json
echo ""
echo "=== Check git history for the file ==="
git log --name-status --oneline -- "*scanoss-scan-config*" 2>&1 | head -20Repository: scanoss/scanoss.java
Length of output: 594
Pipeline failure: Missing test resource scanoss-scan-config.json.
The test testScanConfigFromJson fails at line 160 because the resource file scanoss-scan-config.json does not exist. The setup at lines 63-66 silently leaves scanConfigSettingsPath as null when the resource is missing, causing the assertion to fail.
Either add the missing test resource file to src/test/resources/scanoss-scan-config.json, or throw an error in the setup to match the pattern used for scanoss.json:
Suggested fix: Throw error for missing resource
var scanConfigResource = getClass().getClassLoader().getResource("scanoss-scan-config.json");
- if (scanConfigResource != null) {
- scanConfigSettingsPath = Paths.get(scanConfigResource.toURI());
+ if (scanConfigResource == null) {
+ throw new IllegalStateException(
+ "Required test resource 'scanoss-scan-config.json' not found. Please ensure it exists in src/test/resources/"
+ );
}
+ scanConfigSettingsPath = Paths.get(scanConfigResource.toURI());📝 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.
| var scanConfigResource = getClass().getClassLoader().getResource("scanoss-scan-config.json"); | |
| if (scanConfigResource != null) { | |
| scanConfigSettingsPath = Paths.get(scanConfigResource.toURI()); | |
| } | |
| var scanConfigResource = getClass().getClassLoader().getResource("scanoss-scan-config.json"); | |
| if (scanConfigResource == null) { | |
| throw new IllegalStateException( | |
| "Required test resource 'scanoss-scan-config.json' not found. Please ensure it exists in src/test/resources/" | |
| ); | |
| } | |
| scanConfigSettingsPath = Paths.get(scanConfigResource.toURI()); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/test/java/com/scanoss/TestSettings.java` around lines 63 - 66, The setup
silently leaves scanConfigSettingsPath null when
getResource("scanoss-scan-config.json") returns null, causing
testScanConfigFromJson to fail; update the setup in TestSettings so that if
getResource("scanoss-scan-config.json") is null it fails fast (throw an
exception with a clear message) following the same pattern used for the existing
scanoss.json check, or alternatively add the missing test resource file
"scanoss-scan-config.json" under src/test/resources; locate the code that
assigns scanConfigSettingsPath (the block using
getClass().getClassLoader().getResource and Paths.get) and either add the
resource or replace the null branch with an exception to ensure
scanConfigSettingsPath is never null.
[scanoss.java] Implement CLI scan configuration parameters
Changes
Here's a summary of all changes made to implement the CLI scan configuration parameters (SP-3848):
Summary of Changes
New Files
src/main/java/com/scanoss/settings/ScanConfig.javaminSnippetHits,minSnippetLines,honourFileExts,rankingEnabled,rankingThreshold,skipHeaders,skipHeadersLimit@SerializedNamefor JSON deserialization fromscanoss.jsonisXxxSet()methods to check if values are "set" (non-default/non-unset)resolve()method implementing the 3-layer priority merge:file_snippet(highest) >settings(middle) > CLI (lowest)src/test/resources/scanoss-scan-config.jsonsettingsandsettings.file_snippetlevelsModified Files
src/main/java/com/scanoss/settings/ScanossSettings.javamin_snippet_hits, etc.) andfile_snippetsub-section toSettingsinner classtoScanConfig()method onSettingsto convert settings-level values toScanConfiggetResolvedScanConfig(ScanConfig cliConfig)to resolve effective config from all 3 priority layerssrc/main/java/com/scanoss/cli/ScanCommandLine.java--min-snippet-hits,--min-snippet-lines,--honour-file-exts,--ranking,--ranking-threshold,--skip-headers,--skip-headers-limitbuildCliScanConfig()to createScanConfigfrom CLI argsparseTriStateBoolean()for tri-state flags (true/false/unset/omitted)cliScanConfigtoScanner.builder()src/main/java/com/scanoss/Scanner.javacliScanConfigand resolvedscanConfigfieldssettings.getResolvedScanConfig(cliConfig)skipHeaders/skipHeadersLimittoWinnowingbuilderscanConfigtoScanApibuildersrc/main/java/com/scanoss/rest/ScanApi.javascanConfigfieldscan(): adds non-unset server params (min_snippet_hits,min_snippet_lines,honour_file_exts,ranking_enabled,ranking_threshold) to the multipart request dataskip_headersandskip_headers_limitare local-only and are NOT sent to the serversrc/main/java/com/scanoss/Winnowing.javaskipHeadersandskipHeadersLimitbuilder fieldsdetectHeaderLines()method that detects license comment blocks, single-line comments, blank lines, and import/package statementswfpForContents()to skip header lines during snippet fingerprint generation whenskipHeadersis enabledsrc/test/java/com/scanoss/TestSettings.javatestScanConfigFromJson,testScanConfigResolution,testScanConfigResolutionFromSettingsFile,testScanConfigUnsetValues,testScanConfigResolutionWithNulls,testExistingSettingsWithoutScanConfigsrc/test/java/com/scanoss/TestWinnowing.javaTestDetectHeaderLines- tests header detection with various code patternsTestWinnowingSkipHeaders- tests that skip_headers affects WFP generation while preserving file hashKey Design Decisions
settings.file_snippet>settings> CLI (as specified in ticket)skip_headersandskip_headers_limitapply locally (winnowing), all others are sent to the SCANOSS scanning engine--rankingand--honour-file-extsaccepttrue/false/unsetstring values, mapping toBoolean(null = unset)This PR was automatically generated by Gepeto Escalante.
Summary by CodeRabbit
Release Notes
New Features
Tests