1

継続的インテグレーションに TeamCity を使用しており、ソース管理は Git で、複数の .sln ファイル (約 10) を含む主要なリポジトリが 1 つあります。

全体として、このリポジトリには約100 ~ 200 個の C# プロジェクトがあります。

マスター リポジトリにプッシュすると、TeamCityはリポジトリ内のすべてのプロジェクトをコンパイルするビルドをトリガーします。

どのプロジェクトが特定のコミットによって実際に影響を受けたかを確認できるようにしたいので、それらのプロジェクトの出力のみを現在のビルドのアーティファクトとして公開します。

このために、NDepend をビルド プロセスに統合し、現在と最新のビルド出力間の差分レポートを生成するソリューションを設計しました。変更/追加された出力は、ビルド出力として公開されます。

私は NDepend の経験がほとんどありません。私が見てきたことから、その真の力のすべては、それに組み込まれているクエリ言語から来ています。

どうすれば(可能であれば)次のことを達成できるのだろうかと思っています:

  1. 以前のビルドの出力を含むフォルダーとビルド出力の現在のフォルダーの違い。
  2. コピーする必要があるファイルを特定できるように、NDepend に消費可能な形式でレポートを生成させます。

このシナリオは可能ですか?それはどれほど簡単/難しいでしょうか?

4

1 に答える 1

5

したがって、簡単な答えは、このドキュメントで説明されているように、 Reporting Code Diffの方法を実行することです。この基本的な答えの問題は、2 つの同じアセンブリ セットを常に参照する 2 つの NDepend プロジェクトを前提としていることです。


確かに、アセンブリの数と名前はコンテキストによって異なるため、その場で 2 つのプロジェクト (古い/新しい) をビルドし、それらをNDepend.APIで分析する必要があります。

そのための NDepend.API ソース コードを次に示します。It-Just-Works エクスペリエンスの場合、PowerTools ソース コード ( ) で、登録呼び出しの後にメソッドを$NDependInstallDir$\NDepend.PowerTools.SourceCode\NDepend.PowerTools.sln呼び出すだけ です ( ) 。FoldersDiff.Main();AssemblyResolveProgram.cs

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

NDepend.API を利用するソース コードは次のとおりです。

codeBase2 つのオブジェクトと1 つのオブジェクトを使用して、さらに多くのことができることに注意してくださいcompareContext。アセンブリの追加/削除/codeWasChanges の 3 つのリストを表示するだけでなく、API の破壊的な変更、追加された新しいメソッドと型、変更されたクラスとメソッド、コード品質の回帰を表示できます...そのためには、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);
      }
   }
}
于 2013-02-11T14:46:14.690 に答える