Skip to content

Commit 825485c

Browse files
authored
fix(commit): fix multiline commits with newlines (#413)
* fix(commit): fix multiline commits with newlines * test(commit): fix override commit options test
1 parent 247d2c4 commit 825485c

File tree

5 files changed

+90
-69
lines changed

5 files changed

+90
-69
lines changed

src/cli/parsers/git-cz.js

Lines changed: 31 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,65 +6,50 @@ export {
66
parse
77
};
88

9+
const reShortMessage = /^-([a-zA-Z]*)m(.*)$/;
10+
const reLongMessage = /^--message(=.*)?$/;
11+
912
/**
10-
* Takes args, parses with minimist and some ugly vudoo, returns output
11-
*
12-
* TODO: Aww shit this is ugly. Rewrite with mega leet tests plz, kthnx.
13+
* Strip message declaration from git arguments
1314
*/
1415
function parse (rawGitArgs) {
16+
let result = [];
17+
let skipNext = false;
18+
19+
for (const arg of rawGitArgs) {
20+
let match;
1521

16-
var args = minimist(rawGitArgs, {
17-
alias: {
18-
m: 'message'
22+
if (skipNext) {
23+
skipNext = false;
24+
continue;
1925
}
20-
});
2126

22-
// Loop through all keys
23-
var output = ' ';
27+
match = reShortMessage.exec(arg);
28+
29+
if (match) {
30+
if (match[1]) {
31+
result.push(`-${match[1]}`);
32+
}
2433

25-
for (let arg in args) {
34+
if (!match[2]) {
35+
skipNext = true;
36+
}
2637

27-
if (!args.hasOwnProperty(arg)) {
28-
// The current property is not a direct property
2938
continue;
3039
}
40+
41+
match = reLongMessage.exec(arg);
42+
43+
if (match) {
44+
if (!match[1]) {
45+
skipNext = true;
46+
}
3147

32-
var key = arg;
33-
var value = args[arg];
34-
35-
/**
36-
* Ugly, but this is recompiles an argument string without
37-
* any messages passed in.
38-
*/
39-
if (key === '_' && value.length > 0) {
40-
// Anything in the _ array of strings is a one off file
41-
output += value.join(' ') + ' ';
42-
} else if (key === 'verbose') {
43-
output += '--verbose ';
44-
} else if (key === 'message') {
45-
/**
46-
* We strip out message because we're already handling this
47-
* in minimist's aliases.
48-
*/
49-
continue;
50-
} else if (isString(value)) {
51-
output += '-' + key + ' ' + value + ' ';
52-
} else if (isArray(value) && value.length > 0) {
53-
output += '-' + key + ' ' + value.join(' -' + key) + ' ';
54-
} else if (value === true || value === false) {
55-
output += '-' + key + ' ';
56-
} else {
57-
/**
58-
* Based on the current minimist object structure, we should
59-
* never get here, but we'll protect against breaking changes.
60-
*/
6148
continue;
6249
}
63-
}
6450

65-
if (output.trim().length < 1) {
66-
return '';
67-
} else {
68-
return output;
51+
result.push(arg);
6952
}
53+
54+
return result;
7055
}

src/git/commit.js

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
11
import os from 'os';
2-
import {exec} from 'child_process';
2+
import {spawn} from 'child_process';
33

44
import dedent from 'dedent';
55
import {isString} from '../common/util';
66

77
export { commit };
88

9-
function normalizeCommitMessage (message) {
10-
const signs = os.platform() === 'win32' ?
11-
/(")/g :
12-
/(["|`])/g;
13-
14-
const msg = ` -m "` + dedent(message)
15-
.replace(signs, '\\$1') + `"`;
16-
return msg;
17-
}
18-
199
/**
2010
* Asynchronously git commit at a given path with a message
2111
*/
2212
function commit (sh, repoPath, message, options, done) {
23-
let args = options.args || '';
24-
let commitMessage = normalizeCommitMessage(message);
25-
26-
exec(`git commit ${commitMessage} ${args}`, {
27-
maxBuffer: Infinity,
13+
let called = false;
14+
let args = ['commit', '-m', dedent(message), ...(options.args || [])];
15+
let child = spawn('git', args, {
2816
cwd: repoPath,
2917
stdio: options.quiet ? 'ignore' : 'inherit'
30-
}, function (error, stdout, stderror) {
31-
if (error) {
32-
/* istanbul ignore next */
33-
error.message = [error.message, stderror].filter(Boolean).join('\n');
34-
return done(error);
18+
});
19+
20+
child.on('error', function (err) {
21+
if (called) return;
22+
called = true;
23+
24+
done(err);
25+
});
26+
27+
child.on('exit', function (code, signal) {
28+
if (called) return;
29+
called = true;
30+
31+
if (code) {
32+
done(Object.assign(new Error(`git exited with error code ${code}`), { code, signal }));
33+
} else {
34+
done(null);
3535
}
36-
done();
3736
});
3837
}

test/tests/commit.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ describe('commit', function () {
213213
};
214214

215215
let options = {
216-
args: `--author="${author}" --no-edit`
216+
args: [`--author="${author}"`, '--no-edit']
217217
};
218218

219219
// Quick setup the repos, adapter, and grab a simple prompter

test/tests/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ import './cli';
33
import './commit';
44
import './configLoader';
55
import './init';
6+
import './parsers';
67
import './staging';
78
import './util';

test/tests/parsers.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* eslint-env mocha */
2+
3+
import {expect} from 'chai';
4+
import { parse } from '../../src/cli/parsers/git-cz';
5+
6+
describe('parsers', () => {
7+
describe('git-cz', () => {
8+
it('should parse --message "Hello, World!"', () => {
9+
expect(parse(['--amend', '--message', 'Hello, World!'])).to.deep.equal(['--amend']);
10+
});
11+
12+
it('should parse --message="Hello, World!"', () => {
13+
expect(parse(['--amend', '--message=Hello, World!'])).to.deep.equal(['--amend']);
14+
});
15+
16+
it('should parse -amwip', () => {
17+
expect(parse(['-amwip'])).to.deep.equal(['-a']);
18+
});
19+
20+
it('should parse -am=wip', () => {
21+
expect(parse(['-am=wip'])).to.deep.equal(['-a']);
22+
});
23+
24+
it('should parse -am wip', () => {
25+
expect(parse(['-am', 'wip'])).to.deep.equal(['-a']);
26+
});
27+
28+
it('should parse -a -m wip -n', () => {
29+
expect(parse(['-a', '-m', 'wip', '-n'])).to.deep.equal(['-a', '-n']);
30+
});
31+
32+
it('should parse -a -m=wip -n', () => {
33+
expect(parse(['-a', '-m=wip', '-n'])).to.deep.equal(['-a', '-n']);
34+
});
35+
});
36+
});

0 commit comments

Comments
 (0)