UNPKG

@digitalroute/cz-conventional-changelog-for-jira

Version:

Commitizen adapter following the conventional-changelog format and also asking for JIRA issue.

1,070 lines (1,041 loc) 27.2 kB
var chai = require('chai'); var chalk = require('chalk'); var engine = require('./engine'); var mock = require('mock-require'); var semver = require('semver'); var types = require('./types'); var defaults = require('./defaults'); var expect = chai.expect; chai.should(); var defaultOptions = defaults; const skipTypeOptions = { ...defaultOptions, skipType: true }; var type = 'func'; var scope = 'everything'; var customScope = 'custom scope'; var jira = 'dAz-123'; var jiraUpperCase = 'DAZ-123'; var subject = 'testing123'; const shortBody = 'a'; var longBody = 'a a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a' + 'a a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a' + 'a a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a aa a'; var longBodySplit = longBody.slice(0, defaultOptions.maxLineWidth).trim() + '\n' + longBody .slice(defaultOptions.maxLineWidth, 2 * defaultOptions.maxLineWidth) .trim() + '\n' + longBody.slice(defaultOptions.maxLineWidth * 2, longBody.length).trim(); var body = 'A quick brown fox jumps over the dog'; var issues = 'a issues is not a person that kicks things'; var longIssues = 'b b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b' + 'b b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b' + 'b b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b bb b'; var breakingChange = 'BREAKING CHANGE: '; var breaking = 'asdhdfkjhbakjdhjkashd adhfajkhs asdhkjdsh ahshd'; var longIssuesSplit = longIssues.slice(0, defaultOptions.maxLineWidth).trim() + '\n' + longIssues .slice(defaultOptions.maxLineWidth, defaultOptions.maxLineWidth * 2) .trim() + '\n' + longIssues.slice(defaultOptions.maxLineWidth * 2, longIssues.length).trim(); describe('commit message', function() { it('only header w/ out scope and w/ out type', function() { expect( commitMessage( { jira, subject }, skipTypeOptions ) ).to.equal(`${jiraUpperCase} ${subject}`); }); it('only header w/ out scope and w/ type', function() { expect( commitMessage({ type, jira, subject }) ).to.equal(`${type}: ${jiraUpperCase} ${subject}`); }); it('only header w/ scope and w/ type', function() { expect( commitMessage({ type, scope, jira, subject }) ).to.equal(`${type}(${scope}): ${jiraUpperCase} ${subject}`); }); it('only header w/ scope and w/ out type', function() { expect( commitMessage( { scope, jira, subject }, skipTypeOptions ) ).to.equal(`(${scope}): ${jiraUpperCase} ${subject}`); }); it('header and body w/ out scope and w/ type', function() { expect( commitMessage({ type, jira, subject, body }) ).to.equal(`${type}: ${jiraUpperCase} ${subject}\n\n${body}`); }); it('header and body w/ out scope and w/ out type', function() { expect( commitMessage( { jira, subject, body }, skipTypeOptions ) ).to.equal(`${jiraUpperCase} ${subject}\n\n${body}`); }); it('header and body w/ scope and w/ type', function() { expect( commitMessage({ type, scope, jira, subject, body }) ).to.equal(`${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${body}`); }); it('header and body w/ scope and w/ out type', function() { expect( commitMessage( { scope, jira, subject, body }, skipTypeOptions ) ).to.equal(`(${scope}): ${jiraUpperCase} ${subject}\n\n${body}`); }); it('header and body w/ custom scope', function() { expect( commitMessage({ type, scope: 'custom', customScope, jira, subject, body }) ).to.equal( `${type}(${customScope}): ${jiraUpperCase} ${subject}\n\n${body}` ); }); it('header, body and issues w/ out scope and w/ out type', function() { expect( commitMessage( { jira, subject, body, issues }, skipTypeOptions ) ).to.equal(`${jiraUpperCase} ${subject}\n\n${body}\n\n${issues}`); }); it('header, body and issues w/ out scope and w/ type', function() { expect( commitMessage({ type, jira, subject, body, issues }) ).to.equal(`${type}: ${jiraUpperCase} ${subject}\n\n${body}\n\n${issues}`); }); it('header, body and issues w/ scope and w/ out type', function() { expect( commitMessage( { scope, jira, subject, body, issues }, skipTypeOptions ) ).to.equal( `(${scope}): ${jiraUpperCase} ${subject}\n\n${body}\n\n${issues}` ); }); it('header, body and issues w/ scope and w/ type', function() { expect( commitMessage({ type, scope, jira, subject, body, issues }) ).to.equal( `${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${body}\n\n${issues}` ); }); it('header, body and long issues w/ out scope and w/ out type', function() { expect( commitMessage( { jira, subject, body, issues: longIssues }, skipTypeOptions ) ).to.equal(`${jiraUpperCase} ${subject}\n\n${body}\n\n${longIssuesSplit}`); }); it('header, body and long issues w/ out scope and w/ type', function() { expect( commitMessage({ type, jira, subject, body, issues: longIssues }) ).to.equal( `${type}: ${jiraUpperCase} ${subject}\n\n${body}\n\n${longIssuesSplit}` ); }); it('header, body and long issues w/ scope and w/ out type', function() { expect( commitMessage( { scope, jira, subject, body, issues: longIssues }, skipTypeOptions ) ).to.equal( `(${scope}): ${jiraUpperCase} ${subject}\n\n${body}\n\n${longIssuesSplit}` ); }); it('header, body and long issues w/ scope and w/ tyoe', function() { expect( commitMessage({ type, scope, jira, subject, body, issues: longIssues }) ).to.equal( `${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${body}\n\n${longIssuesSplit}` ); }); it('header and long body w/ out scope and w/ out type', function() { expect( commitMessage( { jira, subject, body: longBody }, skipTypeOptions ) ).to.equal(`${jiraUpperCase} ${subject}\n\n${longBodySplit}`); }); it('header and long body w/ out scope and w/ type', function() { expect( commitMessage({ type, jira, subject, body: longBody }) ).to.equal(`${type}: ${jiraUpperCase} ${subject}\n\n${longBodySplit}`); }); it('header and long body w/ scope and w/ out type', function() { expect( commitMessage( { scope, jira, subject, body: longBody }, skipTypeOptions ) ).to.equal(`(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}`); }); it('header and long body w/ scope and w/ type', function() { expect( commitMessage({ type, scope, jira, subject, body: longBody }) ).to.equal( `${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}` ); }); it('header, long body and issues w/ out scope and w/ out type', function() { expect( commitMessage( { jira, subject, body: longBody, issues }, skipTypeOptions ) ).to.equal(`${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${issues}`); }); it('header, long body and issues w/ out scope and w/ type', function() { expect( commitMessage({ type, jira, subject, body: longBody, issues }) ).to.equal( `${type}: ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${issues}` ); }); it('header, long body and issues w/ scope and w/ out type', function() { expect( commitMessage( { scope, jira, subject, body: longBody, issues }, skipTypeOptions ) ).to.equal( `(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${issues}` ); }); it('header, long body and issues w/ scope and w/ type', function() { expect( commitMessage({ type, scope, jira, subject, body: longBody, issues }) ).to.equal( `${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${issues}` ); }); it('header, long body and long issues w/ out scope and w/ out type', function() { expect( commitMessage( { jira, subject, body: longBody, issues: longIssues }, skipTypeOptions ) ).to.equal( `${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${longIssuesSplit}` ); }); it('header, long body and long issues w/ out scope and w/ type', function() { expect( commitMessage({ type, jira, subject, body: longBody, issues: longIssues }) ).to.equal( `${type}: ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${longIssuesSplit}` ); }); it('header, long body and long issues w/ scope and w/ out type', function() { expect( commitMessage( { scope, jira, subject, body: longBody, issues: longIssues }, skipTypeOptions ) ).to.equal( `(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${longIssuesSplit}` ); }); it('header, long body and long issues w/ scope and w/ type', function() { expect( commitMessage({ type, scope, jira, subject, body: longBody, issues: longIssues }) ).to.equal( `${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${longIssuesSplit}` ); }); it('header, long body, breaking change, and long issues w/ scope', function() { expect( commitMessage({ scope, jira, subject, body: longBody, breaking, issues: longIssues }) ).to.equal( `(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${breakingChange}${breaking}\n\n${longIssuesSplit}` ); }); it('header, long body, breaking change, and long issues w/ scope and w/ type', function() { expect( commitMessage({ type, scope, jira, subject, body: longBody, breaking, issues: longIssues }) ).to.equal( `${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${breakingChange}${breaking}\n\n${longIssuesSplit}` ); }); it('header, long body, breaking change (with prefix entered), and long issues w/ scope and w/ out type', function() { expect( commitMessage( { scope, jira, subject, body: longBody, breaking: `${breakingChange}${breaking}`, issues: longIssues }, skipTypeOptions ) ).to.equal( `(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${breakingChange}${breaking}\n\n${longIssuesSplit}` ); }); it('header, long body, breaking change (with prefix entered), and long issues w/ scope and w/ type', function() { expect( commitMessage({ type, scope, jira, subject, body: longBody, breaking: `${breakingChange}${breaking}`, issues: longIssues }) ).to.equal( `${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${longBodySplit}\n\n${breakingChange}${breaking}\n\n${longIssuesSplit}` ); }); it('header, body, breaking change, and issues w/ scope and w/o type; exclamation mark enabled', function() { expect( commitMessage( { scope, jira, subject, body, breaking, issues }, { ...skipTypeOptions, exclamationMark: true } ) ).to.equal( `(${scope})!: ${jiraUpperCase} ${subject}\n\n${body}\n\n${breakingChange}${breaking}\n\n${issues}` ); }); it('header, body, breaking change, and issues w/ scope and w/ type; exclamation mark enabled', function() { expect( commitMessage( { type, scope, jira, subject, body, breaking, issues }, { ...defaultOptions, exclamationMark: true } ) ).to.equal( `${type}(${scope})!: ${jiraUpperCase} ${subject}\n\n${body}\n\n${breakingChange}${breaking}\n\n${issues}` ); }); it('header, body, breaking change, and issues w/o scope and w/o type; exclamation mark enabled', function() { expect( commitMessage( { jira, subject, body, breaking, issues }, { ...skipTypeOptions, exclamationMark: true } ) ).to.equal( `!: ${jiraUpperCase} ${subject}\n\n${body}\n\n${breakingChange}${breaking}\n\n${issues}` ); }); it('header, body, breaking change, and issues w/o scope and w/ type; exclamation mark enabled', function() { expect( commitMessage( { type, jira, subject, body, breaking, issues }, { ...defaultOptions, exclamationMark: true } ) ).to.equal( `${type}!: ${jiraUpperCase} ${subject}\n\n${body}\n\n${breakingChange}${breaking}\n\n${issues}` ); }); it('skip jira task when optional', function() { expect( commitMessage( { type, scope, jira: '', subject }, { jiraOptional: true } ) ).to.equal(`${type}(${scope}): ${subject}`); }); it('default jiraLocation when unknown', function() { expect( commitMessage( { type, scope, jira, subject, body }, { jiraLocation: 'unknown-location' } ) ).to.equal(`${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${body}`); }); it('pre-type jiraLocation', function() { expect( commitMessage( { type, scope, jira, subject, body }, { jiraLocation: 'pre-type' } ) ).to.equal(`${jiraUpperCase} ${type}(${scope}): ${subject}\n\n${body}`); }); it('pre-description jiraLocation', function() { expect( commitMessage( { type, scope, jira, subject, body }, { jiraLocation: 'pre-description' } ) ).to.equal(`${type}(${scope}): ${jiraUpperCase} ${subject}\n\n${body}`); }); it('post-description jiraLocation', function() { expect( commitMessage( { type, scope, jira, subject, body }, { jiraLocation: 'post-description' } ) ).to.equal(`${type}(${scope}): ${subject} ${jiraUpperCase} \n\n${body}`); }); it('post-body jiraLocation with body', function() { expect( commitMessage( { type, scope, jira, subject, body }, { ...defaultOptions, jiraLocation: 'post-body' } ) ).to.equal(`${type}(${scope}): ${subject}\n\n${body}\n\n${jiraUpperCase}`); }); it('post-body jiraLocation no body', function() { expect( commitMessage( { type, scope, jira, subject, body: false }, { ...defaultOptions, jiraLocation: 'post-body' } ) ).to.equal(`${type}(${scope}): ${subject}\n\n${jiraUpperCase}`); }); it('post-body jiraLocation with body and footer', function() { var footer = `${breakingChange}${breaking}`; expect( commitMessage( { type, scope, jira, subject, body, breaking }, { ...defaultOptions, jiraLocation: 'post-body' } ) ).to.equal( `${type}(${scope}): ${subject}\n\n${body}\n\n${jiraUpperCase}\n\n${breakingChange}${breaking}` ); }); it('jiraPrepend decorator', function() { expect( commitMessage( { type, scope, jira, subject, body }, { jiraPrepend: '-' } ) ).to.equal(`${type}(${scope}): -${jiraUpperCase} ${subject}\n\n${body}`); }); it('jiraAppend decorator', function() { expect( commitMessage( { type, scope, jira, subject, body }, { jiraAppend: '+' } ) ).to.equal(`${type}(${scope}): ${jiraUpperCase}+ ${subject}\n\n${body}`); }); it('jiraPrepend and jiraAppend decorators', function() { expect( commitMessage( { type, scope, jira, subject, body }, { jiraAppend: ']', jiraPrepend: '[' } ) ).to.equal(`${type}(${scope}): [${jiraUpperCase}] ${subject}\n\n${body}`); }); it('jiraLocation, jiraPrepend, jiraAppend decorators', function() { expect( commitMessage( { type, scope, jira, subject, body }, { jiraAppend: ']', jiraPrepend: '[', jiraLocation: 'pre-type' } ) ).to.equal(`[${jiraUpperCase}] ${type}(${scope}): ${subject}\n\n${body}`); }); }); describe('validation', function() { it('subject exceeds max length', function() { expect(() => commitMessage({ type, scope, jira, subject: shortBody }) ).to.throw(`The subject must have at least 2 characters`); }); it('empty subject', function() { expect(() => commitMessage({ type, scope, subject: '' }) ).to.throw(`The subject must have at least 2 characters`); }); it('empty jira if not optional', function() { expect(() => commitMessage( { type, scope, jira: '', subject }, { jiraOptional: false } ) ).to.throw(`Answer '' to question 'jira' was invalid`); }); }); describe('defaults', function() { it('defaultType default', function() { expect(questionDefault('type')).to.be.undefined; }); it('defaultType options', function() { expect( questionDefault('type', customOptions({ defaultType: type })) ).to.equal(type); }); it('defaultScope default', function() { expect(questionDefault('scope')).to.be.undefined; }); it('defaultScope options', () => expect( questionDefault('scope', customOptions({ defaultScope: scope })) ).to.equal(scope)); it('defaultSubject default', () => expect(questionDefault('subject')).to.be.undefined); it('defaultSubject options', function() { expect( questionDefault( 'subject', customOptions({ defaultSubject: subject }) ) ).to.equal(subject); }); it('defaultBody default', function() { expect(questionDefault('body')).to.be.undefined; }); it('defaultBody options', function() { expect( questionDefault('body', customOptions({ defaultBody: body })) ).to.equal(body); }); it('defaultIssues default', function() { expect(questionDefault('issues')).to.be.undefined; }); it('defaultIssues options', function() { expect( questionDefault( 'issues', customOptions({ defaultIssues: issues }) ) ).to.equal(issues); }); }); describe('filter', function() { it('lowercase scope', () => expect(questionFilter('scope', 'HelloMatt')).to.equal('hellomatt')); }); describe('when', function() { it('breaking by default', () => expect(questionWhen('breaking', {})).to.be.undefined); it('breaking when isBreaking', () => expect( questionWhen('breaking', { isBreaking: true }) ).to.be.true); it('issues by default', () => expect(questionWhen('issues', {})).to.be.undefined); it('issues when isIssueAffected', () => expect( questionWhen('issues', { isIssueAffected: true }) ).to.be.true); }); describe('commitlint config header-max-length', function() { //commitlint config parser only supports Node 6.0.0 and higher if (semver.gte(process.version, '6.0.0')) { function mockOptions(headerMaxLength) { var options = undefined; mock('./engine', function(opts) { options = opts; }); if (headerMaxLength) { mock('cosmiconfig', function() { return { load: function(cwd) { return { filepath: cwd + '/.commitlintrc.js', config: { rules: { 'header-max-length': [2, 'always', headerMaxLength] } } }; } }; }); } mock.reRequire('./index'); try { return mock .reRequire('@commitlint/load')() .then(function() { return options; }); } catch (err) { return Promise.resolve(options); } } afterEach(function() { delete require.cache[require.resolve('./index')]; delete require.cache[require.resolve('@commitlint/load')]; delete process.env.CZ_MAX_HEADER_WIDTH; mock.stopAll(); }); it('with no environment or commitizen config override', function() { return mockOptions(72).then(function(options) { expect(options).to.have.property('maxHeaderWidth', 72); }); }); it('with environment variable override', function() { process.env.CZ_MAX_HEADER_WIDTH = '105'; return mockOptions(72).then(function(options) { expect(options).to.have.property('maxHeaderWidth', 105); }); }); it('with commitizen config override', function() { mock('commitizen', { configLoader: { load: function() { return { maxHeaderWidth: 103 }; } } }); return mockOptions(72).then(function(options) { expect(options).to.have.property('maxHeaderWidth', 103); }); }); } else { //Node 4 doesn't support commitlint so the config value should remain the same it('default value for Node 4', function() { return mockOptions(72).then(function(options) { expect(options).to.have.property('maxHeaderWidth', 100); }); }); } }); describe('questions', function() { it('default jira question', function() { expect(questionPrompt('jira')).to.be.eq('Enter JIRA issue (DAZ-12345):'); }); it('optional jira question', function() { expect(questionPrompt('jira', [], { jiraOptional: true })).to.be.eq( 'Enter JIRA issue (DAZ-12345) (optional):' ); }); it('scope with list', function() { expect( questionPrompt('scope', [], { scopes: ['scope1', 'scope2'] }) ).to.be.eq( 'What is the scope of this change (e.g. component or file name): (select from the list)' ); }); it('scope without list', function() { expect(questionPrompt('scope')).to.be.eq( 'What is the scope of this change (e.g. component or file name): (press enter to skip)' ); }); }); function commitMessage(answers, options) { options = options || defaultOptions; var result = null; engine(options).prompter( { prompt: function(questions) { return { then: function(finalizer) { processQuestions(questions, answers, options); finalizer(answers); } }; }, registerPrompt: () => {} }, function(message) { result = message; }, true ); return result; } function processQuestions(questions, answers, options) { for (var i in questions) { var question = questions[i]; var answer = answers[question.name]; var validation = answer === undefined || !question.validate ? true : question.validate(answer, answers); if (validation !== true) { throw new Error( validation || `Answer '${answer}' to question '${question.name}' was invalid` ); } if (question.filter && answer) { answers[question.name] = question.filter(answer); } } } function getQuestions(options) { options = options || defaultOptions; var result = null; engine(options).prompter({ prompt: function(questions) { result = questions; return { then: function() {} }; }, registerPrompt: () => {} }); return result; } function getQuestion(name, options) { options = options || defaultOptions; var questions = getQuestions(options); for (var i in questions) { if (questions[i].name === name) { return questions[i]; } } return false; } function questionPrompt(name, answers, options) { options = options || defaultOptions; var question = getQuestion(name, options); return question.message && typeof question.message === 'string' ? question.message : question.message(answers); } function questionTransformation(name, answers, options) { options = options || defaultOptions; var question = getQuestion(name, options); return ( question.transformer && question.transformer(answers[name], answers, options) ); } function questionFilter(name, answer, options) { options = options || defaultOptions; var question = getQuestion(name, options); return ( question.filter && question.filter(typeof answer === 'string' ? answer : answer[name]) ); } function questionDefault(name, options) { options = options || defaultOptions; var question = getQuestion(name, options); return question.default; } function questionWhen(name, answers, options) { options = options || defaultOptions; var question = getQuestion(name, options); return question.when(answers); } function customOptions(options) { Object.keys(defaultOptions).forEach(key => { if (options[key] === undefined) { options[key] = defaultOptions[key]; } }); return options; }