その他

makeの管理運用の話:Github連携

この記事は「make Advent Calendar 2024」19日目の記事です。

このアドベントカレンダーについて

このアドベントカレンダーは25日間でIPaaS製品の「make」について使い方や、実践を学べる連続ブログ企画です。

おかしん」「ばるす」「たにあん」の3名がリレー形式でお届けします。

25日間のスケジュールは以下の通りです。

日付内容担当
12/1話題のIPaaS製品「make」とはおかしん
12/2makeで作ってみたScenario紹介ばるす
12/3make 基本操作編 機能紹介:Organizationたにあん
12/4make 基本操作編 機能紹介:Scenario、Templateおかしん
12/5make 基本操作編 機能紹介:Connectionsばるす
12/6make 基本操作編 機能紹介:Webhooksたにあん
12/7make 基本操作編 機能紹介:DataStores、DataStructuresおかしん
12/8make 基本操作編 機能紹介:Devicesばるす
12/9make 基本操作編 機能紹介:Functionsたにあん
12/10make 基本操作編 機能紹介:CustomAppsおかしん
12/11make 基本操作編 機能紹介:Flow Control,Tools,Text parserばるす
12/12make ドキュメント動線の話:ResourceHubたにあん
12/13make 検証:Make Bridgeおかしん
12/14make 検証:Make REST APIばるす
12/15make 検証:AI Searchたにあん
12/16make Community Hub:Overviewおかしん
12/17make Community Hub:Academy Courses,Blog Articlesばるす
12/18make Community Hub:Showcase,CustomAppsたにあん
12/19makeの管理運用の話:Github連携おかしん
12/20makeの管理運用の話:実行ログと再実行と停止中リクエスト滞留ばるす
12/21makeの管理運用の話:Connection権限管理たにあん
12/22makeで作ってみた事例:(未定)おかしん
12/23makeで作ってみた事例:(未定)ばるす
12/24makeで作ってみた事例:(未定)たにあん
12/25makeの総論を語るばるす

はじめに

さて、もうすぐクリスマスですね。趣味は情シス、おかしんです。

IPaaSの弱点として、複数人で自動化を管理更新していくのが若干難しいというのがあります。

これにはいくつかの理由があって、まず1つ目は「各アプリケーションとの接続情報の管理」です。IPaaSを最も基本的な使い方をした時は自動化を作成しているユーザー自身の認証情報を使って接続します。その場合、自動化全体(フロー、レシピ、シナリオ、Zapなど)はチームで編集ができたとしても、認証部分は個々人に紐付いてしまっており、変更する場合は別のユーザーで接続しなおすか、最初から共有アカウントを利用するなどといった対策が必要になります。MakeではAPIキーを用いた接続を保存しておくことができますが、それでもAPIのスコープなど結局キーを発行した本人にしか変更できない場合も多いです。
また、Connectionの管理画面も使いやすいものではありません。

こういった運用部分の方針を決めるのがなかなか難易度が高く、結局作成した人が保守運用せざるを得ないケースが多いのではないでしょうか?

2つ目は変更履歴が追いにくいということです。差分をわかりやすく表示してくれるIPaaSは私の知る限りでは少ないです。

ということで、今日の記事ではこの2つ目の課題に対するアプローチとしてGitHub連携を考えてみたいと思います。

IPaaSを使ってAPIを直接操作したり、繰り返し処理をしたり、エラーハンドリングをしたり、とちょっとプログラミングチックな使い方をしている方は、おそらくGitを使ってコードの変更管理をしたことがある方も多いと思います。4日目の記事で書いたとおり、MakeではScenarioやTemplateは全てJSONで表現可能なので、これをGitHubと連携してあげれば、GitHubによる差分管理ができるのではないか?という仮説です。

この記事で学べること

  1. MakeにおけるJSONの扱い
  2. MakeのAPIをMakeから叩く方法
  3. MakeからGitHubのリポジトリにプッシュする方法

MakeにGitHub連携ってあるの?

結論から言うと、今回意図したような使い方での連携は「ありません」。GitHubモジュールはあるのですが、イシューやプルリクエスト関連のモジュールはあるものの、コードそのものを弄ることができるモジュールはありません(コミット、プッシュ、マージ等々)

実は今回のアドベントカレンダーにおいて、25日間のテーマはばるすが考えており、今日のテーマの「GitHub連携」もばるすが割り振っています。「シナリオの更新をトリガーにして、シナリオのJSONをGitHub連携でプッシュするような仕組み」と概要を聞きましたが、GitHub連携なんて無いんですよ。。。

というわけで、APIを使ってごちゃごちゃやるしかないです。

完成イメージ

  1. Makeでシナリオの変更を検知する別のシナリオを作る
  2. 変更を検知したら、MakeのAPIを叩いて、変更後のシナリオのBlueprint(JSON)を取得
  3. 取得したBlueprintをGitHubのAPIを叩いてリポジトリにプッシュ
  4. コミットURLを含めてSlackに通知

大まかな流れはこんな感じです。GitHubのコミットURLをみれば、どこが変更されたのかがなんとなく分かる、という仕様です。

上記の実装のイメージはすぐに考えついたのですが、いくつも試行錯誤して、結果諦めた部分もあったりします。正直あまりスマートではないのでボツにしようかと何度も思いましたが、そういった「ハマりポイント」を紹介すること自体が有益かもしれないので、誰かがMakeからAPIを叩くシナリオを作る時に役に立つことを願って、作り方やハマりポイントを詳細に紹介してみようと思います。

作ってみる

管理対象シナリオを用意

さて、まずは変更の管理対象となるシナリオを用意する必要があるので、適当なものを1つ作ります。

Asanaにタスクが追加されたら、Slackに通知されるだけの簡単なものです

さて、この作成したシナリオを開いた時のURLは以下のようになります

https://us1.make.celonis.com/1638/scenarios/58298/edit

このURLの要素は以下のように分解できます

  • us1.make.celonis.com
    • テナントのURL
      • エンプラの場合はインフラ環境ごと違うので「celonis.com」になります
      • エンプラ以外の場合は us2.make.com のようになります
    • 1638
      • TeamIDです
    • 58298
      • ScenarioIDです

今回作るシナリオでは、この58298 という値を使うことになります。

管理用シナリオの作成

1. Scenarioの変更を検知するモジュールを追加

APIキーの発行

Makeの「Makeモジュール」はログインしているユーザーの認証情報ではなく、全てAPIキーでConnectionを作る必要があるので、先にAPIキーを発行します。

Profile => API ACCESSからトークンを発行できます

organizations:readscenarios:read のスコープを有効にし、Labelをつけて保存します。Makeモジュールについては基本的に何をやるにしても organizations:read が必要だと思います。何故かというとモジュールの設定画面でOrganizationを選択する箇所があるのですが、このスコープがないと選択自体ができずモジュールを保存できません。ちなみにTokenは後からスコープを変更できないので、スコープが足りていないことを確認する度にTokenを再作成し、Connectionも変更する必要があり、非常にだるいです。まじキレそう。

作成すると、一回だけTokenが発行されるのでコピーしておきます。

次に一つ目のモジュール「Make | Watch Scenarios」を追加します

Create a connection

テナントURLとトークンを入力して保存します

OrganizationやTeamなどを選択します。

なお、見ていただいたら分かるようにこのタイミングではScenarioIDを指定することができず、フォルダーまでしか指定できません。意味不明です。1つのシナリオだけ監視したい場合は、フォルダを作って、1つのシナリオだけ入れてあげる必要があります。

シナリオ画面でフォルダを作成できるので、なるべく作成しておきましょう。なお、画面の横幅が狭い場合、フォルダ作成メニューが表示されません。画面を広くして作成しましょう。なめてんのか。

2. シナリオのBlueprintを取得するモジュール

「Get a Scenario Blueprint」というモジュールがあったので、使ってみます。

「Draft」の部分はNoにすると「ON」になっているシナリオだけ、Yesにすると「OFF」になっているシナリオだけ、Emptyにするといずれの状態でも取得します。

今回は、稼働中のシナリオが変更されたことを検知したいので「No」にします。

Advancedオプションでどんなデータを返すかを選択できます。

①In a Raw JSON Objectの場合

このようなデータが返ってきます。

②In a JSON Stringの場合

一行の長いJSONで返ってきます

③In a JSON Fileの場合

さて、この3つのうちどれを利用するかは悩ましいです。最終的にGitHubのAPIを叩いてリポジトリにプッシュするので、GitHub APIの仕様を確認します。

curl -L \
  -X PUT \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/OWNER/REPO/contents/PATH \
  -d '{"message":"a new commit message","committer":{"name":"Monalisa Octocat","email":"octocat@github.com"},"content":"bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz","sha":"95b966ae1c166bd92f8ae7d1c313e738c731dfc3"}'

"content":"bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz" の部分が実際にプッシュするファイルです。BASE64でエンコードした文字列をリクエストに含めます。"sha":"95b966ae1c166bd92f8ae7d1c313e738c731dfc3"} の部分は更新する対象のファイルのハッシュです。新規作成の場合は必要無いですが、更新の場合は更新前のファイルのバージョンを伝える為に必要になります。

後述しますが、Makeでは「Set variable」というモジュールで、base64() という標準Functionを利用することで、BASE64で文字列をエンコードすることが可能である為、このAPIを叩いてMakeからリポジトリにプッシュすることは可能です。

あとはどういった形式でプッシュするのか?

最終的にはGitHubでdiffを取ることを目的とするのですが、①の場合だと分解されたJSONから再度JSONを構成しなおして、リクエストに含める必要があり、毎回JSONの構成も変わるのでMakeでシナリオを作るのが困難です。また③の場合はMake単体でバイナリを処理するモジュールが存在していないのでこれも使えません。

残るは「②In a JSON Stringの場合」ですが、このままアップロードしたとて1行なので、diffでは全体が変わったということしか分からず、本来の目的が達成できません。綺麗に整形されたJSONでプッシュする必要があります。

ですが結論から言うと、綺麗に整形されたJSONをMakeで作り出すことは困難です。

JSONの要素数が絶対に変化せず、ある程度要素数も少ないケースにおいては、「Text Parserモジュール」を利用して整形されたJSONを生成することは可能ですが、例えば今回やろうとしているケースだと、監視対象のシナリオにモジュールが増えたり減ったりした場合はBlueprintのJSONの要素数が変わってしまう為、Text Parserなどで冪等性が担保された処理を行うことは不可能です。

発想の転換

というわけで、「そもそも大まかな変更が検知できたら実際はシナリオを見に行くよね?」という発想のもと、とりあえず①の改行だけを行ってみました。

1行の長いJSONをカンマがある度に改行するというだけの処理を追加し、そうやって改行されたテキストをGitHubにプッシュしたところ、以下のような結果が得られました

これは監視対象のシナリオで、タスクが追加されたときのSlack投稿されるメッセージ部分に適当な文字列を追加した、という変更ですが、インデントなど全然できていないものの「どこが変更されたかを視覚的に簡単に把握する」という目的そのものは達成できているのではないでしょうか?

「シナリオが変更されました」という通知だけでは情報が少なすぎますが、「何か問題のある変更を行っていないか?」を監視する立場になって考えてみると、これだけでも十分な情報が得られていると思います。

というわけで、完成しましためでたしめでたし

納得いかない

一応これでも目的は達成できてはいるものの、インデントされていないJSONなんて生理的に無理!

とはいえMake単体でJSONを整形するのも難しいので、何かしら外部で処理することを検討します。Javascriptのコードを実行できるSaaSのモジュールなどがいくつか存在していましたが、有料のSaaSだったりしてどれもあまり使えなさそうでした。

こうなったら最後の手段。

自分でパブリックAPIを作ってそいつにやらせる!

いやもうこれしか思いつきませんでした。

やってみる

というわけでCloudflare Workersで簡単なパブリックAPIを作ります。Cloudflare WorkersとはCloudflareが提供するサーバーレスなJavaScript/TypeScript実行環境です。エッジ(CDNの各拠点)でコードを実行できるため、低レイテンシかつ高パフォーマンスなサービスを構築できます。ウェブアプリケーションやAPIの軽量な処理をエッジで迅速に行う用途に最適です。(オタク特有の早口)

まあ、あれです。AWS Lambdaのようなもんだと思ってください。

デプロイ方法とかまで書いてたらそれだけで1記事書けちゃうので「Cloudflare Workers wrangler デプロイ」とかで調べてみてください。

そんなわけで。作りました。JSONを整形して返すだけのしょーもないAPIを。

一応コードも置いておきます

export default {
  async fetch(request, env, ctx) {
    // (1) メソッドとContent-Typeをチェック
    if (request.method !== 'POST') {
      return new Response('Method Not Allowed', { status: 405 });
    }
    const contentType = request.headers.get('Content-Type') || '';
    if (!contentType.includes('application/json')) {
      return new Response('Unsupported Media Type', { status: 415 });
    }

    // (2) リクエストボディをJSONとして読み取る
    let jsonData;
    try {
      jsonData = await request.json();
    } catch (e) {
      // JSONパースエラー(不正なJSON)
      return new Response('Invalid JSON', { status: 400 });
    }

    // (3) JSONを整形して文字列化(2スペースインデント)
    const formattedJson = JSON.stringify(jsonData, null, 2);

    // (4) 整形済みJSONをレスポンス(Content-Type: application/json)で返す
    return new Response(formattedJson, {
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

まあなんのことはなくて、Javascriptの標準のメソッドである JSON.stringify() をしてるだけです。

これをデプロイするとURLを発行してくれるのですが、そこに対してPOSTでbodyにJSONを入れてリクエストするだけです。試しに、Blueprintの長い一行のJSONをBodyに入れてPOSTしてみると以下のようなレスポンスが返ってきます。

このAPIを早速処理に盛り込んでみます

Slackには以下のような通知が飛んで来ます

コミットログのURLに飛ぶと。

ちゃんとこのようにキレイなJSONでGitHubにプッシュされています

https://github.com/okash1n/make-blueprints/blob/main/blueprint.json

せっかくなんで記念撮影もしておきましょう。

あとがき

いかがでしたでしょうか?

「MakeではScenarioやTemplateは全てJSONで表現可能なので、これをGitHubと連携してあげれば、GitHubによる差分管理ができるのではないか?」という仮説は「まあ、できなくもない」という感想です。

シナリオ監視のモジュールはフォルダを絞って監視できるので、そのあたりの設計をちゃんとすることと、シナリオ名に従って、GitHubのリポジトリにフォルダをわけてプッシュするような仕組みにしておけば、チームの管理する全てのシナリオを綺麗にGitHubで差分管理するみたいなことも可能ではあると思います。

それにしてもMakeでJSONをそのままJSONとして扱うのがこんなに難しいとは思いませんでした。

しばらくMakeはいいです。ほなさいなら。

okash1n

香川大学医学部医学科中退→SES・情シス・SREを経てクラウドネイティブ入社。趣味はIT。

・有限会社脇屋 代表取締役
・一般社団法人日本ビジネステクノロジー協会 代表理事
・一般社団法人 SRE NEXT 理事
・情シスSlack、BTCONJP、SRENEXT運営