.net TFS 2010或msbuild中的触发器配置转换
我试图在持续集成环境中使用 我需要一种方法来告诉TFS构建代理执行转换。我有点希望它在发现配置转换文件(web.qa-release.config、web.production-release.config等)后能够工作。但事实并非如此 我有一个TFS构建定义,用于构建正确的配置(qa版本、生产版本等),我有一些特定的.proj文件,这些文件在这些定义中构建,并且包含一些特定于环境的参数,例如:.net TFS 2010或msbuild中的触发器配置转换,.net,tfs,msbuild,continuous-integration,config,.net,Tfs,Msbuild,Continuous Integration,Config,我试图在持续集成环境中使用 我需要一种方法来告诉TFS构建代理执行转换。我有点希望它在发现配置转换文件(web.qa-release.config、web.production-release.config等)后能够工作。但事实并非如此 我有一个TFS构建定义,用于构建正确的配置(qa版本、生产版本等),我有一些特定的.proj文件,这些文件在这些定义中构建,并且包含一些特定于环境的参数,例如: <PropertyGroup Condition=" '$(Configuration)'==
<PropertyGroup Condition=" '$(Configuration)'=='production-release' ">
<TargetHost Condition=" '$(TargetHost)'=='' ">qa.web</TargetHost>
...
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)'=='qa-release' ">
<TargetHost Condition=" '$(TargetHost)'=='' ">production.web</TargetHost>
...
</PropertyGroup>
qa.web
...
生产网站
...
我从输出中知道正在构建正确的配置。现在我只需要学习如何触发配置转换。是否有一些hocus pocus可以添加到构建中的最终.proj中,以启动转换并清除单个转换文件?您需要做的就是设置TFS构建定义中应使用的配置
在我的例子中,我专门为CI设置了一个配置,然后执行正确的web.config转换。确保您已经添加了“CI”转换文件,您应该可以开始了。我终于成功地实现了这一点。我使用的是TFS 2008,但也使用了MSBuild 4.0,因此它应该适合您 首先,将此导入添加到TFSBuild.proj:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
接下来,添加BeforeDropBuild目标:
<Target Name="BeforeDropBuild">
<TransformXml Source="$(SolutionRoot)\MySite\Web.config"
Transform="$(SolutionRoot)\MySite\Web.QA.config"
Destination="$(OutDir)\_PublishedWebsites\MySite\Web.QA.config.transformed" />
</Target>
然后,您可以将Web.QA.config.transformed复制到需要的任何位置。要在工作流中执行此操作,您必须创建自定义活动。这方面有一篇很好的文章 对于此特定的活动,您需要创建活动项目(将其从.Net 4客户端配置文件更改为.Net 4)并从GAC中引用Microsoft.Build.Framework和Microsoft.Build.Utilities.v4.0,然后从%programfiles%\msbuild\Microsoft\VisualStudio\v10.0\WebApplications中引用Microsoft.Web.Publishing.Tasks 完成后,将添加以下两个类: 首先,有一个存根:
internal class BuildEngineStub : IBuildEngine
{
public bool BuildProjectFile(string projectFileName, string[] targetNames, System.Collections.IDictionary globalProperties, System.Collections.IDictionary targetOutputs)
{
throw new NotImplementedException();
}
public int ColumnNumberOfTaskNode
{
get { throw new NotImplementedException(); }
}
public bool ContinueOnError
{
get { throw new NotImplementedException(); }
}
public int LineNumberOfTaskNode
{
get { throw new NotImplementedException(); }
}
public void LogCustomEvent(CustomBuildEventArgs e)
{
}
public void LogErrorEvent(BuildErrorEventArgs e)
{
}
public void LogMessageEvent(BuildMessageEventArgs e)
{
}
public void LogWarningEvent(BuildWarningEventArgs e)
{
}
public string ProjectFileOfTaskNode
{
get { throw new NotImplementedException(); }
}
}
然后是活动类it本身:
[BuildActivity(HostEnvironmentOption.Agent)]
public sealed class WebConfigTransform : CodeActivity
{
private const string WEB_CONFIG = "Web.config";
private const string WEB_CONFIG_TRANSFORM_FORMAT = "Web.{0}.config";
private IBuildEngine _buildEngine { get { return new BuildEngineStub(); } }
[RequiredArgument]
public InArgument<string> TransformationName { get; set; }
[RequiredArgument]
public InArgument<string> SourceFolder { get; set; }
[RequiredArgument]
public InArgument<string> DestinationFolder { get; set; }
protected override void Execute(CodeActivityContext context)
{
var transformationName = context.GetValue(this.TransformationName);
var sourceFolder = context.GetValue(this.SourceFolder);
var destinationFolder = context.GetValue(this.DestinationFolder);
var source = Path.Combine(sourceFolder, WEB_CONFIG);
var destination = Path.Combine(destinationFolder, WEB_CONFIG);
var destinationbackup = string.Format("{0}.bak", destination);
var transform = Path.Combine(sourceFolder, string.Format(WEB_CONFIG_TRANSFORM_FORMAT, transformationName));
if(!File.Exists(source))
throw new ArgumentException("Web.config file doesn't exist in SourceFolder");
if (!File.Exists(transform))
throw new ArgumentException("Web.config transformation doesn't exist in SourceFolder");
if (File.Exists(destination))
{
File.Copy(destination, destinationbackup);
File.Delete(destination);
}
var transformation = new TransformXml();
transformation.Source = new TaskItem(source);
transformation.Destination = new TaskItem(destination);
transformation.Transform = new TaskItem(transform);
transformation.BuildEngine = _buildEngine;
if (transformation.Execute())
{
File.Delete(destinationbackup);
}
else
{
File.Copy(destinationbackup, destination);
File.Delete(destinationbackup);
}
}
}
[BuildActivity(HostenEnvironmentOption.Agent)]
公共密封类WebConfigTransform:CodeActivity
{
私有常量字符串WEB_CONFIG=“WEB.CONFIG”;
私有常量字符串WEB_CONFIG_TRANSFORM_FORMAT=“WEB.{0}.CONFIG”;
私有IBuildEngine(u buildEngine{get{return new BuildEngineStub();}}
[必需参数]
公共InArgument转换名称{get;set;}
[必需参数]
公共InArgument源文件夹{get;set;}
[必需参数]
公共InArgument目标文件夹{get;set;}
受保护的覆盖无效执行(CodeActivityContext上下文)
{
var transformationName=context.GetValue(this.transformationName);
var sourceFolder=context.GetValue(this.sourceFolder);
var destinationFolder=context.GetValue(this.destinationFolder);
var source=Path.Combine(sourceFolder,WEB\u CONFIG);
var destination=Path.Combine(destinationFolder,WEB_CONFIG);
var destinationbackup=string.Format(“{0}.bak”,destination);
var transform=Path.Combine(sourceFolder,string.Format(WEB\u CONFIG\u transform\u Format,transformationName));
如果(!File.Exists(source))
抛出新ArgumentException(“SourceFolder中不存在Web.config文件”);
如果(!File.Exists(transform))
抛出新ArgumentException(“SourceFolder中不存在Web.config转换”);
if(File.Exists(destination))
{
文件副本(目的地、目的地备份);
文件删除(目的地);
}
var transformation=new TransformXml();
transformation.Source=新任务项(Source);
transformation.Destination=新任务项(Destination);
transformation.Transform=新任务项(Transform);
transformation.BuildEngine=\u BuildEngine;
if(transformation.Execute())
{
文件删除(destinationbackup);
}
其他的
{
文件副本(目标备份,目标);
文件删除(destinationbackup);
}
}
}
之所以使用buildenginesub,是因为TransformXml类使用它来进行日志记录
唯一需要注意的是,TransformXml.Execute函数会锁定源配置文件,直到构建过程完成。我找到了另一种方法来完成此操作,而不是创建自定义活动。您只需要修改正在构建的web应用程序的visual studio项目文件 添加以下内容(可在项目文件末尾找到“AfterBuild”目标的占位符):
然后,只需将/p:IsAutoBuild=“True”
添加到生成定义的“高级”部分中的“MSBuild Arguments”字段中
这将迫使TFS 2010在TFS进行构建时在web.config上进行转换
有关更多详细信息,请访问。这里有一个更简单的答案: 从链接(如果它被移动/404/etc): 下面是我如何解决这个问题的。钥匙 要在上编辑*.csproj文件 网站,并将以下内容添加到 后构建目标(确保移动 结束上面的评论)。这是给你的 我们的网站建设项目团队 基金会服务器
<Target Name="AfterBuild">
<TransformXml Condition="Exists('$(OutDir)\_PublishedWebsites\$(TargetName)')"
Source="Web.config"
Transform="$(ProjectConfigTransformFileName)"
Destination="$(OutDir)\_PublishedWebsites\$(TargetName)\Web.config" />
</Target>
要保留web.debug.config,
web.release.config等。。。从存在
请务必设置“Bu”
<Target Name="AfterBuild">
<TransformXml Condition="Exists('$(OutDir)\_PublishedWebsites\$(TargetName)')"
Source="Web.config"
Transform="$(ProjectConfigTransformFileName)"
Destination="$(OutDir)\_PublishedWebsites\$(TargetName)\Web.config" />
</Target>
/p:UseWPP_CopyWebApplication=true /p:PipelineDependsOnBuild=false
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<UseWPP_CopyWebApplication>True</UseWPP_CopyWebApplication>
<PipelineDependsOnBuild>False</PipelineDependsOnBuild>
</PropertyGroup>
</Project>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<Import Project="ProjectName.custom.targets"/>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<ItemGroup>
<ExcludeFromPackageFiles Include="Scripts\**\*-vsdoc.js;Resources\Scripts\**\-vsdoc.js">
<FromTarget>Project</FromTarget>
</ExcludeFromPackageFiles>
</ItemGroup>