AzureDevOpsのCIで.NET CoreとAngularのアプリケーションをバージョンアップする
はじめに
この記事内で使用する各フレームは下記バージョンで構成しています。
- Angular: 9.1.8
- .NET Core: 3.1
また、AzureDevOpsは記事作成時点のキャプチャやコマンドが掲載されています。
この記事を参照されるタイミングによっては
動作しなかったり画面が違うといった可能性がありますのでご留意くださいませ。
モチベーション
アプリケーションのバージョンアップ作業って地味で忘れがちです。
そういった作業は自動で行ってしまいたい!!
と、いうわけでAzure DevOpsのCIフローの中でバージョンアップ作業ができないか試してみました。
僕が主に使用しているのは.NET CoreとAngularのアプリケーションですので
その二つのアプリケーションでバージョンアップを実施するCIを組んでみようと思います。
.NETアプリケーション
.NETのアプリケーションのバージョンアップをCIで実現しようと思います。
.NETアプリケーションのバージョン番号はメジャー.マイナー.ビルド番号.リビジョン
で表現されますが
ビルド番号、あるいはリビジョンに*指定で、ビルド時に自動的にバージョンアップをしてくれます。
なので普通に運用する場合は何も考えなくてもバージョンアップはしてくれるのですが
バージョン付番を独自のルールで運用したり、付番したバージョンをデータストアに格納したりとかしたい場合があります。
なので、今回は独自ルールでバージョンを付番してアプリケーションを発行するCIを構築してみようと思います。
バージョンアップルール
今回は下記のルールでバージョンアップしようと思います
- 2020年6月2日からの経過日数をバージョン番号とする
- ビルドを行った日の00:00からの経過分数をリビジョンとする
.NETアプリケーションのビルドコマンドでバージョン番号を指定できるよう準備
MsBuld.exeを使用してビルドする際のコマンドでカスタムプロパティを指定できます。
そこで、ビルドコマンドのArgumentsでバージョンを変更できるようにします。
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <UseWPF>true</UseWPF> <PublishSingleFile>true</PublishSingleFile> <RuntimeIdentifier>win-x86</RuntimeIdentifier> <!-- バージョン番号のベースの経過日数を受け取る --> <BuildNumber Condition=" '$(BuildNumber)' == '' ">0</BuildNumber> <!-- リビジョンのベースの経過分数を受け取る --> <Revision Condition=" '$(Revision)' == '' ">0</Revision> <!-- バージョンの指定--> <AssemblyVersion>0.0.$(BuildNumber).$(Revision)</AssemblyVersion> <VersionPrefix>0.0.$(BuildNumber).$(Revision)</VersionPrefix> </PropertyGroup> </Project>
これで、MsBuild.exe <プロジェクト> /p:BuildNumber=<適当な数字> /p:Revision=<適当な数字>
でバージョンをコマンド上で指定できるようになりました。
MsBuild.exe <プロジェクト> /p:BuildNumber=1 /p:Revision=2
した結果は下図のとおりです
CIの設定
CIで使用する変数の設定
CIの複数のタスクでバージョン情報を使い回すので、その情報を格納する変数を指定します。
経過日数を格納する$days
と経過分数を格納する$dayinterval
を用意しています。
variables: days: 0 dayinterval: 0
Power Shell
まずはPowerShellでコマンドで指定するバージョン番号とリビジョンを生成しています。
現在日付をゴニョゴニョして、$days
と $dayinterval
変数に格納します。
- 2020年6月2日からの経過日数をバージョン番号とする
- ビルドを行った日の00:00からの経過分数をリビジョンとする
ってことをやっています。
- task: PowerShell@2 displayName: 'Calc Build Version' inputs: targetType: inline script: | $baseDate = [datetime]"06/02/2020" $currentDate = $(Get-Date) $interval = NEW-TIMESPAN -Start $baseDate -End $currentDate $days = $interval.Days Write-Host "##vso[task.setvariable variable=days]$days" echo $days $today = Get-Date -f d $startdate = Get-Date $today $todayinterval = NEW-TIMESPAN -Start $startdate -End $currentDate $dayinterval = [Math]::Truncate($todayinterval.TotalMinutes) Write-Host "##vso[task.setvariable variable=dayinterval]$dayinterval" echo $dayinterval
Write-Host "##vso[task.setvariable variable=<変数名>]<PowerShell内の変数(突っ込みたいValue)>"
で👆で作成した変数に突っ込めます。
このPowershellでは、👆で指定したdays
とdayinterval
に値を突っ込んでいますね。
バージョンの情報を管理しているサービスなんかがある場合は
WebAPIを作成して、Invoke-WebRequest
コマンドを使用して引っ張ってきたり登録したりすればいいかなと思います。
MsBuild
MsBuildで👆で指定したバージョンを指定してビルドを行うコマンドを作成していきます。
- task: MSBuild@1 inputs: solution: '**/<プロジェクト名>/**/*.csproj' configuration: Release msbuildArguments: /t:Publish /p:BuildNumber=$(days) /p:Revision=$(dayinterval)
これはそこまで複雑なことはしていないですね。
PowerShellで設定した変数をMsBuildで使用するカスタムプロパティに指定しています。
実行結果
PowerShellタスクで指定するバージョン情報を出力しています。
Publishされたファイルのバージョンが、Powershellで生成した情報で構成されていることが確認できました。
Angularアプリケーション
普通にWebアプリケーションを作成するだけであれば特に意識する必要はないと思うのですが
ライブラリを作成してPublicなりPrivateなnpmレジストリにPublishしたい場合、バージョンアップは必要な作業です。
基本はnpm version
コマンドでバージョンアップしていけば良いかなと思っています。
バージョンアップルール
今回は下記のルールでバージョンアップしようと思います
master
ブランチのCIはnpm version patch
でパッチバージョンを上げるdevelop
ブランチのCIのときはプレリリースでdev
バージョンとしてリリースするnpm version prepatch --preid=dev
でバージョンを設定する- 参考: npm-version
CIの設定
ちょっとCIの順番と連動していないのですが、行う作業の関連など考慮して順不同で説明しています。
Power Shell
npmコマンドをPowerShellで実行します。
このPowershellコマンドでは下記のことを実行します
npm version
の実行- ライブラリの
package.json
のバージョンを上げたいのでライブラリのディレクトリで行う
- ライブラリの
- バージョン変更をリモートリポジトリにPushする
- そうしないと次回以降も同一のバージョンが生成されてしまうためですね
参考: MS Doc - Run Git commands in a script
参考: MS Doc - Build Azure Repos Git or TFS Git repositories
参考: Stack Overflow - How to increase a version of an npm package using Azure Devops pipeline
先にyamlを掲載すると👇な感じになります。
- task: PowerShell@2 displayName: 'Version Up & Commit' inputs: targetType: inline script: | git config user.name "learn-angular-library-ci Build Service (devtakas-public)" git config user.email "dummy@example.com" $BranchName = "$(Build.SourceBranch)" -replace "refs/heads/" git checkout $BranchName --quiet cd projects\sample-lib npm version $env:VERSIONCOMMAND --preid=dev -m "$env:VERSIONCOMMENT" --force --silent git add . git commit -m "$env:VERSIONCOMMENT" git push --quiet
Script内1~2行目
git config user.name "learn-angular-library-ci Build Service (devtakas-public)" git config user.email "dummy@example.com"
gitにコミットするためにユーザーの情報などを設定しています。
ここは好きな値で問題ないです。
Script内3~4行目
$BranchName = "$(Build.SourceBranch)" -replace "refs/heads/" git checkout $BranchName --quiet
Azure DevOpsのCI実行ログを見ればわかるのですが
ソースコードの操作が行われているブランチは厳密にはCIコマンドで指定したブランチと異なります。
バージョン変更を行ったコミットをPushしたいブランチはCIで指定するブランチなので
環境変数に格納されている作業ブランチをベースに作業ブランチのチェックアウトを行う必要があります。
Script内最後の行まで
cd projects\sample-lib npm version $env:VERSIONCOMMAND --preid=dev -m "$env:VERSIONCOMMENT" --force --silent git add . git commit -m "$env:VERSIONCOMMENT" git push --quiet
作業ディレクトリをライブラリのpackage.jsonがあるところまで移動して諸々作業します。
$env:VERSIONCOMMAND
はAzure DevOpsのCI上で設定する変数です。
masterのCIではpatch
、developのCIではprerelease
を指定しています。
AzureDevOpsのCIでは、rootディレクトリ以外ではnpm version
してもCommitが発生しなかったので
別途 git add .
とgit commit
しています。
警告などでるとAzure DevOpsのCIでエラーを吐いてしまうので
適宜--quiet
や--silent
でエラーにならないように回避しています。
参考: Stack Overflow - How to generate NPM release candidate version
参考: はらへり日記 - npm scriptsでエラーログを表示させたくない話
認証の設定
参考: MS Doc - Run Git commands in a script
AzureDevOpsで管理されているリポジトリに対してPushを行いたいので
ソースを取得する段階で認証情報を設定しちゃいます。
下記で設定可能です。
steps: - checkout: self persistCredentials: true
Trigger
例えばdevelop
ブランチの変更があった場合、develop
ブランチにCommit/Pushが行われます。
つまり、なにも考慮しないと無限ループになります(なった)。
自分は、単純に下記の通り自動変更される対象のファイルをexclude設定にしました。
trigger: branches: include: - develop paths: exclude: - projects/sample-lib/package.json
ここは人により設定が変わりそうなところですね。
ユーザーの設定
CIには実行するユーザーが割り振られています。
なのでそのユーザーがソースコードに対してCommitしたりPushできたりするように設定する必要があります。
参考: MS Doc - Run Git commands in a script
設定場所は下図から確認できます。
Usersの<プロジェクト名> Build Service
という名前に基本なっていると思います。
設定は下記のとおりですね。
Contribute
/Read
- 必須
Create Branch
/Create Tag
- 必要があれば
- リリース時にタグ付けしたいとか、自動コミットじゃなくてブランチとPR作りたいとかの場合かな?と思います
Bypass policies when pushing
- ブランチポリシーで保護しているブランチに対してPushしたい時に必要です。
実行結果
今回はDevOps上のArtifactsにライブラリをPublishしました。
- developブランチのCIの場合
preleaseで出力されていることが確認できます。
- masterブランチのCIの場合
patchで出力されていることが確認できます。
おわりに
今回使用したリポジトリは下記の通りです。
Angularの方はブランチポリシー下の動作検証のためAzure DevOpsでソース管理もしています。
.NET Core
Angular
供養
長く苦しい戦いの記録