vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

【ASP.NET Core】Azure Pipelines でコンティニュアスにインテグレーションしてみる その2

はじめに

※ 2019/01/12 更新

  • Azure Pipeline → Azure Pipelines に修正しました。
  • Agent は VM など実行環境上にインストールされているもの、という内容に沿うよう修正しました。

さぁ年も明けましたのでね。張り切っていつも通りぼちぼちとやっていきたいと思います。

前回触れたジョブを実行する Agent から、気になったものをあれこれ調べてみることにします。

Agent について

まずは設定したジョブを実行する環境と Azure Pipelines を連携する Agent から。

Agent は実行環境であるマシン上にインストールされているものです。

以前 Unity プロジェクトをビルドしようとしたときに登録した、自前のマシンを使う Self-hosted agents と、 Microsoft が提供する VM 上で動く Microsoft-hosted agents があります。

ちなみにこれ、下記でいう The Microsoft Azure Virtual Machine Agent が指しているものと同じでしょうか。
(なんか微妙に違う気はします)

なおプロジェクトで使用できる Agent は下記で見ることができます。

https://dev.azure.com/ユーザー名/_settings/agentpools

Microsoft-hosted agents に何がインストールされているかは、上記サイトで Agent を選択 -> Details から見ることができます。

f:id:mslGt:20190105101809j:plain

動きとしては、 Pipeline 実行のたびに新規で VM (Agent がインストールされている) が用意され、 Pipeline の処理が終了するとともに破棄されるとのこと。

前回実行した内容を使って。。。といったことはできないので、設定などの準備を毎回実行するか、 Self-hosted agents として自前で用意するか、という判断となります。

なお上記ページでは Self-hosted agents と比べて Microsoft-hosted agents を強力にプッシュしています。

これは、特に初心者だと自前のホストでやろうとすると色々失敗するでしょ?まずは用意されたものを使ってみ?という意味なのか、 Self-hosted agents の方が Microsoft-hosted agents より Azure ?にかかる負荷が大きい、といった意味なのでしょうか。

といった、どっちでも良いことを考えたり考えなかったりしました。

OAuth token

これも Microsoft Docs で読んだ内容ですが、 Azure Pipelines と Agent との連携はこんな感じだそうです。

  1. Azure Pipelines から Agent を Agent pool に追加
  2. 1.の時 Agent では listener OAuth token をインストールし、ジョブの Queue を待ち受ける
  3. Pipeline 実行時、 Agent は Queue からジョブのリクエストを受ける
  4. 3 の時、 job-specific OAuth token をダウンロードする
  5. ジョブを実行する
  6. ジョブが完了したら、 job-specific OAuth token を破棄し、 Agent は 2 の状態に戻る

2.の時?に実行環境である VM を用意するステップがあるはずなのですが、調べただけだとよくわかりませんでした orz

ビルドの流れ

Azure Pipelines と Agent の流れはわかったようなわからないような状態となりましたが、そもそも GitHub に対して Pull Request や Push を送ったあとビルドが完了するまで、というのはどのような流れとなっているのでしょうか。

  1. Azure Pipelines から GitHub を監視?
  2. ユーザーが GitHub に Pull Request を送る
  3. Azure Pipelines が 2 を受け取り、ジョブの Queue を実行
  4. VM を用意する
  5. Queue はジョブのリクエストを発行する
  6. Agent がリクエストを受け取り、 job-specific OAuth token をインストール
  7. Agent でジョブを実行
  8. ジョブが完了したら Agent から Azure Pipelines にログとともに通知
  9. ジョブ完了後の処理として job-specific OAuth token の破棄などを行う
  10. Agent は次のジョブリクエストを待ち受ける
  11. 全ジョブが完了したら Agent を破棄する? または作り直す?

ところどころよく分かっていませんが、こういうことのようです。

結局 Azure Pipelines は何をしているのか

GitHub に Pull Request や Push が飛んでくるのを監視するのと(これは本当に Azure Pipelines がやっているのかわかりませんが)、ジョブの Queue を実行する、 Agent を管理する、といったことをしています。

つまり、ビルドやテストといった、実際に実行したい内容は(今回の場合) dotnet など他のソフトウェアが実行する、ということです。

ということは、あくまで Azure Pipelines として考えるべきことは、(ビルドやテストなどの)やりたいことをどう呼び出すか、ということとなります。

これは Azure Pipelines に限らず CI/CD ツールを使う上で大切。。。だったりしないのかなぁ。

topic ブランチのビルド設定を追加する

さて、そろそろ実際に動かしてみることにします。

master ブランチのみで開発し続けるのであれば、ローカルでの変更を Push していくだけでビルドされていくのですが、通常ブランチを切って( Microsoft Docs にならって topic ブランチと呼ぶことにします) 開発 -> Pull request -> merge という流れになるかと思います。

が、デフォルトの設定だとビルドの対象は master のみになっており、 topic ブランチの変更を Push してもビルドされません。

また、テストを追加したとしても自動で実行はされません。

ということでこれを変更してみます。
(テストの中身はこちらを参照)

azure-pipeline.yml

~省略~

trigger:
- master
- features/*

pool:
  vmImage: 'Ubuntu-16.04'

variables:
  buildConfiguration: 'Release'

steps:
- script: dotnet build --configuration $(buildConfiguration)
  displayName: 'dotnet build $(buildConfiguration)'
- script: dotnet test
    displayName: 'dotnet test'

pr:
- master
- features/*

最後の pr (Pull Request ビルド対象のブランチ指定)は何となく入れましたが、今回の場合特に意味はないです。

Shell script を実行する

Pull request を送ったあと、 master 側でテストが通ったら自動でマージするようにできないのかな?と思いました。

ということで調べたところ、 Azure Pipelines にはそのような機能がないようです。

これを見るとちょうどマージについて書かれているため、これを試してみることにします。

とりあえず Pull request がきたら、などの条件は置いておくことにします。

上記ページでは bat を使っていますが、実行環境を Ubuntu にしているので Shell script で試してみることにしました。

azure-pipeline.yml

~省略~
steps:
  - script: dotnet build --configuration $(buildConfiguration)
    displayName: 'dotnet build $(buildConfiguration)'
  - script: dotnet test
    displayName: 'dotnet test $(buildConfiguration)'
  - task: ShellScript@2
    inputs:
      scriptPath: git_merge.sh
    displayName: 'git merge'

~省略~
  • task につけられる名前は決まっているようで、今回の場合「ShellScript@2」以外の名前を付けるとエラーとなってしまいました。

ログを見ると、この名前によって Shell script であること、またそのバージョンを指定しているようでした ( Shell scirpt 2.1.3 )。

これで Shell script 自体は実行できます。

で、先ほどのページの Git コマンドをちょっと変更してこのようにしてみました。

git_merge.sh (ちゃんと動きません)

#!/bin/bash

echo SOURCE BRANCH IS %BUILD_SOURCEBRANCH%
if [%BUILD_SOURCEBRANCH% == refs/heads/master]; then 
   echo Building master branch so no merge is needed.
   exit
else
   echo merge
fi

set sourceBranch=origin/%BUILD_SOURCEBRANCH:refs/heads/=%
echo GIT CHECKOUT MASTER
git checkout master
echo GIT STATUS
git status
echo GIT MERGE
git merge %sourceBranch% -m "Merge to master"
echo GIT STATUS
git status
echo GIT PUSH
git push origin
echo GIT STATUS
git status

これを動かすと、下記のようなログが出て、マージはできませんでした。

2019-01-05T00:28:26.6264228Z ##[section]Starting: git merge
2019-01-05T00:28:26.6267544Z ==============================================================================
2019-01-05T00:28:26.6268233Z Task         : Shell Script
2019-01-05T00:28:26.6268617Z Description  : Run a shell script using bash
2019-01-05T00:28:26.6268730Z Version      : 2.1.3
2019-01-05T00:28:26.6268870Z Author       : Microsoft Corporation
2019-01-05T00:28:26.6269023Z Help         : [More Information](https://go.microsoft.com/fwlink/?LinkID=613738)
2019-01-05T00:28:26.6269214Z ==============================================================================
2019-01-05T00:28:26.7689506Z [command]/bin/bash /home/vsts/work/1/s/git_merge.sh
2019-01-05T00:28:26.7756106Z SOURCE BRANCH IS %BUILD_SOURCEBRANCH%
2019-01-05T00:28:26.7756449Z merge
2019-01-05T00:28:26.7756637Z GIT CHECKOUT MASTER
2019-01-05T00:28:26.7761605Z /home/vsts/work/1/s/git_merge.sh: line 4: [%BUILD_SOURCEBRANCH%: command not found
2019-01-05T00:28:26.7761996Z Previous HEAD position was 6105b3a Merge 55ac9c46fb679fef7f3f320765ded4d28e0b04c4 into feb1bcd92a0559c5242b4717b9c11a9a25246217
2019-01-05T00:28:26.7772812Z Switched to a new branch 'master'
2019-01-05T00:28:26.7773575Z Branch 'master' set up to track remote branch 'master' from 'origin'.
2019-01-05T00:28:26.7777038Z GIT STATUS
2019-01-05T00:28:26.7797446Z On branch master
2019-01-05T00:28:26.7798997Z Your branch is up to date with 'origin/master'.
2019-01-05T00:28:26.7799536Z 
2019-01-05T00:28:26.7799811Z nothing to commit, working tree clean
2019-01-05T00:28:26.7801985Z GIT MERGE
2019-01-05T00:28:26.8195510Z merge: %sourceBranch% - not something we can merge
2019-01-05T00:28:26.8198696Z GIT STATUS
2019-01-05T00:28:26.8218335Z On branch master
2019-01-05T00:28:26.8219258Z Your branch is up to date with 'origin/master'.
2019-01-05T00:28:26.8219608Z 
2019-01-05T00:28:26.8219959Z nothing to commit, working tree clean
2019-01-05T00:28:26.8221844Z GIT PUSH
2019-01-05T00:28:28.0116218Z fatal: could not read Username for 'https://github.com': No such device or address
2019-01-05T00:28:28.0137902Z GIT STATUS
2019-01-05T00:28:28.0165334Z On branch master
2019-01-05T00:28:28.0165914Z Your branch is up to date with 'origin/master'.
2019-01-05T00:28:28.0166050Z 
2019-01-05T00:28:28.0166150Z nothing to commit, working tree clean
2019-01-05T00:28:28.0312914Z ##[section]Finishing: git merge

やっぱりまるっとコピーするだけでは無理か。。。

すみませんでした、ということで、VMImage を vs2017-win2016 に変更して、 bat ファイルを実行してみることにしました。

azure-pipeline.yml

~省略~
pool:
  vmImage: 'vs2017-win2016'

steps:
  - script: dotnet build --configuration $(buildConfiguration)
    displayName: 'dotnet build $(buildConfiguration)'
  - script: dotnet test
    displayName: 'dotnet test $(buildConfiguration)'
  - task: ShellScript@2
    inputs:
      scriptPath: git_merge.sh
    displayName: 'git merge'

~省略~

が、今度はバージョンの違いからか dotnet build で失敗する。。。(´・ω・`)

ということで、これはいったん保留とします。

Shell script の方で、要はアカウントの指定ができていないということだと思うので、ここをもう少し調べてみることにします。

まぁそもそも、自動でマージする機能がどこまで必要か?というところは考える必要があるとは思いますが。。。

参照