從Svn Commit資料中統計Web專案數、異動檔案數、修改次數等資料

  • 2953
  • 0
  • 2013-09-11

從Svn Commit資料中統計Web專案數、異動檔案數、修改次數等資料

DotBlogs Tags: , ,

總是會有一些奇妙的需求找上門。這次要完成的需求是,從 Svn 的 Commit 記錄中,統計 Web專案數、異動檔案數、修改次數。本次程式同樣透過 LINQPad 的 C# Program 模式完成。

第一步,要知道怎麼取得 Svn 的 Commit 資料,而且要變成可以透過程式查詢的格式,所以透過 TortoiseSVN 我想是沒機會了,直接到命令列去執行還有點可能:

svn help log

當然列出一堆參數,快速看一下,馬上找到關鍵字:

--xml                    : output in XML

嘿,有 XML 格式就太棒了,馬上執行匯出,然後看一下 XML 會是啥樣子:

svn log https://xxx.com.tw/svn/trunk/Code/GoGo_LeoTodo -r1024:6000 -v --xml >> d:\temp\svnlog.xml

上面的指令是說,匯出版號1024~6000(-r:1024:6000)之間的所有 log 詳細資料(-v),並以 XML 格式呈現(—xml),透過 「>>」  把資料輸出到檔案中。完成後,我們先看一下 XML 的長相,這樣才知道之後要怎麼取欄位做統計:

162548

從 XML 中,我們發現重點就是 <paths> 和 <path>,不過 <msg> 也很重要,因為客戶有要求,有些 Commit 版本要跳過不予計算,依據的就是「非常不精確」的 msg 欄位值,所以這些都是重要資訊。

有了 XML 檔案,接著就進入 LINQPad 開始寫程式了。話不多說,先看 Code:


void Main()
{
    var query = GetCommitPathInfo(@"d:\temp\svnlog.xml");
    var result = GetProjectFileMapping(query);
    Console.WriteLine (@"====== {0} ======", "SVN Commit 統計資料");
    OutputCountInfo(result);
}

public class CommitPathObject
{
    public string ProjectName { get; set; }
    public string FileName { get; set; }
    public int ModifyCount { get; set; }
}

public void OutputCountInfo(IEnumerable<CommitPathObject> result){
    var projectCount = result.Select (r => r.ProjectName).Distinct().Count( );
    var fileCount = result.Select (r => r.FileName).Distinct().Count( );
    var modifyCount = result.Sum (r => r.ModifyCount);
    Console.WriteLine (@"Project Count = {0}", projectCount);
    Console.WriteLine (@"File Count = {0}", fileCount);
    Console.WriteLine (@"Modify Count = {0}", modifyCount);
}

public IEnumerable<string> GetCommitPathInfo(string file)
{
    XmlDocument doc = new XmlDocument();
    XmlTextReader reader = new XmlTextReader(file);
    var xe = XElement.Load(reader);
    var firstFilter = from el in xe.Elements()
            where el.Element("msg") == null 
                  || (el.Element("msg") != null 
                          && !el.Element("msg").Value.ToUpper().Contains("Clean and Refresh")
                          && !el.Element("msg").Value.ToUpper().Contains("清整"))
            select el;
    //firstFilter.Dump();
    var query = from el in firstFilter.Descendants()
                where el.Name == "path"
                orderby el.Value
                select el.Value;
    return query;
}

public IEnumerable<CommitPathObject> GetProjectFileMapping(IEnumerable<string> query)
{
    var reg = new Regex(@"^/.+((?<=RoseRo)|(?<=LeoTodo))/(?<prj>[a-zA-Z_]+)/[\w/]+/(?<file>.+\.\w{2,6})((?<=aspx$)|(?<=ascx$)|(?<=aspx\.vb$)|(?<=ascx\.vb$))$", RegexOptions.IgnoreCase);
    var result = from x in query    
              where reg.IsMatch(x)
              select new CommitPathObject(){ProjectName = reg.Match(x).Result("${prj}"), 
                                              FileName = reg.Match(x).Result("${file}"), 
                                            ModifyCount = 1};
    //result.Dump();
    return result;
}

輸出截圖:

170336

程式流程說明:

  • 先建立好一個 CommitPathObject,用來接 LINQPad 的輸出結果。
  • 調用 GetCommitPathInfo(),把 XML 檔案位置傳進去,進行第一步的 Log 資料整理。
  • 調用 GetProjectFileMapping(),取得 Log 資料中,每筆 <path> 項目所對應的專案名稱、檔案名稱。
  • 調用 OutputCountInfo(),輸出客戶要的統計資料。

GetCommitPathInfo():

  1. 把 XML 檔案讀進來。
  2. 依客戶要求的條件,檢查 <msg> 中若有關鍵字,就予以排除。這裡要特別注意,有可能沒有 <msg> 項目,所以一定要判斷 <msg> 存在才能取值,不然會發生 NullReference Exception。
  3. 把留下來的 log 資料,只取出 <path> 的值,以利後續統計資料使用。

GetProjectFileMapping():

  1. 建立一個正規式,目的是要取出特定副檔名,且父系資料夾為 LeoTodo、RoseR○ 的程式,設定不區分大小寫。
    
    var reg = new Regex(@"^/.+((?<=RoseRo)|(?<=LeoTodo))/(?<prj>[a-zA-Z_]+)/[\w/]+/(?<file>.+\.\w{2,6})((?<=aspx$)|(?<=ascx$)|(?<=aspx\.vb$)|(?<=ascx\.vb$))$", RegexOptions.IgnoreCase);
  2. 執行 LINQ 查詢,透過正規式取回專案名稱(reg.Match(x).Result("${prj}"))和檔案名稱(reg.Match(x).Result("${file}")),並設定每一筆資料的修改次數為 1,方便之後加總、出統計資料。

OutputCountInfo():

  1. 把專案名稱 Distinct() 後,取回 Count 數,即為專案數。
  2. 把檔案名稱 Distinct() 後,取回 Count 數,即為檔案數。
  3. 把修改次數 Sum() 後,可得到修改次數。

--------
沒什麼特別的~
不過是一些筆記而已