Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

git-validate

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

git-validate - npm Package Compare versions

Comparing version 1.2.1 to 2.0.0

bin/install.js

55

lib/utils.js

@@ -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": {

62

README.md

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc