validate-commit-msg.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #!/usr/bin/env node
  2. /**
  3. * Git COMMIT-MSG hook for validating commit message
  4. * See https://docs.google.com/document/d/1rk04jEuGfk9kYzfqCuOlPTSJw3hEDZJTBN5E5f1SALo/edit
  5. *
  6. * Installation:
  7. * >> cd <angular-repo>
  8. * >> ln -s validate-commit-msg.js .git/hooks/commit-msg
  9. */
  10. var fs = require('fs');
  11. var util = require('util');
  12. var MAX_LENGTH = 70;
  13. var PATTERN = /^(?:fixup!\s*)?(\w*)(\((\w+)\))?\: (.*)$/;
  14. var IGNORED = /^WIP\:/;
  15. var TYPES = {
  16. chore: true,
  17. demo: true,
  18. docs: true,
  19. feat: true,
  20. fix: true,
  21. refactor: true,
  22. revert: true,
  23. style: true,
  24. test: true
  25. };
  26. var error = function() {
  27. // gitx does not display it
  28. // http://gitx.lighthouseapp.com/projects/17830/tickets/294-feature-display-hook-error-message-when-hook-fails
  29. // https://groups.google.com/group/gitx/browse_thread/thread/a03bcab60844b812
  30. console.error('INVALID COMMIT MSG: ' + util.format.apply(null, arguments));
  31. };
  32. var validateMessage = function(message) {
  33. var isValid = true;
  34. if (IGNORED.test(message)) {
  35. console.log('Commit message validation ignored.');
  36. return true;
  37. }
  38. if (message.length > MAX_LENGTH) {
  39. error('is longer than %d characters !', MAX_LENGTH);
  40. isValid = false;
  41. }
  42. var match = PATTERN.exec(message);
  43. if (!match) {
  44. error('does not match "<type>(<scope>): <subject>" ! was: "' + message + '"\nNote: <scope> must be only letters.');
  45. return false;
  46. }
  47. var type = match[1];
  48. var scope = match[3];
  49. var subject = match[4];
  50. if (!TYPES.hasOwnProperty(type)) {
  51. error('"%s" is not allowed type !', type);
  52. return false;
  53. }
  54. // Some more ideas, do want anything like this ?
  55. // - allow only specific scopes (eg. fix(docs) should not be allowed ?
  56. // - auto correct the type to lower case ?
  57. // - auto correct first letter of the subject to lower case ?
  58. // - auto add empty line after subject ?
  59. // - auto remove empty () ?
  60. // - auto correct typos in type ?
  61. // - store incorrect messages, so that we can learn
  62. return isValid;
  63. };
  64. var firstLineFromBuffer = function(buffer) {
  65. return buffer.toString().split('\n').shift();
  66. };
  67. // publish for testing
  68. exports.validateMessage = validateMessage;
  69. // hacky start if not run by jasmine :-D
  70. if (process.argv.join('').indexOf('jasmine-node') === -1) {
  71. var commitMsgFile = process.argv[2];
  72. var incorrectLogFile = commitMsgFile.replace('COMMIT_EDITMSG', 'logs/incorrect-commit-msgs');
  73. fs.readFile(commitMsgFile, function(err, buffer) {
  74. var msg = firstLineFromBuffer(buffer);
  75. if (!validateMessage(msg)) {
  76. fs.appendFile(incorrectLogFile, msg + '\n', function() {
  77. process.exit(1);
  78. });
  79. } else {
  80. process.exit(0);
  81. }
  82. });
  83. }