2011-03-22 54 views
3

我目前「自動化構建」我們的.NET解決方案中(其中包含很多項目,至少20.有些的WinForms,一些Web項目,都具有不同的發佈配置...啊!)。我正在使用CruiseControl.NET(或CC.NET,whatevs)和nANT。另外,DOS和PowerShell和其他幾個魔豆,我們不需要進入:)如何將CC.NET自動生成版本信息寫入全局程序集信息文件並由幾個.NET應用程序引用?

我的目標是產生一個內部版本標籤(我已經有BTW半工作)。構建標籤由Min/Maj號碼加上SVN簽入號碼組成。這對我們來說很好,我們對此感到滿意。我現在需要讓我的.NET項目引用內部版本號,以便我的QA團隊成員知道他們正在測試的內部版本號。

我的版本標籤楠任務看起來是這樣的:

<project name="updateassemblyversion" default="updateassemblyversion"> 
<target name="updateassemblyversion" description="generates the version number"> 
    <echo message="Setting the build version to ${CCNetLabel}..." /> 
    <attrib file="AssemblyInfo.cs" readonly="false" /> 
    <asminfo output="AssemblyInfo.cs" language="CSharp"> 
     <imports> 
      <import namespace="System" /> 
      <import namespace="System.Reflection" /> 
     </imports> 
     <attributes> 
      <attribute type="AssemblyVersionAttribute" value="${CCNetLabel}" /> 
      <attribute type="AssemblyFileVersionAttribute" value="${CCNetLabel}" /> 
     </attributes> 
    </asminfo> 
    <attrib file="AssemblyInfo.cs" readonly="true" /> 
</target> 

不管怎麼說,我試圖把我生成服務器上的程序集信息。我已閱讀,它不是最好的做法有20+的AssemblyInfo.cs文件寫入,所以我手動創建一個GlobalyAssemblyInfo.cs文件,因爲這是與我的所有項目「的方案項目」,通過「添加.. .Existing Item ...添加鏈接「。我不認爲這是我將需要,但因爲我的版本將發生在構建服務器上...

這是公平的指出,我目前正在測試的nANT任務(示例上面)使用我需要正確的版本戳記,但該任務對我的場景不正確。它會創建一個新的AssemblyInfo.cs文件,並且版本在編譯完成後貼上它。我知道這是錯誤的,但它本質上是產生我需要的東西,但我不確定如何在我的「構建」腳本中以我需要的順序使用它。我知道它應該在編譯發生之前發生,但是如何讓編譯任務使用新生成的文件? (見問題#4)。

這是我不明白:

  1. 保持我的老20+的AssemblyInfo.cs文件?他們現在有什麼 的目的?我不需要他們,我做 不相信。我可能不應該 從解決方案中的文件刪除, 但他們是無用的,對不對?
  2. 如果我確實使用生成的GlobalAssemblyInfo.cs文件,從我的 nANT任務中,我如何獲得 引用併爲我的編譯內容添加版本戳記 ?
  3. 正在手動創建GlobalAssemblyInfo文件(在我的解決方案中爲 ),並且從每個項目引用它 ,對於我的 情況無效?我想我並不需要在所有在我的解決方案 和 這些文件引用的項目,我只需要它 在我的構建例行我的體型 服務器上。我已經產生 「AssemblyXYZ.cs」文件(從楠) 用正確的版本標記。 不應該我只是用它來編譯我所有的項目 ?
  4. 如果#3爲真,我該如何在CC.NET配置文件 文件(或nant goodness?)中實現它?基本上, 我該如何告訴VS編譯器在我的解決方案中使用我的新GlobalAssemblyInfo.cs (由nANT生成)所有20+ .NET 項目?
  5. 如何讓我的.NET項目引用(內部)新生成的 生成的動態生成 number/versionstamp?我需要質量保證是 能夠在應用程序 UI中看到它。

一旦發生這種情況,我將成爲一個快樂的汽車製造商:) 乾杯!

回答

2

下面是我做的。這並不容易,但也不難。我想我對這個大部分都沒有信心,但幸運的是,這很容易實現。

這是我的任務南特的最終版本,我命名爲 「updateassemblyinfo.build」:

<?xml version="1.0"?> 
<project name="updateassemblyversion" default="updateassemblyversion"> 
    <target name="updateassemblyversion" description="generates the version number"> 
     <echo message="Setting the build version to ${CCNetLabel}..." /> 
     <attrib file="AssemblyInfo.cs" readonly="false" /> 
     <asminfo output="C:\CruiseControl\ProjectFolders\MyBigBadSolution\GlobalAssemblyInfo.cs" language="CSharp"> 
      <imports> 
       <import namespace="System" /> 
       <import namespace="System.Reflection" /> 
      </imports> 
      <attributes> 
       <attribute type="AssemblyVersionAttribute" value="${CCNetLabel}" /> 
       <attribute type="AssemblyFileVersionAttribute" value="${CCNetLabel}" /> 
      </attributes> 
     </asminfo> 
     <attrib file="GlobalAssemblyInfo.cs" readonly="true" /> 
    </target> 
</project> 

我結束了使用Yauheni Sivukha,這裏所示的方法: C# Project Global AssemblyInfo

^我應該指出的一件事是,您的項目級裝配屬性將與您的解決方案級裝配屬性相沖突。基本上,你將會有重複的屬性,編譯器會拋出一個錯誤。只需從項目級別的AssemblyInfo.cs文件中刪除衝突的屬性,然後讓GlobalAssemblyInfo.cs文件覆蓋它們。任何項目特定屬性應該存儲在項目級別的程序集信息中。共享程序集信息在解決方案級別進入全局程序集文件。對於一個完全陌生的人來說,這可能會讓人困惑。

在問候我的5個項目符號「這是我不明白」的疑問,這裏是我的答案:

  1. 是的,你應該讓所有的程序集信息(項目級別)的文件。這些存儲項目級彙編信息。其中一些屬性可能與其他項目不同。最好將這些與每個特定的項目保持一致。
  2. 使用CruiseControl.NET和我的nANT任務,只需使用「asminfo」標記,並將「output」元素指向GlobalAssemblyInfo.cs文件(解決方案級別的程序集文件)的文件路徑。
  3. 不,這種情況並非無效。使用跨多個項目共享的全局彙編文件(解決方案級別)非常方便。成功實施這個之後,我可以看到以前從未處理過的人會感到困惑。
  4. 我認爲在ANT中注意標記很重要。這是「裝配信息」。去搞清楚。
  5. 這裏是一個答案沒有人回答,這是非常重要的:

    Assembly asm = Assembly.GetExecutingAssembly(); 
    this.Text = asm.GetName().Version.ToString(); 
    
2

我一直在與CC.NET一樣的問題掙扎......我最終放棄了NANT並編寫了一個自定義CC.NET插件,以編程方式更新每個項目的AssemblyInfo.cs。實現CC.NET插件非常簡單。

using System.Collections.Generic; 
using System.IO; 
using Exortech.NetReflector; 
using ThoughtWorks.CruiseControl.Core; 

namespace ccnet.AssemblyVersionUpdater.plugin { 
[ReflectorType("assemblyRevisioner")] 
    public class AssemblyRevisioner : ITask { 
    public AssemblyRevisioner() { 
    } 

    [ReflectorProperty("rootFolder", Required = true)] 
    public string RootFolder { get; set; } 

    public void Run(IIntegrationResult result) { 
     foreach (var file in GetAssemblyInfoFiles(RootFolder)) { 
      var tmp = file + ".tmp"; 
      using (var sr = new StreamReader(file)) { 
       using (var st = new StreamWriter(tmp)) { 
        string line; 
        var versionSet = false; 
        var fileVersionSet = false; 
        while ((line = sr.ReadLine()) != null) { 
         if (!versionSet && line.StartsWith("[assembly: AssemblyVersion(")) { 
          st.WriteLine("[assembly: AssemblyVersion(\"{0}\")]", result.Label); 
          versionSet = true; 
         } else { 
          if (!fileVersionSet && line.StartsWith("[assembly: AssemblyFileVersion(")) { 
           st.WriteLine("[assembly: AssemblyFileVersion(\"{0}\")]", result.Label); 
           fileVersionSet = true; 
          } else { 
           st.WriteLine(line); 
          } 
         } 
         st.Flush(); 
        } 
        st.Close(); 
       } 
       sr.Close(); 
      } 
      File.SetAttributes(file, FileAttributes.Normal); 
      File.Copy(tmp, file, true); 
      File.Delete(tmp); 
     } 

    } 

    private static IEnumerable<string> GetAssemblyInfoFiles(string b) { 
     var result = new List<string>(); 
     var stack = new Stack<string>(); 
     stack.Push(b); 
     while (stack.Count > 0) { 
      var dir = stack.Pop(); 
      try { 
       result.AddRange(Directory.GetFiles(dir, "AssemblyInfo.cs")); 
       foreach (var dn in Directory.GetDirectories(dir)) { 
        stack.Push(dn); 
       } 
      } catch { 
      } 
     } 
     return result; 
    } 

    } 
} 

編譯該DLL並將其放置在CruiseControl.NET \ server文件夾中。 CC.NET需要重新啓動插件才能安裝。然後在適當的CC.NET配置文件:

<tasks> 
    <assemblyRevisioner> 
     <rootFolder>E:\Build\Source\Project1</rootFolder> 
    </assemblyRevisioner> 
    ... 
</tasks> 

此代碼編輯「到位」的AssemblyInfo.cs和項目建成之前,一個從CC.NET替換版本號。我敢肯定,有更多優雅的方式來增加版本號,但這對我來說工作得很好。

+0

你在哪裏下載NetReflector?該鏈接不再有效:http://sourceforge.net/projects/netreflector/files/ – D3vtr0n 2011-03-23 15:04:55

+0

反射的東西似乎被棄用。我甚至不能進入他們的SVN主幹自己編譯它。有沒有解決這個問題的方法?否則這個例子是相當無用的...任何方式來獲得.DLL? – D3vtr0n 2011-03-23 15:29:22

+1

@Devtron NetReflector是CruiseControl.NET發行版的一部分。您可以在CruiseControl.NET \ server文件夾中找到該dll。 – 2011-03-24 05:23:33

2

1 - 我會保留您的本地AssemblyInfo.cs文件。某些屬性是(或可能)是特定於每個程序集的,例如說明和COM Guid。

2 - 如前所述,引用每個項目的GlobalAssemblyInfo.cs(在根或任何地方)。將常見屬性放在這裏,如產品和版權。構建應該從兩者中挑選一些數據,並且如果它們發現重複則會發出警告。如果您使用asminfo任務來生成GlobalAssemblyInfo.cs ant,它將在此處編寫一個常見的AssemblyVersion值,然後您的所有項目都將獲得該版本號。

3 - 就我個人而言,無論構建服務器還是開發箱,我都喜歡構建過程。其中一個原因是能夠在不啓動官方構建的情況下測試構建是很好的。另一個是你可能想升級一個主要的依賴項(SQL Server版本或其他),看看是否一切都建立,再次沒有實際升級真正的生成服務器。

4 - 查看答案2