conventional-commits-parser
Advanced tools
Comparing version 0.0.6 to 0.0.7
32
cli.js
@@ -18,6 +18,9 @@ #!/usr/bin/env node | ||
help: [ | ||
'Practice writing commit messages or test from a file.', | ||
'If used without specifying a text file path, you will enter an interactive shell.', | ||
'Parsed results are printed to stdout', | ||
'By default, commits will be split by three newlines (`\\n\\n\\n`) or you can specify a separator.', | ||
'', | ||
'Usage', | ||
' conventional-commits-parser [<commit-separator>] [<path>...]', | ||
' If used without specifying a text file path, you will enter an interactive shell', | ||
' By default, commits will be split by three newlines (`\\n\\n\\n`) or you can specify a separator', | ||
'', | ||
@@ -27,4 +30,17 @@ 'Example', | ||
' conventional-commits-parser log.txt', | ||
' conventional-commits-parser log2.txt \'===\'' | ||
' conventional-commits-parser log2.txt \'===\' >> output.txt', | ||
'', | ||
'Options', | ||
'-m, --max-subject-length Maximum subject length', | ||
'-p, --header-pattern Regex to match header pattern', | ||
'-c, --close-keywords Comma separated keywords that used to close issues', | ||
'-b, --break-keywords Comma separated keywords for breaking changes' | ||
].join('\n') | ||
}, { | ||
alias: { | ||
m: 'maxSubjectLength', | ||
p: 'headerPattern', | ||
c: 'closeKeywords', | ||
b: 'breakKeywords' | ||
} | ||
}); | ||
@@ -47,3 +63,3 @@ | ||
console.warn('Failed to read file ' + filePath + '\n' + err); | ||
if(++fileIndex < length) { | ||
if (++fileIndex < length) { | ||
processFile(fileIndex); | ||
@@ -56,3 +72,3 @@ } | ||
.on('end', function() { | ||
if(++fileIndex < length) { | ||
if (++fileIndex < length) { | ||
processFile(fileIndex); | ||
@@ -80,3 +96,7 @@ } | ||
.pipe(through(function(chunk, enc, cb) { | ||
cb(null, 'result: ' + chunk + '\n\n'); | ||
if (chunk.toString() === '""') { | ||
cb(null, 'Commit cannot be parsed\n\n'); | ||
} else { | ||
cb(null, 'Result: ' + chunk + '\n\n'); | ||
} | ||
})) | ||
@@ -83,0 +103,0 @@ .pipe(process.stdout); |
29
index.js
'use strict'; | ||
var extend = require('lodash').extend; | ||
var _ = require('lodash'); | ||
var parser = require('./lib/parser'); | ||
@@ -7,3 +7,18 @@ var through = require('through2'); | ||
function conventionalCommitsParser(options) { | ||
options = extend({ | ||
if (options && !_.isEmpty(options)) { | ||
var headerPattern = options.headerPattern; | ||
if (typeof headerPattern === 'string') { | ||
options.headerPattern = new RegExp(headerPattern); | ||
} | ||
if (typeof options.closeKeywords === 'string') { | ||
options.closeKeywords = options.closeKeywords.split(','); | ||
} | ||
if (typeof options.breakKeywords === 'string') { | ||
options.breakKeywords = options.breakKeywords.split(','); | ||
} | ||
} | ||
options = _.extend({ | ||
maxSubjectLength: 80, | ||
@@ -27,10 +42,2 @@ headerPattern: /^(\w*)(?:\(([\w\$\.\-\* ]*)\))?\: (.*)$/, | ||
if (!Array.isArray(options.closeKeywords)) { | ||
options.closeKeywords = [options.closeKeywords]; | ||
} | ||
if (!Array.isArray(options.breakKeywords)) { | ||
options.breakKeywords = [options.breakKeywords]; | ||
} | ||
return through.obj(function(data, enc, cb) { | ||
@@ -42,3 +49,3 @@ var commit = parser(data.toString(), options); | ||
} else { | ||
cb(); | ||
cb(null, ''); | ||
} | ||
@@ -45,0 +52,0 @@ }); |
@@ -29,2 +29,6 @@ 'use strict'; | ||
if (!msg.header) { | ||
return null; | ||
} | ||
match = msg.header.match(options.headerPattern); | ||
@@ -31,0 +35,0 @@ if (!match || !match[1] || !match[3]) { |
@@ -8,5 +8,7 @@ 'use strict'; | ||
forEach(breakKeywords, function(val, index) { | ||
re += val; | ||
if (index < maxIndex) { | ||
re += '|'; | ||
if (val) { | ||
re += val.trim(); | ||
if (index < maxIndex) { | ||
re += '|'; | ||
} | ||
} | ||
@@ -22,5 +24,7 @@ }); | ||
forEach(closeKeywords, function(val, index) { | ||
re += val; | ||
if (index < maxIndex) { | ||
re += '|'; | ||
if (val) { | ||
re += val.trim(); | ||
if (index < maxIndex) { | ||
re += '|'; | ||
} | ||
} | ||
@@ -27,0 +31,0 @@ }); |
{ | ||
"name": "conventional-commits-parser", | ||
"version": "0.0.6", | ||
"version": "0.0.7", | ||
"description": "Parse raw conventional commits", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/stevemao/conventional-commits-parser", |
@@ -103,3 +103,3 @@ # [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Coverage Status][coverall-image]][coverall-url] | ||
Returns an object stream. | ||
Returns an object stream. If there is any malformed commits it will be gracefully ignored (an empty data will be emitted so down stream can notice). | ||
@@ -118,5 +118,5 @@ #### options | ||
Type: `regex` Default: `/^(\w*)(?:\(([\w\$\.\-\* ]*)\))?\: (.*)$/` | ||
Type: `regex` or `string` Default: `/^(\w*)(?:\(([\w\$\.\-\* ]*)\))?\: (.*)$/` | ||
Used to match header pattern. The first capturing group captures **type**, second captures **scope** and third captures **subject** | ||
Used to match header pattern. The first capturing group captures **type**, second captures **scope** and third captures **subject**. If it's a `string` it will be converted to a `regex`. | ||
@@ -138,3 +138,3 @@ ##### closeKeywords | ||
This value is case **insensitive**. | ||
This value is case **insensitive**. If it's a `string` it will be converted to an `array` separated by a comma. | ||
@@ -147,3 +147,3 @@ Keywords that used to close issues. | ||
Keywords for breaking changes. | ||
Keywords for breaking changes. If it's a `string` it will be converted to an `array` separated by a comma. | ||
@@ -150,0 +150,0 @@ |
'use strict'; | ||
var concat = require('concat-stream'); | ||
var expect = require('chai').expect; | ||
var readFileSync = require('fs').readFileSync; | ||
var spawn = require('child_process').spawn; | ||
var concat = require('concat-stream'); | ||
var through = require('through2'); | ||
@@ -10,2 +11,3 @@ var cliPath = './cli.js'; | ||
var output2 = readFileSync('test/expected/output2.txt', 'utf-8'); | ||
var output3 = readFileSync('test/expected/output3.txt', 'utf-8'); | ||
@@ -15,6 +17,4 @@ describe('cli', function() { | ||
var cp = spawn(cliPath, ['test/fixtures/log.txt']); | ||
cp.stdout | ||
.pipe(concat(function(chunk) { | ||
expect(chunk.toString()).to.equal(output1); | ||
@@ -27,6 +27,4 @@ done(); | ||
var cp = spawn(cliPath, ['test/fixtures/log2.txt', '===']); | ||
cp.stdout | ||
.pipe(concat(function(chunk) { | ||
expect(chunk.toString()).to.equal(output2); | ||
@@ -39,7 +37,5 @@ done(); | ||
var cp = spawn(cliPath, ['test/fixtures/log.txt', 'test/fixtures/log2.txt', '===']); | ||
cp.stdout | ||
.pipe(concat(function(chunk) { | ||
var expected = output1 + output2; | ||
expect(chunk.toString()).to.equal(expected); | ||
@@ -51,6 +47,23 @@ done(); | ||
it('should error if files cannot be found', function(done) { | ||
var cp = spawn(cliPath, ['test/fixtures/log.txt', 'test/fixtures/log3.txt', 'test/fixtures/log2.txt', 'test/fixtures/log4.txt', '===']); | ||
var i = 0; | ||
var cp = spawn(cliPath, ['test/fixtures/log.txt', 'test/fixtures/log4.txt', 'test/fixtures/log2.txt', 'test/fixtures/log5.txt', '===']); | ||
cp.stderr | ||
.pipe(through(function(chunk, enc, cb) { | ||
if (i === 0) { | ||
expect(chunk.toString()).to.contain('Failed to read file test/fixtures/log4.txt'); | ||
} else { | ||
expect(chunk.toString()).to.contain('Failed to read file test/fixtures/log5.txt'); | ||
} | ||
i++; | ||
cb(); | ||
}, function() { | ||
done(); | ||
})); | ||
}); | ||
it('should work with options', function(done) { | ||
var cp = spawn(cliPath, ['test/fixtures/log3.txt', '--max-subject-length', '5', '-p', '^(\\w*)(?:\\(([:\\w\\$\\.\\-\\* ]*)\\))?\\: (.*)$', '--close-keywords', 'close, fix', '-b', 'BREAKING NEWS']); | ||
cp.stdout | ||
.pipe(concat(function(chunk) { | ||
expect(chunk.toString()).to.equal('Failed to read file test/fixtures/log3.txt\nError: ENOENT, open \'test/fixtures/log3.txt\'\nFailed to read file test/fixtures/log4.txt\nError: ENOENT, open \'test/fixtures/log4.txt\'\n'); | ||
expect(chunk.toString()).to.equal(output3); | ||
done(); | ||
@@ -57,0 +70,0 @@ })); |
@@ -76,7 +76,8 @@ 'use strict'; | ||
.pipe(through.obj(function(chunk, enc, cb) { | ||
expect(chunk.hash).to.equal('13f31602f396bc269076ab4d389cfd8ca94b20ba'); | ||
i++; | ||
if (++i !== 2) { | ||
expect(chunk.hash).to.equal('13f31602f396bc269076ab4d389cfd8ca94b20ba'); | ||
} | ||
cb(); | ||
}, function() { | ||
expect(i).to.equal(2); | ||
expect(i).to.equal(3); | ||
done(); | ||
@@ -86,16 +87,18 @@ })); | ||
var commits = [ | ||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' + | ||
'feat(ng-list) Allow custom separator\n' + | ||
'bla bla bla\n\n' + | ||
'Fix #123\nCloses #25\nfix #33\n', | ||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' + | ||
'fix(ng-list) Another custom separator\n' + | ||
'bla bla bla\n\n' + | ||
'BREAKING CHANGES: some breaking changes\n', | ||
]; | ||
it('should take options', function(done) { | ||
var stream = through(); | ||
var commits = [ | ||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' + | ||
'feat(ng-list): Allow custom separator\n' + | ||
'bla bla bla\n\n' + | ||
'Fix #123\nCloses #25\nfix #33\n', | ||
var length = commits.length; | ||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' + | ||
'feat(ng-list): Allow custom separator\n' + | ||
'bla bla bla\n\n' + | ||
'BREAKING CHANGES: some breaking changes\n', | ||
]; | ||
forEach(commits, function(commit) { | ||
@@ -106,6 +109,37 @@ stream.write(commit); | ||
stream | ||
.pipe(conventionalCommitsParser({ | ||
headerPattern: /^(\w*)(?:\(([\w\$\.\-\* ]*)\))?\ (.*)$/, | ||
closeKeywords: ['fix'], | ||
breakKeywords: ['BREAKING CHANGES'] | ||
})) | ||
.pipe(through.obj(function(chunk, enc, cb) { | ||
if (--length === 1) { | ||
expect(chunk.type).to.equal('feat'); | ||
expect(chunk.scope).to.equal('ng-list'); | ||
expect(chunk.subject).to.equal('Allow custom separator'); | ||
expect(chunk.closes).to.eql([123, 33]); | ||
} else { | ||
expect(chunk.type).to.equal('fix'); | ||
expect(chunk.scope).to.equal('ng-list'); | ||
expect(chunk.subject).to.equal('Another custom separator'); | ||
expect(chunk.breaks['BREAKING CHANGES']).to.equal('some breaking changes'); | ||
done(); | ||
} | ||
cb(); | ||
})); | ||
}); | ||
it('should take string options', function(done) { | ||
var stream = through(); | ||
var length = commits.length; | ||
forEach(commits, function(commit) { | ||
stream.write(commit); | ||
}); | ||
stream.end(); | ||
stream | ||
.pipe(conventionalCommitsParser({ | ||
headerPattern: '^(\\w*)(?:\\(([\\w\\$\\.\\-\\* ]*)\\))?\\ (.*)$', | ||
closeKeywords: 'fix', | ||
@@ -116,4 +150,10 @@ breakKeywords: 'BREAKING CHANGES' | ||
if (--length === 1) { | ||
expect(chunk.type).to.equal('feat'); | ||
expect(chunk.scope).to.equal('ng-list'); | ||
expect(chunk.subject).to.equal('Allow custom separator'); | ||
expect(chunk.closes).to.eql([123, 33]); | ||
} else { | ||
expect(chunk.type).to.equal('fix'); | ||
expect(chunk.scope).to.equal('ng-list'); | ||
expect(chunk.subject).to.equal('Another custom separator'); | ||
expect(chunk.breaks['BREAKING CHANGES']).to.equal('some breaking changes'); | ||
@@ -120,0 +160,0 @@ done(); |
@@ -54,2 +54,6 @@ 'use strict'; | ||
it('should returns null if there is no header', function() { | ||
expect(parser('056f5827de86cace1f282c8e3f1cccc952fcad2e', options)).to.equal(null); | ||
}); | ||
it('should parse header', function() { | ||
@@ -56,0 +60,0 @@ expect(msg.header).to.equal('feat(scope): broadcast $destroy event on scope destruction'); |
@@ -6,11 +6,25 @@ 'use strict'; | ||
describe('regex', function() { | ||
it('getBreaksRegex', function() { | ||
var re = regex.getBreaksRegex(['Breaking News', 'Breaking Change']); | ||
expect(re).to.eql(/(Breaking News|Breaking Change):\s([\s\S]*)/); | ||
describe('getBreaksRegex', function() { | ||
it('should generate correct regex', function() { | ||
var re = regex.getBreaksRegex(['Breaking News', 'Breaking Change']); | ||
expect(re).to.eql(/(Breaking News|Breaking Change):\s([\s\S]*)/); | ||
}); | ||
it('should ignore whitespace', function() { | ||
var re = regex.getBreaksRegex([' Breaking News', 'Breaking Change ', '', ' Breaking SOLUTION ']); | ||
expect(re).to.eql(/(Breaking News|Breaking Change|Breaking SOLUTION):\s([\s\S]*)/); | ||
}); | ||
}); | ||
it('getClosesRegex', function() { | ||
var re = regex.getClosesRegex(['Closes', 'amends']); | ||
expect(re).to.eql(/(?:Closes|amends)\s((?:#\d+(?:\,\s)?)+)/gi); | ||
describe('getClosesRegex', function() { | ||
it('should generate correct regex', function() { | ||
var re = regex.getClosesRegex(['Closes', 'amends']); | ||
expect(re).to.eql(/(?:Closes|amends)\s((?:#\d+(?:\,\s)?)+)/gi); | ||
}); | ||
it('should ignore whitespace', function() { | ||
var re = regex.getClosesRegex([' Closes', 'amends ', '', ' fixes ']); | ||
expect(re).to.eql(/(?:Closes|amends|fixes)\s((?:#\d+(?:\,\s)?)+)/gi); | ||
}); | ||
}); | ||
}); |
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
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
32323
22
587