UNPKG

git-show

Version:

runs git show <commit> and parses the results

235 lines (226 loc) 7.58 kB
var async=require('async'); var Git=require('git-wrapper2'), ss=require('simple-statistics'), Q=require('q'); function GitShow(options) { "use strict"; var debug=require('debug')('git:GitShow'), git=new Git(), gitExecPromise=Q.defer(); debug("showing commit %j", (options && options.commit) || "HEAD"); git.exec("show", [(options && options.commit) || "HEAD"], function results(err, show_out) { debug=require('debug')('git:GitShow:results'); debug("err %j out %j", err, show_out); if(err) { debug("err: %j", err); return gitExecPromise.reject(err); } if( show_out === undefined ) { return gitExecPromise.resolve(null); } //debug("show output: %s", show_out); var out=show_out.split('\n'), currentDiff, allDiffs=[], showPromise=Q.defer(), commit={ hash: undefined, author: undefined, date: undefined, message: undefined }; debug("out %j", out); async.eachSeries( out, function forEachLine(line, nextLine) { var commitMatch, authorMatch, dateMatch, mergeMatch, diffMatch; debug=require('debug')('git:GitShow:results:forEachLine'); debug("line %s", line); //debug("allDiffs %j", allDiffs); debug("commit %j %j", commit, currentDiff); commit.message=""; if( undefined===currentDiff ) { debug("looking for commit in %s", line); commitMatch=line.match(/^commit ([0123456789abcdef]+)/); if( commitMatch ) { commit.hash=commitMatch[1]; debug("setting hash %s", commit.hash); return nextLine(); } debug("looking for merge"); mergeMatch=line.match(/Merge: ([^ ]+) ([^ ]+)^/); if(mergeMatch) { debug("setting merge"); commits.merge={ a: mergeMatch[1], b: mergeMatch[2] }; return nextLine(); } debug("looking for author"); authorMatch=line.match(/Author: ([^ ]+) <([^>]+)>/); if( authorMatch ) { debug("setting author %s", line); commit.author={ name: authorMatch[1], email: authorMatch[2] }; return nextLine(); } debug("looking for date"); dateMatch=line.match(/Date:\s+(.+)$/); if( dateMatch ) { debug("setting date"); commit.date=dateMatch[1]; return nextLine(); } debug("looking for blank line"); if(line.match(/^$/)) { if(commit.message) { debug("adding blank line"); commit.message+="\n"; return nextLine(); } } debug("looking for new diff"); diffMatch=line.match(/^diff --git a\/([^ ]+) b\/(.+)/); if(diffMatch) { debug("new diff %s %s", diffMatch[1], diffMatch[2]); currentDiff={ linesAdded: 0, linesDeleted: 0, deltas: 0, fileOne: diffMatch[1], fileTwo: diffMatch[2] }; return nextLine(); } debug("setting message"); commit.message+=line; return nextLine(); } debug("currentDiff %j", currentDiff); //look for new file line debug("looking for new file"); var newFileLineMatch=line.match(/new file mode ([a-zA-Z0-9]{6})/); if( newFileLineMatch ){ return nextLine(); } //look for index line var indexLineMatch=line.match(/^index ([a-zA-Z0-9]+)\.\.([a-zA-Z0-9]+) ([0-7]{6})/), plusLine, minusLine, newDiffMatch; debug("looking for index"); if( indexLineMatch ) { debug("index line: %s %s %s", indexLineMatch[1], indexLineMatch[2], indexLineMatch[3]); currentDiff.startingHash=indexLineMatch[1]; currentDiff.endingHash=indexLineMatch[2]; currentDiff.mode=indexLineMatch[3]; return nextLine(); } //look for +++ line in a plusLine=line.match(/^\+{3} a\/.+/); debug("looking for +++"); if( plusLine ) { debug("+++"); return nextLine(); } //look for +++ line in b plusLine=line.match(/^\+{3} b\/.+/); debug("looking for +++"); if( plusLine ) { debug("+++"); return nextLine(); } //look for --- line in a minusLine=line.match(/^-{3} a\/.+/); debug("looking for ---"); if( minusLine ) { debug("---"); return nextLine(); } //look for --- line in b minusLine=line.match(/^-{3} b\/.+/); debug("looking for ---"); if( minusLine ) { debug("---"); return nextLine(); } debug("look for @@ line in %s", line); if( line.match(/^@@.+@@$/) ) { debug("@@"); return nextLine(); } //look for the line debug("looking for + or - in %s", line); if(line.match(/^-/)) { currentDiff.linesDeleted++; debug("one more line deleted %d", currentDiff.linesDeleted); } if(line.match(/^\+/)) { currentDiff.linesAdded++; debug("one more line added %d", currentDiff.linesAdded); } newDiffMatch=line.match(/^diff --git a\/([^ ]+) b\/(.+)/); debug("looking for new diff in %s", line); if(newDiffMatch) { currentDiff.deltas=currentDiff.linesAdded-currentDiff.linesDeleted; allDiffs.push(currentDiff); currentDiff={ linesAdded: 0, linesDeleted: 0, deltas: 0, fileOne: newDiffMatch[1], fileTwo: newDiffMatch[2] }; return nextLine(); } nextLine(); }, function afterEveryLineIsProcessed(err) { //add the last diff if( currentDiff ) { currentDiff.deltas=currentDiff.linesAdded-currentDiff.linesDeleted; allDiffs.push(currentDiff); } debug=require('debug')('git:GitShow:results:afterEveryLineIsProcessed'); debug("allDiffs %j", allDiffs); var numDiffs=allDiffs.length, allDeltas=[], allAdditions=[], allDeletions=[], totalLinesChanged=0, averageLinesChanged=0, varianceLinesChanged=0, standardDeviationLinesChanged=0, averageLinesAdded=0, varianceLinesAdded=0, standardDeviationLinesAdded=0, averageLinesDeleted=0, varianceLinesDeleted=0, standardDeviationLinesDeleted=0; debug("all lines processed"); async.each( allDiffs, function eachDiff(d, done) { debug=require('debug')('git:GitShow:results:afterEveryLineIsProcessed:eachDiff'); debug("adding diff %d", d.deltas); totalLinesChanged+=d.deltas; allDeltas.push(d.deltas); allAdditions.push(d.linesAdded); allDeletions.push(d.linesDeleted); done(); }, function afterTotalLinesCalculated(err) { debug=require('debug')('git:GitShow:results:afterEveryLineIsProcessed:afterTotalLinesCalculated'); if(err) { debug("err: %j", err); return gitExecPromise.reject(err); } averageLinesChanged=ss.mean(allDeltas); varianceLinesChanged=ss.variance(allDeltas); standardDeviationLinesChanged=ss.standard_deviation(allDeltas); averageLinesAdded=ss.mean(allAdditions); varianceLinesAdded=ss.variance(allAdditions); standardDeviationLinesAdded=ss.standard_deviation(allAdditions); averageLinesDeleted=ss.mean(allDeletions); varianceLinesDeleted=ss.variance(allDeletions); standardDeviationLinesDeleted=ss.standard_deviation(allDeletions); debug("resolving promise %j %d %d %d", allDeltas, averageLinesChanged, varianceLinesChanged, standardDeviationLinesChanged ); gitExecPromise.resolve({ averageLinesChanged: averageLinesChanged || 0, varianceLinesChanged: varianceLinesChanged || 0, standardDeviationLinesChanged: standardDeviationLinesChanged || 0, averageLinesAdded: averageLinesAdded || 0, varianceLinesAdded: varianceLinesAdded || 0, standardDeviationLinesAdded: standardDeviationLinesAdded || 0, averageLinesDeleted: averageLinesDeleted || 0, varianceLinesDeleted: varianceLinesDeleted || 0, standardDeviationLinesDeleted: standardDeviationLinesDeleted || 0, diffs: allDiffs }); }); }); }); return gitExecPromise.promise; } module.exports=GitShow;