-
Notifications
You must be signed in to change notification settings - Fork 17
/
index.js
194 lines (151 loc) · 5.33 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
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