Skip to content
This repository was archived by the owner on Aug 18, 2024. It is now read-only.

Commit 232555c

Browse files
authored
Merge pull request #16 from dominykas/tests
Add tests
2 parents 6f847d7 + 964ff7e commit 232555c

24 files changed

+563
-31
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
.idea
22
node_modules
3-
3+
test/tmp/

README.md

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,22 @@
22

33
Execute allowed `npm install` lifecycle scripts.
44

5-
## Usage
5+
## tl;dr
6+
7+
- Whitelist packages that you trust in your `package.json`: `"allowScripts": { "packageName": "1.x.x - 2.x.x" }`
8+
- Run `npm install --ignore-scripts` or `yarn install --ignore-scripts`
9+
- Run `npx allow-scripts`
10+
11+
Only the explicitly allowed `[pre|post]install` scripts will be executed.
612

7-
Run your `npm install` with `--ignore-scripts` (or add `ignore-scripts=true` in your `.npmrc`), then:
13+
14+
## Usage
815

916
```
1017
$ npx allow-scripts [--dry-run]
1118
```
1219

13-
Running the command will scan the list of installed dependencies (from the first source available: `npm-shrinkwrap.json`, `package-lock.json`, `npm ls --json`). It will then execute the scripts for allowed dependencies that have them in the following order:
20+
Running the command will scan the list of installed dependencies (using an existing `package-lock.json` or `npm-shrinkwrap.json` or by creating one on the fly). It will then execute the scripts for allowed dependencies that have them in the following order:
1421

1522
- `preinstall` in the main package
1623
- `preinstall` in dependencies
@@ -21,20 +28,21 @@ Running the command will scan the list of installed dependencies (from the first
2128
- `prepublish` in the main package
2229
- `prepare` in the main package
2330

24-
Allowed package list is configurable in `package.json` by adding an `allowScripts` property, with an object where the key is a package name and the value is one of:
25-
26-
* a string with a semver specifier for allowed versions
27-
- non-matching versions will be ignored
28-
* `true` - allow all versions (equivalent to `'*'` semver specifier)
29-
* `false` - ignore all versions
30-
31-
If a package has a lifecycle script, but is neither allowed nor ignored, `allow-scripts` will exit with an error.
31+
### Configuration
3232

33-
Example for `package.json`:
3433
```
3534
"allowScripts": {
3635
"fsevents": "*", # allow install scripts in all versions
3736
"node-sass": false, # ignore install scripts for all versions
3837
"webpack-cli": "3.x.x" # allow all minors for v3, ignore everything else
3938
}
4039
```
40+
41+
Allowed package list is configurable in `package.json` by adding an `allowScripts` property, with an object where the key is a package name and the value is one of:
42+
43+
* a string with a semver specifier for allowed versions
44+
- non-matching versions will be ignored
45+
* `true` - allow all versions (equivalent to `'*'` semver specifier)
46+
* `false` - ignore all versions
47+
48+
If a package has a lifecycle script, but is neither allowed nor ignored, `allow-scripts` will exit with an error.

lib/index.js

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,14 @@ internals.queue = (tree) => {
5151

5252
internals.runScript = (stage, { pkg, path, cwd, unsafePerm }, options) => {
5353

54+
if (!pkg.scripts || !pkg.scripts[stage]) {
55+
return;
56+
}
57+
5458
console.log();
5559

5660
if (options.dryRun) {
57-
console.log(`DRY RUN ==> ${stage} ${path || pkg.name}...`);
61+
console.log(`DRY RUN ==> ${stage} ${path || pkg.name}`);
5862
return;
5963
}
6064

@@ -84,21 +88,13 @@ internals.getLockFile = (cwd) => {
8488
return require(Path.join(cwd, 'package-lock.json'));
8589
}
8690

87-
let output;
88-
try {
89-
output = Cp.execSync('npm ls --json', { cwd });
90-
}
91-
catch (err) {
92-
output = err.output[1]; // npm will exist with an error when e.g. there's peer deps missing - attempt to ignore that
93-
}
91+
Cp.execSync('npm shrinkwrap');
9492

95-
try {
96-
return JSON.parse(output.toString());
97-
}
98-
catch (err) {
99-
console.error(err);
100-
throw new Error('Failed to read the contents of node_modules');
101-
}
93+
const lockFilePath = Path.join(cwd, 'npm-shrinkwrap.json');
94+
const lockFileContents = require(lockFilePath);
95+
96+
Fs.unlinkSync(lockFilePath);
97+
return lockFileContents;
10298
};
10399

104100
exports.run = async (options) => {
@@ -108,7 +104,13 @@ exports.run = async (options) => {
108104

109105
pkg._id = `${pkg.name}@${pkg.version}`; // @todo: find an official way to do this for top level package
110106

111-
const tree = Npm.logicalTree(pkg, internals.getLockFile(cwd));
107+
try {
108+
var tree = Npm.logicalTree(pkg, internals.getLockFile(cwd));
109+
}
110+
catch (err) {
111+
throw new Error('Failed to read the installed tree - you might want to `rm -rf node_modules && npm i --ignore-scripts`.');
112+
}
113+
112114
const queue = internals.queue(tree);
113115

114116
const allowScripts = pkg.allowScripts || {};
@@ -134,6 +136,7 @@ exports.run = async (options) => {
134136

135137
if (allowScripts[name] === false) {
136138
console.warn(`==========> skip ${path} (because it is not allowed in package.json)`);
139+
return false;
137140
}
138141

139142
if (allowScripts[name] === true) {

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/dominykas/allow-scripts.git"
88
},
99
"scripts": {
10-
"test": "lab -L -n"
10+
"test": "lab -L -t 100 -m 5000"
1111
},
1212
"bin": {
1313
"allow-scripts": "./bin/allow-scripts.js"
@@ -20,8 +20,12 @@
2020
"topo": "3.x.x"
2121
},
2222
"devDependencies": {
23+
"code": "5.x.x",
2324
"lab": "18.x.x",
24-
"semantic-release": "15.x.x"
25+
"mkdirp": "0.5.x",
26+
"rimraf": "2.x.x",
27+
"semantic-release": "15.x.x",
28+
"sinon": "7.x.x"
2529
},
2630
"files": [
2731
"bin",

test/fixtures/allowed-false.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"private": true,
3+
"name": "@example/allowed-false",
4+
"version": "0.0.0",
5+
"dependencies": {
6+
"@example/with-install-script": "*",
7+
"@example/with-postinstall-script": "*",
8+
"@example/without-scripts": "*"
9+
},
10+
"allowScripts": {
11+
"@example/with-install-script": false,
12+
"@example/with-postinstall-script": "*"
13+
}
14+
}

test/fixtures/allowed-semver.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"private": true,
3+
"name": "@example/allowed-semver",
4+
"version": "0.0.0",
5+
"dependencies": {
6+
"@example/with-install-script": "*",
7+
"@example/with-postinstall-script": "*",
8+
"@example/without-scripts": "*"
9+
},
10+
"allowScripts": {
11+
"@example/with-install-script": "1.x.x",
12+
"@example/with-postinstall-script": "*"
13+
}
14+
}

test/fixtures/basic.dry-run.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
DRY RUN ==> preinstall @example/basic
2+
3+
DRY RUN ==> preinstall node_modules/@example/with-preinstall-script
4+
5+
DRY RUN ==> install node_modules/@example/with-install-script
6+
7+
DRY RUN ==> postinstall node_modules/@example/with-postinstall-script
8+
9+
DRY RUN ==> install @example/basic
10+
11+
DRY RUN ==> postinstall @example/basic
12+
13+
DRY RUN ==> prepublish @example/basic
14+
15+
DRY RUN ==> prepare @example/basic

test/fixtures/basic.full.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
preinstall from basic
2+
preinstall from with-preinstall-script
3+
install from with-install-script
4+
postinstall from with-postinstall-script
5+
install from basic
6+
postinstall from basic
7+
prepublish from basic
8+
prepare from basic

test/fixtures/basic.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"private": true,
3+
"name": "@example/basic",
4+
"version": "0.0.0",
5+
"dependencies": {
6+
"@example/with-preinstall-script": "*",
7+
"@example/with-install-script": "*",
8+
"@example/with-postinstall-script": "*",
9+
"@example/without-scripts": "*",
10+
"@example/without-install-scripts": "*"
11+
},
12+
"allowScripts": {
13+
"@example/with-preinstall-script": "*",
14+
"@example/with-install-script": "*",
15+
"@example/with-postinstall-script": true
16+
},
17+
"scripts": {
18+
"preinstall": "echo preinstall from basic >> ${OUTPUT}",
19+
"install": "echo install from basic >> ${OUTPUT}",
20+
"postinstall": "echo postinstall from basic >> ${OUTPUT}",
21+
"prepublish": "echo prepublish from basic >> ${OUTPUT}",
22+
"prepare": "echo prepare from basic >> ${OUTPUT}"
23+
}
24+
}

test/fixtures/cycle-a.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"private": true,
3+
"name": "@example/cycle-a",
4+
"version": "0.0.0",
5+
"dependencies": {
6+
"@example/cycle-b": "*"
7+
}
8+
}

0 commit comments

Comments
 (0)