やりたかったこと
- Slack上で作業申請→承認→開始→終了連絡を気軽に実施しつつ、Airtableにて各作業のステータスとともに一覧管理したい
- 申請内容はSlackワークフローのフォームで入力
- 承認・開始・終了連絡はリアクション付けるだけ
- ノーコードで手軽に実施したい
1. 使ったツール
- Slack
- Airtable
- Zapier
2. 全体デザイン
3. 構築手順
1. Slackワークフローの設定
利用者には #リリース管理 チャンネルだけを意識してもらいたいので、#リリース管理チャンネルの関連ページとしてワークフローのリンクを置いておくことにしました。
フォームに入力した内容は敢えて別のチャンネル #zapier-input に出力しています。
この意図としては、以下のとおりです。
- ユーザーにステータス変更のリアクションを付けてもらう投稿にAirtable上のレコード識別子を入れておきたかった。(なのでレコード挿入後に払い出されたレコード識別子を含めた投稿の方だけをユーザに見せたい)
- Slackフォームにて日時タイプで入力された項目をメッセージとして出力した際に、UTCで表示されてしまうためそのままでは見づらい
- Zapierに各項目の値をパースさせるにあたり、目視用にラベルなどをつけているとSplitが必要となるし、separaterのエスケープとか考えるのが面倒
このワークフローを実行して、#zapier-input に出力されたらこんな感じになります。
- 日時はUNIXタイムスタンプ形式にしています。ここの出力結果は目視目的でなくZapierへの受け渡し目的なので。
- 承認者や申請者などのユーザー情報は、ユーザID、表示名、氏名の3パターンで出力してあります。ユーザIDは後でメンションの際に使うため、氏名はAirtableへの記録用です。表示名は今のところ使ってませんが念の為。
2. Airtableの設定
受け手のテーブルを作っておきます。
フォームの入力項目に加えて、
- Autonumberタイプのカラムをレコードの識別子として追加
- Airtableのシステム内での識別子もあり、Zapierからの登録時にレスポンスとしてわかるので、更新対象を明確にするだけであれば不要ですが、ユーザの目に触れさせるものでも無さそうだし、共通言語としてあった方がユーザ同士でも便利だろうと入れることにしました
- ステータス
- とりあえず、Open/Approved/in progress/Done だけ設定
- 各種日時
- 作成日時(Airtable機能としてCreated timeを利用)
- 承認日時
- 実際の作業開始・終了日時
- 最終更新日時(Airtable機能としてLast modified timeを利用)
- 最終更新者
3. Zapierの設定
全部で4つのZapを作ります。
それぞれ以下に対応しています。
a. 作業申請(レコード登録)
b. 作業承認
c. 作業開始
d. 作業終了
a. 作業申請(レコード登録)用のZap
+ Create Zapから新規Zapの作成を開始し、TriggerのAppとしてSlack、Eventとして「New Message Postedto Channel」を選択します。
Accountでは適切なSlackアカウントでログインして権限を許諾します。
Triggerでは、Channnelには先ほどのワークフローが申請内容を出力するチャンネルを選択して、Trigger for Bot Messages? は「Yes」にしておきます。
Testを実行して、対象としたいメッセージが取得できることを確認して、今後のアクションの設定で参照したいテストメッセージを選んでおきます。
Zapierではこのように実際のサンプルデータを確認しながら、後続のアクションを設定できるのが本当にわかりやすくて好きです。
2番目のアクションでは、Filter by Zapierを利用して、投稿者がワークフローの場合のみ後続のアクションを続けるように設定します。
今回はUser Name が一致する場合としました。ここでUser Nameの選択を行う際に、下の画像のように、Insert Data ... が現れて、どのアクションの結果の値を使うか、その中のどの項目を使うかが、テスト結果のサンプルデータとともに表示されるのでわかりやすいです。
次はFormatter by Zapierを利用して、メッセージに含まれる各データ項目を抽出します。
Eventは「Text」を選択します。
Transformは「Split Text」を選び、inputデータは1番目のアクション結果から「Raw Text」を選びます。ここでも選択項目にテストデータが添えられているのでわかりやすいと思います。
Separatorは「[:newline:]」、Segment Indexは「All (as Separate Fields)」を選択しておきます。
Testを実行して、Raw Textから行ごとにデータ項目が別itemとして切り出されたことを確認します。
4つ目のアクションもFormatterです。今度はEventにはDate/Timeを選びます。
Transformでは、3つ目のアクションのテスト結果から作業開始日時の項目を選び、それを日本のタイムゾーンで可読の形式に変更するように設定します。
5つ目のアクションは作業終了日時に関してほぼ同じ内容で設定します。(詳細は割愛します)
6つ目のアクションとしていよいよAirtableへレコードを書き込みます。
AppとしてAirtableを選択、Eventは「Create Record」です。
Accountで、受け手のテーブルを作成したAirtableアカウントを連携すると、ActionセクションにてBaseやTableのプルダウン選択肢にAirtable側の設定が表示されるようになります。
Tableを選択すると、以降のフィールドはTableのカラム構造に合わせたものになります。
Airtable側で自動で値が設定されるAutonumber型のカラムや、Created timeやLast modifiedなどは空欄にしておき、Statusフィールドは文字列で「Open」、その他の項目は3番目のアクションで行単位にSplitした項目から適切なものを選択して、Airtableへ値が設定されるようにします。
このアクションのTestを実行すると、Airtable側へレコードが作成されますので、Airtable側で結果を確認します。
Test結果として、Zapier側でもAirtableの設定結果が取得されます。
最後に登録結果をSlackにメッセージとして投稿するのですが、コンセプトとしてはSlackから入力した値をそのまま投稿するのではなく、できるだけAirtableからの返却値を利用したいと考えましたので、UTCで返却された日時関連の項目をJSTへ変換するアクションを先に追加します。
ここでも利用するのは、Formatterです。前に行ったのと同じ要領ですので説明は割愛します。
最後のアクションはSlackにたいしてSend Channel Messageを設定します。
投稿先のチャンネルは、ユーザーに見てもらう #リリース管理 チャンネル、Messageテキストとしては、Airtableからの返却値にテキストでラベルを付けて設定します。日時項目は先ほど追加したJST変換済みの項目です。Bot Nameは適当に設定しておきましょう。
ここで、承認者や投稿者などの項目はAirtableへ連携した氏名に加えて、メンションするために、<@ユーザID>
を付け加えておきます。ユーザIDはAirtableへは渡してないので(渡すように設計しても良いのですが)、Slackからの入力値を行スプリットしたアクション結果から持ってきています。
このアクションのTestを実行すると、Slackへ実際にメッセージが投稿されます。
これで作業申請(レコード登録)用のZapは完成です。
b.作業承認用のZapの作成
別のZapとして作業承認用のZapを作成します。
今度のEventはNew Reaction Addedです。
先ほどの新規登録用のZapが投稿したSlackメッセージに対して、特定のリアクションを付けられたことをトリガーにして動作するように設定します。今回適切な承認者かどうかのチェックまではスコープにしませんので、Userは誰でも良いように空にしておきます。
このアクションのTestを実行して、これ以降の設定で参照するサンプルデータを選択します。テスト実行前に該当のSlackメッセージへリアクションを付けておきます。
このNew Reaction Addedのtest recordsの取得はかなり曲者だと思いました。
- Trigerで指定したチャンネル以外のデータも候補として表示される
- Trigerで指定したリアクション以外のデータも候補として表示される
- 連携したSlackアカウントが一度もどのリアクションをどこにも付けたことが無なければデータ取得エラーとなる
1,2点目は正直これではテストになってないじゃん!って思いますが、後続アクションの設定用のサンプルデータを拾う意味しか無いと割り切って目を瞑りましょう。
3点目について、私は今回のZapier連携用に専用のSlackアカウントを作成したためハマりました。
正直これでは心配なので、念の為、意図したチャンネルかどうかをチェックするフィルターを念の為入れました。
リアクションを付けたメッセージの投稿者が1つ目のZapであることもチェックしておきます。
リアクションを付けた元のメッセージの内容がMessage Textとして取得できているので、行単位に分解しておきます。1つ目のZapで行ったのと同じ要領なので詳細説明は省略します。
これで取得したメッセージ内容の中からレコードの識別子としてAutonumber型で設定したフィールドの値を抽出しておきます。
次にこの取得したIDを利用して、更新対象のレコードを取得しておきます。
EventはFind Recordです。
レコード作成時と同じようにAccountとBase、Tableを選択形式で設定すると、Search by Fieldも実際のテーブルのカラムから選択できるようになるので、Autonumber型で設定したID用のカラムを選択し、Search Valueへ一つ前のアクションで取得したIDを使用するように設定します。
Testを実行すると、Airtableの該当レコードの内容が取得されます。
そしていよいよレコードの更新です。EventにはUpdate Recordを使用します。
これまでと同じようにBaseとTableを選択肢し、Recordとして、Find Recordsの結果からID(Airtableのシステム設定のレコードID)を設定します。
他は更新すべき項目だけ値を入れていきます。
- Statusを「Approved」に文字列で設定
- 承認者や更新者は、1番目のアクションの結果からSlackのUser Real Nameを持ってきました
- 承認日時は、
{{zap_meta_utc_iso}}
を設定すると、現在日時で設定してくれます
Testを実行するとAirtable側での更新が確認できるとともに、Zapier側でも更新結果が返却値として確認できます。
最後に更新結果をSlackへ投稿する前に、Formatterにて承認日時をJSTに変換しておきます。
Slackへの結果送信は、またSend Channnel Message in Slackを使用します。
Bot Nameはレコード作成時と異なるものにしておいた方が良いでしょう。(その投稿にリアクションを付けられてしまったときにこのZap内で作成したFilterアクションで区別できるように)
また、元の投稿のスレッド返信として投稿するために、Threadフィールドに元のメッセージのタイムスタンプが設定されるようにします。
このアクションをTestすると、Slackにスレッド返信が投稿されます。
これにて2つ目のZapも作成完了です。
c,d. 作業開始・終了記録用のZap
基本的には作業承認と同じなので、説明は省略します。
全部作成が終わったら、各ZapのRunnning ステータスをONにして動かします。
これにて完成です。お疲れ様でした。
4. 終わりに
- nocodeでやりきれましたが、使う頭は結局コーディングしたときと似てるなと感じました。コード構文そのものの知識は不要でも、シンプルな命令を組み合わせてどうやってやりたいことを実現するのかを考えたり、あらかじめここでこういう変数を持たせておくと後で処理に使えるといった設計など。
- 今回、異常系・準正常系をほとんど考慮してないので、その辺りで何かテクニカルな工夫点があればまた共有します。
- Airtableに記録した情報をAirtableにログインせずに気軽に参照できるようにしたいので、UXから検討したいと思います。