Table of Content
はじめに
Googleのバグ予測アルゴリズムというものがあります。
https://www.publickey1.jp/blog/11/post_193.html
簡単にいうと最近、数多くバグ修正したコードはバグが発生しやすいという考えになっています。
今回はnode.jsでそれを実装してみました。
事前準備
simple-gitをインストールします。
npm install --save simple-git
コード
以下のロジックではコミットログのメッセージにfixという文字が会ったらバグ修正をしたとみなしてます。
const simpleGit = require('simple-git')
const fs = require('fs')
function moveFile(path) {
moves = path.match(/(?<=\{)[\s\S]*?(?=\})/g)
if (!moves) return null
let before = path
let after = path
moves.map((move)=>{
const names = move.split(' => ')
before = before.replace(move, names[0])
after = after.replace(move, names[1])
})
return {
before: before.replace(/{|}/g, '').replace(/\/\//g, '/'),
after: after.replace(/{|}/g, '').replace(/\/\//g, '/')
}
}
function checkMessage(message) {
// TODO プロジェクトのルールに合わせてコミットログのメッセージを調整する
if (message.indexOf('fix') >=0) return true
return false
}
async function getCommitLog(repUrl, branch, workFolder) {
const result = {}
try {
if (fs.existsSync(workFolder)) {
fs.rmdirSync(workFolder, { recursive: true })
}
fs.mkdirSync(workFolder)
await simpleGit().clone(repUrl, workFolder, ['-b', branch])
const git = simpleGit(workFolder)
await git.log({'--stat': null, '--stat-width': 1024}, (err, logs) => {
//console.log(err, logs)
logs.all.reverse().map((log)=>{
//console.log(log.hash, log.date, log.message, log.author_name)
if (!log.diff) return
// コミットログのチェックして集計対象か調べる
const fixedLog = checkMessage(log.message)
log.diff.files.map((file)=>{
//console.log(' ', file)
let fileName = file.file
if (fileName.indexOf('=>') > 0) {
const moveResult = moveFile(fileName)
if (moveResult) {
fileName = moveResult.after
if (result[moveResult.before]) {
result[moveResult.after] = result[moveResult.before]
delete result[moveResult.before]
}
} else {
console.warn('unexpected filepath' , log.hash, fileName)
return
}
}
if (!result[fileName]) {
result[fileName] = {
file: fileName,
totalCount: 0,
createdDate: log.date,
fixCount: 0,
fixHistory: []
}
}
++result[fileName].totalCount
if (result[fileName].createdDate > log.date) {
result[fileName].createdDate = log.date
}
if (fixedLog) {
++result[fileName].fixCount
result[fileName].fixHistory.push(log.date)
}
})
})
})
return result
}
catch (e) {
console.log(e)
}
}
function collect(all) {
const files = []
const result = []
for (const key in all) {
if (all[key].fixCount > 0) {
files.push(all[key])
}
}
const baseDate = new Date()
files.map((file)=>{
//console.log(file.file)
const createdDate = new Date(file.createdDate)
const timeCreateToNow = baseDate-createdDate
let score = 0
file.fixHistory.map((history)=>{
const t = ((new Date(history))-createdDate) / timeCreateToNow
//console.log(file.createdDate, history, t)
score = score + (1/(1+Math.exp(-12*t+12)))
})
result.push([file.file, score])
})
result.sort((a,b)=>b[1]-a[1])
return result
}
async function main() {
const all = await getCommitLog('https://github.com/vuejs/vue.git', 'master', './work')
const result = collect(all)
console.log(result)
}
main()