From d80039952b87131de857cc7579b09447cdb736c0 Mon Sep 17 00:00:00 2001 From: Markus Heberling Date: Sun, 19 Sep 2021 11:47:25 +0200 Subject: [PATCH] support installing npm version from package.json engines fixes #798 --- .../it/npm-version-from-engines/package.json | 13 ++++ .../src/it/npm-version-from-engines/pom.xml | 50 ++++++++++++++++ .../it/npm-version-from-engines/verify.groovy | 9 +++ .../plugins/frontend/lib/NPMInstaller.java | 59 ++++++++++++++++++- 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 frontend-maven-plugin/src/it/npm-version-from-engines/package.json create mode 100644 frontend-maven-plugin/src/it/npm-version-from-engines/pom.xml create mode 100644 frontend-maven-plugin/src/it/npm-version-from-engines/verify.groovy diff --git a/frontend-maven-plugin/src/it/npm-version-from-engines/package.json b/frontend-maven-plugin/src/it/npm-version-from-engines/package.json new file mode 100644 index 000000000..bd375490d --- /dev/null +++ b/frontend-maven-plugin/src/it/npm-version-from-engines/package.json @@ -0,0 +1,13 @@ +{ + "name": "example", + "version": "0.0.1", + "engines": { + "npm": ">=7 <8" + }, + "dependencies": { + "less": "~3.0.2" + }, + "scripts": { + "prebuild": "npm install" + } +} diff --git a/frontend-maven-plugin/src/it/npm-version-from-engines/pom.xml b/frontend-maven-plugin/src/it/npm-version-from-engines/pom.xml new file mode 100644 index 000000000..8c1a8fd9b --- /dev/null +++ b/frontend-maven-plugin/src/it/npm-version-from-engines/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + com.github.eirslett + example + 0 + pom + + + + + com.github.eirslett + frontend-maven-plugin + + @project.version@ + + + target + + + + + + install node and npm + + install-node-and-npm + + + v16.0.0 + engines + + + + + npm install + + npm + + + + install + + + + + + + + diff --git a/frontend-maven-plugin/src/it/npm-version-from-engines/verify.groovy b/frontend-maven-plugin/src/it/npm-version-from-engines/verify.groovy new file mode 100644 index 000000000..0a9d23ea4 --- /dev/null +++ b/frontend-maven-plugin/src/it/npm-version-from-engines/verify.groovy @@ -0,0 +1,9 @@ +assert new File(basedir, 'target/node').exists() : "Node was not installed in the custom install directory"; +assert new File(basedir, 'node_modules').exists() : "Node modules were not installed in the base directory"; +assert new File(basedir, 'target/node/npm').exists() : "npm was not copied to the node directory"; + +import org.codehaus.plexus.util.FileUtils; + +String buildLog = FileUtils.fileRead(new File(basedir, 'build.log')); + +assert buildLog.contains('BUILD SUCCESS') : 'build was not successful' diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/NPMInstaller.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/NPMInstaller.java index 34f156470..58352a0a1 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/NPMInstaller.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/NPMInstaller.java @@ -6,6 +6,10 @@ import java.io.IOException; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import com.vdurmont.semver4j.Requirement; +import com.vdurmont.semver4j.Semver; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +32,8 @@ public class NPMInstaller { private final FileDownloader fileDownloader; + private Requirement npmVersionRequirement; + NPMInstaller(InstallConfig config, ArchiveExtractor archiveExtractor, FileDownloader fileDownloader) { this.logger = LoggerFactory.getLogger(getClass()); this.config = config; @@ -78,7 +84,53 @@ public void install() throws InstallationException { if (this.npmDownloadRoot == null || this.npmDownloadRoot.isEmpty()) { this.npmDownloadRoot = DEFAULT_NPM_DOWNLOAD_ROOT; } + if ("engines".equals(this.npmVersion)) { + try { + File packageFile = new File(this.config.getWorkingDirectory(), "package.json"); + HashMap data = new ObjectMapper().readValue(packageFile, HashMap.class); + if (data.containsKey("engines")) { + HashMap engines = (HashMap) data.get("engines"); + if (engines.containsKey("npm")) { + this.npmVersionRequirement = Requirement.buildNPM((String) engines.get("npm")); + } else { + this.logger.info("Could not read npm from engines from package.json"); + } + } else { + this.logger.info("Could not read engines from package.json"); + } + } catch (IOException e) { + throw new InstallationException("Could not read npm engine version from package.json", e); + } + } + if (!npmProvided() && !npmIsAlreadyInstalled()) { + if (this.npmVersionRequirement != null) { + // download available node versions + try { + String downloadUrl = this.npmDownloadRoot + + ".."; + + File archive = File.createTempFile("npm_versions", ".json"); + + downloadFile(downloadUrl, archive, this.userName, this.password); + + HashMap data = new ObjectMapper().readValue(archive, HashMap.class); + + List npmVersions = new LinkedList<>(); + if (data.containsKey("versions")) { + HashMap versions = (HashMap) data.get("versions"); + npmVersions.addAll(versions.keySet()); + } else { + this.logger.info("Could not read versions from NPM registry"); + } + + logger.debug("Available NPM versions: {}", npmVersions); + 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)); + this.logger.info("Found matching NPM version {} satisfying requirement {}.", this.npmVersion, this.npmVersionRequirement); + } catch (IOException | DownloadException e) { + throw new InstallationException("Could not get available node versions.", e); + } + } installNpm(); } copyNpmScripts(); @@ -93,7 +145,12 @@ private boolean npmIsAlreadyInstalled() { HashMap data = new ObjectMapper().readValue(npmPackageJson, HashMap.class); if (data.containsKey(VERSION)) { final String foundNpmVersion = data.get(VERSION).toString(); - if (foundNpmVersion.equals(this.npmVersion)) { + if (npmVersionRequirement != null && npmVersionRequirement.isSatisfiedBy(new Semver(foundNpmVersion, Semver.SemverType.NPM))) { + //update version with installed version + this.nodeVersion = foundNpmVersion; + this.logger.info("NPM {} matches required version range {} installed.", foundNpmVersion, npmVersionRequirement); + return true; + } else if (foundNpmVersion.equals(this.npmVersion)) { this.logger.info("NPM {} is already installed.", foundNpmVersion); return true; } else {