diff --git a/README.md b/README.md index 281cf7e..87c51a7 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ If you run `conventional-commits-parser` without any arguments $ conventional-commits-parser ``` -You will enter an interactive shell. To show your parsed result enter "return" three times. +You will enter an interactive shell. To show your parsed result enter "return" three times (or enter your specified separator). ```sh > fix(title): a title is fixed @@ -235,6 +235,8 @@ $ conventional-commits-parser log2.txt '===' Will be printed out. +You can specify one or more files. The output array will be in order of the input file paths. If you specify more than one separator, the last one will be used. + ## License diff --git a/cli.js b/cli.js index aff012a..c66ada4 100755 --- a/cli.js +++ b/cli.js @@ -1,37 +1,63 @@ #!/usr/bin/env node 'use strict'; var conventionalCommitsParser = require('./'); +var forEach = require('lodash').forEach; +var fs = require('graceful-fs'); +var isTextPath = require('is-text-path'); var JSONStream = require('JSONStream'); var meow = require('meow'); +var readline = require('readline'); var split = require('split'); +var through = require('through2'); + +var filePaths = []; +var separator = '\n\n\n'; var cli = meow({ help: [ 'Usage', - ' conventional-commits-parser ', - ' if used without specifying a file, you can enter an interactive shell', + ' conventional-commits-parser [] [...]', + ' 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', '', 'Example', ' conventional-commits-parser', - ' conventional-commits-parser log.txt' + ' conventional-commits-parser log.txt', + ' conventional-commits-parser log2.txt \'===\'' ].join('\n') }); -if (cli.input.length > 0) { - var fs = require('graceful-fs'); +forEach(cli.input, function(arg) { + if (isTextPath(arg)) { + filePaths.push(arg); + } else { + separator = arg; + } +}); + +var length = filePaths.length; - fs.createReadStream(cli.input[0]) +function processFile(fileIndex) { + fs.createReadStream(filePaths[fileIndex]) .on('error', function(err) { - console.log('Failed to read file ' + cli.input[0] + '\n' + err); + console.log('Failed to read file ' + filePaths[0] + '\n' + err); }) - .pipe(split(cli.input[1] || '\n\n\n')) + .pipe(split(separator)) .pipe(conventionalCommitsParser(cli.flags)) .pipe(JSONStream.stringify()) + .on('end', function() { + if(++fileIndex < length) { + processFile(fileIndex); + } + }) .pipe(process.stdout); +} + +if (length > 0) { + processFile(0); } else { var commit = ''; - var through = require('through2'); - var readline = require('readline'); + var stream = through(); var rl = readline.createInterface({ @@ -49,7 +75,7 @@ if (cli.input.length > 0) { rl.on('line', function(line) { commit += line + '\n'; - if (commit.indexOf('\n\n\n') === -1) { + if (commit.indexOf(separator) === -1) { return; } diff --git a/package.json b/package.json index 786b797..6e76471 100644 --- a/package.json +++ b/package.json @@ -19,15 +19,17 @@ "dependencies": { "JSONStream": "^0.10.0", "graceful-fs": "^3.0.5", + "is-text-path": "^1.0.0", + "lodash": "^3.3.1", "meow": "^3.1.0", "split": "^0.3.3", "through2": "^0.6.3" }, "devDependencies": { "chai": "^2.1.0", + "concat-stream": "^1.4.7", "coveralls": "^2.11.2", "istanbul": "^0.3.6", - "lodash": "^3.3.1", "mocha": "*", "split": "^0.3.3" }, diff --git a/test/cli.spec.js b/test/cli.spec.js new file mode 100644 index 0000000..d7089c8 --- /dev/null +++ b/test/cli.spec.js @@ -0,0 +1,45 @@ +'use strict'; +var expect = require('chai').expect; +var readFileSync = require('fs').readFileSync; +var spawn = require('child_process').spawn; +var concat = require('concat-stream'); + +var cliPath = './cli.js'; + +describe('cli', function() { + it('should parse commits in a file', function(done) { + var cp = spawn(cliPath, ['test/fixtures/log.txt']); + + cp.stdout + .pipe(concat(function(chunk) { + var expected = readFileSync('test/expected/output1.txt', 'utf-8'); + + expect(chunk.toString()).to.equal(expected); + done(); + })); + }); + + it('should work with a separator', function(done) { + var cp = spawn(cliPath, ['test/fixtures/log2.txt', '===']); + + cp.stdout + .pipe(concat(function(chunk) { + var expected = readFileSync('test/expected/output2.txt', 'utf-8'); + + expect(chunk.toString()).to.equal(expected); + done(); + })); + }); + + it('should work with two files', function(done) { + var cp = spawn(cliPath, ['test/fixtures/log.txt', 'test/fixtures/log2.txt', '===']); + + cp.stdout + .pipe(concat(function(chunk) { + var expected = readFileSync('test/expected/output_both.txt', 'utf-8'); + + expect(chunk.toString()).to.equal(expected); + done(); + })); + }); +}); diff --git a/test/expected/output1.txt b/test/expected/output1.txt new file mode 100644 index 0000000..cd510d1 --- /dev/null +++ b/test/expected/output1.txt @@ -0,0 +1,3 @@ +[ +{"hash":"9b1aff905b638aa274a5fc8f88662df446d374bd","header":"feat(ngMessages): provide support for dynamic message resolution","body":"Prior to this fix it was impossible to apply a binding to a the ngMessage directive to represent the name of the error.","footer":"BREAKING CHANGE: The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive.\nCloses #10036\nCloses #9338","breaks":{"BREAKING CHANGE":"The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive."},"closes":[10036,9338],"type":"feat","scope":"ngMessages","subject":"provide support for dynamic message resolution"} +] diff --git a/test/expected/output2.txt b/test/expected/output2.txt new file mode 100644 index 0000000..8c508d6 --- /dev/null +++ b/test/expected/output2.txt @@ -0,0 +1,5 @@ +[ +{"hash":"2d0eda10e43f6b079b531c507282fad082ea0762","header":"docs(ngMessageExp): split ngMessage docs up to show its alias more clearly","body":"","footer":"","breaks":{},"closes":[],"type":"docs","scope":"ngMessageExp","subject":"split ngMessage docs up to show its alias more clearly"} +, +{"hash":"4374f892c6fa4af6ba1f2ed47c5f888fdb5fadc5","header":"fix($animate): applyStyles from options on leave","body":"","footer":"Closes #10068","breaks":{},"closes":[10068],"type":"fix","scope":"$animate","subject":"applyStyles from options on leave"} +] diff --git a/test/expected/output_both.txt b/test/expected/output_both.txt new file mode 100644 index 0000000..94948de --- /dev/null +++ b/test/expected/output_both.txt @@ -0,0 +1,8 @@ +[ +{"hash":"9b1aff905b638aa274a5fc8f88662df446d374bd","header":"feat(ngMessages): provide support for dynamic message resolution","body":"Prior to this fix it was impossible to apply a binding to a the ngMessage directive to represent the name of the error.","footer":"BREAKING CHANGE: The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive.\nCloses #10036\nCloses #9338","breaks":{"BREAKING CHANGE":"The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive."},"closes":[10036,9338],"type":"feat","scope":"ngMessages","subject":"provide support for dynamic message resolution"} +] +[ +{"hash":"2d0eda10e43f6b079b531c507282fad082ea0762","header":"docs(ngMessageExp): split ngMessage docs up to show its alias more clearly","body":"","footer":"","breaks":{},"closes":[],"type":"docs","scope":"ngMessageExp","subject":"split ngMessage docs up to show its alias more clearly"} +, +{"hash":"4374f892c6fa4af6ba1f2ed47c5f888fdb5fadc5","header":"fix($animate): applyStyles from options on leave","body":"","footer":"Closes #10068","breaks":{},"closes":[10068],"type":"fix","scope":"$animate","subject":"applyStyles from options on leave"} +] diff --git a/test/fixtures/log.txt b/test/fixtures/log.txt new file mode 100644 index 0000000..1b6020c --- /dev/null +++ b/test/fixtures/log.txt @@ -0,0 +1,10 @@ +9b1aff905b638aa274a5fc8f88662df446d374bd + +feat(ngMessages): provide support for dynamic message resolution + +Prior to this fix it was impossible to apply a binding to a the ngMessage directive to represent the name of the error. + +BREAKING CHANGE: The `ngMessagesInclude` attribute is now its own directive and that must be placed as a **child** element within the element with the ngMessages directive. + +Closes #10036 +Closes #9338 diff --git a/test/fixtures/log2.txt b/test/fixtures/log2.txt new file mode 100644 index 0000000..3e142e8 --- /dev/null +++ b/test/fixtures/log2.txt @@ -0,0 +1,9 @@ +2d0eda10e43f6b079b531c507282fad082ea0762 + +docs(ngMessageExp): split ngMessage docs up to show its alias more clearly +=== +4374f892c6fa4af6ba1f2ed47c5f888fdb5fadc5 + +fix($animate): applyStyles from options on leave + +Closes #10068