преобразование конфигурации запуска в 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 в сборке, чтобы запустить преобразование и сдуть отдельные файлы преобразования?


person grenade    schedule 08.12.2009    source источник


Ответы (6)


Все, что вам нужно сделать, это указать, какая конфигурация должна использоваться в определении сборки TFS.

  1. Перейти к Team Explorer> Сборки
  2. Отредактируйте определение сборки (или создайте новое)
  3. На этапе «Процесс» есть настройки для «Конфигурации для сборки».

В моем случае я настроил конфигурацию специально для CI, которая затем выполняет правильные преобразования web.config. Убедитесь, что вы добавили файл преобразования «CI», и все готово.

person Wallace Breza    schedule 11.05.2010
comment
Также обратите внимание, что преобразования web.config вызываются только во время развертывания, а не во время стандартных сборок. - person Wallace Breza; 13.05.2010
comment
У меня есть конфигурация выпуска (AnyCpu | Release), но файл Web.config в сборке не меняется. - person Juan Zamudio; 08.01.2011
comment
Это неправильно, эти конфигурации являются конфигурациями сборки, а не файлами конфигурации. - person Alex; 06.02.2012

Я нашел другой способ сделать это вместо создания настраиваемого действия. Вам просто нужно изменить файл проекта 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 2010 выполнять преобразования в файле web.config, когда TFS выполняет сборку.

Более подробную информацию можно найти в блоге Кевина Дейли.

person Josh Gerdes    schedule 10.02.2011

Мне наконец удалось заставить это работать. Я использую 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 туда, куда вам нужно.

person Rohan Singh    schedule 12.05.2010
comment
TFSBuild.proj не существует в TFS 2010, к которому относится и этот вопрос. Они используют новую систему сборки на основе рабочего процесса. Я еще не понял, как преобразовать web.config, так как мне нужно это сделать ... - person Steve Ward; 18.05.2010
comment
Мы только что обновились до TFS 2010. Консультант, выполнявший обновление, настроил своего рода рабочий процесс обратной совместимости, который пока использует наши существующие файлы TFSBuild.proj. Конечно, мы пожалеем об этом позже, но это все еще работает для нас с Team Build 2010 ... - person Rohan Singh; 17.09.2010
comment
Фактически, компонент обратной совместимости был автоматически установлен как часть процесса обновления. MS оставила его на месте как раз для этого сценария. - person NotMe; 04.01.2011

Функциональность преобразования web.config, которая была добавлена ​​к проектам веб-сайтов в Visual Studio 2010, по умолчанию отключена для сборок командной строки и TFS.

Есть два относительно простых решения:

Вариант 1. Измените определение сборки и добавьте следующее в поле «Аргументы MSBuild»:

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

UseWPP_CopyWebApplication вызовет активацию нового конвейера веб-публикации (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 # и веб-проекта. Вставьте импорт в собственные расширения сборки (целевой файл) непосредственно перед импортом 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» - если вы назовете другой файл MSBuild с конкретным именем «ProjectName.wpp.targets», вы сможете контролировать весь процесс публикации веб-сайта. Мы используем его для удаления файлов документации javascript -vsdoc при копировании опубликованного веб-сайта:

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

Все сказано, вам, вероятно, лучше полностью исключить рабочий файл web.configs из своей сборки. Мы размещаем преобразования непосредственно на нашей производственной машине развертывания и используем PowerShell для преобразования при развертывании приложения.

person ShadowChaser    schedule 02.06.2011

Вот вам ответ проще. :)

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

По ссылке (на случай, если он будет перемещен / 404 / и т. Д.):

Вот как я это решил. Ключ состоял в том, чтобы отредактировать файл * .csproj на веб-сайте и добавить следующее в цель AfterBuild (обязательно переместите конечный комментарий над ним). Это для нашего проекта сборки веб-сайта в Team Foundation Server.

<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» или «Productivity Power Tools» для Visual Studio 2010, доступное в галерее Visual Studio. После загрузки все, что вам нужно сделать, это щелкнуть правой кнопкой мыши проект в вашем решении и выбрать «Выгрузить проект». Затем вы можете снова щелкнуть правой кнопкой мыши и выбрать «Изменить ...», чтобы напрямую отредактировать XML-файл csproj. Затем, когда закончите, просто щелкните правой кнопкой мыши еще раз и выберите «Перезагрузить проект».

person captain numerica    schedule 10.03.2011
comment
Это дает дополнительное преимущество работы с другими механизмами сборки, кроме TFS - например, я использую CC.NET с Uppercut. - person David Keaveny; 06.03.2012

Для этого в WorkFlow вам необходимо создать настраиваемое действие. Об этом есть неплохая статья здесь

Для этого конкретного действия вам необходимо создать проект Activity (изменить его с .Net 4 Client profile на .Net 4) и указать Microsoft.Build.Framework < / strong> и Microsoft.Build.Utilities.v4.0 из GAC, а затем Microsoft.Web.Publishing.Tasks из % programfiles% \ msbuild \ Microsoft \ VisualStudio \ v10.0 \ WebApplications (% 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);
        }
    }
}

Причина использования BuildEngineStub заключается в том, что класс TransformXml использует его для ведения журнала.

Единственное, что вам нужно быть осторожным, это то, что функция TransformXml.Execute блокирует исходный файл конфигурации до завершения процесса сборки.

person gislikonrad    schedule 04.01.2011
comment
Это слишком сложно делать что-то, что уже встроено ... Возможно, вы захотите увидеть принятый ответ - person NotMe; 04.01.2011