build: fix macOS/Windows cross-platform build without SAP SDK#39
build: fix macOS/Windows cross-platform build without SAP SDK#39ajinkyaj0211 wants to merge 4 commits into
Conversation
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
📝 WalkthroughWalkthroughNx Maven target commands are standardized across four apps: ChangesNx Maven Build Configuration Alignment
Bootstrap discovery and landscape parsing
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 25 |
| Duplication | 10 |
AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
Code Review
This pull request updates the Nx project configuration files across multiple apps to use Maven install commands with distribution profiles. The review feedback correctly identifies that chaining commands with the && operator is not cross-platform compatible, particularly on Windows PowerShell 5.1. To resolve this, the reviewer suggests utilizing the commands array with parallel set to false in the nx:run-commands executor, which is a safer and more robust approach.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-bootstrap -am -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs install -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", | ||
| "cwd": "{workspaceRoot}" |
There was a problem hiding this comment.
Using && to chain commands in a single command string is not fully cross-platform because Windows PowerShell (specifically Windows PowerShell 5.1, which is the default on Windows) does not support the && operator and will throw a syntax error. Since this PR aims to fix macOS/Windows cross-platform builds, we should use the commands array with "parallel": false in the nx:run-commands executor, which is fully cross-platform and safe. Additionally, the second command was missing the -q flag.
"options": {
"commands": [
"node scripts/mvnw-runner.mjs -q test -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -f pom.xml",
"node scripts/mvnw-runner.mjs -q install -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml"
],
"parallel": false,
"cwd": "{workspaceRoot}"| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q compile -pl apps/openadt-cli -am -Pdistribution -Dopenadt.distribution=true -f pom.xml && bun run scripts/dev-runtime-classpath.ts", | ||
| "command": "node scripts/mvnw-runner.mjs -q install -pl apps/openadt-cli -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml && bun run scripts/dev-runtime-classpath.ts", | ||
| "cwd": "{workspaceRoot}" |
There was a problem hiding this comment.
Using && to chain commands in a single command string is not fully cross-platform because Windows PowerShell 5.1 (the default on Windows) does not support the && operator. To ensure reliable cross-platform execution on Windows, use the commands array with "parallel": false instead.
"options": {
"commands": [
"node scripts/mvnw-runner.mjs -q install -pl apps/openadt-cli -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml",
"bun run scripts/dev-runtime-classpath.ts"
],
"parallel": false,
"cwd": "{workspaceRoot}"| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q compile -pl apps/openadt-config -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q install -N -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml && node scripts/mvnw-runner.mjs -q install -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", | ||
| "cwd": "{workspaceRoot}" |
There was a problem hiding this comment.
Using && to chain commands in a single command string is not fully cross-platform because Windows PowerShell 5.1 (the default on Windows) does not support the && operator. To ensure reliable cross-platform execution on Windows, use the commands array with "parallel": false instead.
"options": {
"commands": [
"node scripts/mvnw-runner.mjs -q install -N -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml",
"node scripts/mvnw-runner.mjs -q install -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml"
],
"parallel": false,
"cwd": "{workspaceRoot}"| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-config -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs -q install -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", | ||
| "cwd": "{workspaceRoot}" |
There was a problem hiding this comment.
Using && to chain commands in a single command string is not fully cross-platform because Windows PowerShell 5.1 (the default on Windows) does not support the && operator. To ensure reliable cross-platform execution on Windows, use the commands array with "parallel": false instead.
"options": {
"commands": [
"node scripts/mvnw-runner.mjs -q test -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -f pom.xml",
"node scripts/mvnw-runner.mjs -q install -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml"
],
"parallel": false,
"cwd": "{workspaceRoot}"| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-sap-adt -am -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs install -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", | ||
| "cwd": "{workspaceRoot}" |
There was a problem hiding this comment.
Using && to chain commands in a single command string is not fully cross-platform because Windows PowerShell 5.1 (the default on Windows) does not support the && operator. To ensure reliable cross-platform execution on Windows, use the commands array with "parallel": false instead. Additionally, the second command was missing the -q flag.
"options": {
"commands": [
"node scripts/mvnw-runner.mjs -q test -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -f pom.xml",
"node scripts/mvnw-runner.mjs -q install -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml"
],
"parallel": false,
"cwd": "{workspaceRoot}"There was a problem hiding this comment.
Pull Request Overview
The PR successfully addresses cross-platform build issues for macOS and Windows by transitioning Maven targets from 'compile' to 'install' and removing recursive build flags that pull in SDK-dependent components. Codacy analysis indicates the changes are up to standards with no new issues introduced.
While the implementation fulfills all acceptance criteria, a systemic redundancy was identified in the build configuration for library modules (bootstrap, config, and sap-adt). The 'test' target currently invokes an 'install' command that repeats work already completed by its dependency, the 'compile' target. Removing these redundant calls will improve build performance without impacting the availability of artifacts in the local repository.
About this PR
- There is a systemic redundancy across library modules where 'mvn install' is executed twice. Since the 'test' target depends on 'compile', and 'compile' has been updated to perform an 'install', the subsequent installation after tests provides no additional benefit and increases build duration due to Maven startup costs.
Test suggestions
- Module 'openadt-bootstrap' build uses 'install' with distribution profile and no '-am' flag
- Module 'openadt-cli' build uses 'install' with distribution profile and no '-am' flag
- Module 'openadt-config' performs non-recursive parent POM install before module install
- Module 'openadt-sap-adt' build uses 'install' with distribution profile and no '-am' flag
- Library modules (bootstrap, config, sap-adt) update local repository after successful tests
TIP How was this review? Give us feedback
| "dependsOn": ["compile"], | ||
| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-sap-adt -am -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs install -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", |
There was a problem hiding this comment.
⚪ LOW RISK
Suggestion: The second Maven invocation is redundant. The artifact is already installed in the local repository during the 'compile' phase. Removing this call speeds up the test execution.
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs install -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", | |
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-sap-adt -Pdistribution -Dopenadt.distribution=true -f pom.xml", |
| "dependsOn": ["compile"], | ||
| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-config -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs -q install -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", |
There was a problem hiding this comment.
⚪ LOW RISK
Suggestion: This second Maven invocation is redundant. The 'compile' target already populates the local repository with the required artifacts. Removing this step reduces build overhead.
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs -q install -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", | |
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-config -Pdistribution -Dopenadt.distribution=true -f pom.xml", |
| "dependsOn": ["compile"], | ||
| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-bootstrap -am -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs install -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", |
There was a problem hiding this comment.
⚪ LOW RISK
Suggestion: The second Maven invocation (install) is redundant because the 'compile' target already ensures the artifact is installed in the local repository. Removing it optimizes the build cycle.
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -f pom.xml && node scripts/mvnw-runner.mjs install -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", | |
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-bootstrap -Pdistribution -Dopenadt.distribution=true -f pom.xml", |
There was a problem hiding this comment.
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 `@apps/openadt-cli/project.json`:
- Around line 27-29: The test target (targets.test) for apps/openadt-cli
currently depends only on "package" and runs the mvnw-runner.mjs test command
without ensuring the project graph is compiled/installed; update targets.test to
depend on "compile" (in addition to or instead of "package") so
openadt-config/openadt-sap-adt/openadt-bootstrap are built first, and modify the
mvnw-runner.mjs invocation used by targets.test to append an install step
(install -DskipTests) after the test phase (matching the pattern used by
openadt-bootstrap and openadt-sap-adt) so required Maven artifacts are available
when running nx test openadt-cli in isolation.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3432862f-c647-4eac-b3ed-2f6dda3425a7
📒 Files selected for processing (4)
apps/openadt-bootstrap/project.jsonapps/openadt-cli/project.jsonapps/openadt-config/project.jsonapps/openadt-sap-adt/project.json
| "dependsOn": ["package"], | ||
| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-cli -am -Pdistribution -Dopenadt.distribution=true -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q test -pl apps/openadt-cli -Pdistribution -Dopenadt.distribution=true -f pom.xml", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if any Maven POMs declare openadt-cli as a dependency
rg -t xml --iglob '**/pom.xml' -C3 '<artifactId>openadt-cli</artifactId>'Repository: abapify/openadt
Length of output: 41
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Read the relevant parts of openadt-cli/project.json
echo "---- apps/openadt-cli/project.json (lines 1-120) ----"
nl -ba apps/openadt-cli/project.json | sed -n '1,120p'
# 2) Find comparable project.json files for bootstrap and sap-adt
echo "---- Find project.json under apps/openadt-* ----"
find apps -maxdepth 3 -name project.json | sed -n '1,200p'
# 3) Read relevant sections from bootstrap/sap-adt project.json if present
for f in $(find apps -maxdepth 4 -name project.json | sort); do
if echo "$f" | rg -q 'openadt-(bootstrap|sap-adt)'; then
echo "---- $f (lines 1-160) ----"
nl -ba "$f" | sed -n '1,160p'
fi
done
# 4) Double-check if openadt-cli is referenced in any non-pom config (quick search)
echo "---- Search for openadt-cli references across repo ----"
rg -n --hidden --no-ignore -S "openadt-cli" -g'*.{xml,yml,yaml,json,properties,gradle,kts,sh,mjs,js,pom}' | head -n 200Repository: abapify/openadt
Length of output: 174
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- apps/openadt-cli/project.json (lines 1-160) ----"
cat -n apps/openadt-cli/project.json | sed -n '1,160p'
echo "---- Find project.json under apps/openadt-* ----"
find apps -maxdepth 3 -name project.json | sort
for f in $(find apps -maxdepth 4 -name project.json | sort); do
if echo "$f" | rg -q 'openadt-(bootstrap|sap-adt)'; then
echo "---- $f (lines 1-220) ----"
cat -n "$f" | sed -n '1,220p'
fi
done
echo "---- Search for openadt-cli references across repo (limited) ----"
rg -n --hidden --no-ignore -S "openadt-cli" -g'*.{xml,yml,yaml,json,properties,gradle,kts,sh,mjs,js,pom}' | head -n 200Repository: abapify/openadt
Length of output: 9113
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- apps/openadt-cli/pom.xml: artifactId/groupId ----"
rg -n --no-heading "<(groupId|artifactId)>" apps/openadt-cli/pom.xml | head -n 80
artifactId="$(rg -n --no-heading "<artifactId>" apps/openadt-cli/pom.xml | head -n 1 | sed -E 's/.*<artifactId>([^<]+)<\/artifactId>.*/\1/' || true)"
echo "Detected artifactId: ${artifactId:-<none>}"
echo "---- Other pom.xml files depending on that artifactId (excluding openadt-cli/pom.xml) ----"
if [ -n "${artifactId}" ]; then
rg -t xml --iglob '**/pom.xml' --glob '!apps/openadt-cli/pom.xml' -n --no-heading "<artifactId>${artifactId}</artifactId>" -C2 || true
fi
echo "---- Check whether any pom references openadt-cli module directory directly ----"
rg -n --no-heading "<module>apps/openadt-cli</module>" -S pom.xml **/pom.xml || trueRepository: abapify/openadt
Length of output: 3750
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- apps/openadt-cli/pom.xml (top + dependencies section excerpt) ----"
cat -n apps/openadt-cli/pom.xml | sed -n '1,220p'
echo "---- apps/openadt-cli/pom.xml: dependency coordinates (groupId/artifactId pairs) ----"
rg -n --no-heading "<dependency>" -n apps/openadt-cli/pom.xml >/dev/null || true
python3 - <<'PY'
import re, pathlib
p=pathlib.Path("apps/openadt-cli/pom.xml").read_text()
# crude parse: capture groupId/artifactId inside <dependency> blocks
deps=[]
for m in re.finditer(r"<dependency>\s*(.*?)\s*</dependency>", p, flags=re.S):
block=m.group(1)
gid=re.search(r"<groupId>\s*([^<]+)\s*</groupId>", block)
aid=re.search(r"<artifactId>\s*([^<]+)\s*</artifactId>", block)
scope=re.search(r"<scope>\s*([^<]+)\s*</scope>", block)
if aid:
deps.append((gid.group(1).strip() if gid else None, aid.group(1).strip(), scope.group(1).strip() if scope else None))
print("\n".join([f"{g or ''}:{a} (scope={s or 'none'})" for g,a,s in deps]))
PY
echo "---- Search other module poms for dependency on org.openadt:openadt ----"
rg -t xml --iglob '**/pom.xml' --glob '!apps/openadt-cli/pom.xml' -n "<groupId>org.openadt</groupId>|<artifactId>openadt</artifactId>" -C1
echo "---- Search other module poms for artifactId openadt (quick) ----"
rg -t xml --iglob '**/pom.xml' --glob '!apps/openadt-cli/pom.xml' -n --no-heading "<artifactId>openadt</artifactId>" -C2 || true
echo "---- apps/openadt-cli/pom.xml: test-related plugins ----"
rg -n --no-heading "(maven-surefire-plugin|maven-failsafe-plugin|surefire|failsafe|jacoco|skipTests|testFailure|maven-surefire)" apps/openadt-cli/pom.xml -S || true
echo "---- apps/openadt-cli/pom.xml: shade/assembly configuration ----"
rg -n --no-heading "(maven-shade-plugin|shade|assembly|classifier|repackage|manifest|mainClass|distribution)" apps/openadt-cli/pom.xml -S || trueRepository: abapify/openadt
Length of output: 14446
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- Find dependencies on org.openadt:openadt in module poms ----"
rg -t xml --iglob 'apps/*/pom.xml' --glob '!apps/openadt-cli/pom.xml' -n \
"<groupId>org\.openadt</groupId>[\s\S]*?<artifactId>openadt</artifactId>" \
-C2 || true
echo "---- Find any pom dependencies with <artifactId>openadt</artifactId> (show groupId around) ----"
rg -t xml --iglob 'apps/*/pom.xml' -n "<artifactId>openadt</artifactId>" -C3 || true
echo "---- Check if any pom depends on the openadt-cli module artifactId openadt ----"
rg -t xml --iglob '**/pom.xml' --glob '!**/target/**' -n "<artifactId>openadt</artifactId>" -C1 || true
echo "---- Search for openadt-cli as a dependency (module name) ----"
rg -t xml --iglob '**/pom.xml' -n "openadt-cli" -C2 || trueRepository: abapify/openadt
Length of output: 1084
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- openadt-cli test sources (files) ----"
find apps/openadt-cli/src/test -type f | head -n 200
echo "---- Search for references to shaded/distribution jar or target paths in openadt-cli tests ----"
rg -n --no-heading "target/|shade|shaded|distribution|openadt.*\\.jar|\\.jar\\b|maven-shade|OpenAdtCommand" apps/openadt-cli/src/test || true
echo "---- openadt-cli surefire/failsafe config in pom.xml ----"
rg -n --no-heading "(maven-surefire-plugin|maven-failsafe-plugin|surefire|failsafe|skipTests|skipITs)" apps/openadt-cli/pom.xml || true
echo "---- Check whether any other module depends on the openadt artifactId openadt (global scan) ----"
rg -t xml --iglob 'apps/*/pom.xml' --glob '!apps/openadt-cli/pom.xml' -n "<artifactId>openadt</artifactId>" -C2 || true
echo "---- Check whether any module depends on org.openadt groupId and artifactId=openadt (global scan) ----"
rg -t xml --iglob 'apps/*/pom.xml' --glob '!apps/openadt-cli/pom.xml' -n "<groupId>org.openadt</groupId>" -C1 | head -n 200Repository: abapify/openadt
Length of output: 4147
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate and show mvnw-runner.mjs behavior (args handling)
ls -la scripts/mvnw-runner.mjs || true
sed -n '1,220p' scripts/mvnw-runner.mjs || true
# Also check if any nx target overrides args or wraps -am internally
rg -n "mvnw-runner\.mjs" -S . | head -n 50
# Confirm whether openadt-cli:package has dependsOn and whether openadt-cli:test needs deps
cat -n apps/openadt-cli/project.json | sed -n '1,120p'Repository: abapify/openadt
Length of output: 6399
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- package.json scripts ----"
cat -n package.json | sed -n '1,120p'
echo "---- Search CI/workflows for nx test openadt-cli ----"
rg -n "nx\s+test\s+openadt-cli|openadt:test" .github package.json . | head -n 200Repository: abapify/openadt
Length of output: 2270
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- Search GitHub workflows for openadt:test or nx test openadt-cli ----"
rg -n "openadt:test|nx\s+test\s+openadt-cli|nx\s+run\s+openadt-cli:test" .github/workflows -S || true
echo "---- Search workflows for openadt-cli compile/package/install targets ----"
rg -n "nx\s+(run\s+)?openadt-cli:(compile|package|test|ensure-dev-jar)|nx\s+(compile|package|test)\s+openadt-cli" .github/workflows -S || true
echo "---- Search workflows for any prior installs of openadt-config/openadt-bootstrap/openadt-sap-adt ----"
rg -n "openadt-(config|bootstrap|sap-adt):" .github/workflows -S || true
echo "---- List workflows ----"
ls -la .github/workflowsRepository: abapify/openadt
Length of output: 564
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- .github/workflows/ci.yml ----"
cat -n .github/workflows/ci.yml | sed -n '1,260p'
echo "---- .github/workflows/release.yml ----"
cat -n .github/workflows/release.yml | sed -n '1,260p'Repository: abapify/openadt
Length of output: 11644
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- scripts/ci-java-test.sh ----"
cat -n scripts/ci-java-test.sh | sed -n '1,220p'Repository: abapify/openadt
Length of output: 883
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- Scan all pom.xml for artifactId openadt (org.openadt module) ----"
rg -t xml --iglob '**/pom.xml' -n "<artifactId>openadt</artifactId>" -C1 || true
echo "---- Scan all pom.xml for groupId org.openadt + artifactId openadt together ----"
rg -t xml --iglob '**/pom.xml' -n "<groupId>org\.openadt</groupId>" -C1 | head -n 200Repository: abapify/openadt
Length of output: 3016
Fix apps/openadt-cli/project.json Nx test target dependency chain
targets.test currently depends on ["package"] and runs mvnw-runner.mjs ... -q test -pl apps/openadt-cli ... without first compiling/install-ing openadt-config, openadt-sap-adt, or openadt-bootstrap (those are only ensured by the compile target). In contrast, openadt-bootstrap and openadt-sap-adt test targets depend on compile (and also append an install -DskipTests step).
The missing post-test install for the openadt-cli artifact itself isn’t the main problem (no other module depends on org.openadt:openadt), but the current test chain can leave required Maven dependencies unavailable when nx test openadt-cli is run in isolation.
🤖 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 `@apps/openadt-cli/project.json` around lines 27 - 29, The test target
(targets.test) for apps/openadt-cli currently depends only on "package" and runs
the mvnw-runner.mjs test command without ensuring the project graph is
compiled/installed; update targets.test to depend on "compile" (in addition to
or instead of "package") so openadt-config/openadt-sap-adt/openadt-bootstrap are
built first, and modify the mvnw-runner.mjs invocation used by targets.test to
append an install step (install -DskipTests) after the test phase (matching the
pattern used by openadt-bootstrap and openadt-sap-adt) so required Maven
artifacts are available when running nx test openadt-cli in isolation.
There was a problem hiding this comment.
1 issue found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/openadt-cli/project.json">
<violation number="1" location="apps/openadt-cli/project.json:39">
P1: `package` target dropped Maven `-am` without adding Nx `dependsOn` for upstream modules, breaking isolated builds</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| "executor": "nx:run-commands", | ||
| "options": { | ||
| "command": "node scripts/mvnw-runner.mjs -q package -pl apps/openadt-cli -am -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", | ||
| "command": "node scripts/mvnw-runner.mjs -q package -pl apps/openadt-cli -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml", |
There was a problem hiding this comment.
P1: package target dropped Maven -am without adding Nx dependsOn for upstream modules, breaking isolated builds
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/openadt-cli/project.json, line 39:
<comment>`package` target dropped Maven `-am` without adding Nx `dependsOn` for upstream modules, breaking isolated builds</comment>
<file context>
@@ -36,7 +36,7 @@
"executor": "nx:run-commands",
"options": {
- "command": "node scripts/mvnw-runner.mjs -q package -pl apps/openadt-cli -am -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml",
+ "command": "node scripts/mvnw-runner.mjs -q package -pl apps/openadt-cli -Pdistribution -Dopenadt.distribution=true -DskipTests -f pom.xml",
"cwd": "{workspaceRoot}"
},
</file context>
Add support for SAP GUI for Java landscape files on macOS: - Detect ~/Library/Preferences/SAP/SAPGUILandscape.xml - Detect external landscape URLs from <Include> tags - Warn users when message server details may be in external landscape - Update spec to document macOS paths and external landscape behavior Also includes previous Eclipse.app bundle support for JCo detection.
| } | ||
| } | ||
|
|
||
| private void detectExternalLandscapeUrls(Document document, Path sourcePath) { |
There was a problem hiding this comment.
WARNING: Unused parameter sourcePath - the parameter is declared but never referenced in the method body.
Code Review SummaryStatus: No New Issues | Recommendation: Merge (pending previous warning) Overview
Other Observations (not in diff)Issues found in unchanged code that cannot receive inline comments:
Files Reviewed (3 files)
Incremental review of commits after 9d14808 (0c69767) Reviewed by laguna-m.1-20260312:free · 639,261 tokens Review guidance: REVIEW.md from base branch |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SapGuiLandscapeDetector.java (1)
62-73: ⚡ Quick winUse
sourcePathin the emitted Include warning context (or remove it).
sourcePathis currently unused, and the log output loses which landscape file triggered the message. Include the file path in the message to keep diagnostics actionable.Suggested patch
private void detectExternalLandscapeUrls(Document document, Path sourcePath) { @@ if (url != null) { - System.err.println("INFO: External SAP landscape URL detected: " + url); + System.err.println("INFO: External SAP landscape URL detected in " + sourcePath + ": " + url); System.err.println("INFO: Some system details (message server hostnames) may be in the external landscape."); System.err.println("INFO: Open SAP GUI once to cache the full landscape, or provide message server manually."); } } }🤖 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 `@apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SapGuiLandscapeDetector.java` around lines 62 - 73, The method detectExternalLandscapeUrls(Document document, Path sourcePath) currently ignores the sourcePath parameter which makes the emitted Include warnings non-actionable; update the log lines in detectExternalLandscapeUrls to include the sourcePath (e.g., append sourcePath.toString() or sourcePath.getFileName()) in the warning messages so each "External SAP landscape URL detected" and related lines identify which file triggered them, and ensure sourcePath is null-checked (or if you intentionally don't need it, remove the sourcePath parameter from the method signature and all callers).
🤖 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
`@apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SetupPathLocator.java`:
- Around line 113-123: The repeated macOS path literal fragments in
SetupPathLocator (e.g., the Path.of(...) calls that use "Eclipse.app",
"Contents", "Eclipse", "plugins", and "libsapcrypto.dylib") should be extracted
into private static final String constants (for example ECLIPSE_APP,
CONTENTS_DIR, ECLIPSE_DIR, PLUGINS_DIR, LIB_SAP_CRYPTO) and then reused when
constructing paths in the methods that call paths.add(Path.of(...)) (including
the blocks shown and the similar code at the other flagged locations around the
other Path.of calls). Replace the repeated string literals with the new
constants to remove duplication and ensure consistent reuse across
SetupPathLocator.
- Around line 139-147: The macOS path-building in SetupPathLocator currently
wraps both absolute and home-dependent candidates behind a check for non-blank
user.home; update the logic in the method that builds mac paths (the block that
checks os.contains("mac")) to always add the absolute, system-level paths (e.g.,
Path.of("/usr","local","lib") and Path.of("/Library","Java","Extensions"), and
the Eclipse.app OSGi cache at Path.of("/Applications","Eclipse.app",...))
regardless of home.isBlank(), while only adding the user-specific candidates
(e.g., Path.of(home,"lib"), Path.of(home,".p2"),
Path.of(home,"Applications","Eclipse.app",...)) when home is non-blank; apply
the same separation to the analogous macOS block later in the class (the second
occurrence around the other mac block).
---
Nitpick comments:
In
`@apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SapGuiLandscapeDetector.java`:
- Around line 62-73: The method detectExternalLandscapeUrls(Document document,
Path sourcePath) currently ignores the sourcePath parameter which makes the
emitted Include warnings non-actionable; update the log lines in
detectExternalLandscapeUrls to include the sourcePath (e.g., append
sourcePath.toString() or sourcePath.getFileName()) in the warning messages so
each "External SAP landscape URL detected" and related lines identify which file
triggered them, and ensure sourcePath is null-checked (or if you intentionally
don't need it, remove the sourcePath parameter from the method signature and all
callers).
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5ba0800b-bd60-4bcb-8367-694c2687cf45
📒 Files selected for processing (3)
apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SapGuiLandscapeDetector.javaapps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SetupPathLocator.javaspecs/setup.md
✅ Files skipped from review due to trivial changes (1)
- specs/setup.md
| paths.add(Path.of(home, ".p2", "pool", "plugins")); | ||
| } | ||
|
|
||
| // macOS: Eclipse.app bundle installations | ||
| if (os.contains("mac")) { | ||
| paths.add(Path.of("/Applications", "Eclipse.app", "Contents", "Eclipse", "plugins")); | ||
| paths.add(Path.of("/Applications", "SAP Business Application Studio.app", "Contents", "Eclipse", "plugins")); | ||
| if (!home.isBlank()) { | ||
| paths.add(Path.of(home, "Applications", "Eclipse.app", "Contents", "Eclipse", "plugins")); | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
Deduplicate repeated path literals to satisfy static analysis and reduce path drift risk.
The new macOS path additions repeat literals ("Eclipse.app", "Contents", "Eclipse", "plugins", "libsapcrypto.dylib") that are already flagged by Sonar failures. Promote these to constants and reuse them across the new path builders.
Also applies to: 145-147, 185-188
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis
[failure] 118-118: Define a constant instead of duplicating this literal "Eclipse" 5 times.
[failure] 118-118: Define a constant instead of duplicating this literal "/Applications" 3 times.
[failure] 118-118: Define a constant instead of duplicating this literal "Contents" 5 times.
[failure] 118-118: Define a constant instead of duplicating this literal "Eclipse.app" 4 times.
[failure] 113-113: Define a constant instead of duplicating this literal "plugins" 4 times.
🤖 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
`@apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SetupPathLocator.java`
around lines 113 - 123, The repeated macOS path literal fragments in
SetupPathLocator (e.g., the Path.of(...) calls that use "Eclipse.app",
"Contents", "Eclipse", "plugins", and "libsapcrypto.dylib") should be extracted
into private static final String constants (for example ECLIPSE_APP,
CONTENTS_DIR, ECLIPSE_DIR, PLUGINS_DIR, LIB_SAP_CRYPTO) and then reused when
constructing paths in the methods that call paths.add(Path.of(...)) (including
the blocks shown and the similar code at the other flagged locations around the
other Path.of calls). Replace the repeated string literals with the new
constants to remove duplication and ensure consistent reuse across
SetupPathLocator.
| if (os.contains("mac") && !home.isBlank()) { | ||
| paths.add(Path.of(home, "lib")); | ||
| paths.add(Path.of(home, ".p2")); | ||
| paths.add(Path.of("/usr", "local", "lib")); | ||
| paths.add(Path.of("/Library", "Java", "Extensions")); | ||
| // Eclipse.app OSGi bundle cache (where JCo native lib is extracted) | ||
| paths.add(Path.of("/Applications", "Eclipse.app", "Contents", "Eclipse", "configuration", "org.eclipse.osgi")); | ||
| paths.add(Path.of(home, "Applications", "Eclipse.app", "Contents", "Eclipse", "configuration", "org.eclipse.osgi")); | ||
| } |
There was a problem hiding this comment.
Don’t gate absolute macOS search paths on user.home.
Both macOS blocks skip /usr/local/lib and /Library/... when user.home is blank, even though those paths are independent of home. Split home-dependent and absolute candidates so discovery remains robust in constrained runtimes.
Also applies to: 184-188
🤖 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
`@apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SetupPathLocator.java`
around lines 139 - 147, The macOS path-building in SetupPathLocator currently
wraps both absolute and home-dependent candidates behind a check for non-blank
user.home; update the logic in the method that builds mac paths (the block that
checks os.contains("mac")) to always add the absolute, system-level paths (e.g.,
Path.of("/usr","local","lib") and Path.of("/Library","Java","Extensions"), and
the Eclipse.app OSGi cache at Path.of("/Applications","Eclipse.app",...))
regardless of home.isBlank(), while only adding the user-specific candidates
(e.g., Path.of(home,"lib"), Path.of(home,".p2"),
Path.of(home,"Applications","Eclipse.app",...)) when home is non-blank; apply
the same separation to the analogous macOS block later in the class (the second
occurrence around the other mac block).
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SetupPathLocator.java">
<violation number="1" location="apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SetupPathLocator.java:139">
P2: Absolute system paths (`/usr/local/lib`, `/Library/Java/Extensions`, `/Applications/Eclipse.app/...`) are gated behind `!home.isBlank()`, but they don't depend on the user's home directory. If `user.home` is blank (e.g., in constrained runtimes), these system-wide paths won't be searched. Split the condition so home-dependent paths (like `home/lib`, `home/.p2`) are guarded by the blank check, while absolute paths are only guarded by the OS check.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| String home = System.getProperty(USER_HOME_PROPERTY, ""); | ||
|
|
||
| // macOS-specific paths for JCo native libraries | ||
| if (os.contains("mac") && !home.isBlank()) { |
There was a problem hiding this comment.
P2: Absolute system paths (/usr/local/lib, /Library/Java/Extensions, /Applications/Eclipse.app/...) are gated behind !home.isBlank(), but they don't depend on the user's home directory. If user.home is blank (e.g., in constrained runtimes), these system-wide paths won't be searched. Split the condition so home-dependent paths (like home/lib, home/.p2) are guarded by the blank check, while absolute paths are only guarded by the OS check.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SetupPathLocator.java, line 139:
<comment>Absolute system paths (`/usr/local/lib`, `/Library/Java/Extensions`, `/Applications/Eclipse.app/...`) are gated behind `!home.isBlank()`, but they don't depend on the user's home directory. If `user.home` is blank (e.g., in constrained runtimes), these system-wide paths won't be searched. Split the condition so home-dependent paths (like `home/lib`, `home/.p2`) are guarded by the blank check, while absolute paths are only guarded by the OS check.</comment>
<file context>
@@ -113,6 +132,20 @@ static List<Path> jcoJarRoots() {
+ String home = System.getProperty(USER_HOME_PROPERTY, "");
+
+ // macOS-specific paths for JCo native libraries
+ if (os.contains("mac") && !home.isBlank()) {
+ paths.add(Path.of(home, "lib"));
+ paths.add(Path.of(home, ".p2"));
</file context>
- Add detection for ~/Library/Preferences/SAP/Cache/SAPUILandscape/*.xml - Extract full message server details from cached landscapes - Update S0D config: s0d-cs.sap.booking.com:3600 - Update S0A config: s0a-cs.sap.booking.com:3600 - Now detects 50+ systems automatically from cache Note: RFC connection requires SNC/sapcrypto configuration
|
CodeAnt AI is reviewing your PR. |
| Element include = (Element) includeNodes.item(i); | ||
| String url = blankToNull(include.getAttribute("url")); | ||
| if (url != null) { | ||
| System.err.println("INFO: External SAP landscape URL detected: " + url); |
There was a problem hiding this comment.
Suggestion: The code prints the full external landscape url value directly to stderr, which can leak embedded credentials or internal endpoints into CI logs and terminal history. Redact sensitive URL parts (user-info/query/fragment) or avoid printing the raw URL value. [security]
Severity Level: Critical 🚨
- ❌ External landscape URLs with credentials exposed in stderr logs.
- ⚠️ SetupAnalyzer CLI leaks internal SAP endpoints to operators.Steps of Reproduction ✅
1. Create an SAP GUI landscape file containing an external include, for example `<Include
url="https://user:secret@example.com/SAPUILandscape.xml"/>`, and place it at a location
returned by `SetupPathLocator.sapGuiLandscapeFiles()` (e.g.
`~/Library/Preferences/SAP/SAPGUILandscape.xml` for macOS as configured in
SetupPathLocator.java:37-42).
2. Run the setup analysis flow, which constructs a default `SetupAnalyzer`
(SetupAnalyzer.java:25-36); its constructor wires in a `SapGuiLandscapeDetector` instance
at line 28 and later calls `analyze()` (SetupAnalyzer.java:45-51), causing each
`SystemDetector` to execute `detect()`.
3. Inside `SapGuiLandscapeDetector.detect()` (SapGuiLandscapeDetector.java:35-47), the
detector iterates over paths from `SetupPathLocator.sapGuiLandscapeFiles()`
(SapGuiLandscapeDetector.java:25-27) and, for each existing file, invokes
`parseLandscapeFile(path)` (SapGuiLandscapeDetector.java:49-56).
4. `parseLandscapeFile()` parses the XML into a `Document`
(SapGuiLandscapeDetector.java:51) and calls `detectExternalLandscapeUrls(document, path)`
(line 55); for each `<Include>` element with a non-blank `url` attribute
(SapGuiLandscapeDetector.java:62-67), `detectExternalLandscapeUrls()` executes
`System.err.println("INFO: External SAP landscape URL detected: " + url);` at line 68,
emitting the full external URL—including any embedded credentials, tokens, or internal
hostnames—directly to stderr and into CLI/CI logs.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SapGuiLandscapeDetector.java
**Line:** 68:68
**Comment:**
*Security: The code prints the full external landscape `url` value directly to stderr, which can leak embedded credentials or internal endpoints into CI logs and terminal history. Redact sensitive URL parts (user-info/query/fragment) or avoid printing the raw URL value.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| stream.filter(f -> f.toString().endsWith(".xml")) | ||
| .forEach(paths::add); |
There was a problem hiding this comment.
Suggestion: Cached landscape files are filtered with a case-sensitive .endsWith(".xml"), so valid files like .XML are silently skipped and never parsed. Use a case-insensitive extension check (as done elsewhere in this class) to avoid missing landscape entries. [logic error]
Severity Level: Major ⚠️
- ⚠️ Cached SAP GUI landscapes with .XML extensions ignored.
- ⚠️ Message server hostnames missing from detected system profiles.Steps of Reproduction ✅
1. On macOS, ensure SAP GUI for Java has cached SAP landscape entries in
`~/Library/Preferences/SAP/Cache/SAPUILandscape` (the cache directory constructed in
`sapGuiLandscapeFiles()` at SetupPathLocator.java:41-43), and rename or create a cache
file with an uppercase extension such as `DEV.XML`.
2. Run `new SapGuiLandscapeDetector().detect()` so that its default constructor uses
`SetupPathLocator.sapGuiLandscapeFiles()` (SapGuiLandscapeDetector.java:24-27) to gather
both main landscape and cache files, and `detect()` (SapGuiLandscapeDetector.java:35-47)
iterates over those paths.
3. Inside `sapGuiLandscapeFiles()`, once `Files.exists(cacheDir)` returns true
(SetupPathLocator.java:43), the code lists the cache directory via `Files.list(cacheDir)`
and applies `stream.filter(f -> f.toString().endsWith(".xml"))` at line 45 before adding
entries to the `paths` set at line 46.
4. Because `.endsWith(".xml")` is case-sensitive and operates on the raw path string, a
cache file named `DEV.XML` does not match the filter and is excluded, unlike other XML
detection paths in this class that normalize to lowercase (see `listXmlFiles()` at
SetupPathLocator.java:31-39); as a result, `SapGuiLandscapeDetector.parseLandscapeFile()`
(SapGuiLandscapeDetector.java:49-56) never parses that cached landscape, and any message
server details present only in the cache remain absent from detected `SystemProfile`
entries.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** apps/openadt-bootstrap/src/main/java/org/openadt/bootstrap/SetupPathLocator.java
**Line:** 45:46
**Comment:**
*Logic Error: Cached landscape files are filtered with a case-sensitive `.endsWith(".xml")`, so valid files like `.XML` are silently skipped and never parsed. Use a case-insensitive extension check (as done elsewhere in this class) to avoid missing landscape entries.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished reviewing your PR. |
- Modify SecureLoginHubClient to try API v3 (Windows) first - Fall back to API v2 (macOS) if v3 fails - Note: macOS Secure Login Client uses incompatible API - Requires further investigation for full macOS SNC support Related: macOS Secure Login hub returns 'Only requests in SLC namespace supported'
|
CodeAnt AI is running Incremental review |
|
|
CodeAnt AI Incremental review completed. |
There was a problem hiding this comment.
Gates Failed
Enforce critical code health rules
(1 file with Bumpy Road Ahead)
Enforce advisory code health rules
(2 files with Complex Method, Complex Conditional, Overall Code Complexity, Code Duplication)
Fix Code Health degradations ℹ️
Gates Passed
4 Quality Gates Passed
Reason for failure
| Enforce critical code health rules | Violations | Code Health Impact | |
|---|---|---|---|
| SetupPathLocator.java | 1 critical rule | 9.69 → 8.28 | Suppress |
| Enforce advisory code health rules | Violations | Code Health Impact | |
|---|---|---|---|
| SetupPathLocator.java | 3 advisory rules | 9.69 → 8.28 | Suppress |
| SecureLoginHubClient.java | 1 advisory rule | 9.10 → 8.55 | Suppress |
Quality Gate Profile: Pay Down Tech Debt
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.
| } | ||
| } | ||
|
|
||
| private String webAdapterStatusV3(String encodedProfileId) throws IOException, InterruptedException { |
There was a problem hiding this comment.
❌ New issue: Code Duplication
The module contains 4 functions with similar structure: loginWebAdapterV2,loginWebAdapterV3,webAdapterStatusV2,webAdapterStatusV3
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java (1)
113-125: ⚡ Quick winConsider extracting shared v2/v3 logic to reduce duplication.
The v2 and v3 status methods (lines 99-111 vs 113-125) differ only in the endpoint path (
/slc3/api/statusvs/slc2/api/status) and error message. The same duplication exists for the login methods (lines 140-163 vs 165-188).♻️ Proposed refactor to extract shared logic
+private String webAdapterStatusForApi(String apiVersion, String encodedProfileId) throws IOException, InterruptedException { + URI uri = URI.create(hubBaseUrl + "/slc" + apiVersion + "/api/status?profileid=" + encodedProfileId); + HttpResponse<String> response = httpClient.send( + hubRequest(uri).GET().build(), + HttpResponse.BodyHandlers.ofString() + ); + if (response.statusCode() != 200) { + String versionLabel = "3".equals(apiVersion) ? "" : " v" + apiVersion; + throw new IOException("Secure Login hub" + versionLabel + " status failed with HTTP " + response.statusCode()); + } + JsonNode root = objectMapper.readTree(response.body()); + JsonNode status = root.path("status"); + return status.isTextual() ? status.asText() : "UNKNOWN"; +} + private String webAdapterStatusV3(String encodedProfileId) throws IOException, InterruptedException { - URI uri = URI.create(hubBaseUrl + "/slc3/api/status?profileid=" + encodedProfileId); - HttpResponse<String> response = httpClient.send( - hubRequest(uri).GET().build(), - HttpResponse.BodyHandlers.ofString() - ); - if (response.statusCode() != 200) { - throw new IOException("Secure Login hub status failed with HTTP " + response.statusCode()); - } - JsonNode root = objectMapper.readTree(response.body()); - JsonNode status = root.path("status"); - return status.isTextual() ? status.asText() : "UNKNOWN"; + return webAdapterStatusForApi("3", encodedProfileId); } private String webAdapterStatusV2(String encodedProfileId) throws IOException, InterruptedException { - URI uri = URI.create(hubBaseUrl + "/slc2/api/status?profileid=" + encodedProfileId); - HttpResponse<String> response = httpClient.send( - hubRequest(uri).GET().build(), - HttpResponse.BodyHandlers.ofString() - ); - if (response.statusCode() != 200) { - throw new IOException("Secure Login hub v2 status failed with HTTP " + response.statusCode()); - } - JsonNode root = objectMapper.readTree(response.body()); - JsonNode status = root.path("status"); - return status.isTextual() ? status.asText() : "UNKNOWN"; + return webAdapterStatusForApi("2", encodedProfileId); }Apply the same pattern for the login methods using a shared
loginWebAdapterForApi(String apiVersion, String profileId, boolean browserMonitor)helper.Also applies to: 165-188
🤖 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 `@apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java` around lines 113 - 125, The webAdapterStatusV2 logic is duplicated with the v3 variant; extract a shared helper like webAdapterStatus(String apiVersion, String encodedProfileId) that builds the URI using apiVersion (e.g., "slc2" or "slc3"), sends the request via hubRequest(...), checks the status code and throws the same IOException with a consistent message, then parses and returns the "status" text; similarly refactor the two login methods into a single loginWebAdapterForApi(String apiVersion, String profileId, boolean browserMonitor) that selects the endpoint path based on apiVersion and contains the shared request/response handling so callers of webAdapterStatusV2/webAdapterStatusV3 and the two login methods can delegate to these helpers.
🤖 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
`@apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java`:
- Around line 89-97: In webAdapterStatus(String profileId) and similarly in
loginWebAdapter, preserve the original v3 IOException when falling back to v2 by
catching the v3 exception, logging an explicit message that v3 failed and v2 is
being attempted (include the v3 exception message), then call the v2 method and
if v2 also throws, add the saved v3 IOException as a suppressed exception on the
v2 exception before rethrowing; also consider narrowing the catch to only the
specific exceptions that should trigger a fallback (rather than broad
IOException) so transient/network errors can be handled appropriately.
- Around line 89-97: Tests only cover the v3 path for webAdapterStatus; add unit
tests in SecureLoginHubClientTest to exercise the v3→v2 fallback and both-fail
cases by stubbing/mocking webAdapterStatusV3 and webAdapterStatusV2 behavior:
create tests where webAdapterStatusV3(encodedProfileId) throws different
IOExceptions (e.g., simulate 404, timeout, parse error) and assert that
webAdapterStatus then calls webAdapterStatusV2(encodedProfileId) and returns its
success result, and add tests where both webAdapterStatusV3 and
webAdapterStatusV2 throw to assert the propagated exception/behavior; reference
the methods webAdapterStatus, webAdapterStatusV3, webAdapterStatusV2 to locate
and mock the behavior in the test.
---
Nitpick comments:
In
`@apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java`:
- Around line 113-125: The webAdapterStatusV2 logic is duplicated with the v3
variant; extract a shared helper like webAdapterStatus(String apiVersion, String
encodedProfileId) that builds the URI using apiVersion (e.g., "slc2" or "slc3"),
sends the request via hubRequest(...), checks the status code and throws the
same IOException with a consistent message, then parses and returns the "status"
text; similarly refactor the two login methods into a single
loginWebAdapterForApi(String apiVersion, String profileId, boolean
browserMonitor) that selects the endpoint path based on apiVersion and contains
the shared request/response handling so callers of
webAdapterStatusV2/webAdapterStatusV3 and the two login methods can delegate to
these helpers.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0c7aaa6a-eab3-4f4a-b72d-c6ef2296f540
📒 Files selected for processing (1)
apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java
| public String webAdapterStatus(String profileId) throws IOException, InterruptedException { | ||
| String encodedProfileId = URLEncoder.encode(profileId, StandardCharsets.UTF_8); | ||
| // Try API v3 first (Windows), fall back to v2 (macOS) | ||
| try { | ||
| return webAdapterStatusV3(encodedProfileId); | ||
| } catch (IOException e) { | ||
| return webAdapterStatusV2(encodedProfileId); | ||
| } | ||
| } |
There was a problem hiding this comment.
Preserve v3 error context when falling back to v2.
When v3 fails with IOException and the fallback to v2 also fails, only the v2 error is propagated—the original v3 failure is lost. This makes debugging harder because users won't know that v3 was attempted first or why it failed.
Additionally, the broad IOException catch means any failure (network timeout, parse error, HTTP 404) triggers the v2 fallback. If v3 fails due to a network issue, v2 will likely fail the same way, and the dual attempt adds latency without helping the user understand the root cause.
🔍 Suggested improvement: Add suppressed exception and logging
public String webAdapterStatus(String profileId) throws IOException, InterruptedException {
String encodedProfileId = URLEncoder.encode(profileId, StandardCharsets.UTF_8);
// Try API v3 first (Windows), fall back to v2 (macOS)
try {
return webAdapterStatusV3(encodedProfileId);
} catch (IOException e) {
+ CliLog.info("Secure Login hub API v3 status failed (" + e.getMessage() + "), trying v2 fallback");
+ try {
return webAdapterStatusV2(encodedProfileId);
+ } catch (IOException v2Error) {
+ v2Error.addSuppressed(e);
+ throw v2Error;
+ }
}
}This preserves the v3 error as a suppressed exception and logs the fallback attempt. Apply the same pattern to loginWebAdapter at lines 131-138.
Note: The same issue and fix apply to the loginWebAdapter fallback at lines 131-138.
🤖 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
`@apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java`
around lines 89 - 97, In webAdapterStatus(String profileId) and similarly in
loginWebAdapter, preserve the original v3 IOException when falling back to v2 by
catching the v3 exception, logging an explicit message that v3 failed and v2 is
being attempted (include the v3 exception message), then call the v2 method and
if v2 also throws, add the saved v3 IOException as a suppressed exception on the
v2 exception before rethrowing; also consider narrowing the catch to only the
specific exceptions that should trigger a fallback (rather than broad
IOException) so transient/network errors can be handled appropriately.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Search for tests covering the v2 fallback behavior
# Search for test methods that might cover v2 fallback
rg -n -C5 'slc2/api/(status|login)' --type=java --glob='*Test.java'
# Search for test assertions that check fallback behavior
rg -n -C3 '(webAdapterStatus|loginWebAdapter).*fallback|v2.*fallback|IOException.*v2' --type=java --glob='*Test.java'Repository: abapify/openadt
Length of output: 41
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the main test class for SecureLoginHubClient
fd -i 'SecureLoginHubClientTest.java' -a . || true
fd -i 'SecureLoginHubClient*Test.java' -a . || true
# Find direct references/usages of v2 fallback helpers in tests
rg -n --glob='*Test.java' 'webAdapterStatusV2|loginWebAdapterV2|webAdapterStatusV3|loginWebAdapterV3' . || true
# Search for any stubbing/mocking of slc2/api endpoints for v2 specifically
rg -n --glob='*Test.java' 'slc2/api' . || true
rg -n --glob='*Test.java' 'slc2/api/.*(v2|_v2|version.?2)' . || true
# Search for fallback-related assertions/flow in tests
rg -n --glob='*Test.java' '(fallback|v3 fails|v2 succeeds|catch \(IOException|IOException.*v2)' . || true
# Narrow search to the secure login hub client test files (if present)
TESTS="$(fd -i 'SecureLoginHubClient*Test.java' . -a || true)"
if [ -n "$TESTS" ]; then
rg -n --glob='*Test.java' 'webAdapterStatus|loginWebAdapter' $TESTS || true
fiRepository: abapify/openadt
Length of output: 2652
🏁 Script executed:
#!/bin/bash
set -euo pipefail
TEST_FILE="apps/openadt-sap-adt/src/test/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClientTest.java"
# Show key parts around the existing assertions
nl -ba "$TEST_FILE" | sed -n '1,220p'
# Targeted searches inside the test file for v2/v3/fallback hints
echo "---- rg v2/v3/fallback in SecureLoginHubClientTest.java ----"
rg -n --glob='*.java' '(webAdapterStatusV[23]|loginWebAdapterV[23]|fallback|v3|v2|slc2/api|/v2|/v3|statusV[23])' "$TEST_FILE" || true
echo "---- Search within the test file for IOException-driven fallback patterns ----"
rg -n --glob='*.java' '(catch\s*\(\s*IOException|throws\s*IOException|IOException)' "$TEST_FILE" || true
# Also find any helper test client setup that might indicate endpoint versions
rg -n --glob='*.java' '(mock|stub|wireMock|server|endpoint|url|baseUrl|host|scheme)' "$TEST_FILE" || trueRepository: abapify/openadt
Length of output: 102
🏁 Script executed:
#!/bin/bash
set -euo pipefail
TEST_FILE="apps/openadt-sap-adt/src/test/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClientTest.java"
# Show key parts around the existing assertions using cat -n
sed -n '1,220p' "$TEST_FILE" | cat -n
echo "---- rg v2/v3/fallback hints in SecureLoginHubClientTest.java ----"
rg -n --glob='*.java' '(webAdapterStatusV[23]|loginWebAdapterV[23]|fallback|v3|v2|slc2/api|/v2|/v3|statusV[23])' "$TEST_FILE" || true
echo "---- Search within the test file for IOException-driven fallback patterns ----"
rg -n --glob='*.java' '(catch\s*\(\s*IOException|throws\s*IOException|IOException)' "$TEST_FILE" || true
echo "---- Search within the test file for mocking/endpoint/version hints ----"
rg -n --glob='*.java' '(mock|stub|wireMock|server|endpoint|url|baseUrl|host|scheme)' "$TEST_FILE" || trueRepository: abapify/openadt
Length of output: 9940
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search all test sources for v2 (slc2) endpoint usage and fallback mentions
rg -n --glob='*Test.java' 'slc2/api/(status|login)' . || true
rg -n --glob='*Test.java' '(webAdapterStatusV2|loginWebAdapterV2|webAdapterStatusV3|loginWebAdapterV3)' . || true
rg -n --glob='*Test.java' '(webAdapterStatus|loginWebAdapter).*catch\s*\(IOException|fallback|v2|slc2)' . || trueRepository: abapify/openadt
Length of output: 260
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search all test sources for v2 (slc2) endpoint usage
rg -n --glob='*Test.java' 'slc2/api/(status|login)' . || true
# Search all test sources for explicit v2/v3 helper method names
rg -n --glob='*Test.java' '(webAdapterStatusV[23]|loginWebAdapterV[23])' . || true
# Search for fallback wording and IOException patterns without problematic regex
rg -n --glob='*Test.java' 'fallback' . || true
rg -n --glob='*Test.java' 'IOException' . || true
rg -n --glob='*Test.java' 'v2' . || true
rg -n --glob='*Test.java' 'v3' . || trueRepository: abapify/openadt
Length of output: 10077
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for v2 endpoint paths (secure login hub v2)
rg -n --glob='*Test.java' '/slc2/api/(status|login)' . || true
# Search for v3 endpoint paths (already seen /slc3/api/status in SecureLoginHubClientTest)
rg -n --glob='*Test.java' '/slc3/api/(status|login)' . || true
# Search for direct references to the v2 helper method names
rg -n --glob='*Test.java' 'webAdapterStatusV2|loginWebAdapterV2' . || true
# Search for try/catch patterns mentioning v3->v2 fallback in tests
rg -n --glob='*Test.java' 'webAdapterStatusV3.*catch|loginWebAdapterV3.*catch|fallback to v2|fall back to v2|v2 \\(macOS\\)' . || trueRepository: abapify/openadt
Length of output: 211
Add test coverage for SecureLoginHubClient’s v3→v2 fallback paths
SecureLoginHubClientTest only validates the v3 status endpoint (assertEquals("/slc3/api/status", lastPath)) and doesn’t exercise any /slc2/api/... behavior or the “v3 throws → v2 succeeds/fails” fallback scenarios. Extend tests to cover:
- v3 failing with different
IOExceptioncauses (e.g., 404, timeout, response/parse issues) and v2 succeeding afterward - both v3 and v2 failing (assert the resulting exception/behavior)
Also applies to: 131-138
🤖 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
`@apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java`
around lines 89 - 97, Tests only cover the v3 path for webAdapterStatus; add
unit tests in SecureLoginHubClientTest to exercise the v3→v2 fallback and
both-fail cases by stubbing/mocking webAdapterStatusV3 and webAdapterStatusV2
behavior: create tests where webAdapterStatusV3(encodedProfileId) throws
different IOExceptions (e.g., simulate 404, timeout, parse error) and assert
that webAdapterStatus then calls webAdapterStatusV2(encodedProfileId) and
returns its success result, and add tests where both webAdapterStatusV3 and
webAdapterStatusV2 throw to assert the propagated exception/behavior; reference
the methods webAdapterStatus, webAdapterStatusV3, webAdapterStatusV2 to locate
and mock the behavior in the test.
There was a problem hiding this comment.
3 issues found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java">
<violation number="1" location="apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java:94">
P2: Fallback from v3 to v2 catches all IOExceptions, masking genuine v3 errors (auth failures, server errors) by making a second request to v2</violation>
<violation number="2" location="apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java:95">
P2: Preserve the original v3 IOException when falling back to v2. If v2 also fails, this currently drops the initial v3 failure context, making root-cause diagnosis harder.</violation>
<violation number="3" location="apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java:136">
P2: Retain the original v3 IOException in the login fallback path. When the v2 call also throws, the initial v3 failure should be attached (for example as a suppressed exception) so error reporting keeps full context.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| // Try API v3 first (Windows), fall back to v2 (macOS) | ||
| try { | ||
| return webAdapterStatusV3(encodedProfileId); | ||
| } catch (IOException e) { |
There was a problem hiding this comment.
P2: Fallback from v3 to v2 catches all IOExceptions, masking genuine v3 errors (auth failures, server errors) by making a second request to v2
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java, line 94:
<comment>Fallback from v3 to v2 catches all IOExceptions, masking genuine v3 errors (auth failures, server errors) by making a second request to v2</comment>
<file context>
@@ -88,6 +88,15 @@ public boolean isReachable() {
+ // Try API v3 first (Windows), fall back to v2 (macOS)
+ try {
+ return webAdapterStatusV3(encodedProfileId);
+ } catch (IOException e) {
+ return webAdapterStatusV2(encodedProfileId);
+ }
</file context>
| try { | ||
| loginWebAdapterV3(profileId, browserMonitor); | ||
| } catch (IOException e) { | ||
| loginWebAdapterV2(profileId, browserMonitor); |
There was a problem hiding this comment.
P2: Retain the original v3 IOException in the login fallback path. When the v2 call also throws, the initial v3 failure should be attached (for example as a suppressed exception) so error reporting keeps full context.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java, line 136:
<comment>Retain the original v3 IOException in the login fallback path. When the v2 call also throws, the initial v3 failure should be attached (for example as a suppressed exception) so error reporting keeps full context.</comment>
<file context>
@@ -101,11 +110,34 @@ public String webAdapterStatus(String profileId) throws IOException, Interrupted
+ try {
+ loginWebAdapterV3(profileId, browserMonitor);
+ } catch (IOException e) {
+ loginWebAdapterV2(profileId, browserMonitor);
+ }
+ }
</file context>
| loginWebAdapterV2(profileId, browserMonitor); | |
| try { | |
| loginWebAdapterV2(profileId, browserMonitor); | |
| } catch (IOException v2Error) { | |
| v2Error.addSuppressed(e); | |
| throw v2Error; | |
| } |
| try { | ||
| return webAdapterStatusV3(encodedProfileId); | ||
| } catch (IOException e) { | ||
| return webAdapterStatusV2(encodedProfileId); |
There was a problem hiding this comment.
P2: Preserve the original v3 IOException when falling back to v2. If v2 also fails, this currently drops the initial v3 failure context, making root-cause diagnosis harder.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/openadt-sap-adt/src/main/java/org/openadt/sap/adt/bootstrap/SecureLoginHubClient.java, line 95:
<comment>Preserve the original v3 IOException when falling back to v2. If v2 also fails, this currently drops the initial v3 failure context, making root-cause diagnosis harder.</comment>
<file context>
@@ -88,6 +88,15 @@ public boolean isReachable() {
+ try {
+ return webAdapterStatusV3(encodedProfileId);
+ } catch (IOException e) {
+ return webAdapterStatusV2(encodedProfileId);
+ }
+ }
</file context>
| return webAdapterStatusV2(encodedProfileId); | |
| try { | |
| return webAdapterStatusV2(encodedProfileId); | |
| } catch (IOException v2Error) { | |
| v2Error.addSuppressed(e); | |
| throw v2Error; | |
| } |


User description
Summary by cubic
Fixes macOS/Windows builds without the SAP SDK by using the
distributionprofile and localinstalls. Adds macOS SAP GUI for Java and cached landscape support, broader JCo/SAP Crypto lookup paths, external landscape logging, and a macOS Secure Login API v2 fallback.Bug Fixes
compiletoinstallwith-Pdistribution -Dopenadt.distribution=true -DskipTestsinopenadt-bootstrap,openadt-cli,openadt-config,openadt-sap-adt.distributionprofile; added post-testinstallwhere needed.install -Nbeforeopenadt-configto register the parent POM.-amto avoid modules that require the SAP SDK.packagetargets use thedistributionprofile and skip tests.New Features
~/Library/Preferences/SAP/SAPGUILandscape.xmland cached landscapes at~/Library/Preferences/SAP/Cache/SAPUILandscape/*.xml; extract message server details; log info when<Include url="...">points to external landscapes..p2pool, system lib dirs) and SAP Crypto candidates.specs/setup.mdwith macOS paths and external landscape behavior.Written for commit 0c69767. Summary will update on new commits.
Summary by CodeRabbit
Chores
New Features
Documentation
CodeAnt-AI Description
Fix cross-platform builds and add macOS SAP setup support
What Changed
Impact
✅ Fewer build failures on macOS and Windows✅ Easier first-time setup on macOS✅ Fewer missing SAP landscape details✅ More reliable Secure Login on macOS💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.