I am trying to setup an auto-versioning system where if I git commit
with the message PATCH: {message}
, the app's patch version will automatically update (and likewise for a prefix of MINOR
and MAJOR
as well). I am using Husky for my pre-commit
and pre-push
hook, so I am trying to get this working with a .husky/commit-msg
hook that looks like this:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run auto-version $1 && git add --all
This works as desired with my auto-version.js
script automatically reading the commit message and updating ./version.json
accordingly. The only problem is the commit is created with the old version.json
file and I'm unsure why. I can tell the git add
is functional because I am left with the updated version.json
file sitting in the Staged Changes
section after committing. My .husky/pre-commit
hook looks like such and stages updated files prior to committing just fine:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint && npm run format && git add --all
I think this could be related to the timing between when the commit-msg
hook is fired and when git
will accept newly staged files, but Husky doesn't provide great docs on how the commit-msg
hook functions. I also tried setting this up using the pre-commit
hook instead, but the new commit message does not get saved to .git/COMMIT_EDITMSG
at this stage (only the old commit message is present).
For some additional context, we are currently just firing npm version patch --no-git-tag-version
on the pre-commit
hook and then manually changing the minor and major versions when needed. I wanted to make a more robust and automatic system, which lead to this blocker.
auto-version.js
const { readFileSync, writeFileSync } = require('fs');
const versionJsonPath = './version.json';
const commitMessagePath = '.git/COMMIT_EDITMSG';
const prefixOptions = ['PATCH', 'MINOR', 'MAJOR'];
const postfixMinLength = 12;
(() => {
// read commit message
const rawMessage = readFileSync(commitMessagePath, 'utf-8');
const message = rawMessage.split(/\r?\n/)[0];
console.log(`Reading commit message "${message}"...`);
// check for merge commit
if (message.startsWith('Merge branch')) {
process.exit();
}
// check for core composition
const messageParts = message.split(':');
if (messageParts.length != 2) {
throwError(`Commit message should take the form "{${prefixOptions.join('|')}}: {message}".`);
}
// check for valid prefix
const messagePrefix = messageParts[0];
if (!prefixOptions.includes(messagePrefix)) {
throwError(`Commit message prefix must be one of the following version types: [${prefixOptions.join(', ')}].`);
}
// check for valid postfix
const messagePostfix = messageParts[1];
if (messagePostfix.trim().length < postfixMinLength) {
throwError(`Commit message postfix must be at least ${postfixMinLength} characters.`);
}
// update app version
const versionJson = JSON.parse(readFileSync(versionJsonPath, 'utf-8'));
const oldVersion = versionJson.appVersion;
const versionParts = oldVersion.split('.').map(v => parseInt(v, 10));
if (messagePrefix == 'MAJOR') {
versionParts[0] ;
versionParts[1] = 0;
versionParts[2] = 0;
} else if (messagePrefix == 'MINOR') {
versionParts[1] ;
versionParts[2] = 0;
} else {
versionParts[2] ;
}
const newVersion = versionParts.join('.');
versionJson.appVersion = newVersion;
console.log(`Updating app version from ${oldVersion} to ${newVersion}...`);
writeFileSync(versionJsonPath, JSON.stringify(versionJson));
process.exit();
})();
function throwError(message) {
console.error(message);
process.exit(1);
}
version.json
{
"appVersion": "0.12.15"
}
CodePudding user response:
Looking at another post (Git hook commit-msg git add file), it seems that doing git add
is not possible during/after the commit-msg
hook stage. Based on one of the answers there, I solved the problem by using a post-commit
hook to amend the commit to include the updated version.json
file with git commit --amend -C HEAD -n version.json
.
.husky/post-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run auto-version-post-commit
The post-commit
script ensures there is a version.json
file to add to prevent infinite git hook recursion:
var exec = require('child_process').exec;
const versionJsonPath = 'version.json';
(() => {
exec('git diff --name-only', (error, stdout, stderr) => {
const modifiedFiles = stdout.trim().split(/\r?\n/);
// check if version.json has been modified by commit-msg hook
if (modifiedFiles.includes(versionJsonPath)) {
// amend the last commit to include the updated version.json
exec(`git commit --amend -C HEAD -n ${versionJsonPath}`);
}
});
})();