GitHubと連携する新しいアプリの形：GitHub Appsの作り方

GitHub Appsとは、GitHubと連携するアプリケーションの新しい形式です。
この形式はアプリケーションのマーケットプレイスである、[GitHub Marketplaceの公開と共にアナウンスされました](https://github.com/blog/2359-introducing-github-marketplace-and-more-tools-to-customize-your-workflow)。つまり、GitHub Appsを作成する、マーケットプレイスで公開する、それで収益を上げる、というエコシステムがしっかりと整備されたということです。

そんな夢の広がるGitHub Appsの作り方を、本記事では紹介しようと思います。

# GitHubと連携するアプリケーションの形式

まず、GitHub Appsを含め、GitHubと連携するアプリケーションの形式を整理しておきます。

## Webhooks

[Webhooks](https://developer.github.com/webhooks/)は、リポジトリの特定のイベント(pushしたとか)をトリガにして、その更新情報を設定先のサーバーなどに通知する形式になります。設定は以下の場所で行います。ここで、通知対象のイベントなどについても設定が可能です。

<img src="https://qiita-image-store.s3.amazonaws.com/0/25990/4b76dac4-6afe-a779-b9d7-2d1fba60dec2.png" width=400 />

なお、Webhooksは[Organizationの単位で設定することもでき](https://developer.github.com/v3/orgs/hooks/)、この場合Organization配下の全てのリポジトリのイベントを受け取ることが可能になります。

ただ、Webhooksは「受け取るだけ」なのでGitHubリポジトリ側に対して何かしらの操作を行うことはできません(Issueにコメントをつけるなど)。GitHubリポジトリ側に対して何かアクションを取る必要がある場合は、以下のOAuth Appsを併用するかGitHub Appsにする必要があります。

## OAuth Apps

OAuth Appsはその名(OAuth)の通り、GitHubユーザーアカウントの認証情報を利用しGitHubリポジトリなどに対して操作を行う形式になります。そのため、OAuth Appsを作成する際はユーザーアカウントのSettings > Developer settingsから登録を行うことになります。

<img src="https://qiita-image-store.s3.amazonaws.com/0/25990/40674cfc-e762-1275-5fd2-ba3d6b526c60.png" width=400 />

こちらはGitHubと連携するアプリだけでなく、単にGitHubユーザーアカウントを認証情報(ログイン情報)として利用するようなサイトの開発でも使用します。OAuthの認証については通常[ページ遷移を挟む形で認証を行います](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/#web-application-flow)が、バックエンドで連携するサービスの場合そもそも画面がないので[オフラインでの認証フローもサポートされています](https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app)。

OAuth Appsは「GitHubユーザーアカウントの認証情報」を利用するという特性上、ユーザーがアクセス権限を失ったりアカウントを閉じてしまったりした場合は当然連携も終了することになります。これは個人が利用する分にはむしろ当然ですが、チーム開発などを行なっている場合好ましくありません(プロジェクトメンバーから退会した人が連携設定をしていた！とか)。また、誰のOAuthで連携しているかわからなくなるといった事態も考えられます。

つまり、OAuth Appsは「GitHubユーザー」が個人的に利用するアプリ/サイトには適していますが、チームで管理する「GitHubリポジトリ」のためのアプリとしてはちょっと問題をはらむ、ということです。

## GitHub Apps

GitHub Appsは、前述のOAuth Appsに対して「GitHubリポジトリ」のためのアプリの開発に向いた形式になります。というのも、インストール単位がユーザー/Organizationの保持するリポジトリ単位になるためです。

リポジトリに対するアクセスだけでなく、リポジトリにおけるイベントの発生も受け取ることができるため(Webhookを備える)、「リポジトリの特定のイベントに反応し、リポジトリに対して何かの操作をする」アプリケーションの開発には最適な方式となります。
なおOAuthの認証も行うことができるため、ログイン認証に利用する他、GitHub Appsとしてでなく[ユーザーの代理として(ユーザーのアクセストークンで)](https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/identifying-users-for-github-apps/)リポジトリに対する処理を行うことも可能です。これは、Gitterのようなリポジトリ単位のサイト(チャットや、タスク管理など、色々アイデアは広がると思います)を作成する際に利用することができます。

細かい認証方式の違いについては、以下に記載されています。

[About choosing an integration type](https://developer.github.com/apps/building-integrations/setting-up-a-new-integration/about-choosing-an-integration-type/)


今回は、このGitHub Appsの開発について見ていきます。

# GitHub Appsの開発

ここからは、実際にGitHub Appsを開発する手順について見ていきます。

## GitHub Appsの登録

まずは開発するGitHub Appsの登録を行います。この登録は、ユーザー、もしくはOrganization単位で可能です。以下の手順に則り、登録を行いましょう。

[Registering GitHub Apps](https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/registering-github-apps/)

ここで登録したGitHub Appsを、あなたのユーザーがリポジトリにインストールして使う、という形になります。ここで登録するPermissionsは、これから開発するGitHub Appsに必要で、インストールするユーザーが許諾する権限になります。

## GitHub Appsの認証

GitHub AppsでもOAuth認証を利用する場合は、OAuthと同様になります。この場合はユーザーのアクセストークンを利用してAPIを利用することになるため、認証したユーザーが行えない操作は当然行うことはできません。

GitHub Appsとしての認証を行う場合は、そこで得られたアクセストークンを用いてPermissionsにて許諾された権限の操作を行うことができます。今回はその認証プロセスについて見ていきます。

[About authentication options for GitHub Apps](https://developer.github.com/apps/building-integrations/setting-up-and-registering-github-apps/about-authentication-options-for-github-apps/)

GitHub Appsとしての認証を行うには、GitHub Apps登録時に得られるPrivate key(pemファイル)が必要になります。これを利用し、[JSON Web Tokens(JWT)](https://jwt.io/introduction/)という方式で認証を行います。そのフローは以下のようになっています。

* Private Keyを含むJWTを作成し、Authorizationヘッダに含め送信する
* GitHub側でこのJWTをチェックし、okならインストールされたリポジトリに対するアクセスを可能にするアクセストークンを発行する
* このアクセストークンを利用し、APIを実行する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/25990/5229d12c-4d6b-001f-501c-d8cdae47c284.png)

JWTを作成するパッケージは各言語で開発されており、実装言語にあったものを利用することができます(GitHub側での認証のためにはRS256で暗号化しないといけないので、その点は注意してください)。

[Libraries for Token Signing/Verification](https://jwt.io/#libraries)

なお、この認証では結構はまりました。アクセストークンは有効期間を指定する必要があるのですが(最大10分)、この日時のチェックがうまくいったりいかなかったりすることがありました。この点は[皆はまっていましたが](https://platform.github.community/t/issued-at-claim-iat-must-be-an-integer-representing-the-time-that-the-assertion-was-issued/1549)、私は発行日時をちょっと過去にすることで安定的に認証が通るようになりました。

最近作成したGitHub Appsで認証を行っているコードは以下の部分なので、実装する際は参考にしていただければと思います

[chakki-works/typot/env.py](https://github.com/chakki-works/typot/blob/master/typot/env.py#L27)

## GitHubリポジトリに対する処理の実装

認証が行えたら、あとは[GitHub API](https://developer.github.com/v3/)を利用してGitHubリポジトリに対して様々な操作を行うことができます。

なお、GitHubではAPIを[GraphQL](https://developer.github.com/v4/reference/mutation/updatepullrequestreview/)ベースのものにしていく予定とのことなので、今後作成する場合はこちらを利用したほうがよいと思います。

## GitHub Appsのテスト

GitHub Appsはその形式上、テストに当たってはテスト用のリポジトリが欠かせなくなってきます。このテスト用のリポジトリに作成したGitHub Appsをインストールをして、所定のイベントに対して処理がトリガされるか、またリポジトリに対する処理は適切に行えるか、をチェックします。
Webhookや認証のテストに際してはグローバルアクセスが必要となりますが、逐一どこかのサーバーにデプロイするのは骨なので、[ngrok](https://ngrok.com/)を利用すると便利です。

とはいえ、実際にイベントを起こすためにIssueを登録したりしないといけないことに変わりはありません。幸いにもGitHub Appsの登録ページの「Advanced」のタブから、過去に発行されたイベントの再送信を行う「Redeliver」が可能なので、こちらを利用するとよいでしょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/25990/0dbbcc79-d122-4b87-9967-e2d8e0d53e30.png)

あとは、個人的にはローカルでテストするために実際に発行されたJSONをテスト用ファイルに保存して利用していました。

このようにテストは結構苦行ですが、これが終わればいよいよ公開に移ります！

# GitHub Appsの公開

開発したアプリを早速マーケットに公開だ！と思うかもしれませんが、そんなあなたには悲しい事実を告げなければなりません。

[Requirements for listing an app on GitHub Marketplace](https://developer.github.com/apps/adding-integrations/listing-apps-on-github-marketplace/requirements-for-listing-an-app-on-github-marketplace/)

* OAuth Appsの場合、最低でも1000人の登録ユーザーがいること
* GitHub Appsの場合、最低でも250インストールがあること

ほかにもセキュリティなどの面で用件はありますが、一番満たすのが難しいのは上記の2点と思います。生まれたてのアプリはおよびじゃねえんだよ、ということです。

なお、インストールしているリポジトリ数は現在のところ画面で確認することができず、以下のAPIをたたいて確認する必要があります。

[GitHub Apps/Find installations](https://developer.github.com/v3/apps/#find-installations)

先日作成したGitHub Appsにはカウントを行うスクリプトを入れているので、ご参考ください。

[chakki-works/typot/get_installations.py](https://github.com/chakki-works/typot/blob/master/get_installations.py)

では公開の場はないのか・・・ということですが、ライト版のWorks with GitHubというサイトが用意されています。

[Works with GitHub](https://github.com/works-with)

こちらはGitHubのサービス規約などに合致していれば申請が可能です(詳細は[こちら](https://developer.github.com/apps/adding-integrations/adding-integrations-to-works-with-github/requirements-for-adding-an-integration-to-works-with-github/)をご覧ください)。
なお、一度申請するとDescriptionなどは修正できず、承認が通った後は窓口まで依頼しないと修正できないので注意してください。[毎週金曜にレビューをしているそうなので](https://developer.github.com/apps/adding-integrations/adding-integrations-to-works-with-github/adding-an-integration-to-works-with-github/)、金曜前に申請するとよいでしょう。

ただ、私もGitHubを利用して長いですがこのサイトの存在を知ったのは今回初めてで、しかも「Works with GitHub」のググラビリティは異常に低くめったなことでは検索に引っかかりません(おまけにGitHubのポータルからのリンクもない)。そのため、ここに掲載したところで恩恵は少ないかもです。

最後に、私が作成したGitHub Appsのリポジトリを紹介しておきます。皆様の実装の参考になれば幸いです。

[chakki-works/typot](https://github.com/chakki-works/typot)
(役立ちましたらStarを頂ければ励みになりますm(_ _)m)

機能については、以下記事をご参照ください。

[Pull Requestに潜むタイポを自動的に検出し、修正を代行するBot](http://qiita.com/icoxfog417/items/5edb32b34dfb7886d426)

GitHub Marketplaceで天下を取るのを目指して頑張りましょう！