もくじ
https://tera1707.com/entry/2022/02/06/144447#Azure
やりたいこと
前回の記事で、AzurePipeline練習のための、AzureDevopsの登録、リポジトリの作成までやった。
今回は、Pileineを実際に作成し、中身の処理を書いて、ビルドするところくらいまでやりたい。
前提
- 以下は、2023年5月時点で試したことのメモ。
やったこと
リポジトリにアプリのソリューションをpushする
前回作ったリポジトリに、アプリのコードをpushして、そいつのビルドをパイプラインで行ってみる。
今回は、WinUI3でテンプレートから精製したばかりの中身のないアプリをpushしてみた。 下記のような構造。
パイプラインの作成
「Pipeline」を押す。
最初、こういう画面になる。
「Create Pipeline」を押す。
Gitの種類を聞かれるので、
「Azure Repos Git」を選ぶ。
※今回は、AzureDevOps上のGitでやってみるので、それを選んだ。 「GitHub」を選べば、Githubで作ってるリポジトリでも、pipelineを組める様子。
リポジトリの一覧が出てくるので、
さっき作ったリポジトリ名を選ぶ。
※ここで、さきほど「GitHub」を選んでると、自分のGithubプロジェクトのアドレスを選ぶ画面になり、 選んだGirhubプロジェクトが持ってるリポジトリの一覧が出てくる。それを選べば、GithubのリポジトリでPipeleineできるっぽい。(未検証)
pipelineの種類の選択が出てくるので、
.NET Desktopを選ぶ。(今回、WIinUI3アプリだが、それっぽい選択肢がなかったのでとりあえず)
これで、デフォルトのデスクトップアプリ向けのyamlが生成される。
yaml書く
pipelineをつくると、デフォルトのyamlがリポジトリの先頭フォルダにできてた。
下記のような内容。
# .NET Desktop # Build and run tests for .NET Desktop or Windows classic desktop solutions. # Add steps that publish symbols, save build artifacts, and more: # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net trigger: - main pool: vmImage: 'windows-latest' variables: solution: '**/*.sln' buildPlatform: 'Any CPU' buildConfiguration: 'Release' steps: - task: NuGetToolInstaller@1 - task: NuGetCommand@2 inputs: restoreSolution: '$(solution)' - task: VSBuild@1 inputs: solution: '$(solution)' platform: '$(buildPlatform)' configuration: '$(buildConfiguration)' - task: VSTest@2 inputs: platform: '$(buildPlatform)' configuration: '$(buildConfiguration)'
とりあえず、デフォyamlに書かれてる内容を理解してみる。
また少し+αになるような内容も調べてみる。(デバッグのための出力方法とか)
trigger:
trigger: - main
上記のように書くと、「main」というブランチがpushされたら、pipelineが走る、という意味になる。
trigger: - main - develop/*
と書くと、
- 「main」ブランチ
- 「develop/」が先頭につくブランチ(
develop/bugfix
など)
がpushされたら、パイプラインが走る、という意味になる。
trigger: branches: include: - main - releases/* exclude: - releases/old*
みたいに、複雑な指定もできる。(こういうブランチ名は走らせるけど、こういうブランチ名は走らせない、などを指定できる)
pool:
pipeleine実行に使う仮想マシンを指定する
一覧はこれ
自分はWindowsだけ使えれば今はいいので、windows-latest
でよさそう
No hosted parallelism has been purchased or granted. エラー
パイプラインをrunすると、
No hosted parallelism has been purchased or granted.
というエラーがでて、パイプラインが止まってしまった。
これは、今のAzureパイプラインを利用するには、無料利用枠の登録というのが必要らしく、それを行っていないために出ている様子。
参考
https://rainbow-engine.com/azure-no-hosted-parallelism/
申請ページ
https://aka.ms/azpipelines-parallelism-request
フォームの記入の仕方
https://qiita.com/Hachiyou-Renge/items/2083f2ce9e8b38558805
無料で使えなくなった理由
https://devblogs.microsoft.com/devops/change-in-azure-pipelines-grant-for-private-projects/
23/04/月ころに、上記のページで、自分の作成したorganization「https://dev.azure.com/XXXXXX/」に対して、申請をした。2,3日後にメールがくるはず。
→次の日にメール来た。日本人からすると、怪しい海外メールのような見た目のメールが来た。
pipelineをrunしてみると、下記のような感じで、runできるようになった。
variables:
変数を定義する。
https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/variables?view=azure-pipelines
variables: solution: '**/PipelineTest.sln' buildPlatform: 'x64' buildConfiguration: 'Release'
上記では、「solution」という名前の「**/PipelineTest.sln」という文字列を定義している。他のも同じ。
使うときはこうする。
- script: | echo $(solution)111111 # outputs my value - script: echo ${{variables.solution}} # outputs my value
※ちなみに、**
は「再帰的なワイルドカード」で、この場合だと、すべてのサブディレクトリ内のすべての .sln ファイルを検索する。
*
は「単一フォルダーのワイルドカード」。
また上記ページの例にあるように、
変数は、
- パイプライン全体レベル
- stageレベル
- jobレベル
のように、適する階層に定義できる。
steps:
こちらのぺージにあるように、
https://learn.microsoft.com/en-us/azure/devops/pipelines/get-started/key-pipelines-concepts?view=azure-devops
- Pipeline
- stage
- job
- task
- task
- job
- task
- job
- stage
- job
- task
- job
- task
- job
- stage
のような構造にできる。
- task: NuGetToolInstaller@1
nugetに必要なお作法っぽい。nugetでリストアとかするならとりあえず配置。
- task: NuGetCommand@2
リストアしたければとりあえず下記を書いとく。(下記はslnを渡してるが、csprojでも行けるっぽい)
- task: NuGetCommand@2 inputs: restoreSolution: '$(solution)'
- task: VSBuild@1
「slnをビルドするとき」は、VSBuildでよいらしい。
https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/msbuild-v1?view=azure-pipelines
「csprojをビルドするとき」は、MSBuildがよいらしい。
https://learn.microsoft.com/ja-jp/azure/devops/pipelines/tasks/reference/vsbuild-v1?view=azure-pipelines
- task: VSBuild@1 inputs: solution: '$(solution)' platform: '$(buildPlatform)' configuration: '$(buildConfiguration)'
デバッグ用変数出力
steps: - script: | echo ${{variables.solution}} # outputs my value
もしくは
- task: CmdLine@2 displayName: echo2 inputs: script: 'echo AAAAAAAAAAAAAAAA'
アーティファクトへの出力
ビルドした成果物を、azurepipelineのVMの中から取り出したい場合は、 「アーティファクト」という領域に成果物をコピーしてやらないといけない。
でないと、VMは毎回起動時にリセットされて、さらピンな環境に戻ってしまうので、毎回きれいに忘れてしまう。
アーティファクトに配置するには、下記のコマンドを使う。
- task: PublishPipelineArtifact@1 inputs: targetPath: '$(Build.SourcesDirectory)\' artifact: 'MyArtifact' publishLocation: 'pipeline'
※ただし、これだとソースコード全部をartifactに含めてしまう。しかるべきフォルダだけをtargetPathに指定するように直す必要あり。
非パッケージアプリだと、これでartifactにフォルダごと置く、が最終出力でよさそう。
成果物をartifactに置くときには、
- ソリューションのslnをVSBuildでビルドして、各プロジェクト(csprojなど)の下にできた成果物(bin)の下を、
PublishPipelineArtifact@1
でartifactに上げる - ソリューションのslnをVSBuildでビルドせず、プロジェクトのcsprojを個別にMSBuildでビルドする。その際、共通の出力先フォルダを指定しておき、できたものを
PublishPipelineArtifact@1
で一括でartifactに上げる
などのやり方が考えられる。(やったことあるのは後者の方。でも前者のほうが、パイプラインのスクリプトの量は減りそう。ソリューションの設定が少し面倒かもだが)
パッケージプロジェクトでパッケージを作る方法
パッケージアプリだと、VSでやってた「発行」のようなことをしないといけないかも?
パッケージを作るときのやり方参考。
https://qiita.com/okazuki/items/ef5f3357e2835be8fbdd
上記ではMSBuildを使ってるが、pipelineのタスク「VSBuild」で、wapprojを含むslnをビルドすれば、それだけでwapprojの下の「AppxPackage」フォルダに、msixができてそう。
- task: VSBuild@1 inputs: solution: '$(solution)' platform: '$(buildPlatform)' configuration: '$(buildConfiguration)'
MSBuildを使うときは、
.wapprojに対して、MSBuildでUapAppxPackageBuildModeをStoreUploadにしておけば、storeに挙げるためのパッケージができるっぽい。 →UapAppxPackageBuildModeを指定しなくても、下記でAppxPackageはできた。
- task: MSBuild@1 inputs: solution: '**/*.wapproj' msbuildVersion: '17.0' msbuildArchitecture: 'x64' platform: 'x64' configuration: 'Release'
※storeuploadだと、.msixupload
のファイルができる。パッケージのフォルダの中身自体は、全く同じだった。
.msixupload
のファイルがが必要であれば、UapAppxPackageBuildMode
をStoreUpload
にしておけばよさそう。
パイプラインキャッシュでビルド時間を短縮する
今回は、20個以上のcsproj、vcsprojを含むソリューションをパイプラインでビルド時、nugetパッケージの解決にとにかく時間がかかるということがあったので、下記のページにあるように、nugetパッケージの解決にかかる時間を短縮するためにキャッシュを使った。
https://learn.microsoft.com/ja-jp/azure/devops/pipelines/artifacts/caching-nuget?view=azure-devops
が、キャッシュ機能は、それ以外にも、次回ビルド時にも保存しておきたいものをおいておける様子。(未検証)
https://learn.microsoft.com/ja-jp/azure/devops/pipelines/release/caching?view=azure-devops
下記はサンプルのコードの、キャッシュ部分を抜き出したもの。
- Nugetツールインストールをして、
- キャッシュを行い、
- リストアをする
- ただし、キャッシュがすでにリストアされてないときだけ
という流れで行う。
variables: NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages steps: - task: NuGetToolInstaller@1 displayName: 'NuGet tool installer' - task: Cache@2 displayName: 'NuGet Cache' inputs: key: 'nuget | "$(Agent.OS)" | **/packages.lock.json,!**/bin/**,!**/obj/**' path: '$(NUGET_PACKAGES)' cacheHitVar: 'CACHE_RESTORED' - task: NuGetCommand@2 displayName: 'NuGet restore' condition: ne(variables.CACHE_RESTORED, true) inputs: command: 'restore' restoreSolution: '$(solution)'
※CACHE_RESTORED
は、キャッシュがヒットしたとき(キャッシュを使ったとき)に、Cache@2
タスクがtrueにしてくれるフラグ。
参考情報
AzurePipeline情報源まとめ