# デプロイメントを配信する

Deployment REST APIを使用すると、サーバーおよびサードパーティアプリケーションとやり取りするカスタムツールを構築できます。

REST API を使用して、所有するサーバー上の GitHub でホストされているプロジェクトをデプロイできます。 配置と状態を管理するエンドポイントの詳細については、「[デプロイ用の REST API エンドポイント](/ja/enterprise-server@3.22/rest/deployments)」を参照してください。 また、この REST API を使うと、コードが既定のブランチに配置されたときに配置を調整できます。 詳しくは、「[CIサーバーの構築](/ja/enterprise-server@3.22/rest/guides/building-a-ci-server)」をご覧ください。

このガイドでは、REST API を使って、利用できる設定を示します。
このシナリオでは、以下を行います。

* Pull Requestをマージします。
* CIが終了したら、それに応じてプルリクエストのステータスを設定します。
* プルリクエストがマージされたら、サーバーでデプロイメントを実行します。

このCIシステムとホストサーバーは、想像上のものです。 Heroku でも、Amazon でも、何でも構いません。 このガイドのポイントは、通信を管理するサーバーを設定し、構成することにあります。

まだ行っていない場合は必ず `ngrok` を[ダウンロードし](https://ngrok.com/)、その[使い方](https://ngrok.com/docs/getting-started/)をご確認ください。 これは、ローカル アプリケーションをインターネットに公開するために非常に便利なツールであることがわかりました。

注: このプロジェクトの完全なソース コードは、[platform-samples リポジトリから](https://github.com/github/platform-samples/tree/master/api/ruby/delivering-deployments)ダウンロードできます。

## サーバーを書く

ローカル接続が機能していることを証明するための、簡単なSinatraアプリケーションを書きます。
まずはこれから始めましょう。

```ruby
require 'sinatra'
require 'json'

post '/event_handler' do
  payload = JSON.parse(params[:payload])
  "Well, it worked!"
end
```

(Sinatra のしくみに詳しくない場合は、[Sinatra ガイド](http://www.sinatrarb.com/)を読むことをお勧めします。)

このサーバーを起動してください。 既定では、Sinatra はポート `4567` で起動するため、`ngrok` もそのポートで待ち受けるように構成してください。

このサーバーが機能するには、webhookでリポジトリを設定する必要があります。 プルリクエストが作成やマージされるたびに、webhookが起動するよう設定すべきです。

思う存分試せるリポジトリを作成してみましょう。 <c1><c0 /> の Spoon/Knife リポジトリはいかがでしょうか。

その後、お使いのリポジトリ内に新しい Webhook を作成し、`ngrok` で提供された URL を指定し、コンテンツ タイプとして `application/x-www-form-urlencoded` を選びます。

**\[Webhook の更新]** をクリックします。
`Well, it worked!` の本文応答が表示されます。
すばらしい。
**\[個々のイベントの選択]** をクリックして、次のイベントを選択します。

* デプロイ
* \[デプロイ ステータス]
* プルリクエスト

これらは、関連するアクションが発生するたびにサーバーに送信 GitHub イベントです。 ここではプルリクエストがマージされたときに\_だけ\_処理するようにサーバーを設定します。

```ruby
post '/event_handler' do
  @payload = JSON.parse(params[:payload])

  case request.env['HTTP_X_GITHUB_EVENT']
  when "pull_request"
    if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
      puts "A pull request was merged! A deployment should start now..."
    end
  end
end
```

何が起こっているのでしょうか。
GitHubが送信するすべてのイベントには、`X-GitHub-Event` HTTP ヘッダーが添付されています。 ここではPRイベントのみに注目しましょう。 プルリクエストがマージされると (その状態は `closed` で、`merged` が `true`)、デプロイが開始されます。

この概念実証をテストするには、テスト リポジトリのブランチで何か変更を行い、プルリクエストを開いてマージします。 そうすると、サーバーはそれに応じてレスポンスを返すはずです。

## デプロイメントを扱う

サーバーの準備が整い、コードがレビューされ、プルリクエストがマージされたので、プロジェクトをデプロイしたいと思います。

まず、イベントリスナーを修正して、プルリクエストがマージされたときに処理し、その後、デプロイメントに注意を払い始めましょう。

```ruby
when "pull_request"
  if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
    start_deployment(@payload["pull_request"])
  end
when "deployment"
  process_deployment(@payload)
when "deployment_status"
  update_deployment_status
end
```

プルリクエストからの情報に基づき、`start_deployment` メソッドを書き込むことから始めます。

```ruby
def start_deployment(pull_request)
  user = pull_request['user']['login']
  payload = JSON.generate(:environment => 'production', :deploy_user => user)
  @client.create_deployment(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], {:payload => payload, :description => "Deploying my sweet branch"})
end
```

デプロイには、一部のメタデータを `payload` および `description` の形式で添付できます。 これらの値はオプションですが、ログの記録や情報の表示に役立ちます。

新しいデプロイメントが作成されると、まったく別のイベントがトリガーされます。 そのため、`switch` のイベント ハンドラーに新しい `deployment` ケースがあります。 この情報を使用して、デプロイメントがトリガーされたときに通知を受け取ることができます。

デプロイメントにはかなり時間がかかる場合があるため、さまざまなイベント (デプロイメントがいつ作成されたか、デプロイメントの状態など) をリッスンしたいと思います。

何らかの作業が行われるデプロイメントをシミュレートして、出力に対する影響を確認してみましょう。 まず、`process_deployment` メソッドを完成させます。

```ruby
def process_deployment
  payload = JSON.parse(@payload['payload'])
  # you can send this information to your chat room, monitor, pager, etc.
  puts "Processing '#{@payload['description']}' for #{payload['deploy_user']} to #{payload['environment']}"
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'pending')
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'success')
end
```

最後に、ステータス情報の保存をコンソールの出力としてシミュレートします。

```ruby
def update_deployment_status
  puts "Deployment status for #{@payload['id']} is #{@payload['state']}"
end
```

状況を細かく分解して説明しましょう。
`start_deployment` イベントをトリガーする `deployment` によって、新しいデプロイが作成されます。 そこから、`process_deployment` を呼び出して、進行中の作業をシミュレートします。 この処理中に `create_deployment_status` も呼び出して、状態を `pending` に切り替えることで、受信者に状況を通知します。

デプロイメントが完了したら、状態を `success` に設定します。

## まとめ

GitHub では、長年にわたってデプロイを管理するために、 `Heaven` のバージョンを使用してきました。 一般的なフローは、上記で構築したサーバーと本質的に同じです。

* CIチェックのステータスに対する応答（成功もしくは失敗）を待つ
* 必要なチェックが成功していれば、Pull Requestをマージする
* `Heaven` マージされたコードを受け取り、ステージング サーバーと運用サーバーにデプロイします
* それまでの間、 `Heaven` は、チャット ルームに座っている [Hubot](https://github.com/github/hubot) を介して、ビルドについて全員に通知します

これで完了です。 この例を使用するために、独自のデプロイメントを構築する必要はありません。

[GitHub統合](https://github.com/integrations)に常に依存できます。