2009-12-08 38 views
16

我試圖在持續集成環境中使用configuration transformations在TFS 2010或msbuild中觸發配置轉換

我需要一種方法來告訴TFS構建代理執行轉換。我很希望它能在發現配置轉換文件(web.qa-release.config,web.production-release.config等)後才起作用。但事實並非如此。

我有一個TFS構建定義,可以構建正確的配置(qa-release,production-release等),並且我有一些特定的.proj文件在這些定義中構建,幷包含一些特定於環境的參數例如:

<PropertyGroup Condition=" '$(Configuration)'=='production-release' "> 
    <TargetHost Condition=" '$(TargetHost)'=='' ">qa.web</TargetHost> 
    ... 
</PropertyGroup> 
<PropertyGroup Condition=" '$(Configuration)'=='qa-release' "> 
    <TargetHost Condition=" '$(TargetHost)'=='' ">production.web</TargetHost> 
    ... 
</PropertyGroup> 

我從輸出中知道正在構建正確的配置。現在我只需要學習如何觸發配置轉換。是否有一些可以添加到構建中的最終.proj中的hocus pocus,以啓動變換並吹走各個變換文件?

回答

1

您應該只需要設置哪些配置應該在TFS構建定義中使用。

  1. 轉到團隊資源管理器>構建
  2. 編輯您的構建定義(或新建)
  3. 在「過程」的步驟有對「配置,以打造」設置。

在我的情況下,我已經爲CI設置了專門的配置,然後執行正確的web.config轉換。確保你已經添加了「CI」轉換文件,你應該很好。

+0

另請注意,web.config轉換僅在部署過程中調用,而不是在標準構建過程中調用。 – 2010-05-13 13:44:41

+4

我有一個發佈配置(AnyCpu | Release),但構建中的Web.config不會更改。 – 2011-01-08 00:23:29

+1

這是錯誤的,那些「配置」是構建配置,而不是配置文件。 – Alex 2012-02-06 09:17:46

6

我終於設法得到這個工作。我使用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無論你需要它去。

+0

TFSBuild.proj沒有人在TFS 2010中存在這個問題。他們使用新的基於工作流的構建系統。我還沒有想出如何transofrm web.config,因爲我需要做到這一點... – 2010-05-17 23:40:49

+1

我們剛剛升級到TFS 2010.進行升級的顧問設置了某種向後兼容的工作流程,使用我們現有的TFSBuild。 proj文件。當然我們會後悔的,但現在我們仍然在爲Team Build 2010工作...... – 2010-09-16 20:43:50

+3

實際上,作爲升級過程的一部分,自動安裝了向後兼容的東西。 MS在這種情況下將其留在原地。 – NotMe 2011-01-04 18:40:45

1

要在WorkFlow中執行此操作,您必須創建一個自定義活動。有一個關於它here

相當不錯的文章,你需要創建和活動項目這一特定活動(從.NET 4的客戶端配置文件改變.NET 4中),並引用Microsoft.Build.FrameworkMicrosoft.Build.Utilities.v4.0從GAC然後Microsoft.Web.Publishing.Tasks%PROGRAMFILES%\的MSBuild \微軟\ VisualStudio的\ V10.0 \ web應用(%PROGRAMFILES(X86)如果你在一個64位系統上)。

如果這樣做了,你加入這兩個類:

首先,有一個存根:

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(); } 
    } 
} 

然後那裏有活動類是自我:

[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); 
     } 
    } 
} 

的原因BuildEngineStubTransformXml類使用它來做日誌記錄。

你需要小心的唯一的事情是,TransformXml.Execute功能鎖定源配置文件,直到生成過程完成。

+1

這太複雜了,無法完成已經構建的內容..您可能想要查看接受的答案 – NotMe 2011-01-04 18:41:24

10

我發現了另一種方法來完成此操作,而不是創建自定義活動。您只需修改正在構建的Web應用程序的Visual Studio項目文件。

添加以下(一個爲「AfterBuild」目標占位符都可以對項目文件的末尾找到):

<Target Name="AfterBuild" Condition="$(IsAutoBuild)=='True'"> 
    <ItemGroup> 
     <DeleteAfterBuild Include="$(WebProjectOutputDir)\Web.*.config" /> 
    </ItemGroup> 
    <TransformXml Source="Web.config" Transform="$(ProjectConfigTransformFileName)" Destination="$(WebProjectOutputDir)\Web.config"/> 
    <Delete Files="@(DeleteAfterBuild)" /> 
</Target> 

然後你只需要添加/p:IsAutoBuild="True"對發現的「的MSBuild參數」字段在構建定義的「高級」部分。

當TFS執行構建時,這將迫使TFS 2010在web.config上進行轉換。

更多詳細資料可在Kevin Daly's Blog找到。

5

以下是對您更簡單的答案。 :)

http://social.msdn.microsoft.com/Forums/en-US/tfsbuild/thread/d5c6cc7b-fbb1-4299-a8af-ef602bad8898/

從鏈接(如果它被移動/ 404 /等):

這是我如何解決這一點。關鍵 是編輯 網站上的* .csproj的文件,並添加以下到 AfterBuild目標(一定要移動它上面的 結束註釋)。這是 我們的網站建立項目團隊 基金會服務器。

<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等..被 公佈一定要設置「構建 行動」,在屬性窗口 每個配置轉換 文件爲「無」。只有主 web.config中應該有一個「構建 行動」,「內容」的

一個簡單的方法來編輯的csproj文件 是爲加載了「PowerCommands 爲Visual Studio 2010」或 「生產力電源工具「擴展 到Visual Studio 2010可從 Visual Studio庫。一旦加載了 所有你需要做的就是對 點擊解決方案中的項目 並選擇「卸載項目」。然後你可以再次右擊並選擇 「編輯...」直接編輯csproj文件XML 。然後,當完成正確的 再次點擊並選擇「重新加載 項目」。

+0

除了TFS之外,這還具有與其他構建引擎一起工作的額外優勢 - 例如,我正在使用CC.NET與上切。 – 2012-03-05 23:05:45

6

對於命令行和TFS構建,添加到Visual Studio 2010網站項目中的web.config轉換功能默認是禁用的。

有兩個相對簡單的解決方案:

選項1:編輯構建定義,並添加以下的「的MSBuild參數」字段:

/p:UseWPP_CopyWebApplication=true /p:PipelineDependsOnBuild=false 

UseWPP_CopyWebApplication將導致新的Web發佈管道(WPP)將被激活用於構建。 WPP執行web.config轉換,也可用於阻止諸如.PDB文件之類的內容被複制到bin文件夾。

選項2:MSBuild和WPP都是完全可擴展的。在與項目相同的目錄中創建一個新的XML文件,並使用「.targets」擴展名 - 例如ProjectName.custom.targets。將以下MSBuild代碼放入目標文件中:

<?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" /> 

這些行是C#和Web項目構建過程連接起來的地方。插入一個進口到您的自定義生成擴展(目標文件)的進口CSHARP立即

<Import Project="ProjectName.custom.targets"/> 
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> 
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" /> 

這就是它 - 你是好去。 MSBuild定製方法需要更多的工作來設置,但好處是您可以使用新的目標文件「掛鉤」到構建過程中,並更好地控制在服務器上的構建方式。例如,你可以掛鉤任務來執行CSS和JS壓縮。

我還建議看看「wpp目標」 - 如果你用特定名稱「ProjectName.wpp.targets」命名另一個MSBuild文件,你可以控制整個網站的發佈過程。我們用它來去除的JavaScript文檔文件的發佈網站輸出複製-vsdoc:

<ItemGroup> 
    <ExcludeFromPackageFiles Include="Scripts\**\*-vsdoc.js;Resources\Scripts\**\-vsdoc.js"> 
    <FromTarget>Project</FromTarget> 
    </ExcludeFromPackageFiles> 
</ItemGroup> 

說的一切,你可能會更好過離開從你的構建完全生產web.configs。我們將轉換直接放置到生產部署機器上,並在部署應用程序時使用powershell進行轉換。