diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ffd2707..870a29d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,6 +5,8 @@ on: tags: - 'v[0-9]+.[0-9]+.[0-9]+' - 'v[0-9]+.[0-9]+.[0-9]+-*' + workflow_dispatch: + jobs: run-build: @@ -23,7 +25,14 @@ jobs: run: Copy-Item (Get-Command node.exe | Select-Object -ExpandProperty Definition) . - run: npm test - run: npm run build + - name: Archive build artifact + if: github.ref_type == 'branch' + uses: actions/upload-artifact@v3 + with: + name: Installer + path: "build/out/NodistSetup-*.exe" - name: Create release draft + if: github.ref_type == 'tag' uses: ncipollo/release-action@v1 with: artifacts: "build/out/NodistSetup-*.exe" diff --git a/build/build.js b/build/build.js index 238577f..c136dd5 100644 --- a/build/build.js +++ b/build/build.js @@ -5,6 +5,7 @@ var fs = require('fs'); var mkdirp = require('mkdirp'); var ncp = require('ncp'); var path = require('path'); +var semver = require('semver'); var recursiveReaddir = require('recursive-readdir'); var request = require('request'); var rimraf = require('rimraf'); @@ -83,6 +84,7 @@ var npm = new (require('../lib/npm'))({nodistDir: stagingDir}); //default npm version to the latest at the time of writing var npmVersion = '6.14.16'; var nodeVersion = '16.15.0'; +var maxNodeMainVersion = '^20'; var versionPathx86 = ''; var versionPathx64 = ''; @@ -102,31 +104,14 @@ console.log('Welcome to the Nodist Builder'); console.log(' before going further we need to prep our staging folder'); //defining helper functions -function getLatestNodeVersionFor(nodeVersions, fileType) { +function getLatestUsableNodeVersionFor(nodeVersions, fileType) { for (var key in nodeVersions) { - if (nodeVersions[key].files.includes(fileType)) { - return nodeVersions[key].version; + if (nodeVersions[key].files.includes(fileType) && semver.satisfies(nodeVersions[key].version, maxNodeMainVersion)) { + return { nodeVersion: nodeVersions[key].version, npmVersion: nodeVersions[key].npm }; } } } -async function resolveLinkedWorkspaces(dirPath) { - let movedLinks = 0; - const files = await fs.readdirAsync(dirPath, { withFileTypes: true }); - const dirPromises = []; - for (const file of files) { - const filePath = path.join(dirPath, file.name); - if (file.isSymbolicLink()) { - const linkTarget = await fs.readlinkAsync(filePath); - await fs.renameAsync(path.join(dirPath, linkTarget), filePath); - movedLinks++; - } else if (file.isDirectory()) { - dirPromises.push(resolveLinkedWorkspaces(filePath)); - } - } - return (await Promise.all(dirPromises)).reduce((sum, num) => sum + num, movedLinks); -} - //start by clearing the staging and tmp folders P.all([ rimraf(outDir), @@ -217,7 +202,7 @@ P.all([ }); }) .then(function(res){ - nodeVersion = getLatestNodeVersionFor(res.body, 'win-x86-exe'); + ({ nodeVersion, npmVersion } = getLatestUsableNodeVersionFor(res.body, 'win-x86-exe')); nodeLatestUrlx86 = nodeLatestUrlx86.replace('VERSION',nodeVersion); nodeLatestUrlx64 = nodeLatestUrlx64.replace('VERSION',nodeVersion); console.log('Latest version of Node ' + nodeVersion); @@ -253,14 +238,9 @@ P.all([ ); }) .then(function(){ - console.log('Figure out the latest version of NPM'); - return npm.latestVersion(); - }) - .then(function(version){ - npmVersion = version; - var downloadLink = npm.downloadUrl(version); - console.log('Determined latest NPM as ' + npmVersion); - console.log('Downloading latest NPM from ' + downloadLink); + var downloadLink = npm.downloadUrl(npmVersion); + console.log('Determined matching NPM as ' + npmVersion); + console.log('Downloading matching NPM from ' + downloadLink); return Promise.resolve() .then(() => mkdirp(stagingNpmDir+'/'+npmVersion.replace('v',''))) .then(() => { @@ -291,7 +271,7 @@ P.all([ }) .then(function() { console.log('Installation complete'); - return resolveLinkedWorkspaces(path.join(stagingNpmDir, npmVersion.replace('v', ''), 'node_modules')); + return helper.resolveLinkedWorkspaces(path.join(stagingNpmDir, npmVersion.replace('v', '')), false); }) .then(function(movedLinks) { if (movedLinks) { diff --git a/lib/build.js b/lib/build.js index 5e60f44..d76b68c 100644 --- a/lib/build.js +++ b/lib/build.js @@ -4,8 +4,12 @@ var path = require('path'); var promisePipe = require('promisepipe'); var ProgressBar = require('progress'); var request = require('request'); +const P = require('bluebird'); var debug = require('debug')('nodist:build') +//make some promising APIs +P.promisifyAll(fs); + /** * Copy File * @param {string} source @@ -141,3 +145,51 @@ exports.downloadFileStream = function downloadFileStream(url) { }); return req } + +/** + * Npm version >= 18 using symlinks that do not work in windows and have to be fixed + * this function replace the broken symlinks with NTFS junction or move the directory if junctions are not supported + * + * @param {string} dirPath + * @param {boolean} preferSymlink + * @returns {Promise} number of changed links + */ +exports.resolveLinkedWorkspaces = async function resolveLinkedWorkspaces(dirPath, preferSymlink = true) { + let fixedLinks = 0; + const packageLockJson = JSON.parse(fs.readFileSync(path.join(dirPath, 'package-lock.json')).toString()); + await Promise.all(Object.entries(packageLockJson.packages) + .filter(([pkgPath, pkg]) => pkg.link === true) + .map(async ([pkgPath, pkg]) => { + + const linkPath = path.join(dirPath, pkgPath); + + + if (await fs.accessAsync(linkPath, fs.constants.F_OK).then(() => true).catch(() => false)) { + await fs.unlinkAsync(linkPath); + } + + let linkCreated = false; + if (preferSymlink) { + const linkTarget = path.join( + ...pkgPath.split('/').slice(0, -1).map(() => '..'), + pkg.resolved + ); + debug('Create symlink for ', linkPath, 'with target', linkTarget); + try { + await fs.symlinkAsync(linkTarget, linkPath, 'junction'); + linkCreated = true; + } catch (e) { + debug('Link ', linkPath, 'could not be created'); + } + } + if (!linkCreated) { + const from = path.join(dirPath, pkg.resolved); + debug('Move', from, 'to', linkPath); + await fs.renameAsync(from, linkPath); + } + + fixedLinks++; + })); + + return fixedLinks; +}; diff --git a/lib/npm.js b/lib/npm.js index 273f6ea..65c3070 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -36,41 +36,6 @@ module.exports = npmist var NPMIST = npmist.prototype -/** - * Npm version >= 18 using symlinks that do not work in windows and have to be fixed - * this function replace the broken symlinks with NTFS junction or move the directory if junctions are not supported - * - * @param {string} dirPath - * @returns {Promise} number of changed links - */ -async function resolveLinkedWorkspaces(dirPath) { - let fixedLinks = 0; - const packageLockJson = JSON.parse(fs.readFileSync(path.join(dirPath, 'package-lock.json')).toString()); - await Promise.all(Object.entries(packageLockJson.packages) - .filter(([pkgPath, pkg]) => pkg.link === true) - .map(async ([pkgPath, pkg]) => { - const linkTarget = path.join( - ...pkgPath.split('/').slice(0, -1).map(() => '..'), - pkg.resolved - ); - const linkPath = path.join(dirPath, pkgPath); - - debug('Create symlink for ', linkPath, 'with target', linkTarget); - if (await fs.accessAsync(linkPath, fs.constants.F_OK).then(() => true).catch(() => false)) { - await fs.unlinkAsync(linkPath); - } - - try { - await fs.symlinkAsync(linkTarget, linkPath, 'junction'); - } catch (e) { - await fs.renameAsync(path.join(dirPath, linkTarget), linkPath); - } - fixedLinks++; - })); - - return fixedLinks; -} - /** * List available NPM versions * @return {string} @@ -331,7 +296,7 @@ NPMIST.install = function(v,done){ .then(() => { if (semver.gte(version, '8.0.0')) { debug('Fix symlinks for npm version >= 8'); - return resolveLinkedWorkspaces(path.join(archivePath)) + return buildHelper.resolveLinkedWorkspaces(path.join(archivePath)) .then(fixedLinks => { debug(`Fixed ${fixedLinks} symlinks for npm node_modules`); });