Azure DevOpsのパイプラインで `version` という名前の変数を作るとNuGetパッケージ生成で面倒くさいことになった話
はじめに
2021年10月時点の情報です。
参照時期によっては動作が変わっている可能性がありますのでご注意ください。
なにをしようとしていたか
.NETのライブラリプロジェクトをビルドしてNuGetパッケージをビルドしようとしています。
ライブラリのバージョンはPrefix/SuffixをCIコマンド上で指定して外からバージョン情報を変更できるようにしたいと考えています。
そこで、Powershellで取得した値をversion
変数に格納し、その値をmsbuild
タスクのmsbuildArguments
で使おうとしていました。
しかし、このバージョン指定が全く意図したとおりに動きません。
下記は検証を踏まえて作成した再現可能な必要最低限のymlとcsprojファイルの構成なります。
- csproj
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <AssemblyVersion>1.2.3.4</AssemblyVersion> <FileVersion>1.2.3.4</FileVersion> <VersionPrefix>1.2.3</VersionPrefix> </PropertyGroup> </Project>
- CIのyml
trigger: branches: include: - master variables: vmImageOfBuild: windows-latest version: '1.2.34' #👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈 stages: - stage: pre_build displayName: PreBuild jobs: - job: build pool: vmImage: $(vmImageOfBuild) steps: - task: NuGetCommand@2 inputs: command: 'restore' feedsToUse: 'config' includeNuGetOrg: true restoreSolution: 'SampleLibrary/*.sln' - task: MSBuild@1 displayName: 'Build PreProd' inputs: solution: '**/SampleLibrary.csproj' configuration: Release
何が起きるか
csprojで指定したバージョンでNuGetパッケージが生成されてほしいところですが
CIのyamlで作成したversion
変数の1.2.34でNuGetパッケージがリリースされます。タスクでプロパティなどに指定はしていません。まじか。
色々試してみる
VersionPrefixはどうなるのか
csprojの<version></version>
でバージョン指定するとそこで指定されたバージョンでNuGetパッケージが発行されます。
ってことは、同じようにVersionPrefix
を指定したら変わるのでは?ということで試してみました。
variables: vmImageOfBuild: windows-latest # version: '1.2.34' versionprefix: '3.2.1'
これはcsprojで設定したバージョンで生成してくれました。
versionprefix
/ versionPrefix
/ VersionPrefix
など試してみましたが変わらなかったので、影響があるのはversion
変数だけのようです。
msbuild
タスクだけなのか
おそらく一番良く使うdotnet
タスクでも同様の現象は発生するのでしょうか?
csprojの構成はそのままに、ymlを下記のように変更してみました。
trigger: branches: include: - master variables: vmImageOfBuild: windows-latest version: '1.2.34-dev.0' stages: - stage: pre_build displayName: PreBuild jobs: - job: build pool: vmImage: $(vmImageOfBuild) steps: - task: DotNetCoreCLI@2 inputs: command: 'restore' projects: '**/*.csproj' - task: DotNetCoreCLI@2 inputs: command: 'build' projects: '**/*.csproj'
結果、パッケージのバージョンは書き換わりました。タスクは関係なく書き換わりそうです。
csprojでバージョン指定しなければどうなるだろうか
csprojのXML内からバージョン指定部分をごっそり消して下記のような構成にしてみました。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <GeneratePackageOnBuild>true</GeneratePackageOnBuild> </PropertyGroup> </Project>
この状態でも書き換わったので、csprojの構成内容に関わらずversion
を指定するとライブラリのバージョンが書き換わるようです。
まとめ
事前定義済み変数でもなさそうですし 、そもそもタスクでプロパティ指定していないのにVariable指定で勝手に書き換わるというのもどうにもバグ臭いです。
まぁPrefix/Sufixを外部から指定する方法面倒くさいっちゃ面倒くさいので楽にできるのはありがたいのですが、さすがにこれは…
フィードバックは投げますが、事前定義済み変数など触りの部分しか調べていないので、これが仕様とわかる何かがあれば教えていただきたいです🙇♂️
と、いうわけで現状version
変数を使用する場合は注意しましょう。というか使わないほうが無難かと思います。
他の変数でも同様の現象が発生する可能性も(めちゃ低いとは思いますが)ありますので、どうしても意図と違う動作から抜け出せないときは変数の名前を変更してみると、なにかヒントが得られるかもしれませんね。
パイプライン結果、検証で使用したソースコードなどは下記から確認可能です。