WorkatoでSlackの発言をリアク字トリガーでAzure DevOpsへチケット起票する

WorkatoでSlackの発言をリアク字トリガーでAzure DevOpsへチケット起票する

こんにちは、俊介です!
Workatoで社内の業務を自動化したので、ブログを書こうと思います。今回はAzure DevOpsとの連携する話です。

弊社は日々お客様からご質問がSlack経由で寄せられます。その際にAzure DevOpsでチケット管理を行うのですが日々SlackとAzure DevOpsを行き来するのが凄い大変で…
なので、Slackで完結出来ないかなと思い、作成してみました。Slackにて特定のリアクションをすると自動的にAzure DevOpsにチケット起票する動きを想定しています。詳しい内容はレシピの概要で書いていきたいと思います。

はじめに

Workatoって何?

そもそもWorkatoって何?って言う方、聞いた事あるけどあまり他のサービスとの違いが分からない….という方は、弊社取扱製品ページにて分かりやすく説明しておりますので弊社のWorkato紹介ページをご覧ください。

Azure DevOpsって何?

Azure DevOpsは開発や運営をしていく上で、作業をスムーズに進めるような、環境やツールが揃っているプラットフォームです。Azure DevOpsには下記のツールが含まれています。

  • Azure Boards
  • Azure Repos
  • Azure Pipelines
  • Azure Test Plans
  • Azure Artifacts

その中で弊社ではAzure Boardsを利用しています。Azure BoardsはAzure DevOpsのサービスの1つで、タスクの管理がしやすく、進捗の可視化されているので、共同作業者も簡単に確認する事が出来ます。

弊社ではAzure Boardを利用して、お客様ごとのプロジェクトを管理したり、日々質問が来た際に集約させて管理する際に使ってます。

レシピの概要

今回作成したレシピは冒頭でも記載した通り、お客様から頂いたご質問を自動的にチケットとして起票するレシピです。今までは手動で特定のチャンネルに質問リンクを貼って、かつAzure DevOpsにチケットを起票しておりましたが、毎日沢山のご質問を受けている中、その度に同じ作業を行っていました。それをWorkatoを使って自動化させてみました。

Before

  1. お客様から質問が来る
  2. 質問に気づいた人が特定のチャンネルにリンクを貼り付ける
  3. その人がAzure DevOpsにアクセスし、質問内容をコピペしてチケットを起票する

After

  1. お客様から質問が来る
  2. 質問に気づいた人が特定のリアクション(スタンプ)を押す
  3. 自動的にAzure DevOpsにチケットが起票される
  4. 特定のSlackチャンネルへURLと合わせて投稿され、投稿したメッセージをピン留めされる

最後にピン留めさせる仕様にしていますが理由は、ピン留めされてるものは現在対応中の物を一覧で見れるように設定しました。ピン留めされている物はまだ対応が残ってる物で、対応が終わり次第ピン留めを外すことによって、対応終了しているかどうかをすぐに判断出来るように設定にしています。

作成したレシピ

WorkatoにはまだAzure DevOpsのAppコネクターが無かったので、自分で作成しました。レシピ自作について詳しくはWorkatoの公式ドキュメントをご覧ください。

作業としては以下の2つです。

  1. Azure DevOpsのカスタムコネクターの作成
  2. レシピの組み立て方法

Azure DevOpsのカスタムコネクターの作成

全体の画面がこちらです。

ブロックごとに簡単に説明していきます。困った点、気をつけるポイントも書いていくので、皆さんのお力になれたらなと思います。

またカスタムコネクターはRubyで記述する必要があります。

connectionブロック

ここはAzure DevOpsと連携する際に認証する部分になります。重要なのはfields部分と、authorization部分です。fields部分接続時に入力させる部分になります。

 connection: {
    fields: [
      {
        name: "user_name",
        optional: false,
      },
      {
        name: "organization",
        optional: false,
      },
      {
        name: "personal_access_token",
        optional: false,
      }
    ],

上記で設定した入力フィールドとして反映されて、下記のように表示されます。

authorization部分では、そのAPI(今回はAzure DevOps)がどのような認証方法を使っているか書いていきます。今回はベーシック認証で書きましたが、連携するサービスのapiによって認証方法が異なりますので、事前にお調べください。

   authorization: {
      type: "basic_auth",

      apply: lambda do |connection| 
        token = "#{connection['user_name']}:#{connection['personal_access_token']}".encode_base64
        headers("Authorization": "Basic #{token}")
      end
    },

    base_uri: lambda do |connection|
      "https://dev.azure.com/#{connection['organization']}/"
    end
  },

test部分

この部分は接続ができるか試す部分になります。基本的にconnectionブロックで記載された部分を見て認証テストを行います。

  test: lambda do |connection| 
    get("https://dev.azure.com/#{connection['organization']}/_apis/projects?api-version=5.1")
  end,

私はRubyを触った事が無いので、ここで大変手こずりました…。書き方がダメだった為、なかなか認証がうまくいきませんでした…。先輩からcurlでリクエストして、ちゃんと期待通りのものが返ってくるか確認すると良いとの助言を頂いて対応しました。

> curl -H'Authorization: Basic <Azure DevOpsから入手したAPIトークン> https://dev.azure.com/<テナント名>/<プロジェクト名>/_apis/wit/workitemtypes?api-version=5.1 | jq .

これは勉強になったので、備忘録として書いておきます。

object_definitionsブロック

ここはMicrosoftの公式ドキュメントのSample Requestから参考にして書きました。コードの様子は長い為、割愛させて頂きます。

actionブロック

ここで重要なのは3つです。

  • input_fields → レシピ作成時の入力フィールドを書く所です
  • execute → どのように動かすか処理部分を書く所です
  • output_fields → レシピの後続のフローでデータを使う為の書く所です
  actions: {
    create_item: {
      title: "Create item",

      input_fields: lambda do |_object_definitions|
        [
          {name: "project", control_type: "text"},
          {name: "type", control_type: "text"},
          {name: "title", control_type: "text"},
          {name: "description", control_type: "text-area"}
        ]
      end,

      execute: lambda do |connection, input|
        body = [
          {
            "op": "add",
            "path": "/fields/System.Title",
            "from": "null",
            "value": input["title"]
          },
          {
            "op": "add",
            "path": "/fields/System.Description",
            "from": "null",
            "value": input["description"]
          },
        ]

        post(
          "https://dev.azure.com/#{connection['organization']}/#{input['project']}/_apis/wit/workitems/$#{input['type']}?api-version=5.1"
        )
          .request_body(body.to_json)
          .headers("Content-Type": "application/json-patch+json")
      end,

      output_fields: lambda do |object_definitions|
        object_definitions["projects"]
      end,
    },

沼にハマった点はexecute部分です。最初は公式ドキュメントに記載されてるpostをそのまま利用してたのですが、エラーが直りませんでした。原因はRequest Bodyを書いていなかった為です。それらを追加してやり直すと無事起票のテストを行う事が出来ました。

レシピの組み立て方法

Trigger部分


トリガーは特定のリアクションをしたら発火する動きを設定します。今回は絵文字の「kihyou_simasita」のリアクションがついたらトリガーが発火するように設定しました。
注意点:WorkBotを事前に発火させたいチャンネルに参加させる必要があります。

Action部分


アクション2-8の動きは、下記の情報収集とAzure DevOpsにチケットを起票します。

  1. 投稿のリンク(用途:特定のチャンネルに貼る為)
  2. チャンネル名(用途:Azure DevOpsのチケットのタイトルに使う為)
  3. 投稿されたテキスト(用途:Azure DevOpsのチケットの説明に使う為)

ループと条件分岐をしてる理由は、リアクションを押した対象のテキストを取得する事が出来なかった為です。対応策としてSlackのapiを利用し、チャンネルの投稿履歴を取得させ、その中から条件を満たしたテキストだけを取得する為です。
注意点:ここで投稿履歴のlimitを絞るのがミソです。 例えば、最新から10投稿まで取得する等です。

limitを設定していないと、同じチャンネルで他の投稿に同じリアクションをした投稿まで取得してしまいます。


アクション9-10では特定のチャンネルに下記の内容を投稿させてピン留めをさせます。

  • 質問のリンク
  • Azure DevOpsのチケットURL

実際に動かした様子

まずは投稿に特定のリアクションをつけます。すると….

今回はテストでやってるので特定のリアクションを「:eyes:」で設定しています。

リアクションを押した結果、自動的にAzure DevOpsにチケットが起票され、URLと合わせて通知用のチャンネルにメッセージが投稿されました。もちろんアイコンや名前も自由に変えれるのでお好きなものに設定出来ます。

リンクを踏むと起票されたチケットに行けることも確認取れました。チケット側にはSlackのリンクも添付されるように設定してあります。

最後に

今回はSlackとAzure DevOpsを連携させて、Slackで特定のリアクションするだけでAzure DevOpsにチケット起票する動きを作りました。ユーザーはリアクション1つするだけでSlack専用チャンネルへの転記とピン留め、更にはAzure DevOpsへの起票まで行えるようになったので、対応時間を大幅に減らす事が出来たと同時に、起票漏れや対応漏れも分かりやすくなりました。

現状はチケット起票までを自動化していますが、別レシピでAzure DevOpsのチケットのステータスをDoneにする、をトリガーにして、ピン留めを外すレシピを作成すると、より便利に。完了していないタスクのSlackリマインドも実装したいと思っています。

あと今回作ったレシピもカスタムコネクターも共有する事が出来ますので、もし気になった方や、使ってみたいう方がいらっしゃいましたらお気軽にご相談ください!ではまた!

情報システム部門は企業のコア

CTA-IMAGE 株式会社クラウドネイティブは、情報システム部門のコンサルティング専門家集団です。 ゼロトラストの概念を国内でいち早く取り入れ、現実的に実装できる国内唯一のコンサルティング会社です。 「どの製品選べばいいの?」 「社内インフラ改革はどこから?」 「セキュリティって結局どうすれば?」 その疑問や不安にお応えします。