Search code examples
gittypescriptgulpgithookshusky

How can I bump the package.json version when I commit based on the commit message?


I am trying to bump the version of my package.json file when I commit, but only if the commit message is prefixed correctly: MJ prefix triggers a patch bump, ^ prefix triggers a minor bump. I wrote a gulp task to do this and it works, the only problem is that I can't get the message of the current commit, execute the task, then add package.json to the commit and continue.

I tried running my task on these two git hooks:

pre-commit

Problem:

  • I only have access the previous commit message in this hook, not the one we're doing right now.

What works

  • I can bump the version, but only based on the previous commit message
  • I can stage package.json
  • package.json can then be added to the commit along with the rest

prepare-commit-msg

Problem:

  • staging package.json does not add it to the commit

What works

  • I can bump the version based on the current commit message
  • I can stage package.json

This is my gulp task that I've tried with the two hooks. I removed some noise to try to keep it minimal.

import * as fs from "fs";
import gulp from "gulp";
import * as shell from "shelljs";
import pkg from "./package.json";

const getCommitMsg = () => fs.readFileSync(".git/COMMIT_EDITMSG", "utf8");
gulp.task(
    BUMP_VERSION.task,
        (done) => {

            const message = getCommitMsg();
            const isMinor = message.startsWith(MINOR_PREFIX);
            const isPatch = message.startsWith(PATCH_PREFIX);

            if (!isMinor && !isPatch) {
                done();
                return exit(EC.NOT_VERSION);
            }

            const newPatch = isPatch ? parseInt(patch) + 1 : 0;
            const newMinor = isMinor ? parseInt(minor) + 1 : minor;

            const newVersion = `${major}.${newMinor}.${newPatch}`;
            const newPkg = Object.assign({}, pkg, { version: newVersion }); // update version
            fs.writeFileSync("./package.json", JSON.stringify(newPkg, null, 4));

            shell.exec("git add ./package.json");

            done();
        },
);

Pretty much everything relies on the commit message, which is fetched using the getCommitMsg function. Maybe fs.readFileSync(".git/COMMIT_EDITMSG", "utf8"); isn't the way to go? Perhaps there is another command I could run (with shelljs) to get the current commit message in the pre-commit hook? Otherwise if I use the prepare-commit-msg hook, then I can get the correct message, but then how would I add it to the current commit along with the other staged files?


Solution

  • You can use the commit-msg hook to read the commit message, take actions based on that, stage files and commit

    .git/hooks/commit-msg

    COMMIT_MSG_FILE=$1
    
    node bump.js
    git add package.json
    git commit -m "`cat $COMMIT_MSG_FILE`" --no-verify
    false
    

    node bump.js will increment the version in package.json (similar to your gulp task)

    git add package.json will stage the modified file

    git commit -m "cat $COMMIT_MSG_FILE" --no-verify will commit the staged files but skipping the hooks (pre-commit and commit-msg)

    false will stop the original commit since we've already committed in the last line