Kesinの知見置き場

知見を共有していきたいじゃないですか

USB接続したiOSのudidをCLIから取得する方法あれこれ

iOS開発をしていると、ちょっとしたことを自動化したいということがたまにある。
今回は、開発用のMacに接続しているiOS実機のudid(とついでにnameも)をrubyから扱いたくなったので、CLIから情報を取得する方法を調べたのでまとめてみた。

3種類の方法を紹介します。

  • xcrun instruments -s
  • mobiledevice
  • FastlaneCore::DeviceManager

xcrun instruments -s

やりたいことをググると一番多く見つかるのがこれ。
実際に実行してみると、たくさんのiOSシミュレータのudidがズラズラと列挙されて分かりにくいが、3行目あたりに接続しているiOS実機のnameとudidが表示されているはず。 少々めんどくさいが、正規表現を使えば抽出することが可能。

ちなみに、よく-sの後にdeviceを付ける紹介を見かけるが、自分が試した感じではdeviceの有無で結果は全く変わらなかった。diffコマンドで確認しても差分はなかった。

そもそもxcrun instrumentsを実行したときに-sというオプションは表示されていないので出自からして若干謎である。隠しコマンドなのだろうか?

mobiledevice

imkira/mobiledevice

iOSバイスの様々な情報を表示したり、アプリのインストールなどができるCLIツール。

仕組みとしては、iTunesが使っているプライベートフレームワークであるMobileDevice.frameworkを叩いてCLIツールとして機能を提供しているようだ。
残念ながら自分はこのあたりに詳しくないが、このMobileDeviceを外から呼び出すライブラリは他にも存在するみたいでこの界隈では有名らしい。
MobileDevice Library - The iPhone Wiki

homebrewからインストールできるが、残念ながらHigh Sierraではインストールできなかった。幸い、git cloneして自分でmakeすればHigh Sierraでも普通に使える。
makeに失敗する場合はxcode-select --installでcommand line developer toolsをインストールすればmakeできるようになるはずだ。

使い方は、mobiledevice list_devicesで接続しているiOSバイスのudidだけが列挙される。シンプル。
udid以外の情報も取得可能で、例えばnameならmobiledevice get_device_prop -u UDID DeviceNameで取れる。UDIDにはlist_devicesで表示されたudidを入れてほしい。
mobiledevice list_device_propsで他にも取得可能な要素の一覧が表示されるので、興味があれば色々試してみると面白いかもしれない。

FastlaneCore::DeviceManager

自分は最終的にここに行き着いた。みんな大好きFastlane。
connected_devicesというメソッドを使うことで接続されているiOS実機の情報を取得できる。 fastlane/device_manager.rb at 2.91.0 · fastlane/fastlane · GitHub

ドキュメントは多分存在しないが、使い方はこんな感じで簡単だ。

require 'fastlane_core/device_manager'
require 'pp'

devices = FastlaneCore::DeviceManager.connected_devices('iOS')

pp devices

# [#<FastlaneCore::DeviceManager::Device:0x007f883c2a3bb0
#  @ios_version="11.2.6",
#  @is_simulator=false,
#  @name="Kesin's iPhone",
#  @os_type="iOS",
#  @os_version="11.2.6",
#  @state="Booted",
#  @udid="*****">] 自分のiPhoneのudidが表示されているので伏せさせて頂く

裏側の仕組みとしては、やはりxcrun instrumens -sの結果を頑張って正規表現でパースしてインスタンスを作っている。
先人の努力に感謝しつつ、ありがたく使わせて頂きます。

まとめ

  • xcrun instruments -s
    • 実行するのは最も手軽。ただし、自力で正規表現を頑張る必要はある
  • mobiledevice
    • macOS 10.2までならhomebrewでインストールできるかも?High Sierraの人は自分でmakeする必要がある
    • 正規表現を頑張る必要はないのでインストールさえできれば簡単
  • FastlaneCore::DeviceManager
    • 自分と同じくrubyから使いたい人は最も手軽

自分の用途に合った方法をどうぞ。

SRE-SET Automation Night #2にお邪魔してきました

2018/03/06に開催されたSRE-SET Automation Night #2へブログ枠として参加させて頂きました。

SRE-SET Automation NightはCIやテスト、Seleniumなどを使った自動化についてが主なテーマの勉強会です。
第1回目のときにも参加させて頂いたので、今回は2回目の参加でした。

会場に着いたのが早めだったので、まだ皆さんが集まっていないうちにケータリングの写真を撮らせて頂きました。 定番のお寿司もいいですが、たまにはこういう違ったおしゃれメニューもいいですね!

f:id:Kesin:20180306191120j:plain

今回の発表の中で特に自分が興味持った2つを紹介します。

AWS Lambdaで作る GitHub bot @siroken3

GitHubでもイベントに反応するbotAWS Lambdaに構築するという発表でした。
おそらく公式ドキュメントだとこのあたりのことなのではないかと思います
https://developer.github.com/apps/getting-started-with-building-apps/

GitHub botができることの例として紹介されていたもの。

  • PRへのコメント
  • Issueの自動ラベリング
  • PRの内容チェック

Issueの自動ラベリングとか、自動クローズとかはOSSで最近見かけることがありますね。

botをLambda上に構築する仕組みは、GitHubのwebhookでAWS Lambdaを起動してLambdaに置いたスクリプトからGitHubAPIを叩いて実現しているようです。 つまりこういう流れ。

Github(webhook) -> Amazon SNS(Topicsを設定) -> Lambda -> Github API

帰宅してからちょっと調べたら、似たような構成でGitHub -> Lambda -> Slackの連携を構築している方がいました。
https://qiita.com/ooharabucyou/items/2a3dca643f6b7783d665

注意点としては、GitHubと連携するためのpersonal access tokenはAWS KMSを使って暗号化しておき、Lambdaから使うときに復号化する必要があるようです。

今回の発表では、サンプルとしてissueにコメントすると単純に同じコメントをbotが返すecho botの作り方を紹介していました。
リポジトリはこちらのようです https://github.com/siroken3/SreSetAutomationNightVol2

echo botはissueにコメントされたタイミングでwebhookを受け取る必要があるのですが、webhookのデフォルトの設定だとpushしたタイミングでしか発火してくれないとのことです。
発表では、コメントされたタイミングでもwebhookが発火するようにcurlでリクエストを投げて設定を変更されていました。 調べてみたところ、リポジトリのsettingsからwebhookを設定するUIにもそれっぽいものがあったので、おそらくこれでもいけるのではないかと思います。

2018/03/08 追記
webhookの設定ではなく、Integration & servicesからAmazon SNSの設定をされているとのことでした。たしかにこちらだとUIから発火するイベントの選択はできないようでした。
訂正いたします

自動回帰テストフローとGitHub Apps @Quramy

こちらもGitHubと連携するbot(Apps)を使って、回帰テストフローを自動化したという内容でした。 少しややこしいのですが、@siroken3さんの発表とは異なるGitHub Appsという仕組みを使っています。
GitHubと連携するbot(Apps)には@siroken3さんのpersonal access tokenを使う方法とは別のGitHub AppsとOAuth Appsという2つの仕組みがあり、 この2つの違いはこのようになっているとのことです。

GitHub Appsの場合は個人のアカウントに紐付かないためチーム開発においてはOAuthより便利だということです。
公式のドキュメントだと多分このあたり
https://developer.github.com/apps/getting-started-with-building-apps/

@Quramyさんのチームではフロントエンド用の自動回帰テスト環境として、修正前の環境でのスクリーンショットと、コードに修正を加えた後の環境でのスクリーンショットを比較して問題がないかの確認を行うツールを作成して運用しているとのことでした。
今回の発表では触れられていませんでしたが、2017年のNode学園祭で発表されていたREG-SUITというツールだと思われます。 https://speakerdeck.com/quramy/introduction-to-visual-regression-testing

スクリーンショットを比較するテストの場合、画像を比較して差分が出ていたとしてもデザイン変更を伴う正しい修正かもしれないため、機械的にOKかNGかを判断することはできず人間がチェックします。
そして差分が意図したものである場合は、修正後のスクリーンショットを次回テストの正として画像を保存しておく必要があります。

今回作成されたGitHub Appsは以下の作業を自動的にしてくれるようでした。

  • CIで実行してスクリーンショットの差分が存在した際に画像チェック用のページのurlをプルリクにコメントする
  • レビューがApproveされたらそれを検知してマージOKのステータスに変更する
  • 今回のスクリーンショットを次回テストの正とするために画像を保存

実装の詳しい説明までは残念ながらおそらく時間の都合上発表されていませんでしたが、AWS Lambda上で構築されているとのことでした。

感想

他の方の発表も非常におもしろかったのですが、最近自分がDangerというプルリクに対するアクションを簡単に書けるライブラリのプラグインを作っていたので、似たようなことができるGitHub連携ツールの発表が非常に興味深かったです。

プルリクへのコメントや、Issueの自動ラベリングはDangerでも実現できるのですが、DangerはCIサービス上で動くことをウリにしているので手軽に導入できる反面、pushされたタイミングでしか処理が行えないという不便さを感じていました。

botなりGitHub Appsは実装とAWS Lambdaにデプロイする手間はかかるはずですが、GitHub上のあらゆるイベントに対して処理を走らせることができるという点が強みだと思います。 特にApproveされたり、LGTMされたタイミングで何かのアクションをするというのは色々なことに使えそうですね。

便利そうだなーと感じる一方で、残念ながら今のところ自分はまだ便利に使えそうなアイディアが浮かんでいないです。ただGitHub Apps自体が発表されたのは去年のようですので、これからどんどん活用事例が増えていくのではないかなという予感がしています。

ちなみに、自分はまだ触っていないのですがGitHubbotを簡単に作るためのライブラリとしてhttps://probot.github.io/というのもあるようです。
今回の発表やprobotを見ていると、元々便利なGitHubをさらに便利にしていくという流れを何となく感じますね。

textlintの結果をプルリクにコメントしてもらう(danger-textlintの紹介)

danger-textlintというdangerプラグインを公開しました!今回はその紹介エントリです。

dangerについて

そもそもdanger自体の知名度がまだまだだと思うので簡単に紹介したいと思います。

dangerはpull requestのコードレビューを助けるためのツールです。
dangerはpull requestのデータにrubyから簡単にアクセスするためのインターフェースと、pull requestにコメントするためのインターフェースを提供してくれます。
例えばdangerを使うとタイトルに[WIP]が含まれる場合は警告のコメントを出してマージできないようにする、ということが簡単に行えます。

textlintについて

textlintはコードの代わりに文章を対象としたlintツールです。最近、紹介エントリを見る機会が増えたのでだいぶ知名度が上がったと思います。

textlintのルールはeslintのようにそれぞれプラグインとなっており、自由にカスタムできることが特長です。 日本語でミスしやすいルールが数多く用意されており、出自からかエンジニアが書く文章のためのルールも充実しています。

個人的にはブログを書くときにtextlintはもはや手放せない存在です。また会社で社外向けブログを書くときはチームメンバーにレビューをしてもらうのですが、日本語のミスが残っていると肝心の内容よりも表現の指摘に終止しがちです。 自動赤ペン先生として事前にtextlintでチェックしておくことでレビューが生産的になります。

danger-textlintについて

dangerのプラグインは既にたくさんあり、その中にはlintの結果をプルリクの中でコメントとして付けてくれるものがあります。danger-textlintはそれらと同じようにtextlintのlint結果をコメントしてくれます。

実際にこのブログを書いているプルリクに対して実行した様子です。こんな感じでtextlintによる日本語のチェック結果をコメントしてくれます。

f:id:Kesin:20180217213341p:plain

導入方法

導入方法はREADMEにまとまめました。他のDangerプラグインと同様にgemをインストールしてDangerfileに以下を追加します。

# デフォルトだとtextlintの結果が1つでも違反しているとマージできなくなる
# max_severity = "warn" を設定するとDangerはコメントするだけに留めてマージまでは禁止しない
textlint.max_severity = "warn"

# 最低限これが必要
textlint.lint

加えて、そもそもtextlintを動かすためには当然nodejsが動く環境とtextlint自体のインストールも必要です。 danger-textlintはnpm i --globalオプションでインストールされても動くように作ってありますが、dangerはCIで動作させる前提のツールなので普通にnpm install textlintでローカルに保存した方が無難です。
node_modulesを.gitignoreに追加するのも忘れないようにしましょう。

CIの設定は普通にdangerを実行するだけですが、textlintを動かすのにnodejsが必要なのでruby + nodeの環境が必要です。自分はCircleCIを使うことが多いのでCircleCIのサンプルを載せておきます。

version: 2
jobs:
  build:
    docker:
       - image: circleci/ruby:2.4.1-node-browsers
    working_directory: ~/repo
    steps:
      - checkout

      # ruby dependencies
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "Gemfile.lock" }}
          # fallback to using the latest cache if no exact match is found
          - v1-dependencies-

      - run:
          name: bundle install
          command: |
            bundle install --jobs=4 --retry=3 --path vendor/bundle

      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      # npm dependencies
      - restore_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}

      - run:
          name: npm install
          command: npm install

      - save_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
          paths:
            - ./node_modules

      - run:
          name: danger
          command: |
            bundle exec danger

なぜ作ったのか

自分が働いているチームではブログを書く環境がめちゃめちゃ整備されていて、そこら辺のプロダクトよりもPR周りの自動化が整備されているんじゃないかというほどです。 その中でDangerも使われているのですが、最近導入されたtextlintはDangerプラグインが存在しなかったのでフローにうまく統合できておらず、textlintに怒られたときは直接CIのコンソールから内容を確認しているという状況でした。

lintの結果はエディタで見るなら分かりやすいのですが、コンソールだと非常に確認しにくいです。CIが落ちたらローカルで再実行して確認すれば済む話ではあるのですが、プルリク上でそのままコメントしてくれた方が楽だし、他のレビュアーもただlintが落ちたという結果だけではなくてどの行でどのような間違えがあったのかを確認できるというメリットがあります。

textlintと同じnodejsで動くeslintのプラグインであるdanger-eslintが既に存在していたので参考にしつつ、サクッと作ってみました。

danger-checkstyle_formatについて

実はdanger-textlintを作る前にそもそも既に存在するdangerプラグインで実現できないか調べていて、その中でdanger-checkstyle_formatというプラグインを見つけました。 これはcheckstyleという形式のxmlを読み込んでDangerにコメントしてもらう汎用的に使えるプラグインです。textlintは--formatオプションで豊富な出力フォーマットを選択可能になっていて、checkstyle形式で出力することも可能です。

なので最初はtextlintが出力したcheckstyle形式のxmlをdanger-checkstyle_formatに食わせるという方法を試してみて、一応自分がやりたかったことは実現できました。ただ、textlintは1つでも違反があると終了ステータスが1になってしまうという仕様になっていて、CircleCIがtextlintで止まってしまうのでDangerの実行までステップが進まないという問題がありました。

その問題は一応こんな感じでtextlintの終了ステータスを握りつぶしてしまうことで回避することはできました。

run:
  name: textlint
  command: |
    set +e
    npm run textlint -- -f checkstyle -o textlint-result.xml
    echo 0

が、ちょっとハックな感じだったのでそれならと自分でDangerプラグインを作ってみました。 プラグイン化することで中間ファイルであるxmlも生成されなくなったし、Dangerfileだけみれば何をしているか一目瞭然になったので、なかなかよかったと思います。

まとめ

というわけでdanger-textlintの紹介でした。
既にGithubのプルリクでレビューをもらいながらブログを書ける環境の方はDangerとdanger-textlintを、まだプルリク運用できていない場合はまずは次の記事からGithubにでもリポジトリを用意して快適な執筆フローを整えてみてはいかがでしょうか。

DroidKaigi 2018最高でした!!

スタッフの皆様や登壇された皆様お疲れ様でした!!
ここ最近参加したカンファレンスの中では最高に楽しかったので珍しく感想エントリを書いてみました。

droidkaigi

会場・スポンサーブースの様子

自分ではほとんど写真を撮っていなかったので雰囲気はこちらからどうぞ。 https://twitter.com/droidkaigi/status/963254146013872128

個人的には最近参加した他のカンファレンスよりもスポンサーブースで自分が普段使っているサービスをお見かけして驚きました。Androidだからか。
コーヒーとお菓子片手に、いつもサービス使ってます!と感謝を伝えまくってきました。

あと印象的だったのはQRコード。ブースでは主催している勉強会のURLや技術同人誌の配布のためのQRコードなど、いたるところでQRコードが使われていました。 やっぱり便利ですよね。

セッション

発表を聞いて印象深かったセッションの感想をいくつか紹介します。
ちなみに自分のバックグラウンドとしてはここ1-2年はjsを追っかけていて、業務の内容が変わったのでiOSAndroidを触り始めてそろそろ半年という感じです。
なのでjsから見たAndroidという感じで読んでもらえればと思います。

アーキテクチャ

Flux for Android by Shohei Kawano

ここ2-3年ぐらいjs界隈を賑やかしていたFluxをAndroidに適用したという発表。とても素直にFluxをAndroidに適用している感じでした。
jsとの違いはDispatcherやStoreといったFluxの構造上各所に引き回されるオブジェクトをDIで渡しているところと、 ReactのVirtualDOMの代わりにStateの更新をデータバインディングに接続しているところぐらいでした。

Android における Model-View-Intent アーキテクチャ by Benoît Quenaudon

Model-View-Intentという単語は初めて聞きましたが、内容としてはFlux(より正確にはRedux)をRxJavaで実装してActionとStore(Reducer)間にビジネスロジックを挟むというアーキテクチャだと理解しました。
ボタンなどをクリックしたときにIntentというものを発行するところが、Actionを発行するFluxとそっくりですね。
RxJavaもガッツリ使ってるので、FluxとRxJavaの両方を知らないと難易度が高かったのではないかと思います。

Kotlin版CleanArchitectureのテンプレート作ったら爆速開発になった話+α by Keisuke kiuchi

こちらもFlux同様、ここ最近話題となっているClean ArchitectureをAndroidに適用する + クラス数が多くなる問題を解決しましたという発表。
これも先程のFluxと同じくAndroidに素直に適用したという感じで、jsとの差異はあまりないかなという感じでした。

Clean Architectureみたいな設計にするとどうしてもクラス数は増えてしまうのですが、だいたい前に作ったクラスをコピペして必要なところだけ書き換えるということを繰り返しがちです。
テンプレを作ってIDEから呼び出せるようにしておくのは地味に生産性に効いてくると思いました。

アーキテクチャの話まとめ

自分はjsで既にFluxやClean Architectureを使ったことがあったので、Androidにもその波が来ているのだなーというのが全体的な感想です。

個人的にはFlux(Redux)のアーキテクチャは非常に好みでして、良い点が2つあります。
1つ目は、例えばボタンを押したときにイベントリスナーから状態を直接更新するのではなくて一度Actionというものを発行する仕組み。これにより状態の更新フローがView層から疎結合になります。
2つ目は、更新フローがAction -> Store(ReduxだとReducer) -> Viewという必ずこの単方向のフローを通るように強制できる(これがFluxにおけるDispatcherの役割)ためデバッグがしやすいという点です。実際、jsの方ではFluxが流行った初期からActionが発行されるごとにログ出力されるプラグインミドルウェアとも呼ばれてます)が存在していたと思います。

Clean ArchitectureのメリットもFlux同様にView層と状態の更新ロジックが疎結合になるところで、こちらはFluxよりもさらに各層を疎結合にしていてDDD的な思想なのでビジネスロジックをどこに入れるかがハッキリしています。
ビジネスロジックに関してFluxの場合は特に非同期処理をActionでやるかStoreでやるか、はたまたActionとStoreの間にミドルウェアという層をおいてそこでやるか(redux-sageとか)でずっと議論しているのでみんなの悩みどころだと思ってます。

FluxでもClean Architectureにおいても個人的に重要だと思っているメリットは、更新フローがView層から疎結合になるという点です。これはAndroidにおいては状態の更新ロジックとUIコンポーネントが完全に切り離されるということを意味します。
これにより、アプリのロジックのユニットテストJVM上で行うためにUIパーツをモックしなくて済む点が大きいです。 もはやボタンというパーツをモックする必要はなくて、ボタンを押したという動作の代わりに本来発行されるActionを発行するだけで更新ロジックのテストを書くことが可能となります。
想定しうる更新フローと最終的な状態(リストに表示するためのオブジェクトなど)を先に決めてしまえばテストをしっかり書きながらロジックを実装することで、ボタンをぽちぽち押して様々なケースの動作確認をするという必要も減らせるはずです。なにせView層はただActionを発行するだけなので。

というわけで、FluxやClean Architectureはテストが書きやすくなるアーキテクチャなので来年はこれらに対してテストをどうやって書くかというセッションが増えるのではないかな(増えて欲しい)と思ってます。

ちなみにFluxにしてもClean Architectureにしてもクラス数が多くなるというデメリットがよく言われるのですが、それに対する自分の見解はこちらです。

ReactNative系

React Native Androidはなぜ動くのか

最近流行り始めているReactNativeのAndroid側から見たディープな話。ReactNativeは趣味で最近触り始めたので深い話が聞けてよかったです。

ReactNativeは今年ぐらいから新しいプロダクトを作るときに選択肢の候補に上がってくるのではないかなーと個人的には予想しています。
自分みたいなjsを書いてきたエンジニアもネイティブアプリの戦力としてカウントできるようになるものの、ReactNativeコンポーネントを自作したりだとかそもそもビルド環境を整えることは今までネイティブを触り続けてきた人達の方が圧倒的に強いと感じています。

ReactNativeで作るにしてもネイティブ未経験者オンリーなチームでは大変だろうなという気がしています。特にiOSの証明書とか・・・。

コードで見るFlutterアプリの実装 by konifar

Flutterって全く聞いたことなかったのですが、発表を聞いた限りではDartで書くGoogle公式のReactNativeに近いフレームワークという印象でした。

公式でUIパーツが一通りそろってるのはよさそうですね。ReactNativeはググるサードパーティコンポーネントの記事がたくさん出てくるので・・・
Dartって表舞台には出てきていないと思っているのですが、Googleの一部でずっと生き続けているっぽいのでもしかすると今後盛り返してくる可能性も?

ReactNativeとFlutterの話まとめ

ReactNativeってネイティブ開発者からすると「昔から存在するjsでネイティブが書けるって吹聴してる一派でしょ?」と思われている気がします。
個人的にはjsで書けるという点はSwiftやKotlinの登場によってそれほどメリットではなくなってきていると思いますが、1つ大きなメリットだと感じているのはコードを編集すると再コンパイル無しでUIを更新できるところです。実際にkonifarさんも発表中にDartのコードを書き換えると自動的にUIが変わっていく様子をデモしていました。
これってWeb界隈でlive reloadやhot reloadができるようになったことでUIのコードを編集するたびにブラウザの更新ボタンをぽちぽち押していた時代から開放されたのと同じだなと思いました。

このデザインをWeb開発のようにガンガン変えていけるというスピード感は普通のネイティブ開発では難しいはず。SwiftやKotlinによるネイティブ開発ではちょっとUIを変更するだけでもコンパイルが必要なので自分は非常にめんどくさいと感じてます。
ちなみにTitaniumとかは知らないので、もしかしてFlutterみたいなことは昔から可能だったのかもしれませんがもしそうだったらすみません。

DroidKaigi 2018のアプリについて

DroidKaigiでは毎年カンファレンスのタイムテーブルを閲覧したり、アンケートを送るためのアプリをOSSで開発していて毎年ナウい構成で作り直されているので名物となっているようです。
https://github.com/DroidKaigi/conference-app-2018

自分もKotlinの勉強のために小さいバグの修正でしたがPRを送ってContributorsに名を連ねさせていただきました。:pray:
多分これぐらいの規模でちゃんと作られてるプロダクションのソースコードを見ることができるのは珍しいと思うので、AndroidやKotlinに興味がある人は良い勉強材料になるのではないかなと思います。

というわけでDroidKaigi 2018の感想エントリでした!来年も絶対行きます!

Jenkins2のPipeline入門のメモ

Jenkins2のPipelineに入門した際にメモした内容をせっかくなので公開しておきます。

基本

step, node, stage

パイプラインのチュートリアルでいきなり図と共に登場するので最初はどう違うのか分かりにくいが、Jenkinsのビルドの流れにそれぞれ対応しているので実は難しくない。

step

今までのbuild stepと同じ。普通に1ジョブ内でやることを分割する。
主にプラグインの機能を呼び出すときにスニペットビルダー(後述)から生成する。

node

キューに独立して乗せられ、毎回削除されるWorkspaceが割り当てられる。
ということがチュートリアルでは書かれているが、要はnodeのブロック単位でJenkinsのキューに積まれるということ。

stage

stepやnodeと違って明確な役割はないが、パイプライン中の処理に名前を付けることができる。
GUI上でどのstageまで通過したか、どこで失敗したか分かりやすくなるのである程度の処理の固まりをstageに分割すると分かりやすい。
一般的にはinstall, build, test, deployみたいな単位でstageを分けると良さそう。

実際にパイプラインを書くときにはnode, stage, stepという順にブロックを作っていくことになる。

node {
    stage('build') {
        echo 'hoge'
    }
}

変数

パイプライン中でのローカル変数は以下のように作れる。

def hoge = 1

Jenkins1系では1ビルド内で新たに変数を作ることができなかったので何気にすごい嬉しい。
(自分が知らなかったでそのようなプラグインはあったかもしれませんが)

関数

パイプライン中での関数も定義することができる。

def hoge(arg) {
  echo 'hoge'
}

これも変数と同じく今までできなかったのでとてもありがたい。

条件分岐・例外処理

ifやtryなど基本的な文法はgroovyのものが使える。 buildで呼び出したジョブがfailしたかはtry-catch-finallyでハンドリングできる。

具体例は後述

別のジョブ呼び出し

build jobで既に作られているジョブやパイプラインを呼び出すことができる。
自分で書いてもいいが、スニペットビルダーを使うとジョブ名の補完が効いたり、必要なパラメータをフォームに入力するとコードを出力してくれるのでこれを使うべし。

f:id:Kesin:20161013013452p:plain

イディオム集

ビルド中に下流ビルドを実行する

今までもParameterized Trigger Pluginを使うことで実現できていましたが、ビルド途中でパラメータの中身を改変したりパラメータの名前を変えることが大変でした。

パイプラインでは変数を新たに定義したり、パラメータを途中で書き換えることも容易です。

node {
    stage ('build start'){
        def text = 'hoge'
        build job: 'my_echo', parameters: [text(name: 'text', value: text)]
    }
}

条件付きで別ジョブを走らせたい

パラメータの内容によって次に走らせるジョブを変更したり、そもそも実行させなかったりするような条件分岐は今まではFlexible Publishを使っていましたが、GUIで条件を設定する必要があったのでめんどくさかった奴です。

パイプラインではif-elseやtry-catch-finallyで制御できるので、普段からコーディングで使ってる我々からすると直感的に書けるようになりました。

前のジョブが失敗したときに次のジョブをスキップして通知を出すというサンプル

node {
    stage ('build'){
        num = 1
        try {
           // failになるジョブ
           build job: 'odd_error', parameters: [string(name: 'num', value: num)]
        } catch (err) {
            currentBuild.result = 'FAILURE'
        } finally {
            echo 'end try block'
        }

        if(currentBuild.result == 'FAILURE') {
            // 実際にはechoの代わりにSlack通知など
            echo 'job failed'
        }
    }

並列に下流ジョブを走らせたい

今までのParameterized Trigger Pluginでは下流ジョブの名前をカンマ区切りで並べていけば実現できていましたが、パイプラインではちょっと複雑な書き方になりました。

job = [:]
job['job1'] = { build job: 'my_echo', parameters: [text(name: 'text', value: 'job1')] }
job['job2'] = { build job: 'my_echo', parameters: [text(name: 'text', value: 'job2')] }
parallel job

この記述でjob1, job2は並列にキューに乗って実行されます。

参考