GitHub Deployments API


## Deployments と Deployment Statuse とは
Deployments は特定の branch, sha, tag のデプロイリクエストを指す。
Deployment Statuses は Commit Status みたいに

* "success"
* "failure"
* "error"
* "pending"

というマークを Deployment に対して付けられる。
これを受け取るには `deployment_status` イベントで取得する。

Deployments と Deployment Statuses はどちらも repository events に紐づけられる。

```
+---------+             +--------+            +-----------+        +-------------+
| Tooling |             | GitHub |            | 3rd Party |        | Your Server |
+---------+             +--------+            +-----------+        +-------------+
     |                      |                       |                     |
     |  Create Deployment   |                       |                     |
     |--------------------->|                       |                     |
     |                      |                       |                     |
     |  Deployment Created  |                       |                     |
     |<---------------------|                       |                     |
     |                      |                       |                     |
     |                      |   Deployment Event    |                     |
     |                      |---------------------->|                     |
     |                      |                       |     SSH+Deploys     |
     |                      |                       |-------------------->|
     |                      |                       |                     |
     |                      |   Deployment Status   |                     |
     |                      |<----------------------|                     |
     |                      |                       |                     |
     |                      |                       |   Deploy Completed  |
     |                      |                       |<--------------------|
     |                      |                       |                     |
     |                      |   Deployment Status   |                     |
     |                      |<----------------------|                     |
     |                      |                       |                     |
```

* GitHub 自体はデプロイ作業は一切しない
* 3rd party のツールとデプロイイベントとの integration を担うもの
* 複数のツールがデプロイイベントを受け取ることができる

### Deployments と Deployment Statuses 使い方イメージ
例、topic ブランチをデプロイしたい

0. topic ブランチ（SHA: XXXXX) をデプロイするという Deployment を作成
 * Deployment id 400, 
 * Deployment Event 作成される
0. id 400 の Deployment の状態を `pending` であることを示す Deployment Status を作成
 * 実際にデプロイ開始
0. デプロイ成功
 * id 400 の Deployment Status `success` を作成

Deployment has many Deployment Status

## 必要な権限
Deployments と Deployments Statuses に必要な OAuth スコープは

* `repo_deployment`

`repo` スコープは必要ない

## Develper Preview だということの Accept

```ruby
deployments = client.list_deployments(
  "wantedly/wantedly",
  accept: "application/vnd.github.cannonball-preview+json"
)
```

## Deployments API
以下 "octokit" gem 使って扱う例

### List Deployments

```ruby
client = Octokit::Client.new(
  access_token: <token>
)

client.list_deployments("user/repo")
```

### Create a Deployments

```ruby
client = Octokit::Client.new(
  access_token: <token>
)

payload = {
  release_version: 1,
}.to_json

client.create_deployment(
  "wantedly/wantedly",
  "21455649bbbacdb370f1c53cbbd90b6772bef804",
  {
    payload: payload,
    task: "deploy",
    environment: "production",
  }
)
```

デプロイ対象の ref の Commit Status が failure だと Create に失敗する

```
Octokit::Conflict: POST https://api.github.com/repos/wantedly/wantedly/deployments: 409 - Conflict: Commit status checks failed for master.
Error summary:
  contexts: [{:context=>"continuous-integration/wercker", :state=>"failure"}]
  resource: Deployment
  field: required_contexts
  code: invalid // See: https://developer.github.com/v3
```

```ruby
e.errors
=> [{:contexts=>[{:context=>"continuous-integration/wercker", :state=>"pending"}], :resource=>"Deployment", :field=>"required_contexts", :code=>"invalid"}]
```

force deploy するには、`required_contexts	` に空配列を渡す `[]`
これはつまり、`required_contexts` に `["continuous-integration/wercker"]` と書くと、 wercker でのテストが通ってない commit status が failure になる。
なので、このチェックが通ってなきゃ行けないよっていう対象を空にすることで force deploy になるという理解

```ruby
client.create_deployment(
  <repo>,
  <ref>,
  {
    environment: "production",
    task: "deploy",
    required_contexts: [],
    description: "deploy request from hubot",
  },
)
```

### Update a Deployment
一度作ったらアップデートはできない

## Deployment Statuses
### Create a Deployment Status

```ruby
client = Octokit::Client.new(
  access_token: <token>
)


client.create_deployment_status(
  "https://api.github.com/repos/wantedly/wantedly/deployments/44167",
  "success",
  {
    target_url: "http://example.com/deployments/1/output",
    description:  "Deployment finished succesfully."
  }
)
```

### List Deployment Statuses
 
```ruby
client = Octokit::Client.new(
  access_token: <token>
)

deployment_statuses = client.list_deployment_statuses(
  "https://api.github.com/repos/wantedly/wantedly/deployments/44167",
)
```

## 感想とメモ

* Deployment API 

最初にいいなと思ったのは開発の履歴として git の commit があり、デプロイ履歴として deployment も github におけること。
デプロイ履歴だけなら Circle CI とか Wercker とか New Relic のデプロイ機能使えばいい気もするけど、この API が良いのは自由度が高いことかなと。application の deploy だけじゃなくて、operation も下記 `task` attribute に持たせれば、何かしらチェックが通った operation code だけを実行したり、実行した operation がどうだったかの履歴を DB を使わずに作れる。 topic ブランチをデプロイするとこんな感じで pull request に deployment event が出てくる。

![_UserFeed__feed_improve_by_imaimiami_·_Pull_Request__7433_·_wantedly_wantedly.png](https://qiita-image-store.s3.amazonaws.com/0/20833/44b28819-fce3-ae76-fc8e-009d08a61eee.png "_UserFeed__feed_improve_by_imaimiami_·_Pull_Request__7433_·_wantedly_wantedly.png")


* Deployment の ID

最初に deployment ID をデプロイバージョンに使おうかと思ったけどDeployment の ID は全ユーザ / 全リポジトリで一意。

* `environment` について

production, staging でそれぞれどの revision 出したっけというときも、deployment を作る際に `environment` も指定おけば、deployments 一覧を取って来て、staging のものだけにフィルタリングすると staging のデプロイ履歴になる。

* `target_url` について

これは後々、「何時何分の成功したデプロイのログ見たい」見たいな場合とか、ChatOps でデプロイをキックしてそのログはここで見れるよみたいな使い方ができると思う。（その出力結果を保持しておく場所の候補は S3, gist とかか）

* Deployment の `payload`

payload には JSON String を渡す。Heroku のように環境変数の変更さえもデプロイと見なそうと思うとその情報もデプロイ履歴に含める必要がある。payload に諸々の設定を encrypted した JSON として入れておけばそれが実現できそう。

* Deployment に `task` という attribute がある

API ドキュメントだとちょっと古いのか載ってないけど、`task` という attribute があってデフォルトだと `deploy` という値が入ってる。capistrano などを使っていて deployment イベント作成後にどの rake タスクを実行するかを伝える必要がある場合に非常に便利そう。

* `required_context` について

GitHub のドキュメントの例だと、CI とセキュリティチェックを通った物だけデプロイしてるのがわかる。

* `auto_merge` について

デフォルトで `true` になってる。GitHub だと topic ブランチをデプロイしてテストする際、最終的に master に merge するものだから、topic ブランチのデプロイの時点で merge したものをデプロイしてテストしてるって前に聞いた。 なので master を merge してない topic ブランチは自動で master を merge するようになってる。こんな感じで auto merge commit が作られる。

![Commits_·_wantedly_wantedly.png](https://qiita-image-store.s3.amazonaws.com/0/20833/71e95e95-9458-b453-6b09-579cab6540a2.png "Commits_·_wantedly_wantedly.png")


## REF

* [Preview the New Deployments API](https://developer.github.com/changes/2014-01-09-preview-the-new-deployments-api/)
* [Deployments - GitHub API](https://developer.github.com/v3/repos/deployments/)
* http://rdoc.info/gems/octokit/
* [remind101/tugboat](https://github.com/remind101/tugboat)