-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Will lint between remotes/origin/master and HEAD. To lint between different commits use: ```sh $ aegir lint-commits --from $COMMITISH --to $COMMITISH ``` This should be set up as a pre-push or post-commit hook as regular linting runs pre-commit so the messages we want to examine won't be in the history yet..
- Loading branch information
1 parent
ec45fe9
commit a972f68
Showing
4 changed files
with
180 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
'use strict' | ||
|
||
module.exports = { | ||
command: 'lint-commits', | ||
desc: 'Lint commit messages', | ||
builder: { | ||
from: { | ||
alias: 'f', | ||
describe: 'The commit-ish to lint from', | ||
default: 'remotes/origin/master' | ||
}, | ||
to: { | ||
alias: 't', | ||
describe: 'The commit-ish to lint to', | ||
default: 'HEAD' | ||
} | ||
}, | ||
handler (argv) { | ||
const lintCommits = require('../src/lint-commits') | ||
const onError = require('../src/error-handler') | ||
lintCommits(argv).catch(onError) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
'use strict' | ||
|
||
const loadCommitLintConfig = require('@commitlint/load') | ||
const readCommits = require('@commitlint/read') | ||
const lintCommitMessage = require('@commitlint/lint') | ||
const conventionalCommits = require('@commitlint/config-conventional') | ||
|
||
function lintCommitMessages (opts = {}) { | ||
const from = opts.from || 'remotes/origin/master' | ||
const to = opts.to || 'HEAD' | ||
|
||
return Promise.all([ | ||
loadCommitLintConfig({ | ||
rules: conventionalCommits.rules | ||
}), | ||
readCommits({ | ||
from, | ||
to | ||
}) | ||
]) | ||
.then(([ { rules, parserPreset }, commits ]) => { | ||
return Promise.all( | ||
commits.map(commit => { | ||
return lintCommitMessage(commit, rules, parserPreset ? { parserOpts: parserPreset.parserOpts } : {}) | ||
}) | ||
) | ||
}) | ||
.then(results => { | ||
let valid = true | ||
|
||
results.forEach(report => { | ||
if (valid === true) { | ||
valid = report.valid | ||
} | ||
|
||
const firstLine = `${report.input.trim().split('\n')[0]}`.trim() | ||
|
||
if (!report.valid) { | ||
console.log(`Commit message '${firstLine}' failed validation:`) | ||
console.log('') | ||
|
||
report.errors.forEach(error => { | ||
console.log(' [ERROR]', `${error.name}:`, error.message) | ||
}) | ||
|
||
report.warnings.forEach(warning => { | ||
console.log(' [WARNING]', `${warning.name}:`, warning.message) | ||
}) | ||
|
||
console.log('') | ||
} | ||
}) | ||
|
||
if (!valid) { | ||
throw new Error(`Linting commits ${from}..${to} failed`) | ||
} | ||
}) | ||
} | ||
|
||
function lintCommits (opts) { | ||
return lintCommitMessages(opts) | ||
} | ||
|
||
module.exports = lintCommits |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* eslint-env mocha */ | ||
'use strict' | ||
|
||
const lintCommits = require('../src/lint-commits') | ||
const expect = require('chai').expect | ||
const path = require('path') | ||
const os = require('os') | ||
const fs = require('fs') | ||
const series = require('async/series') | ||
const child = require('child_process') | ||
|
||
function commitFile (directory, name, contents, message, callback) { | ||
series([ | ||
(cb) => fs.writeFile(path.join(directory, name), contents, cb), | ||
(cb) => child.exec('git add -A', { | ||
cwd: directory | ||
}, cb), | ||
(cb) => child.exec(`git commit -m "${message}"`, { | ||
cwd: directory | ||
}, cb) | ||
], callback) | ||
} | ||
|
||
// Sets up two directories, an origin to represent a remote git repository | ||
// and another to be the current project. | ||
const setupProject = (commitMessage = 'chore: initial commit') => { | ||
const tmpDir = path.join(os.tmpdir(), `test-${Math.random()}`) | ||
|
||
return new Promise((resolve, reject) => { | ||
series([ | ||
(cb) => fs.mkdir(tmpDir, cb), | ||
(cb) => child.exec('git init', { | ||
cwd: tmpDir | ||
}, cb), | ||
(cb) => child.exec('git config user.email "you@example.com"', { | ||
cwd: tmpDir | ||
}, cb), | ||
(cb) => child.exec('git config user.name "test"', { | ||
cwd: tmpDir | ||
}, cb), | ||
(cb) => commitFile(tmpDir, 'hello.txt', 'Amazing', 'chore: initial commit', cb), | ||
(cb) => commitFile(tmpDir, 'goodbye.txt', 'Amazing', commitMessage, cb) | ||
], (error) => { | ||
if (error) { | ||
return reject(error) | ||
} | ||
|
||
process.chdir(tmpDir) | ||
|
||
resolve() | ||
}) | ||
}) | ||
} | ||
|
||
const commitMessageShouldPassLinting = (commitMessage) => { | ||
return setupProject(commitMessage) | ||
.then(() => lintCommits({ | ||
from: 'HEAD~1' | ||
})) | ||
} | ||
|
||
const commitMessageShouldFailLinting = (commitMessage) => { | ||
return setupProject(commitMessage) | ||
.then(() => lintCommits({ | ||
from: 'HEAD~1' | ||
})) | ||
.then(() => { | ||
throw new Error('Should have failed!') | ||
}) | ||
.catch(error => { | ||
expect(error.message).to.contain('Linting commits HEAD~1..HEAD failed') | ||
}) | ||
} | ||
|
||
describe('lint commit messages', () => { | ||
const cwd = process.cwd() | ||
|
||
after(() => { | ||
process.chdir(cwd) | ||
}) | ||
|
||
it('passes with good commit messages', function () { | ||
return commitMessageShouldPassLinting('chore: such a chore') | ||
}) | ||
|
||
it('fails with bad commit messages', function () { | ||
return commitMessageShouldFailLinting('Ahahallolol!!!11shift+1') | ||
}) | ||
}) |