195 lines
5.3 KiB
JavaScript
195 lines
5.3 KiB
JavaScript
var fs = require('fs')
|
|
var ini = require('ini')
|
|
var path = require('path')
|
|
var chalk = require('chalk')
|
|
var Git = require('git-tools')
|
|
|
|
var validate = require('./lib/validate')
|
|
var sanitize = require('./lib/sanitize')
|
|
var defaults = require('./lib/defaults')
|
|
|
|
// If there is a path in process.env.PATH that looks like this:
|
|
// path = prefix + suffix (where suffix is the function argument)
|
|
// then slice off the suffix and return the prefix, otherwise undefiend
|
|
function sliceEnvPath (suffix) {
|
|
var p = process.env.PATH.split(':').filter(
|
|
function (p) {return p.endsWith(suffix)}
|
|
)
|
|
|
|
if (p.length === 1) {
|
|
p = p[0].split(path.sep)
|
|
|
|
p = p.slice(0, p.length - suffix.split(path.sep).length)
|
|
return p.join(path.sep)
|
|
}
|
|
|
|
return undefined
|
|
}
|
|
|
|
// Need to find the path to the project that is installing or running
|
|
// commitplease. Previously, process.cwd() made the job easy but its
|
|
// output changed with node v8.1.2 (at least compared to 7.10.0)
|
|
function getProjectPath () {
|
|
// Rely on npm to inject some path into PATH; However, the injected
|
|
// path can both be relative or absolute, so add extra path.resolve()
|
|
|
|
// During npm install, npm will inject a path that ends with
|
|
// commitplease/node_modules/.bin into process.env.PATH
|
|
var p = sliceEnvPath(
|
|
path.join('node_modules', 'commitplease', 'node_modules', '.bin')
|
|
)
|
|
|
|
if (p !== undefined) {
|
|
return path.resolve(p)
|
|
}
|
|
|
|
// During npm run, npm will inject a path that ends with
|
|
// node_modules/.bin into process.env.PATH
|
|
p = sliceEnvPath(path.join('node_modules', '.bin'))
|
|
|
|
if (p !== undefined) {
|
|
return path.resolve(p)
|
|
}
|
|
|
|
// During git commit there will be no process.env.PATH modifications
|
|
// So, assume we are being run by git which will set process.cwd()
|
|
// to the root of the project as described in the manual:
|
|
// https://git-scm.com/docs/githooks/2.9.0
|
|
return path.resolve(process.cwd())
|
|
}
|
|
|
|
function getOptions () {
|
|
var projectPath = getProjectPath()
|
|
|
|
var pkg = path.join(projectPath, 'package.json')
|
|
var npm = path.join(projectPath, '.npmrc')
|
|
|
|
pkg = fs.existsSync(pkg) && require(pkg) || {}
|
|
npm = fs.existsSync(npm) && ini.parse(fs.readFileSync(npm, 'utf8')) || {}
|
|
|
|
pkg = pkg.commitplease || {}
|
|
npm = npm.commitplease || {}
|
|
|
|
var options = Object.assign(pkg, npm)
|
|
|
|
var base = {
|
|
'projectPath': projectPath,
|
|
'oldMessagePath': defaults.oldMessagePath,
|
|
'oldMessageSeconds': defaults.oldMessageSeconds
|
|
}
|
|
|
|
if (options === undefined ||
|
|
options.style === undefined ||
|
|
options.style === 'jquery') {
|
|
return Object.assign(base, defaults.jquery, options)
|
|
} else if (options.style === 'angular') {
|
|
return Object.assign(base, defaults.angular, options)
|
|
}
|
|
|
|
console.error(chalk.red(
|
|
'Style ' + options.style + ' is not recognised\n' +
|
|
'Did you mistype it in package.json?'
|
|
))
|
|
|
|
process.exit(1)
|
|
}
|
|
|
|
function runValidate (message, options) {
|
|
var errors = validate(sanitize(message), options)
|
|
|
|
if (errors.length) {
|
|
console.error('Invalid commit message, please fix:\n')
|
|
console.error(chalk.red('- ' + errors.join('\n- ')))
|
|
console.error()
|
|
console.error('Commit message was:')
|
|
console.error()
|
|
console.error(chalk.green(sanitize(message)))
|
|
|
|
console.error('\nSee ' + options.guidelinesUrl)
|
|
|
|
// save a poorly formatted message and reuse it at a later commit
|
|
fs.writeFileSync(defaults.oldMessagePath, message)
|
|
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
module.exports = function () {
|
|
var argv = process.argv.slice(2)
|
|
var help = argv.some(function (value) {
|
|
if (value === '-h' || value === '--help') {
|
|
return true
|
|
}
|
|
})
|
|
|
|
if (argv.length > 1 || help) {
|
|
console.log(
|
|
'Usage: commitplease [committish]\n\n' +
|
|
'committish a commit range passed to git log\n\n' +
|
|
'Examples:\n\n' +
|
|
'1. Check all commits on branch master:\n' +
|
|
'commitplease master\n\n' +
|
|
'2. Check all commits on branch feature but not on master:\n' +
|
|
'commitplease master..feature\n\n' +
|
|
'3. Check the latest 1 commit (n works too):\n' +
|
|
'commitplease -1\n\n' +
|
|
'4. Check all commits between 84991d and 2021ce\n' +
|
|
'commitplease 84991d..2021ce\n\n' +
|
|
'5. Check all commits starting with 84991d\n' +
|
|
'commitplease 84991d..\n\n' +
|
|
'Docs on git commit ranges: https://bit.ly/commit-range'
|
|
)
|
|
|
|
process.exit(0)
|
|
}
|
|
|
|
var options = getOptions()
|
|
var message = path.join('.git', 'COMMIT_EDITMSG')
|
|
|
|
if (path.normalize(argv[0]) === message) {
|
|
runValidate(fs.readFileSync(message, 'utf8').toString(), options)
|
|
|
|
process.exit(0)
|
|
}
|
|
|
|
var committish = 'HEAD'
|
|
if (argv.length !== 0) {
|
|
committish = argv[0]
|
|
}
|
|
|
|
var repo = new Git(process.cwd())
|
|
|
|
var secret = '--++== CoMMiTPLeaSe ==++--'
|
|
var format = '--format=%B' + secret
|
|
|
|
repo.exec('log', format, committish, function (error, messages) {
|
|
if (error) {
|
|
if (/Not a git repository/.test(error.message)) {
|
|
console.log(error.message)
|
|
|
|
process.exit(0)
|
|
}
|
|
|
|
if (/does not have any commits yet/.test(error.message)) {
|
|
console.log(error.message)
|
|
|
|
process.exit(0)
|
|
}
|
|
|
|
console.error(error)
|
|
|
|
process.exit(1)
|
|
}
|
|
|
|
messages = messages.trim().split(secret)
|
|
messages.pop()
|
|
|
|
for (var i = 0; i < messages.length; ++i) {
|
|
runValidate(messages[i], options)
|
|
}
|
|
})
|
|
}
|
|
|
|
module.exports.defaults = defaults
|
|
module.exports.getOptions = getOptions
|