Skip to content

Commit

Permalink
Merge 239cbbf into c14a9c3
Browse files Browse the repository at this point in the history
  • Loading branch information
JPeer264 committed Apr 10, 2019
2 parents c14a9c3 + 239cbbf commit f7e5b4a
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 19 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,12 @@ Example:

> Types will define your git commits. If `types` is not set in your own `.sgcrc`, the `types` of the global [.sgcrc](.sgcrc)
> Notice: If the `type` is `false` it will let you to manually add the type. This is usefull especially if you have a `prefix` named `SGC-` to reference these as a ticket number for your ticket tool
**Keys**

- `type` - This will be your commit convention and will be your start of your commit - e.g.: `Feat:`
- `type` (`string` or `false`) - This will be your commit convention and will be your start of your commit - e.g.: `Feat:`
- `prefix` (optional) - This option is just valid, if `type` is `false`
- `description` (optional) - The description to explain what your type is about
- `emoji` (optional) - An emoji which will be appended at the beginning of the commit ([Emoji Cheat Sheet](https://www.webpagefx.com/tools/emoji-cheat-sheet/))
- `argKeys` | Array (optional) - Keys which will be accessed through the `-t` [parameter](#usage-with-parameters)
Expand Down
3 changes: 2 additions & 1 deletion lib/helpers/formatters.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export const formatMessage = (answers, argv) => {
...argv,
};

const type = combineTypeScope(combinedAnswers.type, combinedAnswers.scope);
const correctType = combinedAnswers.customType || combinedAnswers.type;
const type = combineTypeScope(correctType, combinedAnswers.scope);
const formattedMessage = `${type} ${(combinedAnswers.message || '').trim()}`;
let result = formattedMessage;

Expand Down
45 changes: 44 additions & 1 deletion lib/questions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@ import chalk from 'chalk';
import ruleWarningMessages from './rules/ruleWarningMessages';
import { formatMessage } from './helpers/formatters';

const customName = 'Custom';

const choices = (config) => {
const choicesList = [];

let customCount = 1;

config.types.forEach((type) => {
const emoji = config.emoji && type.emoji ? `${type.emoji} ` : '';
const configType = config.lowercaseTypes ? type.type.toLowerCase() : type.type;
let changedType = type.type;

// type = false === it is a custom type
if (!changedType) {
changedType = `${customName} ${customCount}`;
customCount += 1;
}

const configType = config.lowercaseTypes ? changedType.toLowerCase() : changedType;
const description = type.description || '';
const argKeys = type.argKeys || [];
const isArray = Array.isArray(argKeys);
Expand Down Expand Up @@ -75,6 +87,36 @@ const questions = (config, argv = {}) => {
message: 'Select the type of your commit:',
choices: choicesList,
},
{
type: 'input',
name: 'customType',
when: answers => (answers.type.includes(customName) && !modifiedArgv.c),
filter: (answer, answers) => {
let customCount = 1;

const typeChoice = config.types.find((type) => {
// if there is no type it is a custom type
if (!type.type) {
if (answers.type === `${customName} ${customCount}`) {
return true;
}

customCount += 1;
}

return false;
});


if (!typeChoice) {
return answer;
}

return `${typeChoice.prefix || ''}${answer}`;
},
message: 'Choose your custom commit:',
choices: choicesList,
},
{
type: 'input',
name: 'scope',
Expand Down Expand Up @@ -124,6 +166,7 @@ const questions = (config, argv = {}) => {
export default questions;
export {
choices,
customName,
initMessage,
initQuestion,
};
31 changes: 31 additions & 0 deletions test/fixtures/.sgcrc.customType
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"scope": false,
"body": true,
"emoji": false,
"lowercaseTypes": false,
"initialCommit": {
"isEnabled": true,
"emoji": ":tada:",
"message": "Initial commit"
},
"types": [
{
"emoji": ":wrench:",
"type": false,
"description": "A custom type with prefix",
"prefix": "SGC-",
"argKeys": ["cu", "custom"]
},
{
"emoji": ":wrench:",
"type": false,
"description": "Another custom type with prefix",
"prefix": "SGGC-"
}
],
"rules": {
"maxChar": 72,
"minChar": 10,
"endWithDot": false
}
}
9 changes: 9 additions & 0 deletions test/helper/formatters.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ test('FORMATMESSAGE | should format message', (t) => {
t.is(message, 'myType: something');
});

test('FORMATMESSAGE | should format message with customType', (t) => {
const message = formatMessage({
message: ' something ',
customType: 'custom',
});

t.is(message, 'custom: something');
});

test('FORMATMESSAGE | should format with scope', (t) => {
const message = formatMessage({
type: 'myType',
Expand Down
106 changes: 90 additions & 16 deletions test/questions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { withEmoji, withoutEmoji } from './fixtures/questions';
import getConfig from '../lib/getConfig';
import questions, {
choices,
customName,
initMessage,
initQuestion,
} from '../lib/questions';
Expand All @@ -24,6 +25,15 @@ const randomString = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0

let globalExist = false;

const questionsListOrder = {
type: 0,
customType: 1,
scope: 2,
message: 3,
body: 4,
editor: 5,
};

// rename global .sgcrc
test.before(() => {
// rename global config
Expand Down Expand Up @@ -63,6 +73,19 @@ test('choices are rendered with emoji (default)', (t) => {
t.deepEqual(choicesList, withEmoji);
});

test('choices are rendered as custom type', (t) => {
const sgc = getConfig(path.join(fixtures, '.sgcrc.customType'));

sgc.emoji = false;
sgc.types[0].type = false;
sgc.types[1].type = false;

const choicesList = choices(sgc);

t.deepEqual(choicesList[0].value, `${customName} 1`);
t.deepEqual(choicesList[1].value, `${customName} 2`);
});

test('check the values of the question object', (t) => {
const config = getConfig();
const questionsList = questions(config);
Expand Down Expand Up @@ -132,28 +155,79 @@ test('TYPE | just show if type has not been added', (t) => {
const config = getConfig();
const questionsList = questions(config);

t.is(questionsList[0].when(), true);
t.is(questionsList[questionsListOrder.type].when(), true);
});

test('TYPE | not show if type has been added', (t) => {
const config = getConfig();
const questionsList = questions(config, { t: 'feat' });

t.is(questionsList[0].when(), false);
t.is(questionsList[questionsListOrder.type].when(), false);
});

test('SCOPE | check if scope is off by default', (t) => {
const config = getConfig();
const questionsList = questions(config);

t.is(questionsList[1].when(), false);
t.is(questionsList[questionsListOrder.scope].when(), false);
});

test('CUSTOMTYPE | check if customType gets shown when type is defined', (t) => {
const config = getConfig(path.join(fixtures, '.sgcrc.customType'));
const questionsList = questions(config);

t.is(questionsList[questionsListOrder.customType].when({ type: 'Feat:' }), false);
t.is(questionsList[questionsListOrder.customType].when({ type: 'anything' }), false);
});

test('CUSTOMTYPE | check if customType gets shown when type is custom', (t) => {
const config = getConfig(path.join(fixtures, '.sgcrc.customType'));
const questionsList = questions(config);

t.is(questionsList[questionsListOrder.customType].when({ type: customName }), true);
t.is(questionsList[questionsListOrder.customType].when({ type: `${customName}feat` }), true);
});

test('CUSTOMTYPE | should not show when argv is specified', (t) => {
const config = getConfig(path.join(fixtures, '.sgcrc.customType'));
const questionsList = questions(config, { c: 'Feat:' });

t.is(questionsList[questionsListOrder.customType].when({ type: customName }), false);
t.is(questionsList[questionsListOrder.customType].when({ type: `${customName}feat` }), false);
});

test('CUSTOMTYPE | return prefixed answer', (t) => {
const config = getConfig(path.join(fixtures, '.sgcrc.customType'));

config.types[0].prefix = 'myprefix';

const questionsList = questions(config);

t.is(questionsList[questionsListOrder.customType].filter('answer', { type: `${customName} 1` }), 'myprefixanswer');
});

test('CUSTOMTYPE | return nonprefixed answer', (t) => {
const config = getConfig(path.join(fixtures, '.sgcrc.customType'));

config.types[0].prefix = undefined;

const questionsList = questions(config);

t.is(questionsList[questionsListOrder.customType].filter('answer', { type: `${customName} 1` }), 'answer');
});

test('CUSTOMTYPE | return any type', (t) => {
const config = getConfig(path.join(fixtures, '.sgcrc.customType'));
const questionsList = questions(config);

t.is(questionsList[questionsListOrder.customType].filter('something', { type: 'none' }), 'something');
});

test('SCOPE | check if scope is off when it has been added by argv', (t) => {
const config = getConfig();
const questionsList = questions(config, { s: 'some scope' });

t.is(questionsList[1].when(), false);
t.is(questionsList[questionsListOrder.scope].when(), false);
});

test('SCOPE | check if scope is off when it has been added in config and argv', (t) => {
Expand All @@ -163,7 +237,7 @@ test('SCOPE | check if scope is off when it has been added in config and argv',

const questionsList = questions(config, { s: 'some scope' });

t.is(questionsList[1].when(), false);
t.is(questionsList[questionsListOrder.scope].when(), false);
});

test('SCOPE | check if scope is on when it has been added just in config', (t) => {
Expand All @@ -173,53 +247,53 @@ test('SCOPE | check if scope is on when it has been added just in config', (t) =

const questionsList = questions(config);

t.is(questionsList[1].when(), true);
t.is(questionsList[questionsListOrder.scope].when(), true);
});

test('SCOPE | check if scope validates correctly', (t) => {
const config = getConfig();
const questionsList = questions(config);

t.is(questionsList[1].validate('not correct'), 'No whitespaces allowed');
t.is(questionsList[1].validate('correct'), true);
t.is(questionsList[questionsListOrder.scope].validate('not correct'), 'No whitespaces allowed');
t.is(questionsList[questionsListOrder.scope].validate('correct'), true);
});

test('MESSAGE | validate functions in questions', (t) => {
const config = getConfig();
const questionsList = questions(config);

t.is(questionsList[2].validate('', { type: 'Fix' }), 'The commit message is not allowed to be empty');
t.is(questionsList[2].validate('input text', { type: 'Fix' }), true);
t.is(questionsList[2].validate('This message has over 72 characters. So this test will definitely fail. I can guarantee that I am telling the truth', { type: 'Fix' }), 'The commit message is not allowed to be longer as 72 character, but is 120 character long. Consider writing a body.\n');
t.is(questionsList[questionsListOrder.message].validate('', { type: 'Fix' }), 'The commit message is not allowed to be empty');
t.is(questionsList[questionsListOrder.message].validate('input text', { type: 'Fix' }), true);
t.is(questionsList[questionsListOrder.message].validate('This message has over 72 characters. So this test will definitely fail. I can guarantee that I am telling the truth', { type: 'Fix' }), 'The commit message is not allowed to be longer as 72 character, but is 120 character long. Consider writing a body.\n');
});

test('MESSAGE | do not show if there is the message in argv', (t) => {
const config = getConfig();
const questionsList = questions(config, { m: 'something' });

t.is(questionsList[2].when(), false);
t.is(questionsList[questionsListOrder.message].when(), false);
});

test('MESSAGE | show if no argv has been added', (t) => {
const config = getConfig();
const questionsList = questions(config);

t.is(questionsList[2].when(), true);
t.is(questionsList[questionsListOrder.message].when(), true);
});

test('EDITOR | when and default functions in questions', (t) => {
const config = getConfig();
const questionsList = questions(config);

t.is(questionsList[4].when({ body: true }), true);
t.is(questionsList[4].when({ body: false }), false);
t.is(questionsList[questionsListOrder.editor].when({ body: true }), true);
t.is(questionsList[questionsListOrder.editor].when({ body: false }), false);
});

test('EDITOR | should return formatted message', (t) => {
const config = getConfig();
const questionsList = questions(config);

t.is(questionsList[4].default({ message: 'message', type: 'type' }), 'type: message\n\n\n');
t.is(questionsList[questionsListOrder.editor].default({ message: 'message', type: 'type' }), 'type: message\n\n\n');
});

test('CONFIRM EDITOR | check if it shows if it has to', (t) => {
Expand Down

0 comments on commit f7e5b4a

Please sign in to comment.