.NET でコードカバレッジを収集&レポートする
.NET6 を使ったアプリの開発中にコードカバレッジの収集とレポートを出力しようとしたのですが、地味に情報がまとまっていなかったので残しておこうと思います。
なお、コードカバレッジにはcoverlet.collector
、レポート出力にはReportGenerator
を使用します。
coverlet.collector
はxUnit.NET
が規定で統合しているため、選択肢として挙がりやすいと思います。
開発環境
- Visual Studio 2022
- .NET 6.0.300
- coverlet.collector 3.1.2
- ReportGenerator 5.1.9
使用するソリューション
今回使用するソリューションはシンプルにコンソールアプリとしています。
Coverlet.Sample
プロジェクトに実装コードが含まれていて、Coverlet.Sample.Tests
にテストコードを実装するような構成です。
テストするのは次のようなCalculator
クラスとします。
public class Calculator { public int Add(int x, int y) => x + y; public int Subtract(int x, int y) => x - y; }
ReportGenerator をインストールする
基本的に以下の Microsoft Docs を読めばいいんですが、地味に間違っているのがReportGenerator
のインストールコマンドです。
ドキュメントには次のコマンドが記載されていますが、私のローカル環境で実行したところ失敗しました。
dotnet tool install -g dotnet-reportgenerator-globaltool
こんなメッセージが出力されます。 PS C:\Users\user> dotnet tool install -g dotnet-reportgenerator-globaltool
C:\Users\user\AppData\Local\Temp\xwqllpoi.5zb\restore.csproj : error NU1301: ソース https://pkgs.dev.azure.com/iyemon018/ _packaging/All-Packages/nuget/v3/index.json のサービス インデックスを読み込めません。 ツール パッケージを復元できませんでした。 ツール 'dotnet-reportgenerator-globaltool' をインストールできませんでした。この失敗は次の原因で生じた可能性があります。 * プレビュー リリースをインストールしようとしており、--version オプションを使用してバージョンを指定しなかった。 * この名前のパッケージが見つかったが、.NET ツールではなかった。 * 恐らくインターネットの接続の問題で、必須の NuGet フィードにアクセスできない。 * ツールの名前の誤入力。 パッケージの名前付けの強制を含む他の理由については、https://aka.ms/failure-installing-tool にアクセスしてください
実際にはこちらのページに記載されているコマンドを実行します。
次のコマンドであれば成功すると思います。
dotnet tool install --global dotnet-reportgenerator-globaltool --version 5.1.9
テストを実行する
xUnit.NET
+ coverlet.collect
でテストを実行するだけであれば次のコマンドを実行するだけで問題ありません。
dotnet test --collect:"XPlat Code Coverage"
ただし、出力される XML ファイルをレポートツールに食わせて出力する場合、フォーマットを指定する必要があります。
フォーマットのオプションはcoverlet.collection
のプロジェクトに記載されています。
フォーマットのデフォルトはcobertura
になっているので、今回のケースでは使用しなくてもいいのですが覚えておくと応用が効きます。
cobertura
のフォーマットで実行する場合は次のコマンドを実行します。
dotnet test --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura
データ収集構成を設定ファイルで定義する
コマンドでフォーマットを指定することも可能なのですが、coverlet.collect
ではそれ以外にもデータ収集構成を設定することが出来ます。
このデータ収集構成は XML ファイルとして定義でき、実行時に指定することが出来ます。
チームで開発する場合は、このデータ収集構成の設定ファイルを Git に保存しておけば、どの環境でも同一のレポートを出力することが出来ますし、CI を使って出力する際にも使用できます。
データ収集構成は次のような構成になっています。具体的なそれぞれの項目の意味は、上記のcoverlet.collection
プロジェクトページを参照してください。
<?xml version="1.0" encoding="utf-8" ?> <RunSettings> <DataCollectionRunSettings> <DataCollectors> <DataCollector friendlyName="XPlat code coverage"> <Configuration> <Format>json,cobertura,lcov,teamcity,opencover</Format> <Exclude>[coverlet.*.tests?]*,[*]Coverlet.Core*</Exclude> <!-- [Assembly-Filter]Type-Filter --> <Include>[coverlet.*]*,[*]Coverlet.Core*</Include> <!-- [Assembly-Filter]Type-Filter --> <ExcludeByAttribute>Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute</ExcludeByAttribute> <ExcludeByFile>**/dir1/class1.cs,**/dir2/*.cs,**/dir3/**/*.cs,</ExcludeByFile> <!-- Globbing filter --> <IncludeDirectory>../dir1/,../dir2/,</IncludeDirectory> <SingleHit>false</SingleHit> <UseSourceLink>true</UseSourceLink> <IncludeTestAssembly>true</IncludeTestAssembly> <SkipAutoProps>true</SkipAutoProps> <DeterministicReport>false</DeterministicReport> </Configuration> </DataCollector> </DataCollectors> </DataCollectionRunSettings> </RunSettings>
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura
と同じ構成にする場合は次のようにすればOKです。
<?xml version="1.0" encoding="utf-8" ?> <RunSettings> <DataCollectionRunSettings> <DataCollectors> <DataCollector friendlyName="XPlat code coverage"> <Configuration> <Format>cobertura</Format> </Configuration> </DataCollector> </DataCollectors> </DataCollectionRunSettings> </RunSettings>
あとは次のコマンドを実行すれば設定ファイルを使用してテストの実行とコードカバレッジの収集を実行してくれます。
dotnet test --collect:"XPlat Code Coverage" --settings coverlet.collect.runsettings
レポートを出力する
テストとコードカバレッジ収集を実行すると、テストプロジェクトのフォルダ配下にTestResults
フォルダが作成され、その配下にcoverage.cobertura.xml
ファイルが生成されます。
このファイルを使用して以下のコマンドを実行するとレポートが出力されます。
reportgenerator -reports:"Coverlet.Sample.Tests\TestResults\{guid}\coverage.cobertura.xml" -targetdir:"coveragereport" -reporttypes:Html
レポートはこんな感じで出力されます。
スクリプトで実行できるようにする
コマンドラインで毎回実行するのは時間の無駄なのでテスト実行+コードカバレッジ収集+レポート出力をPowerShell
で実行できるようにします。
今回のソリューションでは次のようにしました。
$runSettings = ".\runsettings.xml" $resultDirectory = ".\.TestResults" $reportsDirectory = ".\.TestReports" if (Test-Path $resultDirectory) { Remove-Item $resultDirectory -Recurse } if (Test-Path $reportsDirectory) { Remove-Item $reportsDirectory -Recurse } dotnet test .\Coverlet.Sample.Tests\Coverlet.Sample.Tests.csproj --collect:"XPlat Code Coverage" --results-directory $resultDirectory --settings $runSettings $xmlFileName = (Get-ChildItem $resultDirectory -Filter *.xml -Recurse -File)[0].FullName reportgenerator -reports:$xmlFileName -targetdir:$reportsDirectory -reporttypes:Html
設定ファイルはrunsettings.xml
に保存しておき、コードカバレッジは.TestResults
フォルダに出力します。
coverlet.collect
はカバレッジ結果の出力フォルダを GUID で生成するため、固定のフォルダ名にすることが出来ません。
仕方ないのでGet-ChildItem
でフルパスを取得するようにしています。
コードカバレッジの収集とレポート出力はあまりキャッチアップしないせいか気がつくと過去のプロジェクトでは使用できなくなっていたりします。 .NET の場合は LTS が GA されたタイミングで定期的に見直していくのが良さそうですね。
(Azure Pipelines) ビルドパイプラインの使用するリソースの値を表示する
Azure Pipelines ではパイプライン外でresources
として定義しているリソースの値があります。
例えば、repositories
を使用すると別サービスのリポジトリをチェックアウトすることも可能になっており、他にもpipelines
やcontainers
などを利用することができます。
<resources
のスキーマ>
resources: pipelines: [ pipeline ] builds: [ build ] repositories: [ repository ] containers: [ container ] packages: [ package ] webhooks: [ webhook ]
スキーマは以下のリンクから抜粋しています。
これらの値を定義することは簡単なのですが、どのようなプロパティがあり、どのような値が設定されているのかはドキュメントを読んでもイマイチピンときません。 今回は偶然?このリソースの値を表示する方法を見つけたので備忘録として残しておきます。
リソースって何?って方は以下のリンクを読んでください。
リソースの値を参照するyaml
結論から先に。 リソースの値を参照するには yaml で以下のように各リソースを JSON へ変換します。
variables: pipelineVar: $[ convertToJson(Pipeline) ] # resources.pipeline properties resourcesVar: $[ convertToJson(resources) ] # resources properties variablesData: $[ convertToJson(variables) ] # variables properties
定義する場所は yaml のルートでもいいですし、stage
やjob
配下でもいいです。
これを定義したビルドを実行すると、以下のようにログ画面からジョブ名→Job preparation parameters
を選択するとリソースの値が JSON 形式で表示されます。
実際には以下のような値が表示されます。
今回はresources
- repositories
で別リポジトリを参照している yaml を利用しました。
なので、他のリソースの値は表示されていません。pipelines
やcontainers
を設定している場合は同様にログに出力されます。
Job preparation parameters Variables: variablesData: Parsing expression: <convertToJson(variables)> Evaluating: convertToJson(variables) Result: '{ "resources.triggeringCategory": "", "resources.triggeringAlias": "", "variablesData": "$[ convertToJson(variables) ]", "pipelineVar": "$[ convertToJson(Pipeline) ]", "resourcesVar": "$[ convertToJson(resources) ]", "system": "build", "system.hosttype": "build", "system.servertype": "Hosted", "system.culture": "en-US", "system.collectionId": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "system.collectionUri": "https://dev.azure.com/<Organization>/", "system.teamFoundationCollectionUri": "https://dev.azure.com/<Organization>/", "system.taskDefinitionsUri": "https://dev.azure.com/<Organization>/", "system.pipelineStartTime": "2021-10-14 23:33:56+09:00", "system.teamProject": "Azure Pipelines Learning", "system.teamProjectId": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "system.definitionId": "21", "build.definitionName": "Azure Pipelines Learning", "build.definitionVersion": "1", "build.queuedBy": "<User Name>", "build.queuedById": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "build.requestedFor": "<User Name>", "build.requestedForId": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "build.requestedForEmail": "<User unique name>", "build.sourceVersion": "xxxxxxxxxxxxxxxxxxxxxxxxxxx", "build.sourceBranch": "refs/heads/master", "build.sourceBranchName": "master", "build.reason": "Manual", "system.pullRequest.isFork": "False", "system.jobParallelismTag": "Private", "system.enableAccessToken": "SecretVariable", "MSDEPLOY_HTTP_USER_AGENT": "VSTS_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "AZURE_HTTP_USER_AGENT": "VSTS_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "build.buildId": "1214", "build.buildUri": "vstfs:///Build/Build/1214", "build.buildNumber": "20211014.20", "build.containerId": "6470472", "system.isScheduled": "False", "system.definitionName": "Azure Pipelines Learning", "system.planId": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "system.timelineId": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "system.stageDisplayName": "__default", "system.stageId": "96ac2280-8cb4-5df5-99de-dd2da759617d", "system.stageName": "__default", "system.stageAttempt": "1", "system.phaseDisplayName": "", "system.phaseId": "d768f2aa-2c4b-5810-be30-11cbf757b796", "system.phaseName": "Job1", "system.phaseAttempt": "1" }' pipelineVar: Parsing expression: <convertToJson(Pipeline)> Evaluating: convertToJson(Pipeline) Result: '{ "startTime": "2021-10-14 23:33:56+09:00" }' resourcesVar: Parsing expression: <convertToJson(resources)> Evaluating: convertToJson(resources) Result: '{ "repositories": { "self": { "id": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "name": "Azure Pipelines Learning", "ref": "refs/heads/master", "type": "Git", "url": "https://dev.azure.com/<Organization>/Azure Pipelines Learning/_git/Azure Pipelines Learning" }, "REPOS1": { "id": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "name": "Repos1", "ref": "refs/heads/master", "type": "git", "url": "https://dev.azure.com/<Organization>/Azure Pipelines Learning/_git/Repos1" } }, "containers": {} }' ContinueOnError: False TimeoutInMinutes: 60 CancelTimeoutInMinutes: 5 Expand: MaxConcurrency: 0
variables の値も表示できる
地味にありがたいのがsystem
やbuild
の値が表示されることですね。
variables
も JSON で出力できるのでコンパイル時点で出力可能な変数については確認することができます。
ドキュメントに記載されていないプロパティも確認できる
例えば、resources
のプロパティって何が定義されているのかドキュメントに記載されていません。
yaml を書く際のプロパティはスキーマのドキュメントにはあるのですが、値を参照するときの情報は皆無で必要になった場合は大変困ります。
このあたりにちょろっと.refs
とかは書かれていますが、その程度です。
この手法を使えばref
やtype
, url
などが取得可能なことがわかります。
resourcesVar: Parsing expression: <convertToJson(resources)> Evaluating: convertToJson(resources) Result: '{ "repositories": { "self": { "id": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "name": "Azure Pipelines Learning", "ref": "refs/heads/master", "type": "Git", "url": "https://dev.azure.com/<Organization>/Azure Pipelines Learning/_git/Azure Pipelines Learning" }, "REPOS1": { "id": "xxxxxxx-xxxxxxx-xxxxx-xxxx-xxxx", "name": "Repos1", "ref": "refs/heads/master", "type": "git", "url": "https://dev.azure.com/<Organization>/Azure Pipelines Learning/_git/Repos1" } },
取得できない値
Agent
Environment
Build
,System
の一部の値
定義済みの変数で上記の値は存在することはわかっていますが、この手法で参照することはできません。
variables
の各変数がどのような値を参照しているかなどは yaml の動作検証やバグ発生時に役立つかもしれません。
あとはresources
- repositories
で別リポジトリを参照している場合に、リポジトリの情報を通知したいシーンなどで、どのプロパティがどのような値か確認する場合にも利用できます(私の場合はこちらの調査で偶然この方法を見つけました)。
(Azure Pipelines)手動トリガー時に Agent.Name を指定して実行する方法
ビルドタスクを Self hosted な環境で実行する場合に、たまに手動トリガーを使うことがあります。 何らかの障害原因調査などで特定のエージェントに対してビルドを実行するようなケースはあります。 そんな要件を満たすにはランタイム パラメータを使用します。
ここでは、ランタイム パラメータを使用して手動トリガー実行時にエージェント名を指定する方法についてまとめています。
Azure Pipelines の Runtime Parameters については以下のリンクを参照してください。
通常の手動トリガー
手動トリガーを使用する場合、パイプラインを実行しようとしても Demands を入力することができないため、特定のエージェントで実行することはできません。 Classic editor だと Demands を設定できるんですが、yaml ではそういった手段は存在しません。
# azure-pipelines.yml trigger: none jobs: - job: steps: - script: echo Hello, world! displayName: 'Run a one-line script'
シンプルな yaml ですが、手動でパイプラインを実行しようとするとこのように Demands を入力することはできません。
Runtime parameters
ランタイムパラメータは、パイプラインを実行する際に値を渡すことができます。 この機能を使うことでパイプラインの実行時にユーザーが動作を制御することができます。
イメージとしては以下のリンクが参考になると思います。
Runtime parameters を使用して Agent.Name を指定する
パイプライン実行時に Agent.Name を指定するには以下のように yaml を書き換えます。
ポイントはparameters
とdemands
部分です。
# azure-pipelines.yml trigger: none parameters: - name: agentName displayName: エージェント名(Option) type: string default: 'any' jobs: - job: pool: name: Self hosted pool demands: - ${{ if ne(parameters.agentName, 'any') }}: - Agent.Name -equals ${{ parameters.agentName }} steps: - script: echo Hello, world! displayName: 'Run a one-line script'
今回は、通常であればエージェントを指定することがなく、特定のシチュエーションのみエージェントを指定するような想定にしました。
人間が使用することを考慮してdisplayName
で分かりやすい表示名をつけておきましょう。
日本語も使用できるのでわかりやすさ重視で良いと思います。
parameters.agentName
の初期値はany
とし、それ以外の値が入力されていればエージェント名と判断しています。
なお、ランタイムパラメータは必須入力のため、default
に何も指定しなかったり空文字だと、以下のように Run ボタンが非活性になります。
分かりやすいdefault
の値を設定しておくのが良いでしょう。
ルートの demands でランタイムパラメータを使用することはできない
yaml のルートにあるpool
- demands
でランタイムパラメータを使おうとしても以下のようなメッセージが出力されて実行できません。
何故かはよくわかってないのですが、必ずjob
あるいはstage
配下のdemads
を使用しましょう。
/azure-pipelines.yml (Line: 16, Col: 5): A mapping was not expected
# azure-pipelines.yml trigger: none parameters: - name: agentName displayName: エージェント名(Option) type: string # ここに書いても動かない。 pool: name: Self hosted pool demands: - ${{ if ne(parameters.agentName, 'any') }}: - Agent.Name -equals ${{ parameters.agentName }} jobs: - job: steps: - script: echo Hello, world! displayName: 'Run a one-line script'
手動トリガーはリリース時などによく使用されると思いますが、状況に応じて動作を制御したい場合にランタイムパラメータは必須になってきます。
他にもvalues
で選択肢を予め設定しておくこともできるので、要件に合わせて柔軟に対応しましょう。
(Azure Pipelines) どういったデータがループ(each in)処理に対応しているのか検証してみる
Azure Pipelines で複数回登場するようなタスクなどを Template にまとめると再利用できるため大変便利です。
Template ではeach in
という構文で反復処理(ループ処理)を行うことができます。
ただ、公式ドキュメントはあまり情報が記載されていないため、どういった方法でループ処理ができるのかよくわからないため、いくつかのパターンでループ処理ができるかどうかを検証してみました。
なお、公式ドキュメントは以下を確認してください。
parameters
に文字列配列を渡してループさせる
テンプレート側のparameters
に文字列配列を渡してループさせることができるかどうかを見てみます。
先に結論から言うとこちらは可能です。
反復処理が可能なのは配列やKey-value pair
(steps
やjobs
など)となっており、これを利用することで繰り返しタスクの実行が可能になっています。
(以下参考)
Templates [Iterative insertion] - Azure Pipelines | Microsoft Docs
ループする場合は配列も可能ということですが、例えば文字列配列をparameters
でテンプレートに渡してループ処理を実行することは可能なのでしょうか?
まずは通常よくあるサンプルから見ていきます。
次のようにiterative-string-template.yml
のparameters
で文字列の配列(実際にはobject
型)を指定してループするような構成です。
非常に単純な構成で、これは成功します。
parameters: - name: values type: object default: - "Azure" - "Pipelines" - "Learning" steps: - ${{ each value in parameters.values }}: - script: echo "call ${{ value }}." displayName: script ${{ value }}
trigger: none pool: vmImage: windows-latest jobs: - job: steps: - template: iterative-string-template.yml
ただ、この構成だとループする要素の数が限られているため、可変長の要素をループさせたいような要件には対応できません。 可変長の要素をループさせるような場合は以下のようにすれば良いのでは?と思い、試してみました。
テンプレート側は以下のように書き換えました。
変わったのはparameters
のdefault
です。
parameters: - name: values type: object default: [] steps: - ${{ each value in parameters.values }}: - script: echo "call ${{ value }}." displayName: script ${{ value }}
呼び出し元の yaml は、以下のようにparameters
に文字列配列を指定するように変更しています。
trigger: none pool: vmImage: windows-latest jobs: - job: steps: - template: iterative-string-template.yml parameters: values: ["Azure", "Pipelines", "Learning"]
結果は以下のように成功しています。 スクリプトの呼び出しだけなのでパット見はわかりませんが…
ただし、これが成功するのはtype
を指定した場合のみ
こちらの方法はあるパターンにおいては失敗します。
それはテンプレート側でparameters
のtype
が指定されていない場合です。
具体的には以下のようなものです。
parameters: - values: [] steps: - ${{ each value in parameters.values }}: - script: echo "call ${{ value }}." displayName: script ${{ value }}
この状態でパイプラインを実行すると以下のようなメッセージが出力されます。yaml Editor で Validate を実行した場合も同様です。
/LearningTemplate/iterative-string-template.yml (Line: 2, Col: 5): Unexpected value 'values'
複雑なデータを渡してループすることもできる
文字列だけなど単一のデータを渡すこともあれば、もっと複雑なデータを渡したいケースはあるかもしれません。 例えば key value pair のような構造のデータを渡してループさせることも可能です。
parameters: - name: keyValuePairs type: object default: [] steps: - ${{ each keyValuePair in parameters.keyValuePairs }}: - script: echo "call ${{ keyValuePair.value.Value }}." displayName: script ${{ keyValuePair.value.Key }}
trigger: none pool: vmImage: windows-latest jobs: - job: steps: - template: iterative-string-template.yml parameters: keyValuePairs: pair1: Key: "number1" Value: "Azure" pair2: Key: "number2" Value: "Pipelines" pair3: Key: "number3" Value: "Learning"
azure-pipelines.yml
からは、Key
とValue
という構造の変数を複数定義しています。
このとき、keyValuePairs
変数は配列のように扱われているようです。
iterative-string-template.yml
では、each
ディレクティブでkeyValuePairs
の反復処理を行い、keyValuePair.value
とすることでpair1
やpair2
のデータを参照しています。
つまり、keyValuePair.value.Value
はループ1回目はkeyValuePair.pair1.Value
を参照し、ループ2回目はkeyValuePair.pair2.Value
を参照していることになります。
データ構造が複雑になるとその分 yaml も可読性が下がりますが、こういった機能が必要になるケースもあるかもしれません。
テンプレートを利用して反復処理をしたいようなケースはよくあると思うので、実際に要件にあった方法が実現できるかどうかは検証してみなければわかりません。 今回試した方法であれば割と柔軟に色々なパターンに適応できると思います。
(Azure Pipelines) 複数リポジトリのチェックアウトステップを試してみた
Azure Pipelines では、yaml
ファイルが含まれているリポジトリとは異なるリポジトリをチェックアウトすることができます。
あるリポジトリが別のリポジトリに依存するような仕組みの場合、この機能を使う必要性があります。
私自身、この機能を使ったことがなかったので使い方をまとめます。
使い方
基本的には上記リンクを参照するのが良いです。 これを書いている時点では以下の Git ホスティングサービスに対応しているようです。(ただし、Azure DevOps Server の場合は Azure Repos のみ対応) Azure Repos の場合、別 Project や別 Organization のリポジトリについても認証さえできればチェックアウトすることができるようです。
- Azure Repos
- GitHub
- GitHubEnterprise
- Bitbucket Cloud
基本的な構文
複数リポジトリを利用する上で必要な定義がいくつかあります。
ひとつはresources
、もうひとつはcheckout
です。
複数リポジトリをチェックアウトする上で必須なのがcheckout
で、それを利用するためにresources
のリポジトリ定義が必要になるイメージです。
スキーマはそれぞれこちらを読めばわかります。
resources
は、複数定義することもできてそれぞれ別サービスからリポジトリをチェックアウトすることもできるようです。
resources: repositories: - repository: <yaml で参照するための名称> type: <Azure Repos の場合は`git`。他にも`github`も指定することができる> name: <リポジトリの名称。`プロジェクト名/リポジトリ名`で指定する> ref: <ブランチ名。`refs/heads/main`のように指定する> endpoint: <異なる Organization の場合はここに接続サービスの名称を記載する> trigger: <CI トリガーが必要な場合はここに定義する>
基本的なresources
の構文としては、これで事足りそうです。
repository
に指定する名称にはアルファベット大文字・小文字、数字とアンダースコア_
のみ使用できます。
name
に指定するリポジトリ名は空白スペースが含まれていても問題ありません。プロジェクト名も同様です。
次にcheckout
です。
checkout
はsteps
ごとに指定することができます。
-checkout: self
の場合は、自分自身、つまりyaml
ファイルのあるリポジトリを指定することになります。
別リポジトリを指定する場合は、resources
の- repository:
で指定した名称を設定します。
チェックアウトパス
チェックアウト後にリポジトリがどこにクローンされるかについては以下のページに記載されています。
挙動としては、リポジトリが単体か複数かによって異なります。
単体か複数かの判断基準はyaml
に定義されたcheckout
に定義したリポジトリの数に依存するようです。
単体リポジトリ構成では変数の$(Agent.BuildDirectory)
のサブフォルダであるC:\agent\_work\1\s
にチェックアウトされます。
複数リポジトリ構成の場合は、$(Agent.BuildDirectory)
のサブフォルダにC:\agent\_work\1\<リポジトリ名>
というフォルダが作られ、その配下にチェックアウトされます。
ここの<リポジトリ名>
はresources
の- repository:
で指定した名称が使われます。
複数リポジトリ構成でチェックアウトパスがデフォルトのままでは都合が悪い場合、path
を指定することで別フォルダへチェックアウトすることができます。
初回のリポジトリチェックアウトの認証
別リポジトリをチェックアウトする際に CI を初めて実行すると、チェックアウトするための承認が必要になります。 詳細は以下のリンクを参照してください。
初回だけの操作にはなりますが、手動で実施しなければならないため注意してください。
PR トリガーの挙動
PR(Pull Request) トリガーをブランチに指定していた場合、PR が作成されるとブランチの source と target を merge した結果が使用されます。
チェックアウトステップを使用した場合でも、PR トリガーを指定したリポジトリが merge した結果を使用するかどうか確認してみました。 イメージとしては以下のような構成です。
PR トリガーを指定するのが Repos1 リポジトリで、yaml
ファイルは Repos2 で管理しているような構成です。
master ブランチに対して feature/xxx のようなブランチを作り、Pull Request を作成するようにしています。
この場合でも、Repos1 PR トリガー実行時には feature/xxx と master を merge していました。
試してみた結果、システム全体で複数のリポジトリを使用する場合に想定されそうな運用パターンは結構網羅できていそうです。 具体的な挙動については実際に動かして確認するしかありませんが、すでにあるリポジトリに後から CI を構成するような場合は重宝しそうです。