Skip to content

Commit d800399

Browse files
committed
support installing npm version from package.json engines
fixes #798
1 parent 6e30d51 commit d800399

File tree

4 files changed

+130
-1
lines changed

4 files changed

+130
-1
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "example",
3+
"version": "0.0.1",
4+
"engines": {
5+
"npm": ">=7 <8"
6+
},
7+
"dependencies": {
8+
"less": "~3.0.2"
9+
},
10+
"scripts": {
11+
"prebuild": "npm install"
12+
}
13+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<groupId>com.github.eirslett</groupId>
6+
<artifactId>example</artifactId>
7+
<version>0</version>
8+
<packaging>pom</packaging>
9+
10+
<build>
11+
<plugins>
12+
<plugin>
13+
<groupId>com.github.eirslett</groupId>
14+
<artifactId>frontend-maven-plugin</artifactId>
15+
<!-- NB! Set <version> to the latest released version of frontend-maven-plugin, like in README.md -->
16+
<version>@project.version@</version>
17+
18+
<configuration>
19+
<installDirectory>target</installDirectory>
20+
</configuration>
21+
22+
<executions>
23+
24+
<execution>
25+
<id>install node and npm</id>
26+
<goals>
27+
<goal>install-node-and-npm</goal>
28+
</goals>
29+
<configuration>
30+
<nodeVersion>v16.0.0</nodeVersion>
31+
<npmVersion>engines</npmVersion>
32+
</configuration>
33+
</execution>
34+
35+
<execution>
36+
<id>npm install</id>
37+
<goals>
38+
<goal>npm</goal>
39+
</goals>
40+
<!-- Optional configuration which provides for running any npm command -->
41+
<configuration>
42+
<arguments>install</arguments>
43+
</configuration>
44+
</execution>
45+
46+
</executions>
47+
</plugin>
48+
</plugins>
49+
</build>
50+
</project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
assert new File(basedir, 'target/node').exists() : "Node was not installed in the custom install directory";
2+
assert new File(basedir, 'node_modules').exists() : "Node modules were not installed in the base directory";
3+
assert new File(basedir, 'target/node/npm').exists() : "npm was not copied to the node directory";
4+
5+
import org.codehaus.plexus.util.FileUtils;
6+
7+
String buildLog = FileUtils.fileRead(new File(basedir, 'build.log'));
8+
9+
assert buildLog.contains('BUILD SUCCESS') : 'build was not successful'

frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/NPMInstaller.java

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
import java.io.IOException;
77
import java.util.Arrays;
88
import java.util.HashMap;
9+
import java.util.LinkedList;
10+
import java.util.List;
11+
import com.vdurmont.semver4j.Requirement;
12+
import com.vdurmont.semver4j.Semver;
913
import org.apache.commons.io.FileUtils;
1014
import org.slf4j.Logger;
1115
import org.slf4j.LoggerFactory;
@@ -28,6 +32,8 @@ public class NPMInstaller {
2832

2933
private final FileDownloader fileDownloader;
3034

35+
private Requirement npmVersionRequirement;
36+
3137
NPMInstaller(InstallConfig config, ArchiveExtractor archiveExtractor, FileDownloader fileDownloader) {
3238
this.logger = LoggerFactory.getLogger(getClass());
3339
this.config = config;
@@ -78,7 +84,53 @@ public void install() throws InstallationException {
7884
if (this.npmDownloadRoot == null || this.npmDownloadRoot.isEmpty()) {
7985
this.npmDownloadRoot = DEFAULT_NPM_DOWNLOAD_ROOT;
8086
}
87+
if ("engines".equals(this.npmVersion)) {
88+
try {
89+
File packageFile = new File(this.config.getWorkingDirectory(), "package.json");
90+
HashMap<String, Object> data = new ObjectMapper().readValue(packageFile, HashMap.class);
91+
if (data.containsKey("engines")) {
92+
HashMap<String, Object> engines = (HashMap<String, Object>) data.get("engines");
93+
if (engines.containsKey("npm")) {
94+
this.npmVersionRequirement = Requirement.buildNPM((String) engines.get("npm"));
95+
} else {
96+
this.logger.info("Could not read npm from engines from package.json");
97+
}
98+
} else {
99+
this.logger.info("Could not read engines from package.json");
100+
}
101+
} catch (IOException e) {
102+
throw new InstallationException("Could not read npm engine version from package.json", e);
103+
}
104+
}
105+
81106
if (!npmProvided() && !npmIsAlreadyInstalled()) {
107+
if (this.npmVersionRequirement != null) {
108+
// download available node versions
109+
try {
110+
String downloadUrl = this.npmDownloadRoot
111+
+ "..";
112+
113+
File archive = File.createTempFile("npm_versions", ".json");
114+
115+
downloadFile(downloadUrl, archive, this.userName, this.password);
116+
117+
HashMap<String, Object> data = new ObjectMapper().readValue(archive, HashMap.class);
118+
119+
List<String> npmVersions = new LinkedList<>();
120+
if (data.containsKey("versions")) {
121+
HashMap<String, Object> versions = (HashMap<String, Object>) data.get("versions");
122+
npmVersions.addAll(versions.keySet());
123+
} else {
124+
this.logger.info("Could not read versions from NPM registry");
125+
}
126+
127+
logger.debug("Available NPM versions: {}", npmVersions);
128+
this.npmVersion = npmVersions.stream().filter(version -> npmVersionRequirement.isSatisfiedBy(new Semver(version, Semver.SemverType.NPM))).findFirst().orElseThrow(() -> new InstallationException("Could not find matching node version satisfying requirement " + this.npmVersionRequirement));
129+
this.logger.info("Found matching NPM version {} satisfying requirement {}.", this.npmVersion, this.npmVersionRequirement);
130+
} catch (IOException | DownloadException e) {
131+
throw new InstallationException("Could not get available node versions.", e);
132+
}
133+
}
82134
installNpm();
83135
}
84136
copyNpmScripts();
@@ -93,7 +145,12 @@ private boolean npmIsAlreadyInstalled() {
93145
HashMap<String, Object> data = new ObjectMapper().readValue(npmPackageJson, HashMap.class);
94146
if (data.containsKey(VERSION)) {
95147
final String foundNpmVersion = data.get(VERSION).toString();
96-
if (foundNpmVersion.equals(this.npmVersion)) {
148+
if (npmVersionRequirement != null && npmVersionRequirement.isSatisfiedBy(new Semver(foundNpmVersion, Semver.SemverType.NPM))) {
149+
//update version with installed version
150+
this.nodeVersion = foundNpmVersion;
151+
this.logger.info("NPM {} matches required version range {} installed.", foundNpmVersion, npmVersionRequirement);
152+
return true;
153+
} else if (foundNpmVersion.equals(this.npmVersion)) {
97154
this.logger.info("NPM {} is already installed.", foundNpmVersion);
98155
return true;
99156
} else {

0 commit comments

Comments
 (0)