演练:通过自定义任务自定义 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)。
注册自定义任务
打开 TFSBuild.proj 文件。
将 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"/>
保存该文件。
运行自定义任务
现在已创建并注册了任务,您必须在生成过程中指定要运行该任务的点。
运行任务
确定生成过程中要运行自定义任务的位置。
有关可以扩展生成过程的位置的更多信息,请参见 了解 Team Foundation Build 配置文件。
打开 TFSBuild.proj,并添加前面所选的 Target 元素。
添加 task 元素,以在 Target 元素中运行任务。
例如,下面 TFSBuild.proj 中的 XML 在 BeforeGet 目标中运行 SimpleTask 任务,该目标紧靠 Get 目标之前运行。
<Target Name="BeforeGet"> <SimpleTask /> </Target>
保存该文件。
签入文件
必须签入 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>