2009-11-24 2 views
2

В проектах, в которых рабочее пространство имеет только одну рабочую папку, мои скрипты сборки отлично работают. Теперь, когда я работаю с новым проектом, который требует 2 рабочих папки, все команды проверки и проверки моего предыдущего скрипта терпят неудачу, и файлы не найдены.Можете ли вы использовать несколько рабочих папок с TFS?

Очевидно, что я не понимаю критическую часть реализации рабочей области здесь ... У меня есть проект, который зависит от других проектов, вторая рабочая папка - это в основном сторонняя папка со ссылками на различные опубликованные файлы DLL и заголовки, необходимые для компиляции моего проекта. Есть 2 активные папки и локальные папки:

 
$(SourceDir)\TEAM-MAIN\Address Finalizer 
$(SourceDir)\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party 

Встроенный код работает отлично, но обычай AfterGet терпит неудачу на следующую запись:

<!-- Check out all of the assemblyInfo files --> 
<Exec Command="$(TfCommand) checkout AssemblyInfo.cs /recursive" 
     WorkingDirectory="$(MSBuildProjectDirectory)\..\sources" 
     ContinueOnError="false"/> 

Проект будет, конечно, работать, если у меня есть одну рабочую папку и переместить источник в достаточно высокую точку, чтобы получить все необходимые файлы, но я не хочу троллить 43 других проекта, чтобы сделать то, что я хочу, пускай с файлами сборки ...

Я также пробовал:

<!-- Check out all of the assemblyInfo files --> 
<Exec Command="$(TfCommand) checkout AssemblyInfo.cs /recursive" 
     WorkingDirectory="$(SolutionRoot)" 
     ContinueOnError="false"/> 

Те же проблемы, не смогли найти сборочные файлы ... Я проверил журнал сборки и я определенно видеть файлы сборки проверить на этапе сборки ...

 
Task "Get" 
    Get TeamFoundationServerUrl="http://pgpd-team01:8080/" BuildUri="vstfs:///Build/Build/1430" Force=True Overwrite=False PopulateOutput=False Preview=False Recursive=True Version="C7564" Workspace="SBN01P-TFS03_61" 
<snip> 
    Getting C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\Address Finalizer\Address Finalizer\Properties\AssemblyInfo.cs;C7525. 

Если у кого есть какие-либо идеи или может указать мне на какую-то статью, чтобы лучше объяснить, как работают несколько рабочих папок, я был бы признателен.

Значения некоторых переменных сборки:

 
MSBuildProjectDirectory: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\BuildType 

SolutionRoot: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources 

предоставить более подробную информацию, я добавил следующую команду:

 
    <!-- Report what our working folders are --> 
    <Exec 
     Command='$(TfCommand) workfold' 
     WorkingDirectory="$(SolutionRoot)\TEAM-MAIN\Address Finalizer"/> 

Результат был:

 
Task "Exec" 
    Command: 
    "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\..\tf.exe" workfold 
    =============================================================================== 
    Workspace: SBN01P-TFS03_61 (tfsservice) 
    Server : http://pgpd-team01:8080/ 
    $/InfoTurn/TEAM-MAIN/Address Finalizer: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\TEAM-MAIN\Address Finalizer 
    $/InfoTurn/TEAM-MAIN/HH-CAHPS Project/MAINLINE/3rd Party: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party 

У меня есть что следующий рабочий каталог будет работать:

 
WorkingDirectory="$(SolutionRoot)\TEAM-MAIN\Address Finalizer" 

Но что следующие два нет, обратите внимание, что вторая моя вторая рабочая папка:

 
WorkingDirectory="$(SolutionRoot)" 
WorkingDirectory="$(SolutionRoot)\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party" 

ошибка, что я получаю для выполнения этой задачи этикетки является наиболее полезным:

 
Using "Label" task from assembly "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.Build.Tasks.VersionControl.dll". 
Task "Label" 
    Label TeamFoundationServerUrl="http://pgpd-team01:8080/" BuildUri="vstfs:///Build/Build/1507" Name="Address Finalizer 2.0.1 Build 039" Recursive=True Comments="Automated build: Address Finalizer 2.0.1 Build 039" Version="W" Child="replace" Files="C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources" 
C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\BuildType\TFSBuild.proj(310,5,310,5): error : Error: Unable to determine the workspace. 

фактическая ошибка из заканчивало, который не является полезным, является:

 
Task "Exec" 
    Command: 
    "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\..\tf.exe" checkout AssemblyInfo.cs /recursive 
    No matching items found in C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\AssemblyInfo.cs in your workspace. 
C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\BuildType\TFSBuild.proj(280,5): error MSB3073: The command ""C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\..\tf.exe" checkout AssemblyInfo.cs /recursive" exited with code 1. 
+0

Каковы ваши рабочие пространства? Team Explorer -> rightclick the build definition -> Edit Build Definition -> вкладка Workspace. –

+0

В конце второго параграфа я описываю две рабочие папки, которые у меня есть. – Shire

+0

Убрал много форматов, предоставил больше информации для отладки. Похоже, что все задачи Exec и Label не работают, потому что они не могут определить рабочее пространство. – Shire

ответ

2

это ро возможно одновременное использование непересекающихся сопоставлений рабочего пространства + рекурсия. Вы просто должны быть осторожны.

Это становится все C# файлы в Foo & Bar:

$/project/dir1/foo -> c:\code\foo 
$/project/dir2/bar -> c:\code\bar 

tf get c:\code\*.cs -recursive 

Это обычно получает все под Foo & Bar, но потерпит неудачу, если рабочий каталог не может быть решен в рабочем пространстве однозначно следует:

$/project/foo -> c:\code1\foo 
$/project/bar -> c:\code2\bar 

tf get $/project/* -recursive 

Это может сработать (то же предостережение, что и выше), но, вероятно, оно не делает то, что вы ожидаете!

$/project/foo -> c:\code1\foo 
$/project/bar -> c:\code2\bar 

tf get c:\code* -recursive 

Существует больше вариантов; поведение зависит от того, как определяется ваше рабочее пространство, а также наличия других рабочих областей на одной машине с аналогичными локальными путями. Можете ли вы точно определить свое определение сборки? Можете ли вы добавить некоторые отладочные операторы, чтобы точно определить, какие значения $ (SolutionRoot) и другие свойства MSBuild равны, когда ваша цель выполняется?

/EDIT/

Как я уже говорил, не пересекающиеся отображения + рекурсией очень сложно получить права. Оказывается, это поведение зависит не только от тонких деталей вашего файла и от определения рабочей области, но также варьируется между командами! В отличие от моего первого примера это не удается:

$/project/dir1/foo -> c:\code\foo 
$/project/dir2/bar -> c:\code\bar 

tf checkout c:\code\*.cs -recursive 

Confused еще? Я, и я работал в команде TFS уже несколько лет!

Позвольте мне вкратце мои рекомендации из различных цепочек комментариев:

  • Будьте очень осторожны. Прежде чем вкладывать что-либо в скрипты msbuild, войдите в систему сборки &. Вы получите более приятные сообщения об ошибках & намного быстрее обратной связи при тестировании в интерактивном режиме. Это важно, потому что то, что вы пытаетесь сделать, довольно хрупкое. Ниже приведены некоторые исправления, которые помогут вам начать работу:
    • Задача Checkout должна использовать путь к серверу для достижения наилучших результатов. Как только это исправлено, вы можете запустить его из $ (SolutionRoot) \ TEAM-MAIN \ Address Finalizer или $ (SolutionRoot) \ TEAM-MAIN \ HH-CAHPS Project \ MAINLINE \ 3rd Party, не имеет значения. [не простой старый $ (SolutionRoot), к сожалению - как показано выше, Checkout не так умна, как Get]. Причина, по которой он, похоже, работал с Address Finalizer при использовании локального набора элементов, состоит в том, что на самом деле у вас есть соответствующие файлы в этом локальном каталоге , Предположительно, у вас нет файлов AssemblyInfo.cs под третьей стороной. Напротив, использование пути сервера, такого как $/InfoTurn/TEAM-MAIN/AssemblyInfo.cs, расширит область действия, чтобы TFS выполнила поиск всей команды TEAM-MAIN для сопоставления файлов для проверки. Вам все равно придется запускать его из рабочего каталога, который однозначно определяет рабочую область - или задает параметры/server и/workspace - так что TFS может ограничить запрос элементами на самом деле в рабочей области и знает, кто их проверяет ,
    • Аналогично, задание Label, которое вы написали, должно использовать путь к серверу + запустить из непосредственно сопоставленной папки. Или вы можете использовать полностью квалифицированный versionpec (Wwsname; domain \ wsowner) вместо сокращения (W).
  • еще лучше, не использовать непересекающиеся рабочее пространство, в первую очередь. Посмотрите на все отображаемые локальные пути: их общий предок должен сам быть сопоставленной папкой.В противном случае (а) команды, запущенные оттуда, будут неоднозначными, требующими дополнительных параметров и/или вообще не работающими (б) команды, запускаемые из отдельно отображенных подпапок, не будут запрашивать во всей рабочей области [если вы не используете пути сервера]. Чтобы избежать всего этого, выберите одно сопоставление как «корень», а затем убедитесь, что все последующие сопоставления находятся где-то под ним. Как только вы создали единый, объединенный корень, все становится намного проще. Команды tf, запущенные из любой точки внутри, будут функционировать гораздо более предсказуемо (для новичков & экспертов!). Существует несколько способов настройки единого рабочего пространства, которое соответствует вашим целям:

    • Вернитесь к одному большому картографированию, затем откройте папки, которые вы не хотите. Обратите внимание, что вы можете создавать позитивные сопоставления под плащами (например, cloak $/InfoTurn/TEAM-MAIN/HH-CAHPS Project, сохраняя при этом отображение $/InfoTurn/TEAM-MAIN/HH-CAHPS Project/MAINLINE/3rd Party). Это оставляет вам приятное чистое рабочее пространство и не вызывает напуганных побочных эффектов. Недостатком является объем работы. Если есть несколько папок, вы можете использовать скрипт для создания плащей, но даже в этом случае проблема заключается в том, чтобы поддерживать их в актуальном состоянии при добавлении новых папок или переименовании существующих.
    • Найдите папку, которая является родителем ваших текущих сопоставлений, и создайте одноуровневое сопоставление с ней. Например, вы можете создать одноуровневое отображение $/InfoTurn/TEAM-MAIN/* -> $ (SolutionRoot) \ TEAM-MAIN. Это приведет к вытеснению всех непосредственных детей TEAM-MAIN, но не рекурсивно, за исключением двух папок, которые вы уже добавили, с полной рекурсией. Внизу есть несколько дополнительных файлов, которые будут загружены &.
    • Измените текущие сопоставления, чтобы одна папка отображалась под другим. Например, вы можете отобразить $/InfoTurn/TEAM-MAIN/Address Finalizer -> $ (SolutionRoot) и $/InfoTurn/TEAM-MAIN/HH-CAHPS Project/MAINLINE/3rd Party -> $ (SolutionRoot) \ 3rd Party. Теперь $ (SolutionRoot) является единым корнем для всего кода, который вам нужен. Проблема с этим решением заключается в том, что он может сломать любые make-файлы, которые полагаются на относительные пути, остающиеся постоянными между вашей конфигурацией сборки и другими, которые также пытаются построить Address Finalizer без использования фанковых сопоставлений.
    • Переместите папку третьей стороны в более естественное место в структуре управления источником. В конце концов, вы, вероятно, не единственный человек, работающий в TEAM-MAIN, которому необходимо обратиться к сторонним компонентам. Если вы все согласились сохранить общие ресурсы в корневом каталоге и соответствующим образом обработать свои файлы, то большинство проблем, связанных с отображением глубоких путей в рабочую область, исчезнут.
  • Даже еще лучше, не Checkout/CheckIN файлов в процессе сборки. Шутки в сторону. Обычные ситуации, которые легко обрабатывать людям (например, блокировки, конфликты версий), - это кошмар для автоматизации всех возможных случаев краев. И бог поможет вам, если вы когда-нибудь попытаетесь использовать непрерывную интеграцию ... Между тем, все ваши важные сборки ломаются, когда вы отлаживаете функциональность, на которую я действительно не вижу никакой пользы. Вместо этого:

    • Консолидируйте всю информацию о сборке всей системы (включая строчную нумерацию) в один файл AssemblyInfo.cs.
    • Ссылка на этот файл C# из общего файла MSBuild * .targets, который импортируется каждым проектом. (Хорошая возможность реорганизовать задачи на уровне проектов, если вы этого еще не сделали).
    • Have Team Build модифицируйте этот файл C# по мере необходимости. Например. вы можете заполнить номер сборки в любое время до задания CoreCompile. Обратите внимание, что мы просто перезаписываем вещи на диске, не касаясь источника управления.
    • Если вы хотите, чтобы ваш рабочий стол также имел инкрементную нумерацию (я лично не вижу смысла), добавьте аналогичную задачу в свой общий файл * .targets с условием, исключающим его из Team Builds.
+0

Задача «Сообщение» FOOBAR MSBuildProjectDirectory: C: \ Users \ tfsservice \ AppData \ Local \ Temp \ InfoTurn \ Address Finalizer \ BuildType Выполнено выполнение задачи «Сообщение». Задача «Сообщение» FOOBAR SolutionRoot: C: \ Users \ tfsservice \ AppData \ Local \ Temp \ InfoTurn \ Address Finalizer \ Sources Выполнено выполнение задачи «Сообщение». – Shire

+0

Get работает нормально, это проверка, которая терпит неудачу, btw ... Я отредактировал settign для своих локальных папок, чтобы сделать его более заметным, что я делаю, поскольку я следую вашему делу # 1 .. – Shire

+0

По-прежнему возникают проблемы с пониманием вашего сценария ... почему вы хотите проверить/проверить файлы во время процесса сборки? Не рекомендуется. Но в любом случае ... Пожалуйста, запустите командную строку под учетной записью службы Team Build. Перейдите в рабочую область. Запустите «tf workfold» - это сообщит о сопоставлениях рабочего пространства. Запустите 'tf prop AssemblyInfo.cs/r' - это проверяет, что файлы отображаются и загружаются так, как вы думаете. Запустите 'tf checkout AssemblyInfo.cs/r' - это сообщит о полном сообщении об ошибке. –

1

Мой сценарий сейчас работает, там было несколько небольших проблем, которые вызывает проблемы. Один из них заключался в том, что для многих команд вам нужно ссылаться на точный рабочий каталог (локальная папка), чтобы команды работали. Другая проблема заключалась в том, что настройка свойств должна была быть перенесена в пользовательскую задачу, чтобы их можно было использовать должным образом еще одной задачей. Поэтому, надеюсь, мой полный скрипт сборки, который приведен ниже, поможет кому-то другому. Вставка этого в любом редакторе упростит чтение.

 
    <!-- Generate all of the project specific variables we will need for versioning --> 
    <PropertyGroup> 
    <VersioningFile>$(SolutionRoot)\TEAM-MAIN\Address Finalizer\Address Finalizer\versionNumber.txt</VersioningFile> 
    <TfCommand>"$(TeamBuildRefPath)\..\tf.exe"</TfCommand> 
    <WorkingDirectory>$(SolutionRoot)\TEAM-MAIN\Address Finalizer</WorkingDirectory> 
    <WorkingDirectory2>$(SolutionRoot)\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party</WorkingDirectory2> 
    <DllName>Address_Finalizer.dll</DllName> 
    <PublishedFolder>$(SolutionRoot)\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party\bin\PG File Import</PublishedFolder> 
    <LabelPath>unknown</LabelPath> 
    </PropertyGroup> 

    <!-- Only edit the properties when usign this as a template for other builds --> 

    <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/> 
    <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/> 

    <Target Name="AfterGet"> 
    <Message Text="FOOBAR Version File: $(VersioningFile)" /> 
    <Message Text="FOOBAR Working Dir : $(WorkingDirectory)" /> 

    <!-- Report what our working folders are --> 
    <Exec 
     Command='$(TfCommand) workfold' 
     WorkingDirectory="$(WorkingDirectory)"/> 

    <!-- Generate the version # --> 
    <CallTarget Targets="GenerateVersion"/> 

    <!-- Version the assemblies --> 
    <CallTarget Targets="VersionAssemblies"/>  

    <!-- Configure the deployment for QA --> 
    <CallTarget Targets="ConfigureForQA"/> 

    <!-- Apply a label to everything --> 
    <CallTarget Targets="LabelWorkingDirectory"/> 
    <CallTarget Targets="LabelWorkingDirectory2"/> 
    </Target> 

    <Target Name="AfterDropBuild"> 
    <!-- Generate all of the project specific variables we will need for deployment, dependant on versioning --> 
    <PropertyGroup> 
     <ReleaseDLL>$(DropLocation)\$(BuildNumber)\Release\$(DllName)</ReleaseDLL> 
     <PublishedDLL>$(PublishedFolder)\$(DllName)</PublishedDLL> 
    </PropertyGroup> 

    <!-- Check out the published DLL --> 
    <Exec 
     Command='$(TfCommand) checkout /lock:checkout "$(PublishedDLL)"' 
     WorkingDirectory="$(WorkingDirectory)" /> 

    <!-- Copy release to published --> 
    <Copy 
     SourceFiles="$(ReleaseDLL)" 
     DestinationFolder="$(PublishedFolder)"/> 

    <!-- Check in the published DLL --> 
    <Exec 
     Command='$(TfCommand) checkin /override:Automated /noprompt /comment:"$(VersionComment)" "$(PublishedDLL)"' 
     WorkingDirectory="$(WorkingDirectory)" /> 
    </Target> 

    <Target Name="GenerateVersion"> 
    <!-- Check out the version file --> 
    <Exec 
     Command='$(TfCommand) checkout /lock:checkout "$(VersioningFile)"' 
     WorkingDirectory="$(SolutionRoot)"/> 

    <!-- Increment the revision # in the file and save it --> 
    <Version VersionFile="$(VersioningFile)" BuildType="None" RevisionType="Increment"> 
     <Output TaskParameter="Major" PropertyName="Major" /> 
     <Output TaskParameter="Minor" PropertyName="Minor" /> 
     <Output TaskParameter="Build" PropertyName="Build" /> 
     <Output TaskParameter="Revision" PropertyName="Revision" /> 
    </Version> 

    <!-- Pad the revision out to 3 digits. --> 
    <PropertyGroup> 
     <PaddedRevision Condition="$(Revision) < 1000">$(Revision)</PaddedRevision> 
     <PaddedRevision Condition="$(Revision) < 100">0$(Revision)</PaddedRevision> 
     <PaddedRevision Condition="$(Revision) < 10">00$(Revision)</PaddedRevision> 
    </PropertyGroup> 

    <!-- Generate what our version string looks like for the logfile --> 
    <CreateProperty Value="Address Finalizer $(Major).$(Minor).$(Build) Build $(PaddedRevision)"> 
     <Output TaskParameter="Value" PropertyName="ProjectVersion" /> 
    </CreateProperty> 

    <CreateProperty Value="Automated build: $(ProjectVersion)"> 
     <Output TaskParameter="Value" PropertyName="VersionComment" /> 
    </CreateProperty> 

    <Message Text="New Version is: $(ProjectVersion)"/> 

    <!-- Check in the version file --> 
    <Exec 
     Command='$(TfCommand) checkin /noprompt /comment:"$(VersionComment)" "$(VersioningFile)"' 
     WorkingDirectory="$(SolutionRoot)"/> 
    </Target> 

    <Target Name="VersionAssemblies"> 
    <!-- Get all of the assemblyinfo files from all of the directories (should only be one) --> 
    <ItemGroup> 
     <AssemblyInfoList Include="$(SolutionRoot)\**\assemblyinfo.cs"/> 
    </ItemGroup> 

    <Message Text="FOOBAR Build Dir : $(MSBuildProjectDirectory)"/> 
    <Message Text="FOOBAR Solution Root: $(SolutionRoot)"/> 
    <Message Text="FOOBAR Working Dir : $(WorkingDirectory)"/> 

    <!-- Check out all of the assemblyInfo files --> 
    <Exec 
     Command="$(TfCommand) checkout AssemblyInfo.cs /recursive" 
     WorkingDirectory="$(WorkingDirectory)" 
     ContinueOnError="false"/> 

    <!-- Change the version # on all of the assemblyInfo files --> 
    <MSBuild.ExtensionPack.Framework.AssemblyInfo AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)" AssemblyInfoFiles="@(AssemblyInfoList)"/> 
    <MSBuild.ExtensionPack.Framework.AssemblyInfo AssemblyVersion="$(Major).$(Minor).$(Build).$(Revision)" AssemblyInfoFiles="@(AssemblyInfoList)"/> 

    <!-- Check in all of the assemblyInfo files --> 
    <Exec 
     Command='$(TfCommand) checkin /override:Automated /comment:"$(VersionComment)" /noprompt AssemblyInfo.cs /recursive' 
     WorkingDirectory="$(WorkingDirectory)" 
     ContinueOnError="false"/> 
    </Target> 

    <Target Name="ConfigureForQA"> 
    <!-- Grab all of the QA app.config files (should only be one) --> 
    <CreateItem Include="$(SolutionRoot)\**\app-qa.config"> 
     <Output TaskParameter ="Include" ItemName ="AppConfigFiles"/> 
    </CreateItem> 

    <!-- Copy the QA app.config to app.config to make it the driving config file --> 
    <Copy 
     SourceFiles="@(AppConfigFiles)" 
     OverwriteReadOnlyFiles="True" 
     DestinationFiles="@(AppConfigFiles->'$(SolutionRoot)\%(RecursiveDir)app%(Extension)')"/> 
    </Target> 

    <Target Name="LabelWorkingDirectory"> 
    <Message Text="FOOBAR Version: $(ProjectVersion)" /> 
    <Message Text="FOOBAR Comment: $(VersionComment)" /> 
    <Message Text="FOOBAR Path : $(LabelPath)" /> 

    <!-- Apply Label on workspace --> 
    <Label 
     TeamFoundationServerUrl="$(TeamFoundationServerUrl)" 
     BuildUri="$(BuildUri)" 
     Name="$(ProjectVersion)" 
     Files="$(WorkingDirectory)" 
     Comments="$(VersionComment)" 
     ContinueOnError="False" 
     Recursive="True" /> 
    </Target> 

    <Target Name="LabelWorkingDirectory2"> 
    <Message Text="FOOBAR Version: $(ProjectVersion)" /> 
    <Message Text="FOOBAR Comment: $(VersionComment)" /> 
    <Message Text="FOOBAR Path : $(LabelPath)" /> 

    <!-- Apply Label on workspace --> 
    <Label 
     TeamFoundationServerUrl="$(TeamFoundationServerUrl)" 
     BuildUri="$(BuildUri)" 
     Name="$(ProjectVersion)" 
     Files="$(WorkingDirectory2)" 
     Comments="$(VersionComment)" 
     ContinueOnError="False" 
     Recursive="True" /> 
    </Target>