2013-02-10 100 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