🐙

Azure DevopsのPRをPowerAutomateを使いTeamsで通知する

2024/01/16に公開

記事を作成しようと思った背景

最近開発作業において、プルリクエスト(PR)を他のチームメンバーに送る機会が頻繁にあります。
これまでPRを送った際には、毎回Microsoft Teamsを通じてレビューの確認依頼を行っていました。
この作業がめんどくさかったので、PowerAutomateを使い自動化しようと思いました。

PowerAutomateとは?(※ChatGPTによる解説)

Power Automateは、マイクロソフトによって開発された自動化ツールで、ビジネスプロセスの効率化を目的としています。このツールを使うことで、繰り返し行われる作業や複雑なタスクを自動化し、効率的に処理することができます。具体的には、以下のような特徴があります。

・フローの作成
ユーザーは「フロー」と呼ばれる自動化のスクリプトを作成できます。これにより、特定のトリガーが発生したときに自動的にアクションを実行することが可能です。

・豊富なコネクタ
Power Automateは、多数の外部サービスやアプリケーションと連携できるコネクタを提供しています。これにより、異なるアプリケーション間でのデータの移動や処理を自動化できます。

・利便性とアクセシビリティ
ブラウザベースで利用できるほか、モバイルアプリも提供されています。これにより、場所を選ばずに自動化の設定や管理が可能です。

・AI統合
人工知能(AI)を活用した機能も提供しており、より高度なデータ処理や分析が可能です。

Microsoft 365との統合: Microsoft 365の各種アプリケーション(例えば、Outlook、Teams、SharePoint)との深い統合が可能で、これらのアプリケーションの使用を自動化するフローを簡単に作成できます。

これらの特徴により、Power Automateはビジネスにおける生産性の向上や、作業の効率化に大きく貢献するツールとなっています。

https://www.microsoft.com/ja-jp/power-platform/products/power-automate

フロー全体

解説

1.トリガーは、Azure Devopsの「プル要求が作成されたとき(Git)」
該当のリポジトリがある、組織名、プロジェクト名、リポジトリ名をプルダウンから選択する。

2.Azure Devopsの実行ログをJsonで解析をする。
Jsonの解析コネクタを使い、Azure DevOpsの実行ログを解析する。

↓下記をコピペしください。

{
    "type": "object",
    "properties": {
        "headers": {
            "type": "object",
            "properties": {
                "Cache-Control": {
                    "type": "string"
                },
                "Pragma": {
                    "type": "string"
                },
                "Transfer-Encoding": {
                    "type": "string"
                },
                "Vary": {
                    "type": "string"
                },
                "Set-Cookie": {
                    "type": "string"
                },
                "Strict-Transport-Security": {
                    "type": "string"
                },
                "x-ms-request-id": {
                    "type": "string"
                },
                "X-Content-Type-Options": {
                    "type": "string"
                },
                "X-Frame-Options": {
                    "type": "string"
                },
                "Timing-Allow-Origin": {
                    "type": "string"
                },
                "x-ms-apihub-cached-response": {
                    "type": "string"
                },
                "x-ms-apihub-obo": {
                    "type": "string"
                },
                "Date": {
                    "type": "string"
                },
                "Content-Type": {
                    "type": "string"
                },
                "Expires": {
                    "type": "string"
                }
            }
        },
        "body": {
            "type": "object",
            "properties": {
                "repository": {
                    "type": "object",
                    "properties": {
                        "id": {
                            "type": "string"
                        },
                        "name": {
                            "type": "string"
                        },
                        "url": {
                            "type": "string"
                        }
                    }
                },
                "createdBy": {
                    "type": "object",
                    "properties": {
                        "displayName": {
                            "type": "string"
                        },
                        "uniqueName": {
                            "type": "string"
                        },
                        "id": {
                            "type": "string"
                        },
                        "imageUrl": {
                            "type": "string"
                        },
                        "url": {
                            "type": "string"
                        }
                    }
                },
                "closedBy": {
                    "type": "object",
                    "properties": {}
                },
                "autoCompleteSetBy": {
                    "type": "object",
                    "properties": {}
                },
                "reviewers": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "DisplayName": {
                                "type": "string"
                            },
                            "UniqueName": {
                                "type": "string"
                            },
                            "Id": {
                                "type": "string"
                            },
                            "Url": {
                                "type": "string"
                            },
                            "HasDeclined": {
                                "type": "boolean"
                            },
                            "IsFlagged": {
                                "type": "boolean"
                            },
                            "IsRequired": {
                                "type": "boolean"
                            },
                            "Vote": {
                                "type": "integer"
                            }
                        },
                        "required": [
                            "DisplayName",
                            "UniqueName",
                            "Id",
                            "Url",
                            "HasDeclined",
                            "IsFlagged",
                            "IsRequired",
                            "Vote"
                        ]
                    }
                },
                "reviewerList": {
                    "type": "string"
                },
                "requiredReviewerList": {
                    "type": "string"
                },
                "pullRequestId": {
                    "type": "integer"
                },
                "creationDate": {
                    "type": "string"
                },
                "title": {
                    "type": "string"
                },
                "description": {
                    "type": "string"
                },
                "isDraft": {
                    "type": "boolean"
                },
                "sourceRefName": {
                    "type": "string"
                },
                "targetRefName": {
                    "type": "string"
                },
                "url": {
                    "type": "string"
                },
                "mergeId": {
                    "type": "string"
                },
                "codeReviewId": {
                    "type": "integer"
                },
                "supportsIterations": {
                    "type": "boolean"
                }
            }
        }
    }
}

3.変数(メンション)を定義する
「変数を初期化する」コネクタを使い、変数(メンション)を定義する。
Nameは、「メンション」を入力する。
Typeは、「Array」を選択する。
Vauleは、空のままにする。

4.Teamsの@mentionを定義する
Teamsの「ユーザーの@mentionトークンを取得する」コネクタを使い、メンションを取得する。
ユーザーは、Json解析から出力された「UniqueName」を選択する。
※uniqueNameもあるが、こちらはPRを依頼した人のメールアドレスです。
 UniqueNameは、PR依頼された人のメールアドレスです。

5.変数(メンション)に変数を代入する
「作成」コネクタを使い、変数(メンション)を定義する。
入力は、赤丸から式を挿入する。

挿入する式は、

decodeUriComponent(outputs(

を入力する。


この状態で、動的コンテンツから@ mentionを選択すると下記の式が完成します。

decodeUriComponent(outputs(outputs('ユーザーの_@mention_トークンを取得する')?['body/atMention']

式が完成後、更新をクリックする。

6.変数(メンション)に変数を代入する
「配列変数に追加」コネクタを選択する。
Nameは、3で作成した変数(メンション)を選択する。
Vauleは、5で作成した出力を選択する。

7.結合で複数メンションできるようにする
「統合」コネクタを選択する。
Fromは、6で作成出力を選択する。
Join Withは、「,」を入力する。

8.PRのURLリンクの作成

入力内容は、下記です。

<a herf = "hhtps://dev.azure.com/<組織名>/<プロジェクト名>/<リポジトリ名>/pullrequest/PR番号">PR</a>

※PR番号は、2のjson解析の出力にある「Body pullRequestId」を使用する

9.Teamsのチャネルにメッセージを送信する
Teamsの「チャットまたはチャネルでメッセージを投稿する」を選択する。
以下のパラメータを選択する。
-投稿者:フローボット
-投稿先:Channel
-Teams:投稿したTeamsを選択
-Channel:投稿したいチャネルを選択

Messageの内容は、下記です。
-Output:7で作成した結合のoutputを選択(PRをお願いした相手にメンションがいきます)
-Body display:2でJson解析した際の「Body display」を選択(PRを出した人の名前が取得できます)
-出力:8で作成したPRのリンクを指定

まとめ

プルリクエストを自動化したおかげで、手間が減りました。
これにより、チームメンバーがすぐに通知を受けて対応できるようになり、開発の速度が上がりました。
次は、PRがしばらくレビューされない場合に自動でリマインダーを送る機能を追加使用と思っています。また記事にします。

ヘッドウォータース

Discussion