概要
前回はdependency-cruiser-report-actionでPRの変更ファイルの依存関係を可視化してコメントするを参考に、GitHubActionsを使ってプルリクエストに含まれるファイルの依存性の可視化を行った。
Azure DevOpsのプルリクエストでも同じこと出来るだろ、と軽い気持ちで始めたら意外に大変だったのでメモを残す。
最終的には下記のような図をプルリクエスト時に作成できた。
GitHubとの違い
GitHubと大きく異なった部分としては下記がある
- 既存のCustom Actionがない
- GitHubではユーザ作成のCustom actionが公開されていた
- Azure DevOpsでは同様のものは見つけることができなかった
- プルリクエストのコメントにmermaid記法が使えない
- Azure DevOpsの場合、Wikiのみでmermaid記法を使用することができる。
この条件の違いから、Azure DevOpsでは、プルリク作成時にパイプラインを動かし、mermaidでのグラフ描画用のwikiを作成し、そのwikiへのリンクをプルリクエストのコメントにする方法をとろうと思う。
環境
- AzureDevOps
- リポジトリのブランチをcode as wikiとして使用している
パイプラインのユーザに権限を付与する
- ビルドパイプライン用のユーザが自動作成されているので、下記2つの
Allow
権限を与える- Wikiの更新のための「 Contribute 」
- プルリクエストにコメントするための「Contribute to pull requests」
パイプラインを作成する
- 利用しているリポジトリがモノレポ構成でnpmをモノレポ管理に使っていたため、パイプラインで使用するNodeを更新する必要があった。( デフォルトのnpmが古くてモノレポ管理できないバージョン)
今回は下記の設定としてパイプラインに明記- Node:
20.14.0
- npm:
10.8.1
- Node:
# ブランチポリシーにより起動させる
trigger: none
pr: none
jobs:
- job: check
pool:
vmImage: ubuntu-latest
steps:
- task: UseNode@1
inputs:
version: '20.14.0'
displayName: 'Install Node.js'
- task: Npm@1
inputs:
command: custom
customCommand: 'install -g npm@10.8.1'
displayName: 'Upgrade npm to latest version'
- task: Npm@1
name: npm_install
inputs:
command: custom
customCommand: 'install --ignore-scripts'
workingDir: $(Build.SourcesDirectory)
- task: Bash@3
displayName: 'POST PR Comment'
inputs:
workingDirectory: $(Build.SourcesDirectory)/app
targetType: 'inline'
script: |
# 変数準備
PROJECT_NAME_ENCODED=$(echo -n "$(System.TeamProject)" | perl -MURI::Escape -ne 'print uri_escape($_)')
ADO_API_BASE=$(echo "$(System.CollectionUri)${PROJECT_NAME_ENCODED}/_apis/git/repositories/$(Build.Repository.Name)")
ADO_API_VERSION=$(echo "api-version=7.2-preview.1")
######################################################################
# PRに含まれるファイルを取得
BRANCH1="$(System.PullRequest.TargetBranch)"
BRANCH2="$(System.PullRequest.SourceBranch)"
BASE_BRANCH=${BRANCH1#refs/heads/}
TARGET_BRANCH=${BRANCH2#refs/heads/}
BASE_BRANCH_ENCODED=${BASE_BRANCH//\//%2F}
TARGET_BRANCH_ENCODED=${TARGET_BRANCH//\//%2F}
ADO_DIFF_API=$(echo "${ADO_API_BASE}/diffs/commits?baseVersion=${BASE_BRANCH_ENCODED}&targetVersion=${TARGET_BRANCH_ENCODED}&${ADO_API_VERSION}")
CHANGED_FILES=$(curl "$ADO_DIFF_API" \
--header "Accept: application/json" \
--header "Authorization: Bearer $SYSTEM_ACCESSTOKEN")
CHANGED_FILES_CSV=$(echo $CHANGED_FILES | jq -r '.changes[] | select(.item.isFolder != true and (.item.path | type == "string" and startswith("/app/src") ) ) | .item.path' | sed 's/\/app\///g' | tr '\n' ',')
IFS=',' read -ra FILES <<< "$CHANGED_FILES_CSV"
######################################################################
# dependency-cruiserで解析した結果をmermaid形式で出力
npm install
MERMAID_OUTUPUT=$(npm run depcruise -- "${FILES[@]}")
MERMAID_OUTUPUT=$(echo "${MERMAID_OUTUPUT}" | tail -n +4)
MERMAID_CONTENT=$(echo -e ":::mermaid \n\n ${MERMAID_OUTUPUT} \n\n :::")
WIKI_CONTENT_JSON=$(jq --arg comment "$MERMAID_CONTENT" '.content = $comment' <<< '{"content": ""}')
######################################################################
# meraidグラフ用のwikiが作成済かどうかをチェック
bid=$(echo "$TARGET_BRANCH_ENCODED" | awk -F'%2F' '{print $2}')
WIKI_PATH="pullrequests%2Fbid%2F${bid}"
AZURE_URL=$(echo "$(System.CollectionUri)${PROJECT_NAME_ENCODED}")
WIKI_API_PAGE_URL=$(echo "${AZURE_URL}/_apis/wiki/wikis/%E8%96%AC%E5%91%B3/pages?path=${WIKI_PATH}&api-version=7.1-preview.1")
auth="Authorization: Bearer $SYSTEM_ACCESSTOKEN"
ct="Content-Type: application/json"
EXISTS_CHEKCK_RESPONSE=$(curl -XGET -s -H "$auth" -i "$WIKI_API_PAGE_URL")
{ read -r status_line; read -r etag_line; } < <( echo "$EXISTS_CHEKCK_RESPONSE" | grep -i -P '^(HTTP/|ETag:)' )
######################################################################
if [[ $status_line =~ ^HTTP/[0-9.]+\ 200 ]]; then
######################################################################
# ページが存在する場合は更新
etag_value=$(echo "$etag_line" | awk '{print $2}' | tr -d '\r')
ifmatch="If-Match: ${etag_value}"
response_wiki_page=$(curl -XPUT -s -H "$auth" -H "$ct" -H "$ifmatch" "${WIKI_API_PAGE_URL}&versionDescriptor.version=${BASE_BRANCH_ENCODED}" --data "${WIKI_CONTENT_JSON}")
else
######################################################################
# ページが存在しない場合は新規作成
response_wiki_page=$(curl -XPUT -s -H "$auth" -H "$ct" "${WIKI_API_PAGE_URL}&versionDescriptor.version=${BASE_BRANCH_ENCODED}" --data "${WIKI_CONTENT_JSON}")
######################################################################
# 新規作成時のみ、プルリクエストコメントを投稿する
WIKI_ID=$(echo "$response_wiki_page" | jq -r '.id')
COMMENT=$(echo -e "[mermaid](${AZURE_URL}/_wiki/wikis/%E8%96%AC%E5%91%B3/${WIKI_ID})")
ADO_API=$(echo "${ADO_API_BASE}/pullRequests/$(System.PullRequest.PullRequestId)/threads?${ADO_API_VERSION}")
PR_COMMENT=$(jq --arg comment "$COMMENT" '.comments[0].content = $comment' <<< '{"comments": [{"parentCommentId": 0,"content": "","commentType": 1}],"status": 1}')
curl "$ADO_API" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "Authorization: Bearer $SYSTEM_ACCESSTOKEN" \
--data "$PR_COMMENT" \
--verbose
fi
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
ブランチポリシーの設定
パイプラインで使用するSystem.PullRequest.PullRequestId
が、これはブランチポリシーによるパイプラインでのみ値を取得できるため。
実行結果
プルリクが書き込まれた。リンクをクリックすると、最初に示した mermaid でのファイルの依存関係を表した図が確認できる。
メモ
Wiki作成時のレスポンス例
{
"path": "/pullrequests/bid/474",
"order": 0,
"gitItemPath": "/wiki/pullrequests/bid/474.md",
"subPages": [],
"url": "https://dev.azure.com/...?pagePath=%2Fpullrequests%2Fbid%2F474",
"remoteUrl": "https://dev.azure.com/...?pagePath=%2Fpullrequests%2Fbid%2F474",
"id": 973,
"content": ":::mermaid \n\n \nflowchart LR\n\nsubgraph 0[\"src\"]\nsubgraph 1[\"pages\"]\n2[\"HollowFluxPage.tsx\"]\nend\nsubgraph 3[\"domain\"]\nsubgraph 4[\"hollow\"]\n5[\"constants.ts\"]\n6[\"cards.json\"]\n7[\"createUdonariumZip.ts\"]\nend\nsubgraph 8[\"udonarium\"]\n9[\"common.ts\"]\nA[\"fileArchiver.ts\"]\nB[\"canvas.ts\"]\nC[\"FileReaderUtil.ts\"]\nD[\"mimeType.ts\"]\nE[\"udonariumZip.ts\"]\nend\nend\nend\n2-->5\n2-->7\n5-->6\n7-->9\n7-->A\n7-->E\n9-->A\nA-->B\nB-->C\nB-->D\nE-->9\nE-->A \n\n :::"
}
参考
dependency-cruiser-report-actionでPRの変更ファイルの依存関係を可視化してコメントする
しばやん雑記 - Azure Pipelines のディレクトリを指す変数はどれを使うべきなのか調べた
Azure DevOps Service REST APIでWikiの更新を試してみたメモ
Azure PipelinesのタスクでPullRequestに対してコメントをつけたい
UseNode@1 - エコシステム v1 タスク Node.js 使用する
既定のリポジトリのアクセス許可
テンプレート使用方法のリファレンス
Diffs - Get
システム変数 (DevOps Services)