git-validate
Advanced tools
Comparing version 1.2.1 to 2.0.0
@@ -7,2 +7,4 @@ var Fs = require('fs'); | ||
/* $lab:coverage:off$ */ | ||
// Coverage disabled for this method because we use a child process to test it due to the process.exit() call | ||
internals.throwWarn = function (warning) { | ||
@@ -13,2 +15,3 @@ | ||
}; | ||
/* $lab:coverage:on$ */ | ||
@@ -142,2 +145,4 @@ // Find the topmost parent of the given module. | ||
} | ||
/* $lab:coverage:off$ */ | ||
// Coverage disabled here due to false positive on else if, since we have to trap the throwWarn method | ||
else if (Path.dirname(start) !== start) { | ||
@@ -147,4 +152,5 @@ root = exports.findGitRoot(Path.dirname(start)); | ||
else { | ||
return internals.throwWarn('Unable to find a .git folder for this project'); | ||
return internals.throwWarn('Unable to find a .git directory for this project'); | ||
} | ||
/* $lab:coverage:on$ */ | ||
@@ -166,5 +172,8 @@ return root; | ||
var root = start.slice(0, position === -1 ? undefined : position - Path.sep.length); | ||
/* $lab:coverage:off$ */ | ||
// Coverage disabled here due to having to trap the throwWarn method | ||
if (root === Path.resolve(root, '..')) { | ||
return internals.throwWarn('Unable to find a package.json for this project'); | ||
} | ||
/* $lab:coverage:on$ */ | ||
@@ -219,17 +228,14 @@ while (!Fs.existsSync(Path.join(root, 'package.json'))) { | ||
// Install the git hooks as specified by `hooks`. Should be an array of | ||
// strings, like ['pre-commit']. Will automatically turn a single argument into | ||
// an array for simplicity (e.g. Validate.installHooks('pre-commit') works fine). | ||
// Install the git hook as specified by `hook`. | ||
// For example, Validate.installHook('pre-commit'); | ||
exports.installHooks = function (hooks, root) { | ||
if (!Array.isArray(hooks)) { | ||
hooks = [hooks]; | ||
} | ||
hooks = Array.isArray(hooks) ? hooks : [hooks]; | ||
var gitRoot = exports.findGitRoot(root); | ||
var hookRoot = Path.join(gitRoot, '.git', 'hooks'); | ||
var source = Path.resolve(__dirname, '..', 'bin', 'validate.sh'); | ||
for (var i = 0, l = hooks.length; i < l; ++i) { | ||
for (var i = 0, il = hooks.length; i < il; ++i) { | ||
var hook = hooks[i]; | ||
var dest = Path.join(gitRoot, '.git', 'hooks', hook); | ||
var source = Path.resolve(__dirname, '..', 'bin', 'validate.sh'); | ||
var dest = Path.join(hookRoot, hook); | ||
@@ -243,1 +249,28 @@ if (Fs.existsSync(dest)) { | ||
}; | ||
// Provide a default configuration for a git hook as specified by `hook`. | ||
// For example, Validate.configureHook('pre-commit', ['test', 'lint']); | ||
exports.configureHook = function (hook, defaults, root) { | ||
var packagePath = Path.join(exports.findProjectRoot(root), 'package.json'); | ||
var package = JSON.parse(Fs.readFileSync(packagePath, { encoding: 'utf8' })); | ||
if (!package.hasOwnProperty(hook)) { | ||
package[hook] = Array.isArray(defaults) ? defaults : [defaults]; | ||
Fs.writeFileSync(packagePath, JSON.stringify(package, null, 2), { encoding: 'utf8' }); | ||
} | ||
}; | ||
// Configure a default script by name and content | ||
// For example, Validate.installScript('test', 'lab -a code -L'); | ||
exports.installScript = function (name, script, root) { | ||
var packagePath = Path.join(exports.findProjectRoot(root), 'package.json'); | ||
var package = JSON.parse(Fs.readFileSync(packagePath, { encoding: 'utf8' })); | ||
if (!package.hasOwnProperty('scripts') || | ||
!package.scripts.hasOwnProperty(name)) { | ||
package.scripts = package.scripts || {}; | ||
package.scripts[name] = script; | ||
Fs.writeFileSync(packagePath, JSON.stringify(package, null, 2), { encoding: 'utf8' }); | ||
} | ||
}; |
{ | ||
"name": "git-validate", | ||
"version": "1.2.1", | ||
"version": "2.0.0", | ||
"description": "the extensible core of precommit-hook", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "lab -L -a code -t 100" | ||
"test": "lab -L -a code -t 100", | ||
"install": "node bin/install" | ||
}, | ||
@@ -9,0 +10,0 @@ "repository": { |
@@ -68,24 +68,14 @@ #git-validate | ||
This wouldn't be any fun without the git hooks though, so let's extend it a bit further to make sure that `jshint` is run any time a user tries to `git commit` after installing our module. To do so, let's create a `validate.json` file with the following contents: | ||
This wouldn't be any fun without the git hooks though, so let's extend it a bit further to make sure that `jshint` is run any time a user tries to `git commit` after installing our module. We can do that by configuring the hook in our install script like so: | ||
```javascript | ||
{ | ||
"scripts": { | ||
"lint": "jshint ." | ||
}, | ||
"pre-commit": ["lint"] | ||
} | ||
Validate.installScript('lint', 'jshint .'); | ||
Validate.configureHook('pre-commit', ['lint']); | ||
``` | ||
And then let's add a line to our install.js to make sure it gets installed as `.validate.json` (note the leading dot). | ||
Great, that's it! | ||
```javascript | ||
Validate.copy('validate.json', '.validate.json', { overwrite: true }); | ||
``` | ||
Now when a user installs your package the `installScript` method will see if they already have a script in their package.json named `lint`, if they do not it will add one that runs `"jshint ."`. The second line will also check their package.json for a `pre-commit` key, which is used to configure that specific git hook. If the key does not exist, it will be added with the value `["lint"]` telling git-validate to run the "lint" script on `pre-commit`. | ||
Great, that's it! You'll notice the `{ overwrite: true }` object as the last parameter to `copy`. This tells **git-validate** that it's ok to overwrite an existing file. Without that option, the copy method would fail silently if the file already exists. That's why we didn't use it for our `.jshintrc` because that's something a user should be able to configure. | ||
Now when a user tries to run `git commit` **git-validate** will open `.validate.json` and see that the `pre-commit` event wants to run the `lint` script. It will load your project's `package.json` to see if you have a `lint` script defined there first. If you do not, it will use the `lint` script present in the `.validate.json` file and run it. If the script fails, the commit is denied. Easy! | ||
## The Details | ||
@@ -114,3 +104,3 @@ | ||
The only `option` currently available is `overwrite`. When set to `true` overwrite will *always* copy the given file, overwriting any existing destination file. If this is not set, `copy` will instead silently fail and leave the old file in place. I *highly* recommend always using `{ overwrite: true }` on your `.validate.json` file. | ||
The only `option` currently available is `overwrite`. When set to `true` overwrite will *always* copy the given file, overwriting any existing destination file. If this is not set, `copy` will instead silently fail and leave the old file in place. | ||
@@ -129,26 +119,48 @@ | ||
### `configureHook` | ||
## Configuration | ||
Provide a default configuration for a given hook. | ||
### `.validate.json` | ||
```javascript | ||
Validate.configureHook('pre-commit', ['lint', 'test']); | ||
``` | ||
This is the file that configures defaults for your git hooks. | ||
would write | ||
The `scripts` property should be an object with named scripts, exactly the same as the `scripts` property in your `package.json`. This gives you a place to define some default scripts to be used in your hooks. Note that any script defined in your `package.json` will take precedence over one defined in `.validate.json`. This is what makes it safe to always overwrite `.validate.json` with the newest possible copy, since if your project requires changes to the scripts, you can make them in `package.json` instead. | ||
```javascript | ||
{ | ||
"pre-commit": ["lint", "test"] | ||
} | ||
``` | ||
In addition to the `scripts` property, this file will be parsed and checked for keys matching the name of your git hooks (e.g. `pre-commit`, `pre-push`, etc) and used to provide a default list of hooks to be run for each hook. The keys must be an array of script names to be run. If any of the scripts are not defined, they will be skipped and a message will be printed showing that no script was found, as such it is safe to set scripts here that you wish to always be custom in every project. The `.validate.json` file for [precommit-hook](https://github.com/nlf/precommit-hook) looks like this: | ||
to your package.json, but *only* if the `"pre-commit"` key was not already set. | ||
### `installScript` | ||
Configure a script (if it is not already configured) for the project via package.json. | ||
```javascript | ||
Validate.installScript('test', 'lab -a code'); | ||
``` | ||
would write | ||
```javascript | ||
{ | ||
"scripts": { | ||
"lint": "jshint ." | ||
}, | ||
"pre-commit": ["lint", "validate", "test"] | ||
"test": "lab -a code" | ||
} | ||
} | ||
``` | ||
to your package.json. If the `"test"` script was already defined, this method will do nothing. | ||
## Configuration | ||
In addition to the `scripts` property, your package.json file will be parsed and checked for keys matching the name of your git hooks (e.g. `pre-commit`, `pre-push`, etc) and used to provide a list of hooks to be run for each hook. The keys must be an array of script names to be run. If any of the scripts are not defined, they will be skipped and a message will be printed showing that no script was found. | ||
### per-branch hooks | ||
It is also possible to run scripts only for a specific branch by specifying the key in your `package.json` as `hook-name#branch`: | ||
It is possible to run scripts only for a specific branch by specifying the key in your `package.json` as `hook-name#branch`: | ||
@@ -155,0 +167,0 @@ ```javascript |
@@ -0,1 +1,2 @@ | ||
var ChildProcess = require('child_process'); | ||
var Utils = require('../lib/utils'); | ||
@@ -38,3 +39,3 @@ var Fs = require('fs'); | ||
Fs.writeFileSync(Path.join.apply(null, args), '', 'utf8'); | ||
Fs.writeFileSync(Path.join.apply(null, args), '{}', { encoding: 'utf8' }); | ||
}; | ||
@@ -47,2 +48,3 @@ | ||
internals.mkdir('project2', '.git', 'hooks'); | ||
internals.createFile('project2', 'package.json'); | ||
internals.mkdir('project3', 'actual_project'); | ||
@@ -162,9 +164,10 @@ internals.createFile('project3', 'actual_project', 'package.json'); | ||
it('can return an error when no git root exists', function (done) { | ||
it('logs an error and exits cleanly when no git root is found', function (done) { | ||
expect(function () { | ||
ChildProcess.exec('node -e \'var path = require("path"); var utils = require("./lib/utils"); utils.findGitRoot(path.resolve(__dirname, "..", ".."));\'', function (err, stdout, stderr) { | ||
Utils.findGitRoot(Path.resolve(__dirname, '..', '..')); | ||
}).to.throw('Unable to find a .git folder for this project'); | ||
done(); | ||
expect(err).to.not.exist(); | ||
expect(stderr).to.equal('WARNING: Unable to find a .git directory for this project, installation aborted.\n'); | ||
done(); | ||
}); | ||
}); | ||
@@ -193,8 +196,8 @@ }); | ||
var root = Path.resolve(__dirname, '..', '..'); | ||
expect(function () { | ||
ChildProcess.exec('node -e \'var path = require("path"); var utils = require("./lib/utils"); utils.findProjectRoot(path.resolve(__dirname, "..", ".."));\'', function (err, stdout, stderr) { | ||
Utils.findProjectRoot(root); | ||
}).to.throw('Unable to find a package.json for this project'); | ||
done(); | ||
expect(err).to.not.exist(); | ||
expect(stderr).to.equal('WARNING: Unable to find a package.json for this project, installation aborted.\n'); | ||
done(); | ||
}); | ||
}); | ||
@@ -213,5 +216,6 @@ | ||
expect(projects).to.be.an.array(); | ||
expect(projects).to.have.length(3); | ||
expect(projects).to.have.length(4); | ||
expect(projects).to.contain(Path.dirname(__dirname)); | ||
expect(projects).to.contain(Path.join(internals.fixturePath, 'project1')); | ||
expect(projects).to.contain(Path.join(internals.fixturePath, 'project2')); | ||
expect(projects).to.contain(Path.join(internals.fixturePath, 'project3', 'actual_project')); | ||
@@ -228,3 +232,3 @@ done(); | ||
it('can install a single hook', function (done) { | ||
it('can install a hook', function (done) { | ||
@@ -236,7 +240,7 @@ Utils.installHooks('pre-commit', Path.join(internals.fixturePath, 'project2')); | ||
it('can install multiple hooks', function (done) { | ||
it('can install multiple hooks at once', function (done) { | ||
Utils.installHooks(['pre-commit', 'post-commit'], Path.join(internals.fixturePath, 'project2')); | ||
Utils.installHooks(['pre-commit', 'pre-push'], Path.join(internals.fixturePath, 'project2')); | ||
expect(Fs.existsSync(Path.join(internals.fixturePath, 'project2', '.git', 'hooks', 'pre-commit'))).to.be.true(); | ||
expect(Fs.existsSync(Path.join(internals.fixturePath, 'project2', '.git', 'hooks', 'post-commit'))).to.be.true(); | ||
expect(Fs.existsSync(Path.join(internals.fixturePath, 'project2', '.git', 'hooks', 'pre-push'))).to.be.true(); | ||
done(); | ||
@@ -257,1 +261,77 @@ }); | ||
}); | ||
describe('configureHook()', function () { | ||
beforeEach(internals.createFixture); | ||
it('can install a hook with defaults as a string', function (done) { | ||
Utils.installHooks('pre-commit', Path.join(internals.fixturePath, 'project2')); | ||
Utils.configureHook('pre-commit', 'test', Path.join(internals.fixturePath, 'project2')); | ||
expect(Fs.existsSync(Path.join(internals.fixturePath, 'project2', '.git', 'hooks', 'pre-commit'))).to.be.true(); | ||
var fixturePackage = JSON.parse(Fs.readFileSync(Path.join(internals.fixturePath, 'project2', 'package.json'), { encoding: 'utf8' })); | ||
expect(fixturePackage['pre-commit']).to.deep.equal(['test']); | ||
done(); | ||
}); | ||
it('can install a hook with defaults as an array', function (done) { | ||
Utils.installHooks('pre-commit', Path.join(internals.fixturePath, 'project2')); | ||
Utils.configureHook('pre-commit', ['lint', 'test'], Path.join(internals.fixturePath, 'project2')); | ||
expect(Fs.existsSync(Path.join(internals.fixturePath, 'project2', '.git', 'hooks', 'pre-commit'))).to.be.true(); | ||
var fixturePackage = JSON.parse(Fs.readFileSync(Path.join(internals.fixturePath, 'project2', 'package.json'), { encoding: 'utf8' })); | ||
expect(fixturePackage['pre-commit']).to.deep.equal(['lint', 'test']); | ||
done(); | ||
}); | ||
it('won\'t overwrite existing hook settings', function (done) { | ||
Utils.installHooks('pre-commit', Path.join(internals.fixturePath, 'project2')); | ||
Utils.configureHook('pre-commit', 'test', Path.join(internals.fixturePath, 'project2')); | ||
expect(Fs.existsSync(Path.join(internals.fixturePath, 'project2', '.git', 'hooks', 'pre-commit'))).to.be.true(); | ||
var fixturePackageOne = JSON.parse(Fs.readFileSync(Path.join(internals.fixturePath, 'project2', 'package.json'), { encoding: 'utf8' })); | ||
expect(fixturePackageOne['pre-commit']).to.deep.equal(['test']); | ||
Utils.configureHook('pre-commit', ['lint', 'test'], Path.join(internals.fixturePath, 'project2')); | ||
var fixturePackageTwo = JSON.parse(Fs.readFileSync(Path.join(internals.fixturePath, 'project2', 'package.json'), { encoding: 'utf8' })); | ||
expect(fixturePackageTwo['pre-commit']).to.deep.equal(['test']); | ||
done(); | ||
}); | ||
afterEach(internals.cleanupFixture); | ||
}); | ||
describe('installScript()', function () { | ||
beforeEach(internals.createFixture); | ||
it('can install a script', function (done) { | ||
Utils.installScript('test', 'lab -a code -L', Path.join(internals.fixturePath, 'project2')); | ||
var fixturePackage = JSON.parse(Fs.readFileSync(Path.join(internals.fixturePath, 'project2', 'package.json'), { encoding: 'utf8' })); | ||
expect(fixturePackage).to.deep.equal({ scripts: { test: 'lab -a code -L' } }); | ||
done(); | ||
}); | ||
it('can install a script to an existing scripts object', function (done) { | ||
var packagePath = Path.join(internals.fixturePath, 'project2', 'package.json'); | ||
Fs.writeFileSync(packagePath, '{"scripts":{}}', { encoding: 'utf8' }); | ||
Utils.installScript('test', 'lab -a code -L', Path.join(internals.fixturePath, 'project2')); | ||
var fixturePackage = JSON.parse(Fs.readFileSync(packagePath, { encoding: 'utf8' })); | ||
expect(fixturePackage).to.deep.equal({ scripts: { test: 'lab -a code -L' } }); | ||
done(); | ||
}); | ||
it('does not overwrite an existing script', function (done) { | ||
Utils.installScript('test', 'lab -a code -L', Path.join(internals.fixturePath, 'project2')); | ||
var fixturePackageOne = JSON.parse(Fs.readFileSync(Path.join(internals.fixturePath, 'project2', 'package.json'), { encoding: 'utf8' })); | ||
expect(fixturePackageOne).to.deep.equal({ scripts: { test: 'lab -a code -L' } }); | ||
Utils.installScript('test', 'mocha', Path.join(internals.fixturePath, 'project2')); | ||
var fixturePackage = JSON.parse(Fs.readFileSync(Path.join(internals.fixturePath, 'project2', 'package.json'), { encoding: 'utf8' })); | ||
expect(fixturePackage).to.deep.equal({ scripts: { test: 'lab -a code -L' } }); | ||
done(); | ||
}); | ||
afterEach(internals.cleanupFixture); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
36090
9
466
172
1
2