Last active
November 5, 2019 21:00
-
-
Save austil/a69e006a37404a527c7b5cdf25d582a9 to your computer and use it in GitHub Desktop.
Commit count by tag & author per week in CSV
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
year | week | feat | fix | docs | style | refactor | test | chore | Dev 1 | Dev 2 | Dev 3 | Dev 4 | Dev 5 | Dev 6 | Dev 7 | Dev 8 | Dev 9 | Dev 10 | Dev 11 | Dev 12 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2016 | 43 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |
2016 | 44 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | |
2016 | 45 | 0 | 0 | 0 | 0 | 1 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | |
2016 | 51 | 2 | 0 | 0 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | |
2016 | 52 | 5 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | |
2016 | 53 | 0 | 1 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | |
2017 | 1 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | |
2017 | 2 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | |
2017 | 3 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | |
2017 | 4 | 4 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 0 | 0 | 0 | |
2017 | 5 | 6 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 10 | 0 | 0 | 0 | |
2017 | 6 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 2 | |
2017 | 7 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | |
2017 | 8 | 1 | 2 | 0 | 0 | 1 | 1 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | |
2017 | 11 | 1 | 1 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | |
2017 | 15 | 4 | 1 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | |
2017 | 16 | 0 | 2 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | |
2017 | 18 | 3 | 2 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 0 | 0 | 0 | |
2017 | 19 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | |
2017 | 20 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | |
2017 | 22 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | |
2017 | 23 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |
2017 | 24 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |
2017 | 25 | 2 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | |
2017 | 26 | 1 | 1 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 3 | 0 | |
2017 | 27 | 0 | 3 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 1 | 0 | 0 | |
2017 | 28 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | |
2017 | 29 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | |
2017 | 30 | 0 | 0 | 0 | 0 | 1 | 3 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | |
2017 | 31 | 2 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | |
2017 | 36 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2017 | 38 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |
2017 | 40 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |
2017 | 41 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |
2017 | 43 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | |
2017 | 51 | 3 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | |
2017 | 52 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | |
2018 | 3 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 4 | 0 | 1 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 26 | 0 | 0 | 0 | 0 | 26 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 10 | 0 | 0 | 0 | 0 | 0 | 0 | 15 | 0 | 0 | 0 | 0 | 15 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 11 | 1 | 0 | 0 | 0 | 0 | 0 | 15 | 0 | 0 | 0 | 0 | 15 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 12 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 14 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 15 | 0 | 2 | 0 | 0 | 11 | 3 | 11 | 0 | 0 | 0 | 0 | 25 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 16 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 17 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 23 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 24 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 26 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 27 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 28 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 29 | 0 | 6 | 0 | 0 | 0 | 0 | 4 | 8 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 31 | 0 | 5 | 0 | 0 | 0 | 0 | 2 | 3 | 0 | 1 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 40 | 1 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 41 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 49 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2018 | 51 | 0 | 3 | 0 | 0 | 0 | 0 | 1 | 3 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2019 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2019 | 6 | 0 | 10 | 0 | 0 | 0 | 0 | 1 | 11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2019 | 7 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
2019 | 9 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
year | week | feat | fix | docs | style | refactor | test | chore | Dev 1 | Dev 2 | Dev 3 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2017 | 47 | 13 | 1 | 0 | 0 | 3 | 0 | 0 | 0 | 17 | 0 | |
2017 | 48 | 6 | 1 | 0 | 0 | 4 | 0 | 1 | 1 | 11 | 0 | |
2017 | 49 | 2 | 0 | 3 | 1 | 4 | 0 | 0 | 4 | 6 | 0 | |
2017 | 50 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 0 | 6 | 0 | |
2017 | 51 | 3 | 2 | 0 | 0 | 2 | 0 | 0 | 1 | 6 | 0 | |
2017 | 52 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 3 | 0 | |
2018 | 1 | 2 | 0 | 0 | 1 | 4 | 0 | 4 | 6 | 5 | 0 | |
2018 | 3 | 2 | 0 | 0 | 2 | 0 | 0 | 1 | 5 | 0 | 0 | |
2018 | 4 | 2 | 1 | 0 | 0 | 0 | 0 | 2 | 1 | 0 | 4 | |
2018 | 7 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | |
2018 | 8 | 7 | 7 | 0 | 1 | 1 | 0 | 12 | 8 | 16 | 4 | |
2018 | 9 | 1 | 3 | 1 | 0 | 2 | 0 | 16 | 2 | 21 | 0 | |
2018 | 10 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 3 | 0 | |
2018 | 11 | 0 | 6 | 1 | 0 | 0 | 1 | 1 | 0 | 9 | 0 | |
2018 | 12 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 3 | 0 | |
2018 | 13 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | |
2018 | 16 | 3 | 0 | 0 | 0 | 1 | 0 | 1 | 4 | 0 | 1 | |
2018 | 19 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | |
2018 | 20 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | |
2018 | 21 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | |
2018 | 23 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 2 | 1 | |
2018 | 24 | 3 | 3 | 0 | 0 | 0 | 1 | 1 | 0 | 3 | 5 | |
2018 | 25 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |
2018 | 41 | 1 | 0 | 0 | 0 | 0 | 0 | 2 | 3 | 0 | 0 | |
2018 | 42 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |
2018 | 50 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | |
2018 | 51 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | |
2019 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | |
2019 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 3 | 0 | 0 | |
2019 | 14 | 1 | 1 | 0 | 0 | 5 | 0 | 6 | 6 | 7 | 0 | |
2019 | 18 | 0 | 0 | 0 | 1 | 0 | 0 | 3 | 4 | 0 | 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Summarize a git repos logs as a CSV file. | |
* This script was made for a viz, you can find it at | |
* https://observablehq.com/@austil/project-summary-git-commit-by-type-per-week | |
* | |
* First : export your log in a file using `git log --pretty=format:"%h%x09%an%x09%ad%x09%s" > git-log.txt` | |
* Then process it with this script `node gitLogSummary.js git-log.txt` | |
* and save it in a csv : `node gitLogSummary.js git-log.txt --csvOnly > git-log.csv` | |
*/ | |
// TWEAK THIS TO YOUR NEEDS | |
const COMMIT_TAGS = ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore']; | |
const COMMIT_TAG_REGEX = /^\w*(?=(:|\())/; | |
const RENAMED_AUTHORS = { | |
'Dev X': 'Others', | |
'Dev Y': 'Others', | |
'austil': 'alacour' | |
}; | |
const IGNORED_AUTHORS = ['alacour']; | |
// Thx to https://stackoverflow.com/a/19910622 | |
const getWeek = (date) => { | |
var onejan = new Date(date.getFullYear(),0,1); | |
var millisecsInDay = 86400000; | |
return Math.ceil((((date - onejan) /millisecsInDay) + onejan.getDay()+1)/7); | |
}; | |
const flatten = (arr) => [].concat(...arr); | |
// Let's start | |
const fs = require('fs'); | |
const [ , , logFile, flag] = process.argv; | |
const humanLog = msg => { | |
if(flag !== '--csvOnly') { | |
console.log(msg); | |
} | |
}; | |
let gitLogs = fs.readFileSync(logFile, 'utf8') | |
.split('\n') | |
.map(l => { | |
const log = l.split('\t'); | |
return { | |
'author': RENAMED_AUTHORS[log[1]] || log[1], | |
'date': new Date(log[2]), | |
'msg': log[3] | |
}; | |
}); | |
humanLog(`raw log : ${gitLogs.length} commits`); | |
gitLogs = gitLogs.filter(log => log.msg.match(/(^Merge|^Revert)/) === null); | |
humanLog(`after removing merge/revert : ${gitLogs.length} commits`); | |
gitLogs = gitLogs.filter(log => { | |
const tag = log.msg.match(COMMIT_TAG_REGEX); | |
return tag !== null && COMMIT_TAGS.includes(tag[0]); | |
}); | |
humanLog(`after removing missing tags : ${gitLogs.length} commits`); | |
gitLogs = gitLogs.filter(log => !IGNORED_AUTHORS.includes(log.author)); | |
humanLog(`after removing ignored authors : ${gitLogs.length} commits`); | |
const authors = Array.from(new Set(gitLogs.map(l => l.author))); | |
humanLog(`remaining : ${gitLogs.length} commits from ${authors.length} authors`); | |
const logsSummary = gitLogs | |
.map(log => ({ | |
'week': getWeek(log.date), | |
'year': log.date.getFullYear(), | |
'type': log.msg.match(COMMIT_TAG_REGEX)[0], | |
'author': log.author | |
})) | |
.reverse() // Commit are from younger to older, reverse it | |
.reduce((nest, log) => { | |
// Count by week and year | |
if(!nest[log.year]) nest[log.year] = {}; | |
if(!nest[log.year][log.week]) nest[log.year][log.week] = {}; | |
// for each tag | |
if(!nest[log.year][log.week][log.type]) { | |
nest[log.year][log.week][log.type] = 1; | |
} else { | |
nest[log.year][log.week][log.type] += 1; | |
} | |
// for each author | |
if(!nest[log.year][log.week][log.author]) { | |
nest[log.year][log.week][log.author] = 1; | |
} else { | |
nest[log.year][log.week][log.author] += 1; | |
} | |
return nest; | |
}, {}); | |
const csvLogs = flatten(Object.entries(logsSummary) | |
.map(([year, val]) => Object.entries(val) | |
.map(([week, counts]) => [ | |
year, | |
week, | |
...COMMIT_TAGS.map(t => counts[t] || 0), | |
...authors.map(a => counts[a] || 0), | |
].join(',')) | |
) | |
).join('\n'); | |
const csvHeader = ['year', 'week', ...COMMIT_TAGS, ...authors].join(','); | |
humanLog('\n===== Commit count by tag & author per week =====\n'); | |
console.log(csvHeader); | |
console.log(csvLogs); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ATM contributors spamming commits will appear as more active than the others.
Maybe parse the
--shortstat
output to compute a "change delta" to be used instead of the count of commit.