Skip to content

Instantly share code, notes, and snippets.

@sergey-shpak
Last active October 23, 2019 18:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sergey-shpak/40fe8d2534c5e5941b9db9e28132ca0b to your computer and use it in GitHub Desktop.
Save sergey-shpak/40fe8d2534c5e5941b9db9e28132ca0b to your computer and use it in GitHub Desktop.
Git log to json (git changelog nodejs)
const { exec } = require('child_process');
// Compile 'git log' command
const command = params =>
`git log --pretty=format:"
${params.join(command.format.param)}
${command.format.line}"`;
const hash = 451436388.16325235; //Math.random()*10e8;
command.format = {
line: hash.toString(36),
param: +hash.toString(36),
};
module.exports = (schema, post = (k,v) => v) =>
new Promise((resolve, reject) => {
const keys = Object.keys(schema);
const params = keys.map(key => schema[key]);
// Execute coomand and parse result
exec(command(params), (err, stdout) => {
if(err) reject(err)
else resolve(stdout.split(command.format.line)
.filter(line => line.length)
.map(line => line.split(command.format.param)
.reduce((obj, value, idx) => {
const key = keys[idx];
obj[key] = post(key, value);
return obj;
}, {})
)
);
});
});

Git log to json

The idea is to get more flexible git log structure (json)

Implemetation (./git-log-to-json.js) is quite simple: Mapping requested parameters to git log command as pretty format placeholders

In this particular case I'm going to generate changelog based on commit messages grouped by tags(versions):

#!/usr/bin/env node
const log = require('./git-log-to-json');

const tagName = /tag\:\s*v([\d|\.]*[-\.][\w]*)\,?/g;
const isTagName = str => {
  const match = tagName.exec(str);
  return match && match[1];
}

const changelog = {};

// get log info with mapped properties to log format, 
// https://git-scm.com/docs/git-log#_pretty_formats
log({ tag: "%d", note: "%N", msg: "%s"},  

  // replace \r\n etc from value
  (key, value) => value.replace(/\s\s/g,''))
    .then( records => {

      let tag = changelog['HEAD'] = [];
      records.forEach(record => {
        const tagName = isTagName(record.tag);
        if(tagName) tag = changelog[tagName] = [];
        tag.push(record.msg);
      })

      console.log(changelog);
    });

and the result (from console.log(changelog)):

{
  "HEAD":[],
  "0.0.3":[
    "Commit message #6",
    "Commit message #5",
  ],
  "0.0.2":[
    "Commit message #4",
    "Commit message #3",
  ],
  "0.0.1":[
    "Commit message #2",
    "Commit message #1",
  ]
}

As you could mention there is nodejs hashbang "#!/usr/bin/env node", and now it is possible to run changelog generation from npm scripts: "changelog":"./changelog.js"

Also, why it is important to keep changelog I would recomend to use git notes --ref=changelog/features instead of commit messages to store changelog information

@hasparus
Copy link

Hi Sergey. I wanted to notice that command.format.param is NaN.

@sergey-shpak
Copy link
Author

@hasparus, thanks, I'll take a look if I have free time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment