2

ワークスペースに作業フォルダーが 1 つしかないプロジェクトでは、私のビルド スクリプトはうまく機能します。2 つの作業フォルダーを必要とする新しいプロジェクトで作業しているため、以前のスクリプトのすべてのチェックアウトおよびチェックイン コマンドが失敗し、ファイルが見つかりません。

明らかに、私はここでワークスペースの実装の重要な部分を理解していません...私は他のプロジェクトに依存しているプロジェクトを持っています.2番目の作業フォルダーは基本的に、さまざまな公開された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"/>

同じ問題、アセンブリ ファイルが見つかりません...ビルド ログを確認したところ、ビルド フェーズ中にアセンブリ ファイルがチェックアウトされていることがわかります...

タスク「取得」
  TeamFoundationServerUrl="http://pgpd-team01:8080/" BuildUri="vstfs:///Build/Build/1430" Force=True Overwrite=False PopulateOutput=False Preview=False Recursive=True Version="C7564" ワークスペースを取得します="SBN01P-TFS03_61"
<中略>
  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

詳細情報を提供するために、次のコマンドを追加しました。

    <!-- 作業フォルダを報告 -->
    <実行
      Command='$(TfCommand) ワークフォールド'
      WorkingDirectory="$(SolutionRoot)\TEAM-MAIN\Address Finalizer"/>

結果は次のとおりです。

タスク「実行」
  指示:
  "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\..\tf.exe" ワークフォールド
  ================================================== =============================
  ワークスペース: SBN01P-TFS03_61 (tfsservice)
  サーバー : 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/サードパーティ: C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rdパーティ

次の作業ディレクトリが機能することがわかりました。

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

ただし、次の 2 つはそうではありません。2 番目は私の 2 番目の作業フォルダーであることに注意してください。

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

ラベル タスクで発生するエラーが最も役立ちます。

アセンブリ "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.Build.Tasks.VersionControl.dll" から "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): エラー: エラー: ワークスペースを特定できません。

役に立たないチェックアウトからの実際のエラーは次のとおりです。

タスク「実行」
  指示:
  "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\..\tf.exe" チェックアウト AssemblyInfo.cs /recursive
  ワークスペースの C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\Sources\AssemblyInfo.cs に一致するアイテムが見つかりません。
C:\Users\tfsservice\AppData\Local\Temp\InfoTurn\Address Finalizer\BuildType\TFSBuild.proj(280,5): エラー MSB3073: コマンド ""C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE \PrivateAssemblies\..\tf.exe" checkout AssemblyInfo.cs /recursive" はコード 1 で終了しました。
4

2 に答える 2

2

切り離されたワークスペース マッピング + 再帰を同時に使用することができます。ただ注意が必要です。

これは、Foo & Bar 内のすべての C# ファイルを取得します。

$/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 プロパティが等しいことを正確に確認できますか?

/ 編集 /

私が言ったように、ばらばらなマッピングと再帰は、正しく理解するのが非常に難しいです。ファイル仕様とワークスペース定義の微妙な詳細だけでなく、コマンド間でも動作が異なることが判明しました! 私の最初の例とは異なり、これは失敗します:

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

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

まだ混乱していますか?私は TFS チームで数年間働いていました。

さまざまなコメント スレッドからの私の推奨事項をまとめてみましょう。

  • とても気をつけてください。msbuild スクリプトに何かを入れる前に、ビルド マシンにログオンして、全体をテストしてください。インタラクティブにテストすると、より適切なエラー メッセージとより迅速なフィードバックが得られます。あなたがやろうとしていることは非常に壊れやすいので、これは重要です。スクリプトを額面どおりに解釈して、開始するためのいくつかの修正を次に示します。
    • 最良の結果を得るには、チェックアウト タスクでサーバー パスを使用する必要があります。それが修正されたら、$(SolutionRoot)\TEAM-MAIN\Address Finalizer または $(SolutionRoot)\TEAM-MAIN\HH-CAHPS Project\MAINLINE\3rd Party から実行できますが、違いはありません。[残念ながら単純な古い $(SolutionRoot) ではありません -- 上で示したように、Checkout は Get ほどスマートではありません] ローカル itemspec を使用しているときに Address Finalizer から動作するように見えた理由は、実際にはそのローカル ディレクトリの下に一致するファイルがいくつかあるためです。 . おそらく、サードパーティの下に AssemblyInfo.cs ファイルはありません。対照的に、$/InfoTurn/TEAM-MAIN/AssemblyInfo.cs などのサーバー パスを使用すると範囲が広がるため、TFS はすべての TEAM-MAIN を検索して一致するファイルをチェックアウトします。
    • 同様に、作成した Label タスクは、サーバー パスを使用し、直接マップされたフォルダーから実行する必要があります。または、省略形 (W) の代わりに完全修飾バージョン仕様 (Wwsname;domain\wsowner) を使用することもできます。
  • さらに良いことに、そもそもバラバラなワークスペースを使用しないでください。マップされているすべてのローカル パスを見てください。それらの共通の祖先は、それ自体がマップされたフォルダーである必要があります。そうしないと、(a) そこから実行されるコマンドがあいまいになり、追加のパラメーターが必要になるか、またはまったく機能しなくなります (b) 個別にマップされたサブフォルダーから実行されるコマンドは、[サーバー パスを使用しない限り] ワークスペース全体でクエリを実行しません。これをすべて回避するには、1 つのマッピングを「ルート」として選択し、その後のすべてのマッピングがその下のどこかを指すようにします。単一の統一されたルートを確立すると、作業はずっと簡単になります。その内部のどこからでも実行される tf コマンドは、はるかに予測どおりに機能します (初心者と専門家の両方にとって!)。目標を満たす統合ワークスペースをセットアップするには、いくつかの方法があります。

    • 1 つの大きなマッピングに切り替えてから、不要なフォルダーをクローク アウトします。クロークの下でポジティブ マッピングを作成できることに注意してください (たとえば、$/InfoTurn/TEAM-MAIN/HH-CAHPS Project/MAINLINE/3rd Party をマッピングしながら、$/InfoTurn/TEAM-MAIN/HH-CAHPS Project をクロークします)。これにより、きれいなワークスペースが得られ、ファンキーな副作用はありません. 欠点は、関連する作業の量です。フォルダーが大量にある場合は、スクリプトを使用してクロークを作成できますが、それでも、新しいフォルダーが追加されたり、既存のフォルダーの名前が変更されたりすると、それらを最新の状態に保つという問題があります。
    • 現在のマッピングの親であるフォルダーを見つけて、それに 1 レベルのマッピングを作成します。たとえば、1 レベルのマッピング $/InfoTurn/TEAM-MAIN/* -> $(SolutionRoot)\TEAM-MAIN を作成できます。これにより、TEAM-MAIN のすべての直接の子がプルダウンされますが、完全再帰で既に追加した 2 つのフォルダーを除いて、それ以上再帰することはありません。欠点は、いくつかの余分なファイルをダウンロードしてラベル付けすることです。
    • 現在のマッピングを変更して、1 つのフォルダーが別のフォルダーの下にマップされるようにします。たとえば、$/InfoTurn/TEAM-MAIN/Address Finalizer -> $(SolutionRoot) および $/InfoTurn/TEAM-MAIN/HH-CAHPS Project/MAINLINE/3rd Party -> $(SolutionRoot)\3rd Party をマッピングできます。$(SolutionRoot) は、必要なすべてのコードの統合ルートです。このソリューションの問題は、ビルド構成と、ファンキーなマッピングを使用せずに Address Finalizer をビルドしようとする他の構成との間で相対パスが一定であることに依存する makefile が壊れる可能性があることです。
    • サード パーティ フォルダーをソース管理構造内のより自然な場所に移動します。結局のところ、サードパーティ コンポーネントを参照する必要がある TEAM-MAIN で作業しているのはおそらくあなただけではありません。共有リソースをルートに保持し、メイクファイルを適切に作成することに全員が同意した場合、ワークスペースへの深いパスのマッピングに関する問題のほとんどは解消されます。
  • さらに良いことに、ビルド プロセス中にファイルをチェックアウト/チェックインしないでください。真剣に。人間が簡単に対処できる一般的な状況 (ロック、バージョンの競合など) は、考えられるすべてのエッジ ケースを考えると、自動化するのは悪夢です。そして、もしあなたが継続的インテグレーションを使おうとすることがあれば、助けてください...その間、私が本当に何の利益も見られない機能をデバッグしている間、あなたの重要なビルドはすべて壊れています. その代わり:

    • システム全体のすべてのアセンブリ情報 (ビルド番号を含む) を 1 つの AssemblyInfo.cs ファイルに統合します。
    • 各プロジェクトがインポートする共通の MSBuild *.targets ファイルからこの C# ファイルを参照します。(まだ行っていない場合は、プロジェクト レベルのタスクをリファクタリングする良い機会です)。
    • 必要に応じて、チーム ビルドでこの C# ファイルを変更します。たとえば、CoreCompile タスクの前であればいつでもビルド番号を入力できます。ディスク上のものを上書きしているだけであり、ソース管理には触れていないことに注意してください。
    • デスクトップ ビルドにも増分番号を付けたい場合 (個人的には要点がわかりません)、共通の *.targets ファイルに同様のタスクを追加し、チーム ビルドから除外する条件を指定します。
于 2009-11-24T16:27:42.443 に答える
1

私のスクリプトは現在機能しています。問題の原因となっているいくつかの小さな問題がありました。1 つは、多くのコマンドで、コマンドを機能させるために正確な作業ディレクトリ (ローカル フォルダー) を参照する必要があることです。もう 1 つの問題は、プロパティの設定をカスタム タスクに移動して、さらに別のタスクで適切に使用できるようにする必要があることでした。うまくいけば、以下の完全なビルドスクリプトが他の人に役立つことを願っています. これを任意のエディターに貼り付けると、読みやすくなります。

  <!-- バージョン管理に必要なプロジェクト固有の変数をすべて生成します -->
  <プロパティ グループ>
    <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>不明</LabelPath>
  </プロパティ グループ>

  <!-- これを他のビルドのテンプレートとして使用する場合にのみ、プロパティを編集します -->

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

  <ターゲット名="AfterGet">   
    <Message Text="FOOBAR バージョン ファイル: $(VersioningFile)" />
    <Message Text="FOOBAR Working Dir : $(WorkingDirectory)" />

    <!-- 作業フォルダを報告 -->
    <実行
      Command='$(TfCommand) ワークフォールド'
      WorkingDirectory="$(WorkingDirectory)"/>

    <!-- バージョン # を生成 -->
    <CallTarget Targets="GenerateVersion"/>

    <!-- アセンブリのバージョン -->
    <CallTarget Targets="VersionAssemblies"/>      

    <!-- QA の展開を構成する -->
    <CallTarget Targets="ConfigureForQA"/>

    <!-- すべてにラベルを付ける -->
    <CallTarget Targets="LabelWorkingDirectory"/>
    <CallTarget Targets="LabelWorkingDirectory2"/>
  </ターゲット>

  <Target Name="AfterDropBuild">
    <!-- バージョン管理に応じて、デプロイに必要なプロジェクト固有の変数をすべて生成します -->
    <プロパティ グループ>
      <ReleaseDLL>$(DropLocation)\$(BuildNumber)\Release\$(DllName)</ReleaseDLL>
      <PublishedDLL>$(PublishedFolder)\$(DllName)</PublishedDLL>
    </プロパティ グループ>

    <!-- 公開された DLL をチェックアウト -->
    <実行
      Command='$(TfCommand) checkout /lock:checkout "$(PublishedDLL)"'
      WorkingDirectory="$(WorkingDirectory)" />

    <!-- リリースを公開済みにコピー -->
    <コピー
      SourceFiles="$(ReleaseDLL)"
      DestinationFolder="$(PublishedFolder)"/>

    <!-- 公開された DLL をチェックインします -->
    <実行
      Command='$(TfCommand) checkin /override:Automated /noprompt /comment:"$(VersionComment)" "$(PublishedDLL)"'
      WorkingDirectory="$(WorkingDirectory)" />
  </ターゲット>

  <Target Name="GenerateVersion">
    <!-- バージョン ファイルをチェックアウト -->
    <実行
      Command='$(TfCommand) checkout /lock:checkout "$(VersioningFile)"'
      WorkingDirectory="$(SolutionRoot)"/>

    <!-- ファイルのリビジョン # をインクリメントして保存します -->
    <Version VersionFile="$(VersioningFile)" BuildType="None" RevisionType="Increment">
      <Output TaskParameter="Major" PropertyName="Major" />
      <出力 TaskParameter="マイナー" PropertyName="マイナー" />
      <Output TaskParameter="Build" PropertyName="Build" />
      <Output TaskParameter="リビジョン" PropertyName="リビジョン" />
    </バージョン>

    <!-- リビジョンを 3 桁にパディングします。-->
    <プロパティ グループ>
      <PaddedRevision Condition="$(リビジョン) < 1000">$(リビジョン)</PaddedRevision>
      <PaddedRevision Condition="$(リビジョン) < 100">0$(リビジョン)</PaddedRevision>
      <PaddedRevision Condition="$(リビジョン) < 10">00$(リビジョン)</PaddedRevision>
    </プロパティ グループ>

    <!-- ログファイルのバージョン文字列がどのように見えるかを生成します -->
    <CreateProperty Value="Address Finalizer $(Major).$(Minor).$(Build) Build $(PaddedRevision)">
      <Output TaskParameter="Value" PropertyName="ProjectVersion" />
    </CreateProperty>

    <CreateProperty Value="自動ビルド: $(ProjectVersion)">
      <Output TaskParameter="Value" PropertyName="VersionComment" />
    </CreateProperty>

    <Message Text="新しいバージョンは: $(ProjectVersion)"/>

    <!-- バージョン ファイルをチェックインします -->
    <実行
      Command='$(TfCommand) checkin /noprompt /comment:"$(VersionComment)" "$(VersioningFile)"'
      WorkingDirectory="$(SolutionRoot)"/>
  </ターゲット>

  <Target Name="VersionAssemblies">
    <!-- すべてのディレクトリからすべての assemblyinfo ファイルを取得します (1 つのみにする必要があります) -->
    <アイテムグループ>
      <AssemblyInfoList Include="$(SolutionRoot)\**\assemblyinfo.cs"/>
    </ItemGroup>

    <Message Text="FOOBAR ビルド ディレクトリ: $(MSBuildProjectDirectory)"/>
    <Message Text="FOOBAR ソリューション ルート: $(SolutionRoot)"/>
    <Message Text="FOOBAR Working Dir : $(WorkingDirectory)"/>

    <!-- すべての assemblyInfo ファイルをチェックアウトします -->
    <実行
      Command="$(TfCommand) checkout AssemblyInfo.cs /recursive"
      WorkingDirectory="$(WorkingDirectory)"
      ContinueOnError="false"/>

    <!-- すべての assemblyInfo ファイルのバージョン # を変更します -->
    <MSBuild.ExtensionPack.Framework.AssemblyInfo AssemblyFileVersion="$(メジャー).$(マイナー).$(ビルド).$(リビジョン)" AssemblyInfoFiles="@(AssemblyInfoList)"/>
    <MSBuild.ExtensionPack.Framework.AssemblyInfo AssemblyVersion="$(メジャー).$(マイナー).$(ビルド).$(リビジョン)" AssemblyInfoFiles="@(AssemblyInfoList)"/>

    <!-- すべての assemblyInfo ファイルをチェックインします -->
    <実行
      Command='$(TfCommand) checkin /override:Automated /comment:"$(VersionComment)" /noprompt AssemblyInfo.cs /recursive'
      WorkingDirectory="$(WorkingDirectory)"
      ContinueOnError="false"/>
  </ターゲット>

  <Target Name="ConfigureForQA">
    <!-- すべての QA app.config ファイルを取得します (1 つだけにする必要があります) -->
    <CreateItem Include="$(SolutionRoot)\**\app-qa.config">
      <Output TaskParameter="Include" ItemName="AppConfigFiles"/>
    </CreateItem>

    <!-- QA app.config を app.config にコピーして、駆動構成ファイルにします -->
    <コピー
      SourceFiles="@(AppConfigFiles)"
      OverwriteReadOnlyFiles="True"
      DestinationFiles="@(AppConfigFiles->'$(SolutionRoot)\%(RecursiveDir)app%(Extension)')"/>
  </ターゲット>

  <Target Name="LabelWorkingDirectory">
    <Message Text="FOOBAR バージョン: $(ProjectVersion)" />
    <Message Text="FOOBAR コメント: $(VersionComment)" />
    <Message Text="FOOBAR パス : $(LabelPath)" />

    <!-- ワークスペースにラベルを適用 -->
    <ラベル
      TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
      BuildUri="$(BuildUri)"
      Name="$(ProjectVersion)"
      Files="$(作業ディレクトリ)"
      コメント="$(バージョンコメント)"
      ContinueOnError="False"
      Recursive="True" />
  </ターゲット>

  <Target Name="LabelWorkingDirectory2">
    <Message Text="FOOBAR バージョン: $(ProjectVersion)" />
    <Message Text="FOOBAR コメント: $(VersionComment)" />
    <Message Text="FOOBAR パス : $(LabelPath)" />

    <!-- ワークスペースにラベルを適用 -->
    <ラベル
      TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
      BuildUri="$(BuildUri)"
      Name="$(ProjectVersion)"
      Files="$(WorkingDirectory2)"
      コメント="$(バージョンコメント)"
      ContinueOnError="False"
      Recursive="True" />
  </ターゲット>
于 2009-12-02T13:59:20.853 に答える