Metadata

Metadataとは?

Metadataは ビルド に関する情報を保持する key/value ストアです。Metadataは steps 内で組み込まれている meta CLI を利用することで、全てのビルドで更新と取得が可能です。

デフォルトMetadata

Screwdriver.cdはデフォルトでMetadataに以下のキーを設定しています。

キー 説明
build.buildId ビルドのID
build.jobId ビルドと紐付いているジョブのID
build.eventId ビルドと紐付いているイベントのID
build.pipelineId ビルドと紐付いているパイプラインのID
build.sha ビルドが実行しているコミットのsha
build.jobName ジョブ名
event.creator ビルドと紐付いているイベントの作成者
commit.author avatar, name, url, usernameを含むAuthor情報のオブジェクト
commit.committer avatar, name, url, usernameを含むCommitter情報のオブジェクト
commit.message コミットメッセージ
commit.url コミットへのURL
commit.changedFiles カンマ区切りの変更ファイルリスト
注意: UIから新たにイベントを開始した場合はコミットでトリガーされたことにならないので、この値は空になります
sd.tag.name タグ名
sd.release.id リリースID
sd.release.name リリース名
sd.release.author リリース

Metadataの操作

Screwdriver は meta store から情報を取得するためのシェルコマンド meta get と、meta store に情報を保存するためのシェルコマンド meta set を提供しています。

同一パイプライン

Screwdriverのビルドでは、同ビルドでセットされたMetadata、もしくは同イベントの以前のビルドでセットされたMetadataを取得することができます。

例: build1 -> build2 -> build3

build2 のMetadataは、自身でセットしたMetadataと build1 でセットしたMetadataを保持しています。

build3 のMetadataは、 build2 が持っていたMetadataを保持しています。 ( build1 のMetadataも含む)

$ meta set example.coverage 99.95
$ meta get example.coverage
99.95
$ meta get example
{"coverage":99.95}

例:

$ meta set foo[2].bar[1] baz
$ meta get foo
[null,null,{"bar":[null,"baz"]}]

サンプルリポジトリ: https://github.com/screwdriver-cd-test/workflow-metadata-example

注意:

外部パイプライン

Screwdriverのビルドは外部トリガー元のジョブのMetadataにも --external フラグにトリガー元のジョブを指定することでアクセスすることができます。

例: sd@123:publish -> build1 の時 build1 のビルド内で:

$ meta get example --external sd@123:publish
{"coverage":99.95}

注意:

APIを使用する

/v4/eventsへのPOSTリクエストのpayloadに設定することでも、イベントメタを設定することができます。

APIのエンドポイントについての詳細は、APIのドキュメントを参照してください。

イベントメタトリガーのサンプルリポジトリや、それに対応したイベントメタのサンプルリポジトリも参考にしてください。

プルリクエストコメント

注意:この機能は現在のところGithubプラグインでのみ使用可能です

Metadataを使用することで、ScrewdriverのビルドからGitのプルリクエストにコメントを書き込むことができます。コメントの内容はパイプラインのPRビルドから、metaのsummaryオブジェクトに書き込まれます。

プルリクエストにMetadataを書き出すには、meta.summaryに必要な情報をセットするだけです。このデータはheadlessなGitのユーザからのコメントとして出てきます。

例として、カバレッジの説明を加えたい場合には、screwdriver.yamlは以下のようになります。

jobs:
  main:
    steps:
      - comment: meta set meta.summary.coverage "Coverage increased by 15%"

以下の例のようにMarkdown記法で書くこともできます。

jobs:
  main:
    steps:
      - comment: meta set meta.summary.markdown "this markdown comment is **bold** and *italic*"

これらの設定をすると、以下のようにGitにコメントがされます。

PR comment

さらにmeta.splitCommentsを設定することで、1つではなく複数のコメントを行うことができます。

jobs:
  main:
    steps:
      - comment: meta set meta.splitComments "split"

この設定を行うと、以下のようにGitにコメントがされます。

PR comment

注意: ビルドを複数実行すると、Gitの同じコメントを編集します。

追加のプルリクエストチェック

注意:この機能は現在のところGithubプラグインでのみ使用可能です

プルリクエストビルドのより詳細な状態を知るために追加のステータスチェックをプルリクエストに加えることができます。

プルリクエストに追加のチェックをするには、meta.status.<check>にJSON形式で必要な情報を設定するだけでできます。このデータはGitのプルリクエストのチェックとして出てきます。

設定できるフィールドは以下の通りです。

Key Default Description
status (String) SUCCESS チェックのステータス 次から一つ選びます。 SUCCESS, FAILURE, PENDING
message (String) fieldName check failed チェックの説明
url (String) ビルドのリンク チェックのリンクのURL

例として、findbugscoverageの2つの追加のチェックを加える場合、screwdriver.yamlは次のようになります。

jobs:
  main:
    steps:
      - status: |
          meta set meta.status.findbugs '{"status":"FAILURE","message":"923 issues found. Previous count: 914 issues.","url":"http://findbugs.com"}'
          meta set meta.status.coverage '{"status":"SUCCESS","message":"Coverage is above 80%."}'

これらの設定は以下のようにGitのチェックになります。

PR checks

カバレッジとテスト結果

metadataを利用して、Screwdriverのビルドからビルドページにカバレッジの結果やテスト結果をそれらの生成物へのURLと一緒に取り込むことができます。ScrewdriverのUIはmetadata内のtests.coveragetests.resultstests.coverageUrltests.resultsUrlを読み込んで対応するものを表示させたり設定したりします。

screwdriver.yamlの例:

jobs:
  main:
    steps:
      - set-coverage-and-test-results: |
          meta set tests.coverage 100 # カバレッジパーセンテージ数
          meta set tests.results 10/10 # 成功テスト数/全テスト数
          meta set tests.coverageUrl /test/coverageReport.html # ビルド成果物への相対パスで指定します
          meta set tests.resultsUrl /test/testReport.html # ビルド成果物への相対パスで指定します

注意: metadataはSonarQubeの結果を上書きします。 metaの優先順位は meta.tests.saucelabs > meta.tests.sonarqube > meta.tests となります。

これらの設定により、ビルドページは次のようになります:

coverage-meta

イベントラベル

metaのキーにlabelを指定するとイベントにラベルを付与することができます。このキーはロールバックするイベントの指定に役立ちます。

screwdriver.yamlの例:

jobs:
  main:
    steps:
      - set-label: |
          meta set label VERSION_3.0 # 設定した値はイベントに紐づいてパイプラインページ上に表示されます

結果: Label

Slack通知

metaを利用することで通知メッセージをカスタマイズすることができます。metaのキーは通知ブラグインごとに異なります。

Slackのメンションやチャンネルリンクには特殊なフォーマット文字列が必要です。利用可能なオプションについては、Slack ドキュメント を参照してください。

基本

Slack通知をするscrewdriver.yamlの例:

jobs:
  main:
    steps:
      - meta: |
          meta set notification.slack.message "<@yoshwata> Hello Meta!"

Result: notification-meta

ジョブベースのSlackメッセージ

注意 ジョブベースのSlack通知のメタデータは基本的な通知メッセージを上書きします。

メタ変数の構造は、notification.slack.<jobname>.messageです。 <jobname>をScrewdriver.cdのジョブ名に置き換えます。

特定のジョブをSlackメッセージで通知する例:

jobs:
  main:
    steps:
      - meta: |
          meta set notification.slack.slack-notification-test.message "<@yoshwata> Hello Meta!"

Result: notification-meta

ジョブベースのSlackチャンネル

注意: ジョブベースのSlackチャンネルのメタデータは基本的なSlack通知チャンネルを上書きするだけです。チャンネル通知設定の代わりになるものではありません。

メタ変数の構造は、notification.slack.<jobName>.channelsです。 <jobname>をScrewdriver.cdのジョブ名に置き換えます。

コンマ区切りの文字列にすることで、複数のチャンネルを設定することができます。

componentジョブで失敗した時に別のSlackチャンネルへ通知するscrewdriver.yamlの例:

shared:
    image: docker.ouroath.com:4443/x/y/z

    settings:
        slack:
            channels: [ main_channel ]
            statuses: [ FAILURE ]
jobs:
   component:
    steps:
      - meta: |
          meta set notification.slack.component.channels "fail_channel, prod_channel"

上記の例では、Slackの失敗通知のメッセージはmain_channelへ送られる代わりにfail_channelと、prod_channelへ送られます。パイプラインの他のすべてのジョブは、main_channelへ通知します。

ジョブベースで通知を最小化する設定

ジョブベースのSlackの minimized メタの設定はデフォルトのSlack minimized設定を上書きします。

メタ変数の構造は、 notification.slack.<jobName>.minimized です。 <jobName> をScrewdriverのジョブ名に置き換えてください。

例えば、 component ジョブがスケジューラーによってトリガーされた場合に、最小化したSlackメッセージを投稿します:

shared:
    image: docker.ouroath.com:4443/x/y/z

    settings:
        slack:
            channels: [ main_channel ]
            statuses: [ FAILURE ]
            minimized: false
jobs:
   component:
    steps:
      - meta: |
          if [[ $SD_SCHEDULED_BUILD == true ]]; then
             meta set notification.slack.component.minimized true
          fi

上記の例では、スケジューラーによってトリガーされた component ジョブでのSlack通知は minimized 形式で投稿されます。

ビルドにWarningを設定してマークする

build.warning を設定することで、ビルド/イベントを warning のステータスでマークできます。

screwdriver.yamlの例:

jobs:
  main:
    steps:
      - warning: meta set build.warning true

結果: warning-event-tab

warningのメッセージを追加することもできます。

screwdriver.yamlの例:

jobs:
  main:
    steps:
      - setWarning: meta set build.warning.message "this is a warning message"
      - setAnotherWarning: meta set build.warning.anotherMessage "this is another warning message"

結果: warning-message

注意: マークされるのはSUCCESSのビルド/イベントのステータスの場合のみですが、warningメッセージはビルド/イベントのステータスに関わらずビルド詳細ページに表示されます。

アトミックな処理のためにLuaを使用

metaツールはロックファイルを作成し、各処理毎にflockを管理します。これはビルドを並列に実行できるようにするためです。(例えば、make -j 4で起動されたMakefileなど)

アトミックな参照や書き込み処理に加えて、「更新」が必要な場合は、埋込み型のLuaインタプリタを使用してメタコマンドを呼び出すことができます。

使用例:

アトミックな数値のインクリメント

meta lua -E 'meta.set("myNum", (tonumber(meta.get("myNum")) or 0) + 1)'
Lua code Description
meta.get("myNum") 前の値を取得
tonumber(meta.get(“myNum”)) tonumberは数値の場合はその引数を返し、文字列の場合は解析し、解析不能な場合や数値や文字列でない場合はnilを返す
tonumber(meta.get(“myNum”)) or 0 or 0は非数値を0に変換して計算できるようにする
(tonumber(meta.get(“myNum”)) or 0) + 1 +1は前の値(この例では初期値は0)に1をインクリメントする
meta.set(“myNum”, (tonumber(meta.get(“myNum”)) or 0) + 1) meta.setはインクリメントした値をセットする

atomically insert some json into an array and return its index

よくあるユースケースは、(Dockerイメージのような)多くのものを並行してビルドし、その後の”publish”ステップで(Dockerレジストリ等へ)pushするために配列に問い合わせを行います。

meta lua insert.lua myArray '{"foo": "baz"}'

Lua CLIの慣習に従い、Luaコードではグローバルテーブルargで引数を利用できるようになっています。 -Eフラグを指定しない場合、arg[0]はファイルとして実行されます。

insert.luaファイルの中身:

-- Ensure args are passed as expected
assert(#arg >= 2, string.format("usage: %s key json_value", arg[0]))

-- https://github.com/vadv/gopher-lua-libs is preloaded, so any of its modules may be required
local json = require("json")
local key = arg[1]

-- This converts the json string argument to a Lua table, error
local toInsert, err = json.decode(arg[2])

-- Report errors, if any
assert(not err, tostring(err))

-- Get the current array from meta using the key arg or, when nil, an empty table
local array = meta.get(key) or {}

-- table.insert without index does "append"
table.insert(array, toInsert)

-- meta.set to save the value after insertion - Lua values are passed and converted to json for storage under the hood.
meta.set(key, array)

-- print the index
-- NOTE: index for meta.(get/set) purposes is 0-based, so subtract 1 from the array size
print(#array - 1)