Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add command line parameters to ignore the local .bin folder and emit verbose output #27

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -21,6 +21,12 @@ Add the following to your `package.json`:

Where the `node` and `npm` engine properties specify a valid semver range for Node and npm version respectively.

> By default, if you have a `node` or `npm` binary installed locally to the project (thus ending up in `./node_modules/.bin`), it will take precedence. If you want to check against a globally installed version instead, you can pass the `--ignore-local-bin` parameter (`-i` for short).
>
> It's worth noting that, while you may not be directly depending on `node` or `npm` packages, you may still have them as transitive dependencies - in any case, `ensure-node-env` will show which one is being considered and where it comes from.

By default, the script's output is minimal. If you want it to display more information, such as the exact versions being compared, you can pass the `--verbose` parameter (`-v` for short).

### Usage in libraries

This script is designed to be used as a development-only preinstall check in the project root. For libraries that are published and consumed in other projects it is considered good enough to include it as a pretest check:
Expand Down
2 changes: 1 addition & 1 deletion dist/cli.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

118 changes: 89 additions & 29 deletions index.js
Expand Up @@ -21,6 +21,34 @@
import path from 'path';
import semver from 'semver';
import { execSync } from 'child_process';
import { existsSync } from 'fs';
import { EOL } from 'os';

const { argv } = process;
const verbose = argv.indexOf('-v') !== -1 || argv.indexOf('--verbose') !== -1;
const ignoreLocalBin =
argv.indexOf('-i') !== -1 || argv.indexOf('--ignore-local-bin') !== -1;

const logger = {
info: console.info,
debug: verbose ? console.debug : () => null,
error: console.error,
};

const getVersion = ({ command, localBinFolder, global = true }) => {
const env = { PATH: process.env.PATH };

if (global) {
env.PATH = env.PATH.replace(`${localBinFolder}${path.delimiter}`, '');
} else {
env.PATH = `${localBinFolder}${path.delimiter}${env.PATH}`;
}

return execSync(command, { env })
.toString()
.replace('v', '')
.trim();
};

const checkVersion = (engineName, command) => {
let pkg = null;
Expand All @@ -30,60 +58,92 @@ const checkVersion = (engineName, command) => {
// eslint-disable-next-line global-require, import/no-dynamic-require
pkg = require(pkgJsonPath);
} catch (e) {
console.log(`Unable to find ${pkgJsonPath}! 😱`);
console.log('');
console.log(
'Please ensure that this script is executed in the same directory.',
logger.error(`Unable to find ${pkgJsonPath}! 😱${EOL}`);
logger.error(
`Please ensure that this script is executed in the same directory.${EOL}`,
);
console.log('');
process.exit(1);
}

let expected = null;

try {
expected = pkg.engines[engineName];
} catch (e) {
console.log(
`There is no engine named ${engineName} specified in package.json! 😱`,
if (!pkg.engines || !pkg.engines[engineName]) {
logger.error(
`There is no engine named "${engineName}" specified in package.json! 😱${EOL}`,
);
console.log('');
process.exit(1);
}

let version = null;
const expected = pkg.engines[engineName];

let globalVersion = null;
let localVersion = null;
let usedVersion = null;
let globalVersionValid = null;
let localVersionValid = null;

try {
version = execSync(command)
const localBinFolder = execSync('npm bin')
.toString()
.replace('v', '')
.trim();

const hasLocalVersion = existsSync(
`${localBinFolder}${path.sep}${engineName}`,
);

globalVersion = getVersion({ command, localBinFolder });
globalVersionValid = semver.satisfies(globalVersion, expected);

logger.debug(`Expected ${engineName} version:\t${expected}`);
logger.debug(
`╰─ Global ${engineName} version:\t${globalVersion}\t${
globalVersionValid ? '✅️' : '❌️'
matthewdavidson marked this conversation as resolved.
Show resolved Hide resolved
}`,
);

if (hasLocalVersion) {
localVersion = getVersion({ command, localBinFolder, global: false });
localVersionValid = semver.satisfies(localVersion, expected);
logger.debug(
`╰─ Local ${engineName} version:\t${localVersion}\t${
localVersionValid ? '✅️' : '❌️'
} (from ${localBinFolder})`,
);
}

if (ignoreLocalBin) {
usedVersion = globalVersion;
} else {
usedVersion = localVersion || globalVersion;
}

logger.debug(`╰─ (using: ${usedVersion})${EOL}`);
} catch (e) {
console.log(`Unable to get ${engineName} version! 😱`);
console.log('');
logger.error(`Unable to get ${engineName} version! 😱${EOL}`);
process.exit(1);
}

if (!semver.satisfies(version, expected)) {
if (!semver.satisfies(usedVersion, expected)) {
const guide =
'https://github.com/Skyscanner/ensure-node-env/blob/master/README.md#guide';
console.log(
`Expected ${engineName} version to match ${expected}, but got ${version}. 😱`,
logger.error(
`Expected ${engineName} version to match ${expected}, but got ${usedVersion}. 😱${EOL}`,
);
console.log('');
console.log(
`Please follow Skyscanner's node environment guide (see ${guide}).`,

if (!verbose) {
logger.error(
`(pass the --verbose flag to the script for a more detailed output)${EOL}`,
);
}

logger.error(
`Please follow Skyscanner's node environment guide (see ${guide}).${EOL}`,
);
console.log('');
process.exit(1);
}
};

console.log('Checking node & npm versions...');
console.log('');
logger.info(`Checking node & npm versions...${EOL}`);

checkVersion('node', 'node --version');
checkVersion('npm', 'npm -g --version');

console.log('All good. 👍');
console.log('');
logger.info(`All good. 👍${EOL}`);
9 changes: 4 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -36,7 +36,9 @@
"rollup": "^0.67.1",
"rollup-plugin-commonjs": "^9.1.8",
"rollup-plugin-node-resolve": "^3.4.0",
"rollup-plugin-terser": "^3.0.0",
"rollup-plugin-terser": "^3.0.0"
},
"dependencies": {
"semver": "^5.5.1"
}
}
11 changes: 7 additions & 4 deletions rollup.config.js
Expand Up @@ -2,15 +2,18 @@ import { terser } from 'rollup-plugin-terser';
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';

const COMMON_IMPORTS = ['path', 'child_process', 'os', 'fs'];
const COMMON_PLUGINS = [resolve(), commonjs(), terser()];

export default [
{
input: 'index.js',
output: {
file: 'dist/index.js',
format: 'cjs',
},
external: ['path', 'child_process'],
plugins: [resolve(), commonjs(), terser()],
external: COMMON_IMPORTS,
plugins: COMMON_PLUGINS,
},
{
input: 'index.js',
Expand All @@ -19,7 +22,7 @@ export default [
format: 'cjs',
banner: '#!/usr/bin/env node',
},
external: ['path', 'child_process'],
plugins: [resolve(), commonjs(), terser()],
external: COMMON_IMPORTS,
plugins: COMMON_PLUGINS,
},
];