Skip to content
This repository has been archived by the owner on Feb 5, 2018. It is now read-only.

Commit

Permalink
fix(cli): Fix cli to work with COMMIT_EDITMSG, custom path, or text
Browse files Browse the repository at this point in the history
Sometime ago I had included support to validate a commit message from a text instead of only from files.
The validation from a commit message argument stopped working on adding support for GIT GUI tool: maxcnunes@d850cf4

This fixing makes CLI support 3 usage ways:
1. Default usage is not passing any argument. It will automatically read from COMMIT_EDITMSG file.
2. Passing a file path argument. For instance GIT GUI stores commit msg @GITGUI_EDITMSG file.
3. Passing commit message as argument. Useful for testing quickly a commit message from CLI.
  • Loading branch information
maxcnunes authored and Garbee committed Jul 7, 2017
1 parent 3d34ba0 commit 8486495
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
"login": "maxcnunes",
"name": "Max Claus Nunes",
"avatar_url": "https://avatars1.githubusercontent.com/u/680356?v=3",
"profile": "http://blog.maxcnunes.net/",
"profile": "http://maxcnunes.com/",
"contributions": [
"code"
]
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ nohup.out
*.ignored
.opt-in
.opt-out

tmp
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [<img src="https://avatars.githubusercontent.com/u/2112202?v=3" width="100px;"/><br /><sub>Shawn Erquhart</sub>](http://www.professant.com)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=erquhart) [📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=erquhart) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=erquhart) | [<img src="https://avatars.githubusercontent.com/u/194482?v=3" width="100px;"/><br /><sub>Tushar Mathur</sub>](http://tusharm.com)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=tusharmath) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=tusharmath) | [<img src="https://avatars.githubusercontent.com/u/904007?v=3" width="100px;"/><br /><sub>Jason Dreyzehner</sub>](https://twitter.com/bitjson)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=bitjson) [📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=bitjson) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=bitjson) | [<img src="https://avatars.githubusercontent.com/u/9654923?v=3" width="100px;"/><br /><sub>Abimbola Idowu</sub>](http://twitter.com/hisabimbola)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=hisabimbola) | [<img src="https://avatars.githubusercontent.com/u/2212006?v=3" width="100px;"/><br /><sub>Gleb Bahmutov</sub>](https://glebbahmutov.com/)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=bahmutov) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=bahmutov) | [<img src="https://avatars.githubusercontent.com/u/332905?v=3" width="100px;"/><br /><sub>Dennis</sub>](http://dennis.io)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=ds82) | [<img src="https://avatars.githubusercontent.com/u/6425649?v=3" width="100px;"/><br /><sub>Matt Lewis</sub>](https://mattlewis.me/)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=mattlewis92) |
| [<img src="https://avatars.githubusercontent.com/u/323761?v=3" width="100px;"/><br /><sub>Tom Vincent</sub>](https://tlvince.com)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=tlvince) | [<img src="https://avatars.githubusercontent.com/u/615381?v=3" width="100px;"/><br /><sub>Anders D. Johnson</sub>](https://andrz.me/)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=AndersDJohnson) [📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=AndersDJohnson) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=AndersDJohnson) | [<img src="https://avatars.githubusercontent.com/u/1643758?v=3" width="100px;"/><br /><sub>James Zetlen</sub>](http://jameszetlen.com)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=zetlen) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=zetlen) | [<img src="https://avatars.githubusercontent.com/u/235784?v=3" width="100px;"/><br /><sub>Paul Bienkowski</sub>](http://opatut.de)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=opatut) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=opatut) | [<img src="https://avatars.githubusercontent.com/u/324073?v=3" width="100px;"/><br /><sub>Barney Scott</sub>](https://github.com/bmds)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=bmds) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=bmds) | [<img src="https://avatars.githubusercontent.com/u/5572221?v=3" width="100px;"/><br /><sub>Emmanuel Murillo Sánchez</sub>](https://github.com/Emmurillo)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=Emmurillo) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=Emmurillo) | [<img src="https://avatars.githubusercontent.com/u/968267?v=3" width="100px;"/><br /><sub>Hans Kristian Flaatten</sub>](https://starefossen.github.io)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=Starefossen) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=Starefossen) |
| [<img src="https://avatars.githubusercontent.com/u/16605186?v=3" width="100px;"/><br /><sub>Bo Lingen</sub>](https://github.com/citycide)<br />[📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=citycide) | [<img src="https://avatars.githubusercontent.com/u/1057324?v=3" width="100px;"/><br /><sub>Spyros Ioakeimidis</sub>](http://www.spyros.io)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=spirosikmd) [📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=spirosikmd) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=spirosikmd) | [<img src="https://avatars.githubusercontent.com/u/126441?v=3" width="100px;"/><br /><sub>Matt Travi</sub>](https://matt.travi.org)<br />[🐛](https://github.com/kentcdodds/validate-commit-msg/issues?q=author%3Atravi) | [<img src="https://avatars.githubusercontent.com/u/868301?v=3" width="100px;"/><br /><sub>Jonathan Garbee</sub>](http://jonathan.garbee.me)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=Garbee) [📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=Garbee) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=Garbee) | [<img src="https://avatars.githubusercontent.com/u/2978876?v=3" width="100px;"/><br /><sub>Tobias Lins</sub>](https://lins.in)<br />[📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=tobiaslins) | [<img src="https://avatars1.githubusercontent.com/u/680356?v=3" width="100px;"/><br /><sub>Max Claus Nunes</sub>](http://blog.maxcnunes.net/)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=maxcnunes) | [<img src="https://avatars3.githubusercontent.com/u/750319?v=3" width="100px;"/><br /><sub>standy</sub>](https://github.com/standy)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=standy) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=standy) |
| [<img src="https://avatars.githubusercontent.com/u/16605186?v=3" width="100px;"/><br /><sub>Bo Lingen</sub>](https://github.com/citycide)<br />[📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=citycide) | [<img src="https://avatars.githubusercontent.com/u/1057324?v=3" width="100px;"/><br /><sub>Spyros Ioakeimidis</sub>](http://www.spyros.io)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=spirosikmd) [📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=spirosikmd) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=spirosikmd) | [<img src="https://avatars.githubusercontent.com/u/126441?v=3" width="100px;"/><br /><sub>Matt Travi</sub>](https://matt.travi.org)<br />[🐛](https://github.com/kentcdodds/validate-commit-msg/issues?q=author%3Atravi) | [<img src="https://avatars.githubusercontent.com/u/868301?v=3" width="100px;"/><br /><sub>Jonathan Garbee</sub>](http://jonathan.garbee.me)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=Garbee) [📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=Garbee) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=Garbee) | [<img src="https://avatars.githubusercontent.com/u/2978876?v=3" width="100px;"/><br /><sub>Tobias Lins</sub>](https://lins.in)<br />[📖](https://github.com/kentcdodds/validate-commit-msg/commits?author=tobiaslins) | [<img src="https://avatars1.githubusercontent.com/u/680356?v=3" width="100px;"/><br /><sub>Max Claus Nunes</sub>](http://maxcnunes.com/)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=maxcnunes) | [<img src="https://avatars3.githubusercontent.com/u/750319?v=3" width="100px;"/><br /><sub>standy</sub>](https://github.com/standy)<br />[💻](https://github.com/kentcdodds/validate-commit-msg/commits?author=standy) [⚠️](https://github.com/kentcdodds/validate-commit-msg/commits?author=standy) |
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
107 changes: 70 additions & 37 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
* Git COMMIT-MSG hook for validating commit message
* See https://docs.google.com/document/d/1rk04jEuGfk9kYzfqCuOlPTSJw3hEDZJTBN5E5f1SALo/edit
*
* This CLI supports 3 usage ways:
* 1. Default usage is not passing any argument. It will automatically read from COMMIT_EDITMSG file.
* 2. Passing a file name argument from git directory. For instance GIT GUI stores commit msg @GITGUI_EDITMSG file.
* 3. Passing commit message as argument. Useful for testing quickly a commit message from CLI.
*
* Installation:
* >> cd <angular-repo>
* >> ln -s ../../validate-commit-msg.js .git/hooks/commit-msg
Expand All @@ -18,50 +23,78 @@ var getGitFolder = require('./getGitFolder');
// hacky start if not run by mocha :-D
// istanbul ignore next
if (process.argv.join('').indexOf('mocha') === -1) {
var commitMsgFileOrText,
gitFolder = getGitFolder() + '/',
//GIT GUI stores commit msg @GITGUI_EDITMSG file, so user can pass file name has argument
//if it doesn't exist then we are considering "/COMMIT_EDITMSG" file
filename = (process.argv[2] && fs.existsSync(gitFolder + process.argv[2])) ? process.argv[2] : 'COMMIT_EDITMSG';

var bufferToString = function (buffer) {
return hasToString(buffer) && buffer.toString();
};

var hasToString = function (x) {
return x && typeof x.toString === 'function';
var hasToString = buffer && typeof buffer.toString === 'function';
return hasToString && buffer.toString();
};

var validate = function (msg, isFile, filename) {
if (!validateMessage(msg)) {
var incorrectLogFile = (
isFile
? commitMsgFileOrText.replace(filename, 'logs/incorrect-commit-msgs')
: (getGitFolder() + '/logs/incorrect-commit-msgs')
);

fs.appendFile(incorrectLogFile, msg + '\n', function appendFile() {
process.exit(1);
});
} else {
process.exit(0);
var getFileContent = function (filePath) {
try {
var buffer = fs.readFileSync(filePath);
return bufferToString(buffer);
} catch (err) {
// Ignore these error types because is most likely it is validating
// a commit from a text instead of a file
if(err && err.code !== 'ENOENT' && err.code !== 'ENAMETOOLONG') {
throw err;
}
}
};

commitMsgFileOrText = gitFolder + filename;
var getCommit = function() {
var fileContent;
var gitDirectory;

fs.readFile(commitMsgFileOrText, function readFile(err, buffer) {
if(err && err.code !== 'ENOENT') {
throw err;
}
var commitMsgFileOrText = process.argv[2];
var commitErrorLogPath = process.argv[3];

var commit = {
// if it is running from git directory or for a file from there
// these info might change ahead
message: commitMsgFileOrText,
errorLog: commitErrorLogPath || null,
};

// On running the validation over a text instead of git files such as COMMIT_EDITMSG and GITGUI_EDITMSG
// is possible to be doing that the from anywhere. Therefore the git directory might not be available.
try {
gitDirectory = getGitFolder();

// Try to load commit from a path passed as argument
if (commitMsgFileOrText) {
fileContent = getFileContent(gitDirectory + '/' + commitMsgFileOrText);
}

var isFile = !err;
var msg = (
isFile
? bufferToString(buffer)
: commitMsgFileOrText
);
// If no file or message is available then try to load it from the default commit file
if (!fileContent && !commitMsgFileOrText) {
fileContent = getFileContent(gitDirectory + '/COMMIT_EDITMSG');
}

// Could resolve the content from a file
if (fileContent) {
commit.message = fileContent;
}

// Default error log path
if (!commit.errorLog) {
commit.errorLog = gitDirectory + '/logs/incorrect-commit-msgs';
}
} catch (err) {}

return commit;
};

var validate = function (commit) {
if (!validateMessage(commit.message) && commit.errorLog) {
fs.appendFileSync(commit.errorLog, commit.message + '\n');
}
};

validate(msg, isFile, filename);
});
try {
validate(getCommit());
process.exit(0);
} catch (err) {
console.error(err);
process.exit(1);
}
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@
"cz-conventional-changelog": "1.1.5",
"husky": "0.12.0",
"istanbul": "0.4.2",
"mkdirp": "^0.5.1",
"mocha": "2.3.4",
"opt-cli": "1.5.1",
"rimraf": "^2.6.1",
"semantic-release": "^6.3.2",
"sinon": "1.17.2"
},
Expand Down
112 changes: 112 additions & 0 deletions test/cli.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
'use strict';

var spawnSync = require('child_process').spawnSync;
var expect = require('chai').expect;
var fs = require('fs');
var path = require('path');
var rimraf = require('rimraf');
var mkdirp = require('mkdirp');

var TMP_PATH = path.join(__dirname, 'tmp/');
var GIT_TMP_PATH = path.join(TMP_PATH, '.git');
var LOGS_GIT_TMP_PATH = path.join(GIT_TMP_PATH, 'logs');
var COMMIT_EDITMSG_GIT_TMP_PATH = path.join(GIT_TMP_PATH, 'COMMIT_EDITMSG');
var GITGUI_EDITMSG_GIT_TMP_PATH = path.join(GIT_TMP_PATH, 'GITGUI_EDITMSG');
var CLI_PATH = path.join(__dirname, '../lib/cli.js');

var cliSources = [
'COMMIT_EDITMSG',
'commit text argument',
'commit file argument',
];

function executeCliBySource(cliSource, commitMessage) {
var options = {};
var args = [];
switch (cliSource) {
case 'COMMIT_EDITMSG': {
fs.writeFileSync(COMMIT_EDITMSG_GIT_TMP_PATH, commitMessage);
options.cwd = TMP_PATH;
break;
}
case 'commit text argument': {
args.push(commitMessage);
break;
}
case 'commit file argument': {
fs.writeFileSync(GITGUI_EDITMSG_GIT_TMP_PATH, commitMessage);
options.cwd = TMP_PATH;
args.push('GITGUI_EDITMSG');
break;
}
}

return spawnSync(CLI_PATH, args, options);
}

describe('cli', function() {
beforeEach(function () {
rimraf.sync(GIT_TMP_PATH);
mkdirp.sync(GIT_TMP_PATH);
mkdirp.sync(LOGS_GIT_TMP_PATH);
});

describe('all cli sources have the same behavior', function () {
cliSources.forEach(function (cliSource) {
describe(cliSource, function () {
describe('when the commit message is valid', function () {
it('should not print anything into output', function () {
var commitMessage = 'chore: This a valid commit message';
var result = executeCliBySource(cliSource, commitMessage);
expect(result.stdout.toString()).to.eql('');
expect(result.stderr.toString()).to.eql('');
expect(result.status).to.eql(0);
});
});

// only check for COMMIT_EDITMSG because if the other cases are empty
// then they will fallback to COMMIT_EDITMSG anyway
if (cliSource === 'COMMIT_EDITMSG') {
describe('when the commit message is empty', function () {
it('should print into output the commit message is invalid', function () {
var commitMessage = '';
var result = executeCliBySource(cliSource, commitMessage);
expect(result.stdout.toString()).to.eql('Aborting commit due to empty commit message.\n');
expect(result.stderr.toString()).to.eql('');
expect(result.status).to.eql(0);
});
});
}

describe('when the commit message is not following the rules', function () {
it('should print into output the commit message is invalid', function () {
var commitMessage = 'my invalid commit message';
var result = executeCliBySource(cliSource, commitMessage);
expect(result.stdout.toString()).to.eql([
commitMessage + '\n\n',
'Please fix your commit message (and consider using http://npm.im/commitizen)\n\n'
].join(''));
expect(result.stderr.toString()).to.eql('INVALID COMMIT MSG: does not match "<type>(<scope>): <subject>" !\n');
expect(result.status).to.eql(0);
});
});

describe('when the commit message is using an invalid type', function () {
it('should print into output the commit message is invalid', function () {
var commitMessage = 'patch: my invalid commit message';
var result = executeCliBySource(cliSource, commitMessage);
expect(result.stdout.toString()).to.eql([
commitMessage + '\n\n',
'Please fix your commit message (and consider using http://npm.im/commitizen)\n\n'
].join(''));
expect(result.stderr.toString()).to.eql([
'INVALID COMMIT MSG: "patch" is not allowed type ! ',
'Valid types are: feat, fix, docs, style, refactor, perf, test, chore, revert, custom\n'
].join(''));
expect(result.status).to.eql(0);
});
});
});
});
});
});

0 comments on commit 8486495

Please sign in to comment.