Is it possible to use the Husky "commit-msg" hook to git add new files?

I am currently setting up an automatic versioning system where if I use git commit with the message format PATCH: {message}, the app's patch version will automatically be updated (and the same for the prefixes MINOR and MAJOR as well). My approach involves using Husky for my pre-commit and pre-push hooks. To achieve this, I have created 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 setup works as expected, with my auto-version.js script correctly reading the commit message and updating the ./version.json file accordingly. However, there is one issue - the commit is generated with the old version.json file and I'm unsure of the reason behind this. Although the git add command seems to work fine as the updated version.json file appears in the 'Staged Changes' section after the commit. On the other hand, my .husky/pre-commit hook functions properly and stages the updated files before committing:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint && npm run format && git add --all

I suspect that the problem might be related to the timing between when the commit-msg hook triggers and when git accepts newly staged files but Husky lacks detailed documentation on the functioning of the commit-msg hook. Additionally, I attempted to set this up using the pre-commit hook instead, but the new commit message does not get saved to

.git/COMMIT_EDITMSG</code at this stage (only the old commit message remains).</p>
<p>To provide more context, we are currently executing <code>npm version patch --no-git-tag-version
on the pre-commit hook and manually adjusting the minor and major versions when necessary. The goal was to establish a more reliable and automated system, which led me to face this hurdle.

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(`The 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(`The commit message postfix must consist of 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 the 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"
}

Answer №1

After reading through a different post (Git hook commit-msg git add file), it became clear that running git add is not feasible during or after the commit-msg hook stage. Taking advice from one of the responses, I resolved this issue by utilizing a post-commit hook to amend the commit and include the updated version.json file using

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 that there's a version.json file to add in order to avoid infinite recursion with git hooks:

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 altered by commit-msg hook
        if (modifiedFiles.includes(versionJsonPath)) {
            // amend the last commit to incorporate the updated version.json
            exec(`git commit --amend -C HEAD -n ${versionJsonPath}`);
        }
    });
})();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is jQuery's $.trim() function reliable or poorly implemented?

$.trim() utilizes a specific RegExp pattern to trim a string: /^(\s|\u00A0)+|(\s|\u00A0)+$/g However, this can lead to some issues, as demonstrated in the following example: var mystr = ' some test -- more text ...

After submitting the form, React checkboxes fail to reset their state

Being a relative newcomer to React, I embarked on creating a skincare app as a project to enhance my understanding. In designing the app, I incorporated a form for product registration which includes checkboxes. My current dilemma revolves around clearing ...

Element cannot be located following the addition of a className in the HTML document

When manually adding id, test-id or classname in an HTML file, it's important to note that Cypress may have trouble finding the element. For example, I have included 'Classname' here just for demonstration purposes. https://i.stack.imgur.co ...

Issue with Node.js: npm is failing to install now

I'm facing an issue while trying to install a module using npm as it keeps returning errors. Even when attempting to install the same module, like in this example: npm install socket.io The following error is shown: npm ERR! TypeError: Cannot call ...

Retrieve the past week's data based on names using JavaScript

Is there a way to dynamically fetch the past seven day names, starting from today, in JavaScript? I am looking to format the result as follows: (Wednesday, Tuesday, Monday, Sunday, Saturday, Friday, Thursday, Wednesday). ...

Having difficulty installing better-sqlite3 to enable the operation of Discord bot

My setup involves using a raspberry pi 4 with Visual Studio Code to run my bot. I encountered an issue where all packages installed except for better-sqlite3. I attempted re-installing node-gyp (which was successful) and then tried installing better-sqli ...

Issue encountered when attempting to install React modules

Attempted to install sass-loader, as well as node-sass using both yarn and npm; however, encountered identical errors. Various methods were tried: yarn add <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="057664767628696a646160 ...

Tips for managing encoding when transmitting values through ajax

When working in WordPress, I encountered an issue with an Ajax call where a value was being sent inaccurately. blow = \'blo\ Upon receiving the value on the server end, it appeared to have an extra backslash (\). blow = \\& ...

`There was an issue with an unfinished string literal.`

Currently, I am utilizing jQuery to display the information from a JSON string generated by PHP and extracted from a database. However, I have encountered an issue where some of the data spans multiple lines... How can I prevent this from triggering an un ...

What is the best way to create a TypeScript interface or type definition for my constant variable?

I'm facing challenges in defining an interface or type for my dataset, and encountering some errors. Here is the incorrect interfaces and code that I'm using: interface IVehicle { [key: number]: { model: string, year: number }; } interface IV ...

Having trouble with a malfunctioning part of the API in my NodeJS code. Any suggestions on how to resolve the issue

I'm currently working on developing a REST API in NodeJS for an online store. Here's a snippet of my code for handling POST requests: router.post('/', (req, res, next) => { const order = new Order({ _id: new mongoose.Typ ...

Steps for filling an HTML table within a dynamically loaded DIV

I have a container in my HTML page where I dynamically load other pages using the jQuery.load() function. One of the pages requires me to populate a table from the database just after/before it loads. How can I trigger a JavaScript function to execute righ ...

The behavior of JS Array.push may catch you off guard

There seems to be an issue with the push function in my code. The problem lies in the last line of code shown below. export enum non_searchFieldsNames { language = 'language', categories = 'categories', subtitle = 'subt ...

Encountering a console error: Prop type validation failed for the `Rating` component with the message that the prop `value` is required but is currently `undefined`

I am encountering a proptype error which is causing an issue with the URL display on my Chrome browser. Instead of showing a proper address, I am seeing the URL as undefined like this: http://localhost:3000/order/undefined Instead of undefined, I should h ...

The 'fetch' operation could not be completed on the current window due to a TypeError

The error message I am receiving is: TypeError: Failed to execute 'fetch' on 'Window' : The provided value is not of type '(sequence<sequence> or record<ByteString, ByteString>)'. My current challenge involves fetc ...

After clicking multiple times within the modal, the modal popup begins to shift towards the left side

I successfully implemented a modal popup in my project, but encountered an issue where the popup moves to the left side if clicked multiple times. Despite searching extensively online, I have not been able to find a solution to this problem. Below is the ...

JavaScript retrieve data from an external JavaScript file

How can I retrieve the id value from my rendering.js file? <script type="text/javascript" src="./js/rendering.js?id=3"> I am trying to access the id value in my rendering.js script. Any suggestions on how to accomplish this? ...

Reorganize the JSON data to match the specified format

{ "EUR": { "Description": "", "Bid": "1.1222", "Region": "", "Bid1": "1.1283", "CurrencyCode": "EUR", "FeedSource": "1", "Ask": "1.1226", "ProviderName": "TEST 1", "Low": "1.1195", ...

Make sure to allow the async task to complete before beginning with Angular JS

As I develop an app using MobileFirst v8 and Ionic v1.3.1, I encounter issues with timing in my code execution. Specifically, when the application initiates, the regular ionic angular code within my app.js file runs. This section of the code handles the i ...

Accessing a TypeScript variable in Angular2 and binding it to the HTML DOM

While I have experience with AngularJS, delving into Angular2 has proven to be a new challenge for me. Understanding the ropes is still a work in progress. In my list of files, there's a home.ts and a home.html Within my home.ts, this snippet reside ...