Git
章 ▾ 第2版

6.5 GitHub - GitHubのスクリプト

GitHubのスクリプト

さて、これでGitHubの主要な機能とワークフローをすべて説明しましたが、大規模なグループやプロジェクトでは、カスタマイズや外部サービスの統合を検討する場合があります。

幸いなことに、GitHubはさまざまな方法で非常にハック可能です。このセクションでは、GitHubフックシステムとそのAPIを使用して、GitHubを望むように動作させる方法について説明します。

サービスとフック

GitHubリポジトリ管理の[フックとサービス]セクションは、GitHubを外部システムと対話させる最も簡単な方法です。

サービス

まず、サービスを見ていきましょう。フックとサービスの両方の統合は、リポジトリの[設定]セクションにあります。ここでは、以前にコラボレーターの追加とプロジェクトのデフォルトブランチの変更を行いました。[Webhooks and Services]タブの下に、サービスとフックの設定セクションのようなものが表示されます。

Services and Hooks configuration section
図129。サービスとフックの設定セクション

選択できるサービスは数十あり、そのほとんどが他の商用およびオープンソースシステムへの統合です。それらのほとんどは、継続的インテグレーションサービス、バグと問題追跡ツール、チャットルームシステム、およびドキュメントシステム向けです。非常に簡単なもの、つまりメールフックのセットアップを順を追って説明します。[サービスを追加]ドロップダウンから[メール]を選択すると、メールサービスの設定のような構成画面が表示されます。

Email service configuration
図130。メールサービスの設定

この場合、[サービスの追加]ボタンを押すと、誰かがリポジトリにプッシュするたびに、指定したメールアドレスにメールが送信されます。サービスはさまざまな種類のイベントをリッスンできますが、ほとんどはプッシュイベントのみをリッスンし、そのデータを使って何かを行います。

GitHubと統合したいシステムを使用している場合は、既存のサービス統合が利用可能かどうかをここで確認してください。たとえば、Jenkinsを使用してコードベースでテストを実行している場合は、Jenkins組み込みサービス統合を有効にして、誰かがリポジトリにプッシュするたびにテスト実行を開始できます。

フック

さらに具体的なものが必要な場合や、このリストに含まれていないサービスまたはサイトと統合したい場合は、代わりに、より一般的なフックシステムを使用できます。GitHubリポジトリフックは非常に簡単です。URLを指定すると、GitHubは任意のイベントでそのURLにHTTPペイロードを投稿します。

一般的に、この仕組みは、GitHubのフックペイロードをリッスンする小さなWebサービスをセットアップし、受信したデータを使って何かを行うというものです。

フックを有効にするには、サービスとフックの設定セクションにある「Webhookを追加」ボタンをクリックします。これにより、Webhookの設定のようなページが表示されます。

Web hook configuration
図131. Webhookの設定

Webhookの設定は非常にシンプルです。ほとんどの場合、URLとシークレットキーを入力して「Webhookを追加」をクリックするだけです。GitHubがペイロードを送信するイベントをいくつかオプションで選択できます。デフォルトでは、誰かがリポジトリの任意のブランチに新しいコードをプッシュしたときに発生するpushイベントのペイロードのみを取得します。

Webhookを処理するために設定するWebサービスの簡単な例を見てみましょう。RubyのWebフレームワークであるSinatraを使用します。これは非常に簡潔で、何をしているのかを簡単に理解できるはずです。

特定の人物が特定のファイルが変更されたプロジェクトの特定のブランチにプッシュした場合にメールを受信したいとします。このようなコードで比較的簡単に行うことができます。

require 'sinatra'
require 'json'
require 'mail'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON

  # gather the data we're looking for
  pusher = push["pusher"]["name"]
  branch = push["ref"]

  # get a list of all the files touched
  files = push["commits"].map do |commit|
    commit['added'] + commit['modified'] + commit['removed']
  end
  files = files.flatten.uniq

  # check for our criteria
  if pusher == 'schacon' &&
     branch == 'ref/heads/special-branch' &&
     files.include?('special-file.txt')

    Mail.deliver do
      from     'tchacon@example.com'
      to       'tchacon@example.com'
      subject  'Scott Changed the File'
      body     "ALARM"
    end
  end
end

ここでは、GitHubが配信するJSONペイロードを取得し、誰がプッシュしたのか、どのブランチにプッシュしたのか、およびプッシュされたすべてのコミットでどのファイルが触られたのかを調べています。次に、それを基準と照合し、一致する場合はメールを送信します。

このようなものを開発およびテストするために、フックを設定するのと同じ画面に便利な開発者コンソールがあります。GitHubがそのWebhookに対して行った最後の数回の配信を確認できます。各フックについて、いつ配信されたか、成功したかどうか、リクエストとレスポンスの両方のボディとヘッダーを詳しく調べることができます。これにより、フックのテストとデバッグが非常に簡単になります。

Web hook debugging information
図132. Webhookのデバッグ情報

この他の優れた機能は、サービスのテストのために、ペイロードを簡単に再配信できることです。

Webhookの書き方と、リッスンできるすべての異なるイベントタイプの詳細については、GitHub開発者ドキュメントのhttps://docs.github.com/en/webhooks-and-events/webhooks/about-webhooksを参照してください。

GitHub API

サービスとフックは、リポジトリで発生するイベントに関するプッシュ通知を受信する手段を提供しますが、これらのイベントに関する詳細情報が必要な場合はどうでしょうか?共同作業者の追加やIssueへのラベル付けなどの操作を自動化する必要がある場合はどうでしょうか?

ここでGitHub APIが役に立ちます。GitHubには、Webサイトで実行できるほぼすべてのことを自動化された方法で実行するためのAPIエンドポイントが多数あります。このセクションでは、APIの認証と接続の方法、Issueへのコメント方法、APIを介してプルリクエストのステータスを変更する方法について学習します。

基本的な使い方

最も基本的なことは、認証を必要としないエンドポイントに対する単純なGETリクエストを実行することです。これは、ユーザーまたはオープンソースプロジェクトに関する読み取り専用の情報である可能性があります。たとえば、「schacon」というユーザーの詳細を知りたい場合は、次のようなものを実行できます。

$ curl https://api.github.com/users/schacon
{
  "login": "schacon",
  "id": 70,
  "avatar_url": "https://avatars.githubusercontent.com/u/70",
# …
  "name": "Scott Chacon",
  "company": "GitHub",
  "following": 19,
  "created_at": "2008-01-27T17:19:28Z",
  "updated_at": "2014-06-10T02:37:23Z"
}

組織、プロジェクト、Issue、コミットなど、GitHubで公開されているほぼすべての情報を取得するためのエンドポイントが多数あります。APIを使用して任意のMarkdownをレンダリングしたり、.gitignoreテンプレートを検索したりすることもできます。

$ curl https://api.github.com/gitignore/templates/Java
{
  "name": "Java",
  "source": "*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}

Issueへのコメント

ただし、Issueやプルリクエストにコメントするなどのウェブサイト上でアクションを実行する場合、またはプライベートコンテンツを表示または操作する場合は、認証を行う必要があります。

認証にはいくつかの方法があります。ユーザー名とパスワードのみを使用する基本認証を使用できますが、一般的には個人アクセストークンを使用することをお勧めします。これは、設定ページの「アプリケーション」タブから生成できます。

Generate your access token from the “Applications” tab of your settings page
図133. 設定ページの「アプリケーション」タブからアクセストークンを生成

このトークンに使用するスコープと説明を求められます。スクリプトまたはアプリケーションが不要になったときにトークンを安心して削除できるように、わかりやすい説明を使用してください。

GitHubはトークンを一度しか表示しないため、必ずコピーしてください。これで、スクリプトでユーザー名とパスワードを使用する代わりに、これを使用して認証できます。これにより、実行したいことの範囲を制限でき、トークンは取り消し可能であるため便利です。

これにより、レート制限が増加するという利点もあります。認証しない場合、1時間に60件のリクエストに制限されます。認証すると、1時間に最大5,000件のリクエストを行うことができます。

それでは、それを使用してIssueの1つにコメントしてみましょう。特定のIssue(Issue#6)にコメントを残したいとします。そのためには、先ほど生成したトークンをAuthorizationヘッダーとして使用して、repos/<user>/<repo>/issues/<num>/commentsにHTTP POSTリクエストを行う必要があります。

$ curl -H "Content-Type: application/json" \
       -H "Authorization: token TOKEN" \
       --data '{"body":"A new comment, :+1:"}' \
       https://api.github.com/repos/schacon/blink/issues/6/comments
{
  "id": 58322100,
  "html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
  ...
  "user": {
    "login": "tonychacon",
    "id": 7874698,
    "avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
    "type": "User",
  },
  "created_at": "2014-10-08T07:48:19Z",
  "updated_at": "2014-10-08T07:48:19Z",
  "body": "A new comment, :+1:"
}

これで、そのIssueに移動すると、GitHub APIから投稿されたコメントのように、正常に投稿したコメントが表示されます。

A comment posted from the GitHub API
図134. GitHub APIから投稿されたコメント

APIを使用すると、Webサイトでできるほぼすべての操作を行うことができます。たとえば、マイルストーンの作成と設定、Issueとプルリクエストへのユーザーの割り当て、ラベルの作成と変更、コミットデータへのアクセス、新しいコミットとブランチの作成、プルリクエストのオープン、クローズ、マージ、チームの作成と編集、プルリクエストのコード行へのコメント、サイトの検索などです。

プルリクエストのステータスの変更

プルリクエストを操作する場合に非常に便利なため、最後に別の例を見てみましょう。各コミットには、1つ以上のステータスを関連付けることができ、そのステータスを追加およびクエリするためのAPIがあります。

ほとんどの継続的インテグレーションおよびテストサービスは、このAPIを使用して、プッシュされたコードをテストすることでプッシュに対応し、そのコミットがすべてのテストに合格したかどうかを報告します。また、コミットメッセージが適切にフォーマットされているか、提出者がすべてのコントリビューションガイドラインに従っているか、コミットが有効に署名されているかなど、さまざまなことを確認するために使用できます。

コミットメッセージにSigned-off-by文字列があるかどうかをチェックする小さなWebサービスにヒットするWebhookをリポジトリにセットアップするとします。

require 'httparty'
require 'sinatra'
require 'json'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON
  repo_name = push['repository']['full_name']

  # look through each commit message
  push["commits"].each do |commit|

    # look for a Signed-off-by string
    if /Signed-off-by/.match commit['message']
      state = 'success'
      description = 'Successfully signed off!'
    else
      state = 'failure'
      description = 'No signoff found.'
    end

    # post status to GitHub
    sha = commit["id"]
    status_url = "https://api.github.com/repos/#{repo_name}/statuses/#{sha}"

    status = {
      "state"       => state,
      "description" => description,
      "target_url"  => "http://example.com/how-to-signoff",
      "context"     => "validate/signoff"
    }
    HTTParty.post(status_url,
      :body => status.to_json,
      :headers => {
        'Content-Type'  => 'application/json',
        'User-Agent'    => 'tonychacon/signoff',
        'Authorization' => "token #{ENV['TOKEN']}" }
    )
  end
end

おそらくこれは非常に簡単だと思います。このWebhookハンドラーでは、プッシュされたばかりの各コミットを調べ、コミットメッセージに「Signed-off-by」という文字列があるかどうかを調べ、最後に、ステータスとともに/repos/<user>/<repo>/statuses/<commit_sha> APIエンドポイントにHTTP経由でPOSTします。

この場合、状態(「成功」、「失敗」、「エラー」)、発生したことの説明、ユーザーが詳細情報を参照できるターゲットURL、および単一のコミットに複数のステータスがある場合に備えて「コンテキスト」を送信できます。たとえば、テストサービスがステータスを提供し、このような検証サービスもステータスを提供する場合があります。「コンテキスト」フィールドは、それらを区別する方法です。

誰かがGitHubで新しいプルリクエストを開き、このフックが設定されている場合、APIによるコミットステータスのようなものが表示される可能性があります。

Commit status via the API
図135. APIによるコミットステータス

これで、メッセージに「Signed-off-by」文字列があるコミットの横に小さな緑色のチェックマークが表示され、署名を忘れたコミットには赤いバツ印が表示されます。また、プルリクエストがブランチの最後のコミットのステータスを取得し、失敗した場合は警告することもできます。これは、テスト結果にこのAPIを使用している場合に、最後のコミットがテストに失敗しているものを誤ってマージしないようにするために非常に便利です。

Octokit

これらの例では、ほとんどすべてのことをcurlと単純なHTTPリクエストを介して行ってきましたが、このAPIをより慣用的な方法で利用できるようにするいくつかのオープンソースライブラリが存在します。この執筆時点では、サポートされている言語には、Go、Objective-C、Ruby、.NETが含まれています。これらに関する詳細については、https://github.com/octokitを参照してください。これらのライブラリはHTTP処理の多くを代行します。

これらのツールが、特定のワークフローに合わせてGitHubをカスタマイズおよび変更するのに役立つことを願っています。API全体に関する完全なドキュメントと、一般的なタスクのガイドについては、https://docs.github.com/をご覧ください。

scroll-to-top