演练:通过自定义任务自定义 Team Foundation Build

更新:2007 年 11 月

创建自定义任务并在生成期间运行这些任务,便可以扩展 Team Foundation Build。本主题说明使用自定义任务扩展生成定义所需的步骤。

必需的权限

若要完成此演练,必须将“管理生成”权限设置为“允许”。有关更多信息,请参见 Team Foundation Server 权限

创建生成定义

使用“生成定义”对话框,可以创建新的生成定义。使用“MSBuild 项目文件创建向导”,可以共享现有 TFSBuild.proj 文件,也可以创建一个新的文件。编辑 TFSBuild.proj 文件可以自定义与该文件相关联的每一个生成定义。有关创建生成定义的更多信息,请参见如何:创建生成定义

创建自定义任务

这些任务提供在生成过程中运行的代码。这些任务包含在 MSBuild 项目文件的 Target 元素中。MSBuild 是 Team Foundation Build 背后的引擎。自定义任务必须采用 MSBuild 理解的格式。每个任务都必须实现为一个实现 ITask 接口的 .NET 类,该接口在 Microsoft.Build.Framework.dll 程序集中定义。

实现任务可以采用两种方法:

  • 直接实现 ITask 接口。

  • 从帮助器类 Task 派生您的类,该帮助器类在 Microsoft.Build.Utilities.dll 程序集中定义。Task 实现 ITask 并提供某些 ITask 成员的默认实现。

这两种方法中,都必须向类添加一个名为 Execute 的方法,该方法在任务运行时调用。该方法不带任何参数,返回一个 Boolean 值。如果任务成功,则返回 true;如果失败,则返回 false。下面的示例显示一个不执行任何操作并返回 true 的任务。

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace MyTasks
{
    public class SimpleTask : Task
    {
        public override bool Execute()
        {
            return true;
        }
    }
}

任务还可以接受参数,引发事件和记录输出。有关更多信息,请参见 MSBuild 任务MSBuild 概述

签出 TFSBuild.proj

编写了任务后,必须注册该任务并在一个目标中将它调用出,以便在生成过程中需要的点上执行任务代码。如果使用“MSBuild 项目文件创建向导”创建 MSBuild 项目文件,并且接受源代码管理中的默认位置,则 TFSBuild.proj 文件位于 Visual Studio Team System 源代码管理的文件夹“$/MyTeamProject/TeamBuildTypes/MyBuildName”中。这种情况下,MyTeamProject 是团队项目的名称,也是所有团队项目源代码的根节点;MyBuildName 是生成定义的名称,该 TFSBuild.proj 文件最初是为该生成定义创建的。

若要确定 TFSBuild.proj 文件的源代码管理位置,请在团队资源管理器的“Builds”文件夹中选择生成定义,右击该生成定义,然后单击“编辑”。TFSBuild.proj 文件的源代码管理位置显示在“生成定义”对话框中的“项目文件”窗格中。

说明:

不要编辑 Microsoft.TeamFoundation.Build.targets 文件,因为自定义将应用到该计算机上的所有生成中。

有关签出文件的信息,请参见 使用 Team Foundation 版本控制

注册任务

创建任务之后,必须通过在 TFSBuild.proj 文件的 UsingTask 元素中指定该任务来注册它。UsingTask 元素会将该任务映射到包含该任务的实现的程序集。有关更多信息,请参见 UsingTask 元素 (MSBuild)

注册自定义任务

  1. 打开 TFSBuild.proj 文件。

  2. UsingTask 元素添加到该文件中,并指定任务的详细信息。

    例如:

    <UsingTask 
        TaskName="MyTasks.SimpleTask" 
        AssemblyName="MyAssembly.Build.Tasks"/>
    

    - 或 -

    <UsingTask 
        TaskName="MyTasks.SimpleTask" 
        AssemblyFile="MyAssembly.Build.Tasks.dll"/>
    

    - 或 -

    <UsingTask
        TaskName="MyTasks.SimpleTask"
        AssemblyFile="c:\somediskpath\MyAssembly.Build.Tasks.dll"/>
    
  3. 保存该文件。

运行自定义任务

现在已创建并注册了任务,您必须在生成过程中指定要运行该任务的点。

运行任务

  1. 确定生成过程中要运行自定义任务的位置。

    有关可以扩展生成过程的位置的更多信息,请参见 了解 Team Foundation Build 配置文件

  2. 打开 TFSBuild.proj,并添加前面所选的 Target 元素。

  3. 添加 task 元素,以在 Target 元素中运行任务。

    例如,下面 TFSBuild.proj 中的 XML 在 BeforeGet 目标中运行 SimpleTask 任务,该目标紧靠 Get 目标之前运行。

    <Target Name="BeforeGet">
        <SimpleTask />
    </Target>
    
  4. 保存该文件。

签入文件

必须签入 TFSBuild.proj 文件才能使更改生效。Team Foundation Build 将此文件从源代码管理复制到生成计算机上,这样,对您的计算机上的本地副本所做的任何更改都不会影响生成。有关将文件签入到源代码管理的更多信息,请参见 如何:签入挂起的更改

如果需要 Team Foundation Build 将任务 DLL 复制到生成计算机,则必须将该任务 DLL 添加到团队项目节点下的源代码管理中。

示例任务

本示例创建一个自定义任务,该任务通过记录由生成产生的文件的大小来扩展与 TFSBuild.proj 文件相关联的生成定义。示例包含两个部分:

  • 任务代码。

  • TFSBuild.proj 文件。

可以在生成日志文件 Buildlog.txt 中查看此任务中记录的信息,该日志文件位于生成放置文件夹中。生成日志包含的信息与下面相似:

总大小为 9216 字节,位于 d:\BuildDir\MyTeamProj\MyBuildType\sources\..\Binaries\Release dir

C# 任务代码

下面的示例包含计算二进制文件总大小的代码,方法是将二进制文件夹中文件的大小相加。

说明:

生成期间所生成的所有二进制文件都位于生成代理上生成目录文件夹的“Binaries”文件夹中。

要将该任务包含在生成中,必须将已编译的 DLL 签入到团队项目文件夹下的源代码管理中。这样可以保证在生成期间,该文件会被复制到生成代理中。

下面的代码计算生成目录的“Binaries”文件夹中存在的二进制文件的大小。解决方案根属性将通过 Team Foundation Build 脚本传递给此任务。

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Framework; 
using Microsoft.Build.Utilities;
using System.Diagnostics;
using System.IO;

namespace BuildTask
{
    public class BinSize : Task
    {
        private string sourceDir;

        [Required]
        public string SourceDir
        {
            get { return sourceDir; }
            set { sourceDir = value; }
        }
        public override bool Execute()
        {
            string szDir = sourceDir + "\\..\\Binaries";
            ProcessDirectory(szDir);
            return true;
        }
        private void ProcessDirectory(string targetDirectory)
        {
            // Process the list of files found in the directory.
            string[] fileEntries = Directory.GetFiles(targetDirectory, "*.*");
            if (fileEntries.Length > 0)
            {
                dwSize = 0;
                szCurrDir = targetDirectory;
                foreach (string fileName in fileEntries)
                    ProcessFile(fileName);
                ////////////////////////////////////////////////////////////////////////
                // This log message would just print out a line in the build log file. 
                // You need to add code to do what you need to do with this data. e.g. 
                // publishing it into the warehouse for reporting. 
                ///////////////////////////////////////////////////////////////////////
                Log.LogMessage("The total size of is {0} bytes in {1} dir",
                    dwSize, targetDirectory);
            }
            // Recurse into subdirectories of this directory.
            string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
            foreach (string subdirectory in subdirectoryEntries)
                ProcessDirectory(subdirectory);
        }
        private void ProcessFile(string path)
        {
            FileInfo fi = new FileInfo(path);
            dwSize = dwSize + fi.Length;
        }
        private long dwSize;
        private string szCurrDir;
    }
}

TFSBuild.proj 文件

一旦将任务编译并签入到源代码管理中,就必须从 TFSBuild.proj 文件调用该任务。在本示例中,应该在已编译了文件且已将所有的二进制文件复制到二进制目录之后,才调用该任务。因此,该任务应该在 BeforeDropBuild 目标中运行。有关 TFSBuild.proj 中可扩展目标的更多信息,请参见了解 Team Foundation Build 配置文件

下面的示例包含已修改的 TFSBuild.proj 文件中的代码。除了位于文件末尾的 UsingTask 元素和 Target 元素之外,该示例 XML 几乎完全是由“MSBuild 项目文件创建向导”生成的。

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="DesktopBuild" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
  <!-- TO EDIT BUILD TYPE DEFINITION

   TODO: Update all of the comments in this file!

   To edit the build type, you will need to edit this file which was generated
   by the Create New Build Type wizard.  This file is under source control and
   needs to be checked out before making any changes.

   The file is available at:
   
       $/{TeamProjectName}/TeamBuildTypes/{BuildTypeName}
       
   where you will need to replace TeamProjectName and BuildTypeName with your
   Team Project and Build Type name that you created

   Checkout the file
     1. Open Source Control Explorer by selecting View -> Other Windows -> Source Control Explorer
     2. Ensure that your current workspace has a mapping for the $/{TeamProjectName}/TeamBuildTypes folder and 
        that you have done a "Get Latest Version" on that folder
     3. Browse through the folders to {TeamProjectName}->TeamBuildTypes->{BuildTypeName} folder
     4. From the list of files available in this folder, right click on TfsBuild.Proj. Select 'Check Out For Edit...'


   Make the required changes to the file and save

   Checkin the file
     1. Right click on the TfsBuild.Proj file selected in Step 3 above and select 'Checkin Pending Changes'
     2. Use the pending checkin dialog to save your changes to the source control

   Once the file is checked in with the modifications, all future builds using
   this build type will use the modified settings
  -->

  <!-- Do not edit this -->
  <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />

  <ProjectExtensions>

    <!-- Team Foundation Build Version - DO NOT CHANGE -->
    <ProjectFileVersion>2</ProjectFileVersion>

    <!--  DESCRIPTION
     TODO: Obsolete.
    -->
    <Description>this one automatically  builds on check in</Description>

    <!--  BUILD MACHINE
     TODO: Obsolete.
    -->
    <BuildMachine>ahetod-test2</BuildMachine>

  </ProjectExtensions>

  <PropertyGroup>

    <!-- Properties set by the build type creation wizard -->
    
    <!--  TEAM PROJECT
     TODO: Obsolete.
    -->
    <TeamProject>TeamProjectName</TeamProject>

    <!--  BUILD DIRECTORY
     TODO: Obsolete.
    -->
    <BuildDirectoryPath>C:\Documents and Settings\user\Local Settings\Temp\1\TeamProjectName\BuildDefinitionName</BuildDirectoryPath>

    <!--  DROP LOCATION
     TODO: Obsolete.
    -->
    <DropLocation>\\UNKNOWN\drops</DropLocation>

    <!--  TESTING
     Set this flag to enable/disable running tests as a post build step.
    -->
    <RunTest>false</RunTest>

    <!--  CODE ANALYSIS
     To change CodeAnalysis behavior edit this value. Valid values for this
     can be Default,Always or Never.

         Default - To perform code analysis as per the individual project settings
         Always  - To always perform code analysis irrespective of project settings
         Never   - To never perform code analysis irrespective of project settings
     -->
    <RunCodeAnalysis>Never</RunCodeAnalysis>

    <!-- Additional Properties -->

    <!--  WorkItemType
     The type of the work item created on a build break - if empty, "Bug" will be used 
     -->
    <WorkItemType Condition=" '$(WorkItemType)'=='' "></WorkItemType>

    <!--  WorkItemFieldValues
     Add/edit key value pairs to set values for fields in the work item created
     during the build process. Please make sure the field names are valid 
     for the work item type being used.
     -->
    <WorkItemFieldValues>Symptom=build break;Steps To Reproduce=Start the build using Team Build</WorkItemFieldValues>

    <!--  WorkItemTitle
     Title for the work item created on build failure 
     -->
    <WorkItemTitle>Build failure in build:</WorkItemTitle>

    <!--  DescriptionText
     Description for the work item created on a build failure 
     -->
    <DescriptionText>This work item was created by Team Build on a build failure.</DescriptionText>

    <!--  BuildLogText
     Additional text for the work item create on a build failure.
     -->
    <BuildlogText>The build log file is at:</BuildlogText>

    <!--  ErrorWarningLogText
     Additional text for the work item create on a build failure 
     -->
    <ErrorWarningLogText>The errors/warnings log file is at:</ErrorWarningLogText>

    <!--  UpdateAssociatedWorkItems
     Set this flag to enable/disable updating associated workitems on a successful build
     -->
    <UpdateAssociatedWorkItems>true</UpdateAssociatedWorkItems>

    <!--  AdditionalVCOverrides
     Additional text for the VCOverrides file generated for VC++ projects
     -->
    <AdditionalVCOverrides></AdditionalVCOverrides>

    <!--  CustomPropertiesForClean
     Custom properties to pass to the MSBuild task while calling the "Clean" target for all solutions.
     The format should be: PropertyName1=value1;PropertyName2=value2;...
     -->
    <CustomPropertiesForClean></CustomPropertiesForClean>

    <!--  CustomPropertiesForBuild
     Custom properties to pass to the MSBuild task while calling the default targets for all solutions.
     The format should be: PropertyName1=value1;PropertyName2=value2;...  To pass custom properties to
     individual solutions, use the Properties metadata item of the SolutionToBuild ItemGroup.
     -->
    <CustomPropertiesForBuild></CustomPropertiesForBuild>

  </PropertyGroup>

  <ItemGroup>
    <!--  SOLUTIONS
     The paths of the solutions to build. To add/delete solutions, edit this
     ItemGroup. For example, to add a solution MySolution.sln, add the following line:
         
         <SolutionToBuild Include="$(BuildProjectFolderPath)\path\MySolution.sln" />

     To change the order in which the solutions are built, modify the order in
     which the solutions appear below.
     
     To call a target (or targets) other than the default, add a metadata item named
     Targets.  To pass custom properties to the solution, add a metadata item named
     Properties.  For example, to call the targets MyCustomTarget1 and MyCustomTarget2,
     passing in properties Property1 and Property2, add the following:
         
         <SolutionToBuild Include="$(BuildProjectFolderPath)\path\MySolution.sln">
             <Targets>MyCustomTarget1;MyCustomTarget2</Targets>
             <Properties>Property1=Value1;PropertyTwo=Value2</Properties>
         </SolutionToBuild>
    -->
    <SolutionToBuild Include="$(BuildProjectFolderPath)/../../SimpleAppToBuild/SimpleAppToBuild.sln">
        <Targets></Targets>
        <Properties></Properties>
    </SolutionToBuild>

  </ItemGroup>

  <ItemGroup>
    <!--  CONFIGURATIONS
     The list of configurations to build. To add/delete configurations, edit
     this value. For example, to add a new configuration, add the following lines:
         
         <ConfigurationToBuild Include="Debug|x86">
             <FlavorToBuild>Debug</FlavorToBuild>
             <PlatformToBuild>x86</PlatformToBuild>
         </ConfigurationToBuild>

     The Include attribute value should be unique for each ConfigurationToBuild node.
    -->
    <ConfigurationToBuild Include="Release|Any CPU">
        <FlavorToBuild>Release</FlavorToBuild>
        <PlatformToBuild>Any CPU</PlatformToBuild>
    </ConfigurationToBuild>

  </ItemGroup>

  <ItemGroup>
    <!--  TEST ARGUMENTS
     If the RunTest property is set to true then the following test arguments will be used to run 
     tests. Tests can be run by specifying one or more test lists and/or one or more test containers.

     To run tests using test lists, add MetaDataFile items and associated TestLists here:
     
        <MetaDataFile Include="$(SolutionRoot)\HelloWorld\HelloWorld.vsmdi">
            <TestList>BVT1;BVT2</TestList>
        </MetaDataFile>

     To run tests using test containers, add TestContainer items here:
     
        <TestContainer Include="$(OutDir)\HelloWorldTests.dll" />
        <TestContainer Include="$(SolutionRoot)\TestProject\WebTest1.webtest" />
        <TestContainer Include="$(SolutionRoot)\TestProject\LoadTest1.loadtest" />

    -->

  </ItemGroup>

  <ItemGroup>
    <!--  ADDITIONAL REFERENCE PATH
     The list of additional reference paths to use while resolving references.
     For example:
     
         <AdditionalReferencePath Include="C:\MyFolder\" />
         <AdditionalReferencePath Include="C:\MyFolder2\" />
    -->
  </ItemGroup> 
 <UsingTask TaskName="BuildTask.BinSize" AssemblyFile="$(SolutionRoot)\tools\BuildTask.dll" />  <Target Name="BeforeDropBuild">    <BinSize SourceDir="$(SolutionRoot)" />  </Target>
  
</Project>

请参见

任务

如何:编写任务

概念

MSBuild

其他资源

自定义 Team Foundation Build