@emanprague/cz-redmine-smart-commit
Version:
A commitizen adapter for Redmine smart commits
168 lines (149 loc) • 4.41 kB
JavaScript
const inquirer = require('inquirer');
const types = require('conventional-commit-types').types;
const map = require('lodash.map');
const longest = require('longest');
const rightPad = require('right-pad');
const branchName = require('current-git-branch');
// This can be any kind of SystemJS compatible module.
// We use Commonjs here, but ES6 or AMD would do just
// fine.
module.exports = {
prompter: prompter,
formatCommit: formatCommit,
branchParser: defaults,
};
// Generate proper choices
var length = longest(Object.keys(types)).length + 1;
var choices = map(types, function(type, key) {
return {
name: rightPad(key + ':', length) + ' ' + type.description,
value: key
};
});
function undefinedWhenEmpty(str) {
if (str && str.length > 0) {
return str;
} else {
return undefined;
}
}
// Return default values from current branch name.
function defaults(branch) {
let defaultType = undefined;
let defaultIssue = undefined;
let defaultMessage = undefined;
const slashIndex = branch.indexOf("/");
if (slashIndex >= 0) {
defaultType = branch.substr(0, slashIndex);
defaultIssue = branch.substr(slashIndex + 1);
// Parse "redmine" 203003 or "jira" JIRA-3040 like commits
// and generate message line.
const splitted = defaultIssue.split('-');
if (splitted.length >= 2) {
if (splitted[0].match(/^\d+$/)) { // Redmine issue just number
defaultMessage = defaultIssue.substr(splitted[0].length + 1);
defaultIssue = splitted[0];
} else if (splitted[0].match(/^[a-zA-Z]+$/) && splitted[1].match(/^\d+$/)) { // Jira issue number +
defaultMessage = defaultIssue.substr(splitted[0].length + splitted[1].length + 2)
defaultIssue = splitted[0] + "-" + splitted[1];
} else { // weird stuff
defaultMessage = defaultIssue;
defaultIssue = undefined;
}
} else {
// This should be feat/303200 (just redmine issue) check that
if (!defaultIssue.match(/^\d+$/)) {
defaultMessage = defaultIssue;
defaultIssue = undefined;
}
}
}
return [
undefinedWhenEmpty(defaultType),
undefinedWhenEmpty(defaultIssue),
undefinedWhenEmpty(defaultMessage)
];
}
// When a user runs `git cz`, prompter will
// be executed. We pass you cz, which currently
// is just an instance of inquirer.js. Using
// this you can ask questions and get answers.
//
// The commit callback should be executed when
// you're ready to send back a commit template
// to git.
//
// By default, we'll de-indent your commit
// template and will keep empty lines.
function prompter(cz, commit) {
const branch = branchName() || "";
const [
defaultType,
defaultIssue,
defaultMessage
] = defaults(branch);
// Let's ask some questions of the user
// so that we can populate our commit
// template.
//
// See inquirer.js docs for specifics.
// You can also opt to use another input
// collection library if you prefer.
inquirer.prompt([
{
type: 'list',
name: 'type',
message: "Select the type of change that you're committing:",
choices: choices,
default: defaultType,
},
{
type: 'input',
name: 'message',
message: 'Commit message (required):\n',
default: defaultMessage,
validate: function(input) {
if (!input) {
return 'empty commit message';
} else {
return true;
}
}
},
{
type: 'checkbox',
name: 'target',
message: 'FE/BE/CI (optional):\n',
choices: [
'BE', 'FE', 'CI',
],
},
{
type: 'input',
name: 'issues',
message: 'Redmine Issue ID(s) (optional):\n',
default: defaultIssue
},
{
type: 'input',
name: 'description',
message: 'Description (optional):\n'
},
]).then((answers) => {
formatCommit(commit, answers);
});
}
function formatCommit(commit, answers) {
let message = answers.type;
if (answers.issues) {
message += ` [${answers.issues}]`
}
if (answers.target && answers.target.length && answers.target.length > 0) {
message += ` ${answers.target.join(',')}`;
}
message += `: ${answers.message}`;
if (answers.description && answers.description.length && answers.description.length > 0) {
message += `\n\n${answers.description}`;
}
commit(message);
}