Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions lib/git-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,11 @@ module.exports = {
return path.resolve(hooksDirname, hookName);
})
.filter(function (hookPath) {
var isFile = fs.lstatSync(hookPath).isFile();
var isExecutable = fs.lstatSync(hookPath).isFile() && fsHelpers.isExecutable(hookPath);

if (isFile && !isExecutable) {
if (!isExecutable(hookPath) && !isJS(hookPath) && !isBash(hookPath)) {
console.warn('[GIT-HOOKS WARNING] Non-executable file ' + hookPath + ' is skipped');
return false;
}

return isFile && isExecutable;
return true;
});

runHooks(hooks, args, callback);
Expand Down Expand Up @@ -167,7 +164,15 @@ function runHooks(hooks, args, callback) {
*/
function spawnHook(hookName, args) {
args = args || [];
return spawn(hookName, args, {stdio: 'inherit'});
if (isExecutable(hookName)) {
return spawn(hookName, args, {stdio: 'inherit'});
}
if (isJS(hookName)) {
return spawn('node', [hookName].concat(args), {stdio: 'inherit'});
}
if (isBash(hookName)) {
return spawn('bash', [hookName].concat(args), {stdio: 'inherit'});
}
}

/**
Expand Down Expand Up @@ -195,3 +200,33 @@ function getClosestGitPath(currentPath) {

return getClosestGitPath(nextPath);
}

/**
* Check if the file is executable
*
* @param {String} filePath
* @returns {Boolean}
*/
function isExecutable(filePath) {
return fs.lstatSync(filePath).isFile() && fsHelpers.isExecutable(filePath);
}

/**
* Check if the file is a JavaScript file
*
* @param {String} filePath
* @returns {Boolean}
*/
function isJS(filePath) {
return fs.lstatSync(filePath).isFile() && path.extname(filePath) === '.js';
}

/**
* Check if the file is a bash script file
*
* @param {String} filePath
* @returns {Boolean}
*/
function isBash(filePath) {
return fs.lstatSync(filePath).isFile() && path.extname(filePath) === '.sh';
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
},
"engine-strict": true,
"scripts": {
"postinstall": "./bin/git-hooks --install",
"preuninstall": "./bin/git-hooks --uninstall",
"postinstall": "node ./bin/git-hooks --install",
"preuninstall": "node ./bin/git-hooks --uninstall",
"test": "jscs . && jshint . && mocha --reporter spec --recursive tests",
"coverage": "istanbul cover _mocha --recursive tests"
},
Expand Down
33 changes: 33 additions & 0 deletions tests/run.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,38 @@ describe('git-hook runner', function () {
});
});
});

describe('and a hook is unexecutable but is a JavaScript file', function () {
var logFile = SANDBOX_PATH + 'hello.log';
beforeEach(function () {
var content = 'var fs = require("fs"); ' +
'fs.writeFileSync("' + logFile.replace(/\\/g, '\\\\') + '", "Hello, world!");';
fs.writeFileSync(PROJECT_PRECOMMIT_HOOK + 'hello.js', content);
});

it('should run a hook with success status', function (done) {
gitHooks.run(PRECOMMIT_HOOK_PATH, [], function (code) {
code.should.equal(0);
fs.readFileSync(logFile).toString().should.equal('Hello, world!');
done();
});
});
});

describe('and a hook is unexecutable but is a bash script file', function () {
var logFile = SANDBOX_PATH + 'hello.log';
beforeEach(function () {
var content = 'echo "Hello, world!" > ' + logFile.replace(/\\/g, '\\\\');
fs.writeFileSync(PROJECT_PRECOMMIT_HOOK + 'hello.sh', content);
});

it('should run a hook with success status', function (done) {
gitHooks.run(PRECOMMIT_HOOK_PATH, [], function (code) {
code.should.equal(0);
fs.readFileSync(logFile).toString().should.equal('Hello, world!\n');
done();
});
});
});
});
});