Skip to content

#1965: improve dependent installation - #2246

Open
MeShehi wants to merge 11 commits into
devonfw:mainfrom
MeShehi:1965_improve_dependent
Open

#1965: improve dependent installation#2246
MeShehi wants to merge 11 commits into
devonfw:mainfrom
MeShehi:1965_improve_dependent

Conversation

@MeShehi

@MeShehi MeShehi commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

This PR fixes #1965

Implemented changes:

  • Fixed npm and pip-based installation to avoid double installation cycle
  • Added ToolInstallRequest as a parent of PackageManagerRequest, added possibility to use PackageManagerRequest as a parent to ToolinstallRequest

Testing instructions

  1. Create or edit your configuration to run -cp ide-cli with ide uninstall npm and run, wait to end
  2. Run the same configuration with ide install nest
  3. No duplication should be present by the logs shown in terminal

Checklist for this PR

Make sure everything is checked before merging this PR. For further info please also see
our DoD.

  • When running mvn clean test locally all tests pass and build is successful
  • PR title is of the form #«issue-id»: «brief summary» (e.g. #921: fixed setup.bat). If no issue ID exists, title only.
  • PR top-level comment summarizes what has been done and contains link to addressed issue(s)
  • PR and issue(s) have suitable labels
  • Issue is set to In Progress and assigned to you or there is no issue (might happen for very small PRs)
  • You followed all coding conventions
  • You have added the issue implemented by your PR in CHANGELOG.adoc unless issue is labeled
    with internal
  • You have formulated clear instructions on how to test your contribution under "Testing instructions"

@MeShehi MeShehi self-assigned this Aug 3, 2026
@MeShehi MeShehi moved this from 🆕 New to Team Review in IDEasy board Aug 3, 2026
@MeShehi

MeShehi commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Please, when checking the code give extra attention to ToolInstallRequest.detectInstallLoopRecursively, since that's where I suspect the new changes might have unsuspected failures. The tests do pass, but maybe edge cases are not covered

@coveralls

coveralls commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 30882542201

Coverage increased (+0.03%) to 72.616%

Details

  • Coverage increased (+0.03%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 25 coverage regressions across 4 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

25 previously-covered lines in 4 files lost coverage.

File Lines Losing Coverage Coverage
com/devonfw/tools/ide/tool/ToolInstallRequest.java 17 75.17%
com/devonfw/tools/ide/tool/PackageManagerRequest.java 5 77.78%
com/devonfw/tools/ide/tool/PackageManagerBasedLocalToolCommandlet.java 2 90.59%
com/devonfw/tools/ide/version/VersionSegment.java 1 90.55%

Coverage Stats

Coverage Status
Relevant Lines: 17274
Covered Lines: 13087
Line Coverage: 75.76%
Relevant Branches: 7657
Covered Branches: 5017
Branch Coverage: 65.52%
Branches in Coverage %: Yes
Coverage Strength: 3.21 hits per line

💛 - Coveralls

@quando632 quando632 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What works well

The root cause is correctly identified. runPackageManager built the nested install request without a parent, so isInstallLoop() could never see the cycle. A repeated ide install nest now skips the extra npm installation cycle that ran before, which is what the issue asks for.

NpmBasedCommandlet.java:68 and PipBasedCommandlet.java:113 also bring both callers in line with the contract already documented on computeInstalledVersion.

Findings

1. PackageManagerBasedLocalToolCommandlet.java:94 no longer uses pc.createChild(). The nested install now shares the caller's ProcessContext, including errorHandling and exitCodeAcceptor, which the child deliberately resets (ProcessContextImpl.java:84). Restoring it has to happen inside the constructor, since setProcessContext rejects a second write.

2. ToolInstallRequest.java:69 hard-codes silent to false, the replaced code passed true. With the current ng fixture this moves the "already installed" lines for node and npm from DEBUG to INFO. Was that intended, or should the flag come from the parent request?

3. The fixed duplication has no test. computeInstalledVersion is only reached on a repeated installation, so a second install() in NgTest pins it. The mock npm in the ng fixture needs a list branch for this, it currently answers --version only:

commandlet.install();
context.getTestStartContext().getEntries().clear();
commandlet.install();
assertThat(context).log().hasNoMessageContaining("No CVEs found for version 9.9.2 of tool npm");

4. Step 1 of the testing instructions has no effect. ide uninstall npm refuses the uninstall because Npm.canBeUninstalled() is false, and still prints "Successfully uninstalled npm". Running ide install nest twice reproduces the duplication reliably and would be the clearer instruction.

Optional: one parent field instead of two

Both inline bugs come from two mutually exclusive parent fields with two constructors that must be kept in sync. Resolving the parent in runPackageManager via request.getToolInstallRequest() keeps a single field, and the nested request then inherits silent and ignoreProject automatically.

Nits

  • ToolInstallRequest.java:90: the private constructor has no javadoc, and its silent and direct parameters are always false at the single call site.
  • PackageManagerBasedLocalToolCommandlet.java:93 lost the // See Node.postInstallOnNewInstallation pointer that explained the npm/node cycle.

Comment on lines +137 to +141
} else if (this.parentPackageManagerRequest != null) {
if (this.parentPackageManagerRequest.getType().equals("uninstall")) {
return false;
}
loopFound = this.parentPackageManagerRequest.getToolInstallRequest().detectInstallLoopRecursively(toolEditionAndVersion, sb);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

getToolInstallRequest() is null for every request that carries no tool installation, so only the hard-coded "uninstall" comparison keeps this from dereferencing null. The public one-arg runPackageManager makes other types reachable. Guarding on the parent itself covers the uninstall case too, since those requests never carry one.

Suggested change
} else if (this.parentPackageManagerRequest != null) {
if (this.parentPackageManagerRequest.getType().equals("uninstall")) {
return false;
}
loopFound = this.parentPackageManagerRequest.getToolInstallRequest().detectInstallLoopRecursively(toolEditionAndVersion, sb);
} else if (this.parentPackageManagerRequest != null) {
// a package manager request without tool installation (e.g. uninstall) cannot be part of an installation loop
ToolInstallRequest parentRequest = this.parentPackageManagerRequest.getToolInstallRequest();
if (parentRequest == null) {
return false;
}
loopFound = parentRequest.detectInstallLoopRecursively(toolEditionAndVersion, sb);

Comment on lines +96 to +98
if (parent != null) {
this.processContext = parent.getProcessContext();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This constructor does not propagate ignoreProject, while the constructor above it does (line 86). An install request that ignores the project therefore loses that flag as soon as it goes through a package manager, silently and without any error.

Suggested change
if (parent != null) {
this.processContext = parent.getProcessContext();
}
if (parent != null) {
this.processContext = parent.getProcessContext();
ToolInstallRequest parentRequest = parent.getToolInstallRequest();
if (parentRequest != null) {
this.ignoreProject = parentRequest.ignoreProject;
}
}

Comment thread CHANGELOG.adoc
Comment on lines +9 to +10
* https://github.com/devonfw/IDEasy/issues/1965[#1965]: Improve dependent installation, fixed npm and pip-based installation duplication
* https://github.com/devonfw/IDEasy/issues/2100[#2100]: Fix Python not available for Mac x64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The #2100 entry already exists further down in the same release block, added by PR #2152.

Suggested change
* https://github.com/devonfw/IDEasy/issues/1965[#1965]: Improve dependent installation, fixed npm and pip-based installation duplication
* https://github.com/devonfw/IDEasy/issues/2100[#2100]: Fix Python not available for Mac x64
* https://github.com/devonfw/IDEasy/issues/1965[#1965]: Improve dependent installation, fixed npm and pip-based installation duplication

Comment on lines +178 to +183
/**
* @param toolInstallRequest new value of {@link #getToolInstallRequest()} ToolInstallRequest()}.
* @return this {@link PackageManagerRequest} for fluent API calls.
*/
public PackageManagerRequest setToolInstallRequest(
ToolInstallRequest toolInstallRequest) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The javadoc contains a copy/paste artifact, and the signature fits on one line within the 160 character limit.

Suggested change
/**
* @param toolInstallRequest new value of {@link #getToolInstallRequest()} ToolInstallRequest()}.
* @return this {@link PackageManagerRequest} for fluent API calls.
*/
public PackageManagerRequest setToolInstallRequest(
ToolInstallRequest toolInstallRequest) {
/**
* @param toolInstallRequest new value of {@link #getToolInstallRequest()}.
* @return this {@link PackageManagerRequest} for fluent API calls.
*/
public PackageManagerRequest setToolInstallRequest(ToolInstallRequest toolInstallRequest) {

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

Labels

None yet

Projects

Status: Team Review

Development

Successfully merging this pull request may close these issues.

Improve dependent installations

3 participants