noxi雑記

.NET、Angularまわりの小ネタブログ

Azure Pipeline内でソースを更新してPull Requestを自動生成する

仕事の関係で GitHub Actions よりも Azure Pipeline を色々と試しています。
AutoRest クライアントをパイプラインで自動的に更新しつつ Pull Request を作成して投げるものを作ったのでメモを書き残します。



パイプラインの構成

今回作成したパイプラインは

  1. Git Checkout して
  2. UseNode して
  3. UseDotNet して
  4. AutoRest 生成用の OpenAPI 定義 JSON をダウンロードして
  5. AutoRest クライアント生成して
  6. Git Commit & Push して
  7. Pull Request 作成して

という構成になっています。やっていることはとてもシンプルです。
実際の YAML はこちらに置いてあります。

https://gist.github.com/noxi515/9bc5749fccd04ebb6f459c2393e2162f

Git Checkout

- checkout: self
  clean: true
  persistCredentials: true

ソースをチェックアウトしているだけです。 persistCredentials を設定することで Git 設定ファイルに OAuth トークンを保存することができ、このタスク以降も Git で Remote Repository に対してアクセス可能になります。

Use Node

- task: UseNode@1
  inputs:
    version: '12.x'

AutoRest クライアントを生成するために使用する Node.js を指定&インストールします。

Use DotNet

- task: UseDotNet@2
  inputs:
    packageType: sdk
    useGlobalJson: true

以前は DotNetCoreInstaller タスクだった気がするのですが、いつの間にか名前が変わっていました。おこ。
AutoRest が内部で .NET Core SDK を使用するので .NET Core SDK もインストールします。今回は global.json をレポジトリー内に用意しているので、そのバージョンを使用するように指定しました。

Download JSON File

- task: PowerShell@2
  displayName: Download JSON File
  inputs:
    targetType: inline
    pwsh: true
    script: |
      $url = "https://example.com/swagger/v1/swagger.json"
      $fileName = "${env:AGENT_TEMPDIRECTORY}/${env:BUILD_BUILDNUMBER}_swagger.json"

      Invoke-RestMethod -Uri $url -OutFile $fileName

Windows でも Ubuntu でも、ホストに関係無く実行出来ることを期待して PowerShell Core なタスクです。
AutoRest の --input-filehttps を指定するとどうにも生成がうまくいかなかったため、一度 TEMP ディレクトリーに JSON ファイルをダウンロードします。

AutoRest クライアント生成

- task: PowerShell@2
  displayName: Update ClientLibrary Code
  inputs:
    targetType: inline
    pwsh: true
    script: |
      $fileName = "${env:AGENT_TEMPDIRECTORY}/${env:BUILD_BUILDNUMBER}_swagger.json"

      npx autorest --csharp --add-credentials --clear-output-folder --namespace="ApiClient.Hoge" --input-file="$fileName" --output="./src/ApiClient.Hoge/generated"

AutoRest を使用してクライアントコードを生成します。
PowerShell Core のタスクとして npx から AutoRest のコマンドラインツールを実行しています。
一時ファイルのパスなどタスクを超えて使用する変数は、 Output Variable としてどこかで外に出した方がまとめやすいかもしれません。

Git Commit & Push

- task: PowerShell@2
  displayName: Git Commit and Push
  inputs:
    targetType: inline
    pwsh: true
    script: |
      $branchName = "pr/client-update/ApiClient.Hoge/${env:BUILD_BUILDNUMBER}"

      git config --global user.email "tzo.ppl@gmail.com"
      git config --global user.name "noxi515"

      git checkout -b $branchName
      git add .
      git commit -m "Updaet client library code"
      git push origin $branchName

Git でビルド番号を元に新しいブランチをチェックアウトしてコミットし、リモートレポジトリーへプッシュをします。この時ユーザー名が未設定だと失敗するのでメールアドレスとユーザー名を Global に設定しています。
また Pipeline を実行する BuildService に対して Create branch の権限を付与することも必要です(後述します)。

Pull Request の作成

- task: PowerShell@2
  displayName: Create PR
  env:
    SYSTEM_ACCESSTOKEN: $(System.AccessToken)
  inputs:
    targetType: inline
    pwsh: true
    script: |
      $body = @{
        sourceRefName = "refs/heads/pr/client-update/ApiClient.Hoge/${env:BUILD_BUILDNUMBER}"
        targetRefName = "refs/heads/master"
        title         = "Update client library (ApiClient.Hoge)"
        description   = ""
      }
      $jsonBody = ConvertTo-Json $body

      $url = "${env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI}${env:SYSTEM_TEAMPROJECT}/_apis/git/repositories/${env:BUILD_REPOSITORY_NAME}/pullrequests?api-version=5.0"
      $headers = @{
        Authorization = "Bearer ${env:SYSTEM_ACCESSTOKEN}"
      }

      Invoke-RestMethod -Uri $url -Method Post -Headers $headers -Body $jsonBody -ContentType application/json

Azure DevOps の Pull Request 作成 API を実行します。 API の呼び出しは Pull Request を作成するタスクのソースを参考にしました。

github.com

なお API を実行するための AccessToken はタスクに対してこのように環境変数として定義しないと利用できません。

  env:
    SYSTEM_ACCESSTOKEN: $(System.AccessToken)

Pipeline 実行サービスへの権限付与

今回のパイプラインの中では Git の新しいブランチプッシュと Pull Request の生成を行っています。この2つを実行するには前者が Create branch 、 後者が Contribute to pull requests の権限が必要になります。レポジトリーの設定から Xxx Build Service に対してこの2つを Allow に設定します。

f:id:noxi515:20200119230123p:plain
BuildServiceに権限付与