• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 17820842601

18 Sep 2025 07:05AM UTC coverage: 68.539% (-0.08%) from 68.618%
17820842601

push

github

web-flow
#1491: fix reuse software from repo (#1495)

3420 of 5461 branches covered (62.63%)

Branch coverage included in aggregate %.

8919 of 12542 relevant lines covered (71.11%)

3.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.14
cli/src/main/java/com/devonfw/tools/ide/tool/npm/NpmBasedCommandlet.java
1
package com.devonfw.tools.ide.tool.npm;
2

3
import java.nio.file.Files;
4
import java.nio.file.Path;
5
import java.util.List;
6
import java.util.Set;
7

8
import com.devonfw.tools.ide.cache.CachedValue;
9
import com.devonfw.tools.ide.common.Tag;
10
import com.devonfw.tools.ide.context.IdeContext;
11
import com.devonfw.tools.ide.process.ProcessContext;
12
import com.devonfw.tools.ide.process.ProcessErrorHandling;
13
import com.devonfw.tools.ide.process.ProcessMode;
14
import com.devonfw.tools.ide.process.ProcessResult;
15
import com.devonfw.tools.ide.tool.LocalToolCommandlet;
16
import com.devonfw.tools.ide.tool.repository.ToolRepository;
17
import com.devonfw.tools.ide.version.VersionIdentifier;
18

19
/**
20
 * {@link LocalToolCommandlet} for tools based on <a href="https://www.npmjs.com/">npm</a>.
21
 */
22
public abstract class NpmBasedCommandlet extends LocalToolCommandlet {
23

24
  private final CachedValue<VersionIdentifier> installedVersion;
25

26
  /**
27
   * The constructor.
28
   *
29
   * @param context the {@link IdeContext}.
30
   * @param tool the {@link #getName() tool name}.
31
   * @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} method.
32
   */
33
  public NpmBasedCommandlet(IdeContext context, String tool, Set<Tag> tags) {
34

35
    super(context, tool, tags);
5✔
36
    this.installedVersion = new CachedValue<>(() -> runNpmGetInstalledPackageVersion(getNpmPackage()));
12✔
37
  }
1✔
38

39
  @Override
40
  protected boolean isIgnoreSoftwareRepo() {
41

42
    // node and node.js are messy - see https://github.com/devonfw/IDEasy/issues/352
43
    return true;
2✔
44
  }
45

46
  @Override
47
  protected boolean isIgnoreMissingSoftwareVersionFile() {
48

49
    return true;
2✔
50
  }
51

52
  /**
53
   * @return the package of this tool from the NPM registry.
54
   */
55
  protected abstract String getNpmPackage();
56

57
  @Override
58
  public Path getToolPath() {
59

60
    Path toolPath = this.context.getSoftwarePath().resolve("node");
6✔
61
    if (!this.context.getSystemInfo().isWindows()) {
5✔
62
      toolPath = toolPath.resolve("bin");
4✔
63
    }
64
    return toolPath;
2✔
65
  }
66

67
  protected VersionIdentifier runNpmGetInstalledPackageVersion(String npmPackage) {
68
    if (!Files.isDirectory(this.context.getSoftwarePath().resolve("node"))) {
9!
69
      this.context.trace("Since node is not installed, also package {} for tool {} cannot be installed.", npmPackage, this.tool);
15✔
70
      return null;
2✔
71
    }
72
    ProcessResult result = runNpm(ProcessMode.DEFAULT_CAPTURE, ProcessErrorHandling.NONE, "list", "-g", npmPackage, "--depth=0");
×
73
    if (result.isSuccessful()) {
×
74
      List<String> versions = result.getOut();
×
75
      String parsedVersion = null;
×
76
      for (String version : versions) {
×
77
        if (version.contains(npmPackage)) {
×
78
          parsedVersion = version.replaceAll(".*" + npmPackage + "@", "");
×
79
          break;
×
80
        }
81
      }
×
82
      if (parsedVersion != null) {
×
83
        return VersionIdentifier.of(parsedVersion);
×
84
      }
85
    } else {
×
86
      this.context.debug("The npm package {} for tool {} is not installed.", npmPackage, this.tool);
×
87
    }
88
    return null;
×
89
  }
90

91
  @Override
92
  public VersionIdentifier getInstalledVersion() {
93

94
    return this.installedVersion.get();
5✔
95
  }
96

97
  @Override
98
  public String getInstalledEdition() {
99

100
    if (getInstalledVersion() != null) {
3!
101
      return this.tool;
×
102
    }
103
    return null;
2✔
104
  }
105

106
  @Override
107
  protected void performToolInstallation(ToolRepository toolRepository, VersionIdentifier resolvedVersion, Path installationPath, String edition,
108
      ProcessContext processContext) {
109

110
    // runNpmUninstall(getNpmPackage()); // first uninstall a previously installed version
111
    runNpmInstall(getNpmPackage() + "@" + resolvedVersion);
8✔
112
    this.installedVersion.invalidate();
3✔
113
  }
1✔
114

115
  @Override
116
  protected void performUninstall(Path toolPath) {
117

118
    runNpmUninstall(getNpmPackage());
4✔
119
    this.installedVersion.invalidate();
3✔
120
  }
1✔
121

122
  /**
123
   * Performs a global npm uninstall.
124
   *
125
   * @param npmPackage the npm package to uninstall.
126
   */
127
  protected void runNpmUninstall(String npmPackage) {
128
    runNpm("uninstall", "-g", npmPackage).failOnError();
17✔
129
  }
1✔
130

131
  /**
132
   * Performs a global npm install.
133
   *
134
   * @param npmPackage the npm package to install.
135
   * @return the {@link ProcessResult} of the npm execution.
136
   */
137
  protected ProcessResult runNpmInstall(String npmPackage) {
138

139
    return runNpm("install", "-g", npmPackage);
17✔
140
  }
141

142
  private ProcessResult runNpm(String... args) {
143

144
    return runNpm(ProcessMode.DEFAULT, ProcessErrorHandling.THROW_CLI, args);
6✔
145
  }
146

147
  private ProcessResult runNpm(ProcessMode processMode, ProcessErrorHandling errorHandling, String... args) {
148

149
    ProcessContext pc = this.context.newProcess().errorHandling(errorHandling);
6✔
150
    Npm npm = this.context.getCommandletManager().getCommandlet(Npm.class);
7✔
151
    return npm.runTool(processMode, null, pc, args);
7✔
152
  }
153

154
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc