- scripts/normalize-commit-msg.js: capitalizes subject, strips trailing period, trims whitespace, warns when subject > 72 chars - scripts/commit-msg: shell wrapper symlinked into .git/hooks/commit-msg - scripts/install-hooks.sh: contributor setup script (sh scripts/install-hooks.sh) - scripts/package.json: test runner + hooks:install npm script - scripts/__tests__/normalize-commit-msg.test.js: 15 unit tests Nightshift-Task: commit-normalize Nightshift-Ref: https://github.com/marcus/nightshift
96 lines
2.4 KiB
JavaScript
Executable File
96 lines
2.4 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
/**
|
|
* normalize-commit-msg.js
|
|
*
|
|
* Git commit-msg hook: reads the commit message file, applies normalization
|
|
* rules to the subject line, rewrites the file in place.
|
|
*
|
|
* Rules:
|
|
* 1. Trim leading/trailing whitespace from the subject line
|
|
* 2. Capitalize the first letter of the subject
|
|
* 3. Strip a trailing period from the subject
|
|
* 4. Warn (but do not block) if the subject exceeds 72 characters
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const fs = require('fs');
|
|
|
|
const MAX_SUBJECT_LEN = 72;
|
|
|
|
/**
|
|
* Normalize the subject line of a commit message.
|
|
* Returns { subject, warned } where warned is true if a length warning was emitted.
|
|
*
|
|
* @param {string} subject
|
|
* @returns {{ subject: string, warned: boolean }}
|
|
*/
|
|
function normalizeSubject(subject) {
|
|
let s = subject.trimEnd();
|
|
|
|
// Trim leading whitespace
|
|
s = s.trimStart();
|
|
|
|
// Capitalize first letter
|
|
if (s.length > 0) {
|
|
s = s[0].toUpperCase() + s.slice(1);
|
|
}
|
|
|
|
// Strip trailing period
|
|
if (s.endsWith('.')) {
|
|
s = s.slice(0, -1);
|
|
}
|
|
|
|
const warned = s.length > MAX_SUBJECT_LEN;
|
|
|
|
return { subject: s, warned };
|
|
}
|
|
|
|
/**
|
|
* Normalize a full commit message string.
|
|
* Only the subject line (first non-empty, non-comment line) is modified.
|
|
*
|
|
* @param {string} message
|
|
* @returns {{ message: string, warned: boolean }}
|
|
*/
|
|
function normalizeMessage(message) {
|
|
const lines = message.split('\n');
|
|
let warned = false;
|
|
|
|
// Find the subject line (first non-comment line)
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const line = lines[i];
|
|
if (!line.startsWith('#')) {
|
|
const result = normalizeSubject(line);
|
|
lines[i] = result.subject;
|
|
warned = result.warned;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return { message: lines.join('\n'), warned };
|
|
}
|
|
|
|
// Only run as a hook when invoked directly (not when required in tests)
|
|
if (require.main === module) {
|
|
const msgFile = process.argv[2];
|
|
if (!msgFile) {
|
|
process.stderr.write('commit-msg hook: no message file argument\n');
|
|
process.exit(1);
|
|
}
|
|
|
|
const original = fs.readFileSync(msgFile, 'utf8');
|
|
const { message, warned } = normalizeMessage(original);
|
|
|
|
if (warned) {
|
|
process.stderr.write(
|
|
`commit-msg warning: subject line exceeds ${MAX_SUBJECT_LEN} characters — consider shortening it.\n`
|
|
);
|
|
}
|
|
|
|
fs.writeFileSync(msgFile, message, 'utf8');
|
|
process.exit(0);
|
|
}
|
|
|
|
module.exports = { normalizeSubject, normalizeMessage };
|