2013-02-10 65 views
1

我們正在使用TeamCity進行持續集成,我們的源代碼控制是Git,並且我們有1個包含多個.sln文件(大約10個)的主要存儲庫。在構建期間使用NDepend生成差異報告

總而言之,此存儲庫有大約〜100 - 200個C#項目

在推送到主存儲庫時,TeamCity會觸發一個構建,該構建將編譯存儲庫中的所有項目

我希望能夠告訴哪些項目實際上受特定提交影響,因此只發布那些項目的輸出作爲當前構建的工件。爲此,我設計了一個解決方案,將NDepend集成到我們的構建過程中,並生成當前和最新構建輸出之間的差異報告。 已更改/添加的輸出將作爲構建輸出發佈。

我幾乎沒有NDepend的經驗;從我所看到的所有真正的力量來自於它的查詢語言。

我想知道如何(如果可能的話),我可以實現以下目標:

  1. DIFF包含以前的版本的輸出和生成輸出的當前文件夾中的文件夾之間。
  2. 讓NDepend以可使用格式生成報告,以便我可以確定需要複製的文件。

這種情況可能嗎?那會是多麼容易/困難?

回答

5

所以最簡單的答案是做報告代碼Diff的方式,如this documentation所述。這個基本答案的問題是,它預先假定兩個NDepend項目總是指向兩個相同的程序集。


當然,數量和組件的名稱在您的上下文不同,所以我們需要在飛行中建立兩個項目(新/舊),並通過NDepend.API分析它們。

這是NDepend.API源代碼。對於It-Just-Works體驗,在PowerTools源代碼(在$NDependInstallDir$\NDepend.PowerTools.SourceCode\NDepend.PowerTools.sln中)只需在AssemblyResolve註冊調用後調用FoldersDiff.Main();方法,即Program.cs

... 
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolverHelper.AssemblyResolveHandler; 
FoldersDiff.Main(); 
... 

下面是利用NDepend.API的源代碼。

請注意,可以通過兩個codeBase對象和compareContext對象完成更多操作。您可以顯示API中斷更改,添加的新方法和類型,修改後的類和方法,代碼質量回歸等,而不是僅顯示已添加/刪除/ codeWasChanges程序集的3個列表。爲此,請參閱default code rules關於diff的說明基於相同的NDepend.CodeModel API

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using NDepend; 
using NDepend.Analysis; 
using NDepend.CodeModel; 
using NDepend.Path; 
using NDepend.Project; 


class FoldersDiff { 

    private static readonly NDependServicesProvider s_NDependServicesProvider = new NDependServicesProvider(); 

    internal static void Main() { 
     var dirOld = @"C:\MyProduct\OldAssembliesDir".ToAbsoluteDirectoryPath(); 
     var dirNew = @"C:\MyProduct\NewAssembliesDir".ToAbsoluteDirectoryPath(); 

     Console.WriteLine("Analyzing assemblies in " + dirOld.ToString()); 
     var codeBaseOld = GetCodeBaseFromAsmInDir(dirOld, TemporaryProjectMode.TemporaryOlder); 
     Console.WriteLine("Analyzing assemblies in " + dirNew.ToString()); 
     var codeBaseNew = GetCodeBaseFromAsmInDir(dirNew, TemporaryProjectMode.TemporaryNewer); 

     var compareContext = codeBaseNew.CreateCompareContextWithOlder(codeBaseOld); 

     // So much more can be done by exploring fine-grained diff in codeBases and compareContext 
     Dump("Added assemblies", codeBaseNew.Assemblies.Where(compareContext.WasAdded)); 
     Dump("Removed assemblies", codeBaseOld.Assemblies.Where(compareContext.WasRemoved)); 
     Dump("Assemblies with modified code", codeBaseNew.Assemblies.Where(compareContext.CodeWasChanged)); 
     Console.Read(); 
    } 

    internal static ICodeBase GetCodeBaseFromAsmInDir(IAbsoluteDirectoryPath dir, TemporaryProjectMode temporaryProjectMode) { 
     Debug.Assert(dir.Exists); 
     var dotNetManager = s_NDependServicesProvider.DotNetManager; 
     var assembliesPath = dir.ChildrenFilesPath.Where(dotNetManager.IsAssembly).ToArray(); 
     Debug.Assert(assembliesPath.Length > 0); // Make sure we found assemblies 
     var projectManager = s_NDependServicesProvider.ProjectManager; 
     IProject project = projectManager.CreateTemporaryProject(assembliesPath, temporaryProjectMode); 

     // In PowerTool context, better call: 
     // var analysisResult = ProjectAnalysisUtils.RunAnalysisShowProgressOnConsole(project); 
     var analysisResult = project.RunAnalysis(); 
     return analysisResult.CodeBase; 
    } 

    internal static void Dump(string title, IEnumerable<IAssembly> assemblies) { 
     Debug.Assert(!string.IsNullOrEmpty(title)); 
     Debug.Assert(assemblies != null); 
     Console.WriteLine(title); 
     foreach (var @assembly in assemblies) { 
     Console.WriteLine(" " + @assembly.Name); 
     } 
    } 
} 
+0

有好東西在那裏,帕特里克!看起來足夠長,以實際工作。一旦我測試這個,我會標記爲答案。 – 2013-02-11 19:23:43

+0

不客氣:) – 2013-02-12 09:02:23