ConcourseのPipelineとは下図のようなものです。

- GitHubのPRを取得する
 - 対象のPRのstatusを
pendingにする - unit-testを実行する
- (成功) 対象のPRのstatusを
successにする - (失敗) 対象のPRのstatusを
failureにする 
 - (成功) 対象のPRのstatusを
 
今回のSampleはcappyzawa/pipelines になります。
Job
Jobはパイプライン中のアクションを定義します。
今回の例でいうと、以下になります。
- GitHubのPRを取得する
 - 対象のPRのstatusを
 pendingにする- unit-testを実行する
 
- (成功) 対象のPRのstatusを
 successにする- (失敗) 対象のPRのstatusを
 failureにする
個人的にはJobから記述し始めるのが書きやすいと思います。
以下がPipleine中のJobになります。
jobs:
- name: test-pr
  plan:
  - get: pr
    trigger: true
  - put: pr
    params:
      path: pr
      status: pending
  - task: unit-test
    file: pr/ci/tasks/unit-test.yml
    on_success:
      put: pr
      params:
        path: pr
        status: success
    on_failure:
      put: pr
      params:
        path: pr
        status: failure
name: test-pr
Jobの名前を定義します。
Jobにはplanが存在し、処理実行の流れを記述していきます。
get: pr
pull requestを取得します。
これは後述のResourceです。Resourceの取得はget、送信はputのように記述します。
put: pr
unit-testを実行する前にPRのstatusをpendingにしておきます。
task: unit-test
unit-testを実行します。
これは後述のTaskです。Taskの定義は別ファイルに切り出しておくとパイプラインの定義ファイルがすっきりします。
on_success/on_failure
インデントを揃えることでstepの成功時、失敗時の処理を分岐することができます。
今回の場合、task: unit-testが成功したらGitHubのPullRequestに成功のステータスを送信し、失敗したら失敗のステータスを送信します。
Resource
ResourceはJobで利用されるオブジェクトです。
Resourceは振る舞いが抽象化されており、少ない記述量で決められた振る舞いを行うことができます。
今回はPullRequestを取得、ステータスを送信したいのでtelia-oss/github-pr-resource: Github pull request resource for Concourse	を利用します。
resource_types
これはConcourse本体にpackagingされていないResourceですので、resource_typesブロックで利用するDockerImageを指定する必要があります。
resource_types:
- name: pull-request
  type: docker-image
  source:
    repository: teliaoss/github-pr-resource
上記のように記述するとteliaoss/github-pr-resourceのDockerImageをpull-reqeustというエイリアスをつけて利用することが可能になります。
厳密にいうと、Resourceにはtypeが存在し、このように記述するとpull-request typeということになります。
resource
利用するResourceを定義します。
resources:
- name: pr
  type: pull-request
  check_every: 24h
  webhook_token: ((webhook-token))
  source:
    repository: cappyzawa/pipelines
    access_token: ((github-access-token))
先ほど定義したpull-requestのresource typeを利用しています。
check_every
Resourceにはput, getの他にcheckという振る舞いがあります。
これは定義されたResourceに更新があるか定期的に確認するという振る舞いになります(Resourceによってはないものもある)。
今回の場合github.comのPullRequestに対し、更新がないか確認しにいくため、limitを考慮して24hとしています。
webhook_token
上記のcheck_everyではConcourseが定期的に更新を確認しにいくのですが、対象にwebhookを設定し、能動的にConcourseにresourceの更新を確認させることができます。
今回はGitHubのPullRequestが対象なので、該当するRepositoryにwebhookを設定してみます。
Setting->Webhooks->Add Webhook
| 項目 | 内容 | 
|---|---|
| Payload URL | http:///api/v1/teams//pipelines//resources/pr/check/webhook?webhook_token=token | 
| Content type | application/json | 
| SSL Verification | どちらでも | 
| Which events would you like to trigger this webhook? | Pull requests | 
今回は((webhook-token))にtokenを注入します。
注入方法は後述します。
これで、PullRequestに何かしらの更新が入ると、pr resourceに更新の確認をお願いできるようなります。
source
このブロックがResourceの定義になります。
記述の仕方も各Resourceによって異なりますので、対象ResourceのREADMEを見て、適宜記述してください。
今回のpr resourceには以下を記述します。
| パラメータ | 内容 | 
|---|---|
| repository | github.comに存在する対象のRepository(ORG/REPO)を記述 | 
| access_token | Personal Access Tokenを記述 | 
今回は必須のパラメータしか記述していません。
https://github.com 以外のGitHubホストを利用する場合は、v3_endpoint、または、v4_endpointを記述する必要があります。
Source Configuration
Task
TaskではInputに対して任意の処理を実行することができます。
必要であれば、処理結果をOutputとすることも可能です。
今回であれば、unit-testを行うだけで良いのでOutputは利用しません。
Resourceは振る舞いを抽象化することで、利用者は最低限の記述で処理を実行できるようになりますが、このTaskは逆で自分でゴリゴリ処理を書いていくことができます。
任意のDockerImage上で動作するのでできないことというのはあまりないと思います。
Jobにてtask:unit-testはpr/ci/tasks/unit-test.ymlを利用すると定義したので対象のファイルを記述します。
prは前のステップで取得したpathであり、prの中にはPullReqeustの対象コードが含まれています。
unit-test.yml
Taskの設定を記述していきます。
---
platform: linux
image_resource:
  type: docker-image
  source:
    repository: golang
    tag: 1.11-alpine
inputs:
- name: pr
run:
  path: pr/ci/tasks/unit-test.sh
platform
実行するplatformとしてlinuxを選択します。
image_resource
ここでTaskを実行するためのDockerImageを記述します。
今回はgolang:1.11-alpineを利用します。
inputs
このTaskのinputとして必要なものの名前を記述します。
run
実行するコマンドのconfigを設定します。
今回はpathだけを指定しました。
(unit-test.shに実行権限を付与するのを忘れないようにしましょう)
unit-test.sh
taskの設定ファイル(unit-test.yml)から指定された実行ファイルです。
# !/usr/bin/env sh
mkdir -p ${GOPATH}/src/github.com/cappyzawa/pipelines
cp -r pr/* ${GOPATH}/src/github.com/cappyzawa/pipelines
cd ${GOPATH}/src/github.com/cappyzawa/pipelines
go test ./...
Pipleine
ここまでを終えて、Pipelineの設定ファイル全体は以下のようになりました
resource_types:
- name: pull-request
  type: docker-image
  source:
    repository: teliaoss/github-pr-resource
resources:
- name: pr
  type: pull-request
  check_every: 24h
  webhook_token: ((webhook-token))
  source:
    repository: cappyzawa/pipelines
    access_token: ((github-access-token))
jobs:
- name: test-pr
  plan:
  - get: pr
    trigger: true
  - put: pr
    params:
      path: pr
      status: pending
  - task: unit-test
    file: pr/ci/tasks/unit-test.yml
    on_success:
      put: pr
      params:
        path: pr
        status: success
    on_failure:
      put: pr
      params:
        path: pr
        status: failure
このPipelineをsetします。
$ fly -t <target> set-pipeline -p sample-unit-test -c ci/pipeline.yml -v webhook-token=token -v github-access-token=XXXXXXXXX
Pipelineの設定ファイル中にて(())と表記したパラメータに-vで値を注入します。
| パラメータ | 内容 | 
|---|---|
webhook-token | 
GitHubのWebhookのpayloadに設定したtoken。今回はtokenとして登録している。 | 
github-access-token | 
GitHubのPersonalAccessToken | 
まとめ
ConcourseのPipelineを開発する上で知っておくべき以下の概念の説明と簡単な例を示しました。
- Job
 - Resource
 - Task
 
今回は継続的にPRのunit-testを行うpipelineを作成しましたので、最後に更新時のgifを添えます。
※ 今回はlocalに立てているConcourseであったためWebhookを使えなかったのですが、GitHubからアクセス可能な場合は上図のように動作します

