2011-10-06 48 views
6

我關注產品的構建,並被要求提供一種自定義現有構建定義的方法,以便在需要時構建不同的分支。單個TFS 2010構建定義可以用於多個分支嗎?

該產品的構建過程已經有幾個自定義步驟和操作,並且該產品包含大量構建的項目文件,因此無法爲創建的每個新分支設置新的構建定義。

構建定義設置爲從主分支構建。目標是輸入一個特定的分支(使用可以在構建排隊時輸入的工作流參數),然後將構建它而不是默認的主分支,而無需編輯構建定義。

我有一個單獨的測試程序,用於測試我所有的自定義構建活動和過程。在此構建定義的工作流程中,爲了記錄目的,我添加了相當少的構建消息,以便我可以查看構建過程中使用的變量的值。

我還創建了一個分支在此基礎上測試程序準備好了,可以用來構建多個分支

首先生成定義的測試,我跑了原始的測試解決方案的項目文件的生成從原來的分支開始,然後更改構建定義,以便使用新分支完成相同的操作並運行另一個構建。比較兩個分支之間的構建日誌時,它們之間只有一些細微差異。 (設置診斷日誌記錄級別)

1差異 - 我看了一個工作區變量和的建立參照各自的分支,特別是文件夾屬性的ServerItem屬性的文件夾屬性

第二差 - 該項目的文件正在修建(BuildSettings.ProjectsToBuild)從各個分支

我沒見過比這

主要的問題在這裏其他2構建日誌之間的任何其他方面的差異來:

是否有標準方式交換正在爲單個構建定義構建的分支?

如果沒有,當排隊構建時,是否可以簡單地將定製工作流模板中的所有引用(Workspace和BuildSettings.ProjectsToBuild)更改爲輸入的分支?

一如既往,感謝您事先的任何和所有幫助

回答

4

我已經設法修改我的構建的工作流程模板,以便可以爲解決方案的多個分支構建。爲了實現這一點,我不得不改變工作流中的某些內容,併爲運行構建的服務帳戶創建一些額外的工作空間。

  1. 我向工作流中添加了一個參數,以便在構建排隊時輸入所需的分支。

  2. 我改變放置位置的構建,使其相關的輸入分支(可選)

  3. 創建構建機器的分支在一個單獨的源目錄中建立

  4. 初始化的WorkspaceName和SourcesDirectory,以便它們與新的工作區名稱和源目錄文件夾相匹配

  5. 我創建了一個自定義活動來更改BuildSettings.ProjectsToBuild中項目/解決方案的列表,以便它們引用他們從輸入的分支

  6. 我注意到,通過我的測試階段,即使我輸入分支的新工作區最初設置爲使用輸入的分支作爲其ServerItem,它仍然會創建工作區與ServerItem是輸入到構建定義中。爲了解決這個問題,我創建了另一個自定義活動重新映射分支工作空間,使ServerItem指着正確的分支

有,我參與我的工作流程中的其他一些東西,但他們更調整,我的開發人員已經要求,上述步驟導致多個分支構建單個構建定義。

+0

如果您將詳細說明如何解決此問題,那麼我將upvote。 –

+1

@ Vermin:同意......我想看看你的解決方案。 –

0

總之:否,是:-)

多一點闡述這些答案中,TFS系統默認模板,希望有一個單一的爲您想要構建的每個分支構建定義,或者指定需要構建的所有分支,但是在一個構建定義中。沒有一種標準方法可以從隊列新建版本對話框中的可用分支中進行選擇。

接下來的答案是肯定的,因爲確實可以自定義您的構建模板,我知道您已經開始這樣做了。根據你的分支結構,向隊列中添加一個屬性會很容易,該屬性出現在隊列新建對話框中,並且在運行期間有一個(例如)半列分隔的字符串,對於該列表中的每個元素,在模板實際開始迭代該列表之前,添加一個解決方案以構建工作流過程。

但是,應該做這項工作,我對你如何最終想要這個能力感興趣?你沒有使用VS解決方案文件?

+0

嗨,感謝您的幫助。我已經開始改變我的工作流程(希望)實現我的目標。 在回答你的問題時,沒有爲構建解決方案的項目文件而不是解決方案文件本身設置構建定義。 – Vermin

+0

另外,它更多的是替換構建定義中構建的默認分支,而不是將分支添加到構建中,所以即時通訊工具正在使用所選分支的不同工作空間(在排隊時通過工作流參數輸入)構建),然後將更改BuildSetting.ProjectsToBuild以引用選定的分支而不是默認分支 – Vermin

1

我還想在構建定義中使用更多的分支靈活性,所以我實現了一個代碼活動來更改ProjectsToBuild(如上面的Vermin的第5步)。下面的代碼(除去特定項目的東西):爲ConvertProjects()

[BuildActivity(HostEnvironmentOption.All)] 
public sealed class ConvertProjectsAccordingToBranch : CodeActivity 
{ 
    public static string s_MainBranch = "$/MyTeamProject/Main"; 

    public InArgument<IBuildDetail> BuildDetail { get; set; } 
    public InArgument<BuildSettings> BuildSettingsOriginal { get; set; } 
    public OutArgument<BuildSettings> BuildSettingsConverted { get; set; } 

    protected override void Execute(CodeActivityContext context) 
    { 
     Logger.Instance.Init(context); 
     IBuildDetail buildDetail = BuildDetail.Get(context); 
     BuildSettingsConverted.Set(context, ConvertProjects(BuildSettingsOriginal.Get(context), buildDetail.BuildDefinition)); 
    } 

    /// <summary>Returns a BuildSettings with ProjectsToBuild converted according to the build definition's workspace</summary> 
    public BuildSettings ConvertProjects(BuildSettings settingsOriginal, IBuildDefinition buildDefinition) 
    { 
     var mappings = buildDefinition.Workspace.Mappings; 
     if (mappings.Count() != 1) 
     { 
      throw new BuildProcessException(string.Format(CultureInfo.InvariantCulture, 
       "Build definition must have exactly one workspace mapping. Build definition ID:{0} has {1} mappings", 
       buildDefinition.Id, // IBuildDefinition doesn't have any Name property, seriously! 
       mappings.Count())); 
     } 

     string definitionBranch = mappings.First().ServerItem; 
     var settingsConverted = new BuildSettings() 
     { 
      PlatformConfigurations = settingsOriginal.PlatformConfigurations, 
     }; 

     foreach (string projectOriginal in settingsOriginal.ProjectsToBuild) 
     { 
      var projectConverted = projectOriginal.Replace(s_MainBranch, definitionBranch); 
      if (!projectConverted.StartsWith(definitionBranch)) 
      { 
       throw new BuildProcessException(string.Format(CultureInfo.InvariantCulture, 
        "Project {0} is not under main branch {1}, Definition branch: {2}", 
        projectOriginal, s_MainBranch, definitionBranch)); 
      } 

      settingsConverted.ProjectsToBuild.Add(projectConverted); 
      Logger.Instance.Log("Converted ProjectToBuild: {0}, original: {1}", projectConverted, projectOriginal); 
     } 

     return settingsConverted; 
    } 
} 

我也有單元測試,但它是依賴於當地的東西,所以我沒有張貼在這裏。這是微不足道的,絕對值得寫!

1

我知道這是非常古老的,但萬一有人發現這篇文章。

我們有相同的要求:能夠構建一個功能分支,以在合併到開發之前提供用於測試的特定功能的構建。

這是我們都做到了:

創建了一套Visual Studio的擴展:

  • 創建分支建立
  • 啓動分支建立
  • 刪除支線

創建分支構建將克隆構建de它們被用作模板。根據分支更改構建定義名稱和工作區。構建定義將在團隊資源管理器(VS2012)中可見。

啓動分支構建將找到構建定義並啓動構建。

刪除分支將查找構建定義,刪除所有構建,刪除構建定義以及刪除分支(清理)。構建和分支的壽命很短,因此清理它們非常重要。

相關問題