【问题标题】:Generating a diff report using NDepend during build在构建期间使用 NDepend 生成差异报告
【发布时间】:2013-01-25 23:28:30
【问题描述】:

我们正在使用 TeamCity 进行持续集成,我们的源代码控制是 Git,我们有 1 个包含多个 .sln 文件(大约 10 个)的主要存储库。

总而言之,这个存储库有大约 ~ 100 - 200 个 C# 项目

在推送到主存储库后,TeamCity 会触发构建,该构建将编译存储库中的所有项目

我希望能够知道哪些项目实际上受到了特定提交的影响,从而仅将这些项目的输出作为当前构建的工件发布。

为此,我设计了一个解决方案,将 NDepend 集成到我们的构建过程中,并生成当前和最新构建输出之间的差异报告。 更改/添加的输出将作为构建输出发布。

我对 NDepend 的经验很少;据我所知,它的所有真正力量都来自于其中的查询语言。

我想知道如何(如果可能)实现以下目标:

  1. 包含先前构建输出的文件夹与当前构建输出文件夹之间的差异。
  2. 让 NDepend 生成可消耗格式的报告,以便我确定需要复制的文件。

这种情况可能吗?那有多容易/多难?

【问题讨论】:

    标签: c# .net build continuous-integration ndepend


    【解决方案1】:

    所以简单的答案是按照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 对象可以做更多事情。除了显示添加/删除/codeWasChanges 的 3 个程序集列表之外,您还可以显示 API 中断更改、添加的新方法和类型、修改的类和方法、代码质量回归......为此,只需查看有关 diff 的 default code rules ,基于相同的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);
          }
       }
    }
    

    【讨论】:

    • 那里的东西真棒,帕特里克!看起来足够长,可以实际工作。一旦我对此进行测试,我将标记为答案。
    猜你喜欢
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多