Automate Git commit + versioning + tag by npm node
Asked Answered
H

3

12

What I have been trying to get is, work with npm version to update the package.json and create a tag and then commit my changes. In this way, I will be able to have tags by version, auto versioning and commit with the info.

The problem I am having is, when I am using npm version, it's doing a tag + commit automatically and then it can not be done if you have previously some changes, So for me, it doesn't make sense to increase the version of your project, before to do the changes/implementation/fixes.

Then, another problem I was having is that I first increase the version as a 'patch', then I do some changes, I add all, I commit and then I publish, at the end, I have 2 commits, 1 because of the npm version patch, and the other one the good one.

I saw in the documentation here that there is a parameter that allow you to disable this auto tag + commit, but then I would really like to use a command in the console to be able to update the package console and get that version set up as a tag.

By another hand, not sure if this that I am saying it does make sense because as far as I know, when you create a tag, you can go back in your project to that point, So how I pretend to work like that if I am disabling the auto commit?

Finally, What I want to make clear is my goal, What I really want to reach is handle by node scripts a semi-automated script to be able to increase the version of the project, create a tag with the new version, add all changes, commit and push.

Note: I don't want to use gulp-git as I think there is a way to handle this without it.

Not sure if I was clear enough, if not, please ask and help me :)

Hildehildebrand answered 19/7, 2016 at 13:27 Comment(1)
Use release-it: npmjs.com/package/release-itPole
H
11

Ok guys, I got it! What I was looking for is to run a simple command and automate some boring tasks we have to do always in the same order for Git.

So, What I do here is, first I run this command:

$> npm run commit -- 'v.1.0.1: Fixes'

What it happens is that I firstly clean of folders/files and I dont need/want, then I run:

$> npm version patch -no-git-tag-version --force

That command increase my package.json version, not commit & not tag, So Then I add all changes as normal, then I commit my changes and after this, I create the tag with the tag:commit gulp task.

In the gulp task (attached bellow), I am getting the version of the package with require and treat it as a object.

"scripts": {
   "start": "gulp start",
   "initialize": "npm install & typings install",
   "clean": "gulp clean:folders",
   "commit:example": "echo 'npm run commit -- 'v.1.0.1: Fixes'",
   "commit:patch": "npm version patch --no-git-tag-version --force",
   "commit:minor": "npm version minor --no-git-tag-version --force",
   "commit:major": "npm version major --no-git-tag-version --force",
   "precommit": "npm run clean && npm run commit:patch && git add --all",
   "postcommit": "gulp tag:commit && git push origin master && git status && gulp commit:done",
   "commit": "git commit -m "
},

and then, I have this in my gulp file:

///// ***** GIT ***** /////


gulp.task('tag:commit', function () {
    var version = pjson.version;
    console.log(colors.bgWhite.black.bold(' \nTagging the version ' + version + ' \n'));
    return run('git tag ' + version).exec();
});

I didn't want to use gulp-git as I knew there was a way to do that, If I need to merge, create brunch or whatever, I will run the console and fix it, but for daily commits, it's painful to remember to tag, update the package version, put it in the git commit....

I hope that's useful for someone else!

Cheers,

Hildehildebrand answered 20/7, 2016 at 14:43 Comment(1)
Found this particularly helpful as I'm working on a capacitor/electron project with one package.json for the repo, and one for the electron project subfolder -- keeping the two in sync is a pita.Spann
S
8

How about just one npm script called commit added to the package.json :

"scripts": {
    ...
    "commit": "node commit"
    ...
},

Used like so:

$> npm run commit patch "Your commit message goes here"

Where patch can be replaced by minor or major, depending on what version bump you want/need.

The ./commit.js script content looks like this:

#!/usr/bin/env node
'use strict';

const util = require('util');
const exec = util.promisify(require('child_process').exec);
const spawn = require('child_process').spawnSync;

async function version(versionType) {
    const { stdout, stderr } = await exec(`npm version ${versionType} --no-git-tag-version --force`);
    if (stderr) throw stderr;
    return stdout;
}

async function branch() {
  const { stdout, stderr } = await exec(`git rev-parse --abbrev-ref HEAD`);
  if (stderr) throw stderr;
  return stdout;
}

const run = async () => {
  try {
    const versionType = process.argv[2];
    const gitMessage = process.argv[3];

    if (versionType !== 'patch' && versionType !== 'minor' && versionType !== 'major') throw new Error('You need to specify npm version! [patch|minor|major]');
    if (!gitMessage) throw new Error('You need to provide a git commit message!');

    const npmVersion = await version(versionType);
    await spawn('git', ['add', 'package.json', 'package-lock.json'], { stdio: 'inherit' });
    await spawn('git', ['commit', '-m', gitMessage.trim()], { stdio: 'inherit' });
    await spawn('git', ['tag', npmVersion.trim()], { stdio: 'inherit' });
    await spawn('git', ['status'], { stdio: 'inherit' });
    const currentBranch = await branch();
    await spawn('git', ['push', 'origin', currentBranch.trim()], { stdio: 'inherit' });

  } catch (err) {
    console.log('Something went wrong:');
    console.error(err.message);
    console.error('\nPlease use this format: \nnpm run commit [patch|minor|major] "Commit message"');
  }
};

run();

Please note that I didn't add git add --all since I prefer to be more selective with my commits, however the format of this script should be easy enough for anyone to grok and expand upon. Alas I do have git add package.json so each execution of this script will bump the version of the package.json/package-lock.json and commit these files at minimum. My strategy would be to perform git add prior executing the higher mentioned command.

Another thing to consider here is that this script is fully compatible with husky hooks, specifically pre-commit which in my case drives lint-staged coupled to eslint and prettier. This way everything is nicely automated, slim, and standardized.

I hope this helps someone, Cheers!

Sirreverence answered 8/1, 2020 at 21:1 Comment(4)
I'm trying to use this, but it seems that I'm getting an undefined value: "npm run commit major "update" > [email protected] commit > node commit "major" "update" Something went wrong: undefined Please use this format: npm run commit [patch|minor|major] "Commit message""Deutzia
I'm currently trying to use this but it seems that I'm just getting an undefined value. Do we have to install any npm dependency or libary or what could be missing?Deutzia
Which node version are you using? As the script is using async/await, you'll need at least node v7.6 to use itSirreverence
I'm using node 14Deutzia
K
1

Simplest thing I can think of is to create the git tags at a later moment in time. In that case the repository log and the commit specific version of the package.json will be the source of truth.

Here is a quick script that creates the git tags by iterating over your commits. I use this to keep the npm versions and my git version tags in sync.

  git tag --list 'v*' | xargs -r git tag -d

  local version

  git rev-list --reverse "${1:-$BRANCH}" | while read -r commit; do
    {
      git show "$commit:package.json" | jq -e .version &> /dev/null || continue
      version="$(git show "$commit:package.json" | jq -er .version)"
      echo -n "version $version: commit: $commit: "
      git tag "v$version" "$commit" || continue
      echo "created: tag '$version' (was ${commit:0:6})"
    } 1>&2 || continue
    echo "v$version"
  done | xargs -r git push origin -f

This does create a few tag already exists warnings but you can ignore those.

We use --reverse because e want the first commit with that specific version to be tagged. In that case more commits can be added with the same version in a more consistent manner.

Once the tags are created you still have to push them to the remote.

To make the npm packs cleaner, I use another script which clones the local repo and performs a publish withing a specific branch. This prevents packing undesired files. See git-npm repo's git-npm publish

Repository: https://github.com/bas080/git-npm

Kermit answered 30/9, 2021 at 16:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.