kkamegawa's weblog

Visual Studio,TFS,ALM,VSTS,DevOps関係のことについていろいろと書いていきます。Google Analyticsで解析を行っています

TFS版BufSpotsを実装した

グーグルのバグ予測アルゴリズムを実装したツール「bugspots」、オープンソースで公開 - Publickey
gitとsubversionだけで悔しいので、BugSpotsをTFSで実装してみました(結構しょうもないところで詰まったのは内緒だ)。ちょっと前にSQL Serverのビュー定義のことを書きましたが、少し変えています。TFS2010でしか確認していません。
一式動くプロジェクトが必要ならgithubか私のところかどこかにあげます。

USE [Tfs_DefaultCollection]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE VIEW [dbo].[My_BugSpots]
AS
SELECT TOP (100) PERCENT a.ItemId, a.CreationDate, b.ParentPath, b.ChildItem
FROM (SELECT dbo.tbl_Version.ItemId, dbo.tbl_ChangeSet.CreationDate
 FROM dbo.tbl_ChangeSet INNER JOIN
  dbo.tbl_Version ON dbo.tbl_ChangeSet.ChangeSetId = dbo.tbl_Version.VersionFrom
  WHERE (dbo.tbl_Version.Encoding >= 0)) AS a INNER JOIN
   dbo.tbl_VersionedItem AS b ON a.ItemId = b.ItemId
ORDER BY a.CreationDate
GO

これでdbo.My_BugSpotsというビューができるので、このビューをEntityFrameworkなどで参照してください。Primary Keyがないので参照しかできないといわれますが、更新しないので無視で。
C#側のソースです。コンソールプロジェクトです。WPFやらSilverlightやらでりっちにしてみてください。チェックインコメントは取っていませんが、まぁできると思います。

using System;
using System.Collections.Generic;
using System.Linq;

namespace BugSpotsConsole
{
  class Program
  {
    static void Main(string[] args)
    {
       var Spots = new Dictionary<string, List<DateTime>>();
       var tfsBugSportConnection = new Tfs_DefaultCollectionEntities(); 
       var results = tfsBugSportConnection.My_BugSpots.
           OrderBy(x => x.ParentPath).OrderBy(x => x.ChildItem).
           OrderBy(x => x.CreationDate);

       foreach(var result in results) {
         var fullpath = default(string);
         fullpath = result.ParentPath + 
           result.ChildItem.Substring(0, result.ChildItem.Length - 1);
           var currentSpot = Spots.Where(y => y.Key == fullpath);
           if (currentSpot.Count() == 0) {
             var DateList = new List<DateTime>() { result.CreationDate };
             Spots.Add(fullpath, DateList);
           } else {
             currentSpot.First().Value.Add(result.CreationDate);
           }
        }
        var Now = DateTime.Now;
        var ranking = new Dictionary<string, double>();
        foreach (var Spot in Spots) {
          var FirstCheckinTime = Spot.Value.Min();
          var SpotValue = default(double);
          Spot.Value.ForEach(y => {
            var t = 1.0 -
              ((double)(Now - y).Ticks / (double)(Now - FirstCheckinTime).Ticks);
              SpotValue += 1.0 / (1.0 + Math.Exp((-12.0 * t) + 12.0));
          });
          ranking.Add(Spot.Key, SpotValue);
        }

        var limits = ranking.OrderBy(x => x.Value);
        foreach (var limit in limits) {
          Console.WriteLine("File:{0} Rate:{1:F4}", limit.Key, limit.Value);
        }
      }
    }
}

実行するとこんな感じで値を出してくれます。