2011-10-06 53 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)中可见。

启动分支构建将找到构建定义并启动构建。

删除分支将查找构建定义,删除所有构建,删除构建定义以及删除分支(清理)。构建和分支的寿命很短,因此清理它们非常重要。