從Svn Commit資料中統計Web專案數、異動檔案數、修改次數等資料
總是會有一些奇妙的需求找上門。這次要完成的需求是,從 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 的長相,這樣才知道之後要怎麼取欄位做統計:
從 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;
}
輸出截圖:
程式流程說明:
- 先建立好一個 CommitPathObject,用來接 LINQPad 的輸出結果。
- 調用 GetCommitPathInfo(),把 XML 檔案位置傳進去,進行第一步的 Log 資料整理。
- 調用 GetProjectFileMapping(),取得 Log 資料中,每筆 <path> 項目所對應的專案名稱、檔案名稱。
- 調用 OutputCountInfo(),輸出客戶要的統計資料。
GetCommitPathInfo():
- 把 XML 檔案讀進來。
- 依客戶要求的條件,檢查 <msg> 中若有關鍵字,就予以排除。這裡要特別注意,有可能沒有 <msg> 項目,所以一定要判斷 <msg> 存在才能取值,不然會發生 NullReference Exception。
- 把留下來的 log 資料,只取出 <path> 的值,以利後續統計資料使用。
GetProjectFileMapping():
-
建立一個正規式,目的是要取出特定副檔名,且父系資料夾為 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);
- 執行 LINQ 查詢,透過正規式取回專案名稱(reg.Match(x).Result("${prj}"))和檔案名稱(reg.Match(x).Result("${file}")),並設定每一筆資料的修改次數為 1,方便之後加總、出統計資料。
OutputCountInfo():
- 把專案名稱 Distinct() 後,取回 Count 數,即為專案數。
- 把檔案名稱 Distinct() 後,取回 Count 數,即為檔案數。
- 把修改次數 Sum() 後,可得到修改次數。
--------
沒什麼特別的~
不過是一些筆記而已