2018年12月20日木曜日

[Azure Pipelines] ビルドをスキップするコミットメッセージコマンド

この記事は Azure DevOps Advent Calendar 2018 20日目の記事です。

今回の内容は非常に短いのですが、Azure Pipelines でビルドをスキップするコミットメッセージコマンドを紹介したいと思います。
前回、前々回の記事はこちら

コミットメッセージコマンド
多くの CI サービスで使われている機能で、コミットメッセージに特定の文字列を入れておくと、CI 上の機能を呼び出せるものになります。
その定番がビルドのスキップです。

ドキュメントの更新だけのときなど、CI が実行されなくても問題ないようなケースで役に立ちます。
筆者が使用している CI サービスの各スキップコマンドを以下のリポジトリでまとめていますので、Azure Pipelines 以外のサービスで気になるものがあれば見ていただければと思います。
https://github.com/srz-zumix/ci-skip/tree/master

Azure Pipelines でビルドスキップするコミットメッセージコマンド
さて、肝心の Azure Pipelines のスキップメッセージですが、
***NO_CI***
になります。

多くの CI サービスで使われている [ci skip] や [skip ci] は対応していないようです。
ちょっと残念ですが、 issue もあるようなので対応されることを期待して待ってます。
https://github.com/Microsoft/azure-pipelines-agent/issues/858


実際にスキップメッセージを入れたときの挙動は先に紹介した ci-skip リポジトリで見ることができます。
exsample commit: add Azure Pipelines ***NO_CI***

今回は以上です。
では。

2018年12月11日火曜日

Azure Pipelines でマトリックスを組んでみた

この記事はAzure DevOps Advent Calendar 2018 11日目の記事です。
4日目に投稿した「ブログズミ: Azure Pipelines 始めました」の続きになります。


早速ですが、上のスクリーンショットは 31 個のジョブを実行している様子です。
いやホント10 並列は素晴らしいですね!

では、今回はマトリックスを組んでみた流れを紹介したいと思います。
テンプレートを作る
まずは、パラメータで処理パターンを増やすためのベースとなるテンプレート部分を作ります。
ドキュメントを見た感じですと、ジョブ、もしくはステップをテンプレートにできるようです。
Job and step templates - Azure Pipelines & TFS | Microsoft Docs

テンプレートの記述と利用
テンプレートは azure-pipelines.yml とは 別の yaml ファイルに記述します。
そして、azure-pipelines.yml もしくは別のテンプレートから下記のように参照します。
steps:
  - template: templates/sample.yml  # Template reference
jobs:
  - template: templates/jobs.yml  # Template reference

サンプルがドキュメントに載ってますので、そちらを見ていただくとわかりやすいと思います。
テンプレートは別のリポジトリのファイルを参照することもできるようですが、今回は使わないので省略します。 > Using other repositories

テンプレートにパラメータを渡す
テンプレートにパラメータとして任意の要素を渡し、パラメータに応じて処理内容を変えたいと思います。
Passing parameters
(ドキュメントを見ていると、単純の値や配列だけでなく、ジョブをパラメータとして扱うこともできるようですが、まだ実践してないので今回は省略)

まずは、パラメータのやり方から。

template 側の yaml
parameters:
  name: ''
  options: ''
  vmImage: 'ubuntu 16.04' # デフォルト値

jobs:
  - job: ${{ parameters.name }}
    pool:
      vmImage: ${{ parameters.vmImage }}
parameters にパラメータを定義します。ここでセットした値はデフォルト値になります。
パラメータの値を使用する場合は、${{ parameters.hogehoge }} のようにします。

azure-pipelines.yml 側
jobs:
  - template: .ci/azure_pipelines/template-make-test.yml
    parameters:
      name: default
 
パラメータを渡す場合も、parameters に記述します。
これでパラメータの受け渡しができるようになりました。

パラメータに応じて処理を変える
さて、中核に迫ってまいりました。
パラメータの内容によって、処理を変える方法はいろいろ考えられます。
ドキュメントを見ていると、高度なことができそうな感じがしているのですが・・・
まだ使いこなせてないので、省略。
* Template expression functions
   Expressions
* Insertion
* Conditional insertion
* Iterative insertion

今回はとてもシンプルにパラメータをスクリプトの引数として使いました。
(Azure Pipelines 側の書き方や制約に縛られず、自分の好きな書き方をできるので、まずはこの方法で良いと思います。)

iutest では以下のようにしました。
parameters:
  options: ''
  package_name: 'default'

steps:
- script: make -C test -j4 OUTPUTXML=junit ${{ parameters.options }}
  displayName: 'make'
- script: make -C test -j4 OUTPUTXML=junit ${{ parameters.options }} ${run_option} test
  displayName: 'test'
  env:
    run_option: RUN_OPTION="--iutest_default_package_name=${{ parameters.package_name }}"

make にオプションを渡せるようにしたのと、テスト実行時のオプションを指定するようにしました。

azure-pipelines.ym > job template > step template
さて、ここまででほぼほぼテンプレートを作ることができるようになっていると思いますが、最後にテンプレートを2段構成にしてみました。
テンプレートをテンプレートで使うことも問題なくできるのです!

iutest では、make test とテスト結果を集計するステップテンプレート、
そして、それをある程度の粒度でパラメタライズドしたジョブテンプレートにしました。



azrue-pipelines.yml は以下のように、ジョブテンプレートを利用するだけの非常にシンプルな内容になりました。
jobs:
  - template: .ci/azure_pipelines/template-make-test.yml
    parameters:
      name: default
  - template: .ci/azure_pipelines/template-make-disabled-test.yml
    parameters:
      name: disabled

テンプレート側の yaml は長いので、GitHub を見てくださいmm
iutest/azure-pipelines.yml at master · srz-zumix/iutest
iutest/.ci/azure_pipelines at master · srz-zumix/iutest

マトリックスを書く

これが、ちょっと長いのですが・・・こんな感じになりました。


ステップテンプレートに make のオプションを生成して流しているジョブテンプレートになるのですが、
やっていることは1つのマクロを定義して config を変えて、ビルド・テストをさせています。
そのマクロ部分をマトリックスにしたのですが、いちいち名前をつけないといけないのが面倒・・・
DISABLED_CONFIG 配列に定義できると楽なんですが・・・

たぶん、もっとキレイに書けるんだろうなーという感触はありますが、今後の課題としたいと思いますmm

10並列の効果はどんなもんよ?
iutest の現時点で、1 pipeline で 57 ジョブが実行しています。
各ジョブでやっていることは、ほぼほぼ同等でマクロ定義が1つ異なるだけのビルド・テストです。
1ジョブの実行時間が約5分。

直列に行った場合は、5 x 57 分で約5時間です・・・

が、これが、


なんと!


およそ 35分 !!
10並列のパワー素晴らしい

テスト失敗してますよ?
はい。
今まで config 変更のテストは、ローカルの Jenkins もしくは今はなき SnapCI でやっていたのですが(それかローカル実行)、とにかく時間がかかって辛かった!のでやってませんでした。すみませんmm
今回、Azure Pipelines の力によってメンテナンスできてなかった部分が炙り出された感じです。
本当、ありがとうございます!!って感じです。
(FAIL はちゃんと直します。ごめんなさい)

今後やりたいこと
さて、今回はこれで以上となりますが、
まだまだ Azure Pipelines でやりたいこと・できることは多そうです。
また進展あったらまとめたいと思います。ではでは。

* [ci skip]
* auto cancel
* 簡易テスト後に、マトリックスが走るようにする(dependsOn の挿入?)
* 条件分岐(xml 出力がされないことを期待する場合に、集計をしない)
* yaml に書く量を減らしたい
* 本当のマトリックス( N x M )で爆発させたい

2018年12月4日火曜日

Azure Pipelines 始めました

この記事は(ちょうど公開するタイミングで空きがあったので)
Azure DevOps Advent Calendar 2018 4日目の記事になりました。


Azure Pipelines が9月にリリースされたようですが、最近知りました。
なんと! OSS なら 10 並列・時間制限なし!!
これは組み合わせ爆発させざるをえない!!!(マテ



Sign Up
脊髄反射で SignUp しましょう。

MS アカウントでサインインして、名前決めたら完了です。


あれ?すでに Organization がありますね?


どうやら、昔作った Visual Studio Online のが残ってたみたいです。
新規作成した Organization は削除。
Overview で「組織のURL」を更新し、プロジェクトもすべて削除しました。


ともあれ、これでサインナップ完了です。

パイプラインを作る
では、パイプライン作っていきましょう。
Azure Dev Ops のダッシュボードからプロジェクト作成しても良かったのですが、 GitHub からやったほうが楽かなーと思ったのでそっちにしました。

GitHub から登録
GitHub Marketplace に Azrue Pipeline があるので、インストールします。


フリープランで Order


リポジトリを選択(全部もしくは任意のリポジトリを選べます)


Organization を選択(SignUp 時に作成したもの)
プロジェクト名は任意で(すでにあれば選択)


認証したら・・・


プロジェクトの出来上がり!


ここまでで、プロジェクト作成が完了してパイプライン作成の第一ステップのロケーション(GitHub)の選択が終わっている状態になっています。
ここから、パイプラインを設定していきます。

リポジトリの選択
つづいて、リポジトリの選択をします。今回の場合は iutest を選択します。

テンプレートの選択
Choose a template でパイプラインのテンプレートを選びます。
c++ のテンプレートがあったので、「C/C++ with GCC」を選択しました。(リポジトリの内容によってオススメが出てくるみたいですね)


YAML
テンプレートから azure-pipelines.yml が生成されます。
ルートディレクトリで make するだけですが、iutest はそれではビルドされないので、ビルドとテストの実行をするように少し書き換えました。


Save and Run2
最後に保存して、最初のビルドを実行してみましょう!
生成した azure-pipelines.yml を commit/push するので、master に入れるかブランチ切るかを選択し、(必要であればコメントも)「Save and run」ボタンを押します。


今回はブランチを作成しました。
https://github.com/srz-zumix/iutest/pull/120

はじめてのビルド
「Save and run」を押すとビルドがキューに積まれて、処理が始まります。






しばらく待つと・・・無事成功!
ここまでは簡単でしたね!


テストの集計タスクを追加してみる
まだまだ、Azure Pipelines のことで把握していないことばかりではありますが、この流れのままテストの集計までしてしまいましょう。

テストができるようになったので、テストの集計をします。
テストの集計は「タスク」になっているようなので、タスクを追加します。

Publish Test Results task - Azure Pipelines & TFS | Microsoft Docs
先程作成した azure-pipelines.yml に以下を追加します。
- task: PublishTestResults@2
  inputs:
    testResultsFiles: 'test/*.xml'
変更を最初に作ったブランチに push しましょう。


集計できました!簡単!!
さて、これで GitHub に push するとテストが実行され、結果が集計されるところまで確認できました。
(失敗すべきテストまで集計されてしまっているのは make のオプションミスです・・・)
CI をするにあたっての基本的なことができるようになったので、ここからやりたいことを組み込んでいこうと思いますが、そのへんはまた次回で・・・

バッジを付ける
次回に行く前に・・・やっぱりバッジはつけておきましょう!
バッジはパイプラインのダッシュボードページの右上メニューの中にあります。

バッジのブランチは「?branchName=develop」をつけると指定できます。
※ ビルドページの URL のブランチ指定がうまくできなかったので、方法があれば知りたいですmm

最後に
OSS プロジェクトなら 10 並列が無料で使えるのは、個人的にすごくありがたいです。
まだ、10 並列を使い切ってはないのですが、これから使っていこうと思ってます。

また、導入してしばらく経っているのですが、GitHub に push してからビルドが走るまでの時間も早いので、そこも嬉しい。
YAML の書き方は・・・ちょっと四苦八苦しながらも書いてるので、もう少しドキュメントがわかりやすいと嬉しいな、とも思いました。(圧倒的英語力不足ともいう・・・)

OS も Windows だけでなく、macOS/Linux も使えるようなです。
(最近は、この辺での優位性がなくなりつつありますが・・・)

Azure Pipelines は非常に強力なサービスなのは間違いなさそうなので、これからもお世話になると思います。よろしくお願いしますmm

今回は以上です。

2018年11月26日月曜日

[Jenkins] 種類ごとにジョブをリストアップ

参照:

下記をスクリプトコンソールで実行しましょう。

ジョブのクラス名付きでリストアップ
def list = Jenkins.instance.getAllItems(Job.class)
list.each{ 
  println it.name + " - " + it.class
}
return list.size()

目的のクラスでリストアップ
def list = Jenkins.instance.getAllItems(class hudson.model.FreeStyleProject)
list.each{ 
  println it.name
}
return list.size()

2018年11月20日火曜日

iutest のテストをするリポジトリ iutest-test を GitLab/GitLab CI に引っ越しました

iutest の外部テストリポジトリとして iutest-test を作成し、そこで Google Test との互換性テストを行ってきましたが、別リポジトリにしたのなら、GitLab に引っ越しして GitLab CI を使えるのでは?
ということで引っ越ししました。

Sign Up & Import
まずは GitLab への SignUp をしましょう。(GitLab は有名なので省略)
GitLab は GitHub からリポジトリをインポートできるので、その機能を使って iutest-test を持ってきます。


New Project から Import project を開いて、GitHub を選択(いっぱい対応してますね)


インポートしたいリポジトリを選択して、Import ボタンを押したら完了です。






簡単ですね!

.gitlab-ci.yml の作成
続いて、CI の設定をします。
もともと iutest-test では Travis-CI で定期ビルドして、iutest のサブモジュール更新を行い、
その push トリガーによって、Codefresh でテストを実行していました。
(そのときの記事はこちら→「」)

今回 GitLab に引っ越してすごく良かったのが、この2つのビルドを GitLab CI 1つで完結できたことです。できあがった .gitlab-ci.yml は以下になります。


そして、Google Test 最新コミットとの互換性テストの構成はこのようになりました。


画像の上半分あたりは、
ブログズミ: 依存ライブラリの GitHub を Travis CI で定期的に監視して DockerHub Automate Build を実行する(+ Codefresh ジョブを Trigger)」で紹介した内容とほぼ同じです。
(違いは Webhook 先が変わったのと、Google Test の更新検知をサブモジュールにしたくらい)

サブモジュールの更新
update_submodule のパイプラインがサブモジュールの iutest の更新を担います。
こちらは、毎日1回のスケジュールトリガーで起動します。
特に難しいことはなく、サブモジュールを最新にしているだけです。
リモートに push する部分ですが、Protected な環境変数に記録した秘密鍵を使って行います。
やり方はこちらを参考にしました。
.gitlab.ci.yml for SSH with private key.

Deploy Key の登録
まずは公開鍵を登録します。
「Settings」 > 「Repository」の「Deploy Keys」から登録してください。


push のためのキーを環境変数に設定する
https://docs.gitlab.com/ee/ci/variables/#variables
「Settings」 > 「CI/CD」 に 「Variables」 があるのでそこで設定します。
Protected にしてくださいね!


> They can be protected by only exposing them to protected branches or tags. 
ちなみに、ここで設定した Protected Variable は Protected branch or tag でしか使えないので注意!
ブランチ設定は「Settings」 > 「Repository」 > 「Protected Branches」でできます。


update_submodule ブランチの意味は?
サブモジュールを更新して master ブランチに push する update_submodule パイプラインですが、これを行うのは master ブランチではなく update_submodule ブランチです。
なぜ、別ブランチで行っているかというと、バッジのためです。

サブモジュールを更新するパイプラインも立派なパイプラインの1つです。
バッジはブランチ単位で発行できますが、パイプラインでわけることができないので、同じブランチでやってしまうと「テストパイプラインは失敗している」「サブモジュール更新は成功している」ときに、正しく最新のテスト状況を表示できません。
そのため、ブランチを分けています。
(パイプラインごとにバッジ出せると嬉しいですが・・・)

テストの実行
テストの部分は前回から特に変わってません。
Google Test の最新コミットが入った docker コンテナを落としてきて、その中で iutest の互換性テストを実行しています。
前回との差分としては、DockerHub からの Webhook が latest と latest-alpine の2つが飛んでくる(release があるとそのタグも)ので、 latest のみパイプラインを起動するようにフィルタリングするようにしました。
フィルタリング部分は最近お気に入りの Integromat で行いました。
そのへんは別の記事を参考にしていただければと思います。
ブログズミ: Travis CI の結果をツイートするのを Zapier から Integromat に引っ越した

これで完成、あとは・・・
バッジを付けましょう!お約束ですね。
GitLab CI のバッジは、「Settings」 > 「CI / CD」 > 「General pipelines」 を展開すると、「」があるのでそちらで取得できます。



(失敗してるのは気にしないでください・・・)
pipeline status
ところで、そもそもなんでリポジトリを分けてるの?
(このへんもブログにしとけばよかったなーと思いつつ)・・・理由は簡単で関連先が理由でテストが失敗したままになるのが困るからです。
iutest は独立したフレームワークですが、Google Test の Add on としての機能を持っていたりするので、Google Test を使ったテストもしています。
PR とかあったときに、Fail となっても困惑を生むだけだと思ったので、テスト用にリポジトリを分け、さらに粒度も1日1回程度にしました。

最後に
個人的に、外部依存のライブラリとのテスト構築のパターンが出来上がった、という感想。
こう、カチッとハマった感じはいいですね。

今回は以上です。
では。



2018年11月14日水曜日

CI/CD Test Night #1/#2 に参加してきた

CI/CD Test Night #1
CI/CD Test Night #2


1日目は、補欠だったのですが当日繰り上がったので参加。
2日目は、当選してたので予定通り参加してきました。
(ブログ参加枠ではないのでテキトーに書きます)


(両日参加でパーカーもらえたようですが、Tシャツを着ていく必要があったようで、思いっきりネタTシャツで行ってしまいもらえなかった・・・)

感想
Bitrise の方が来日してくれたこともあって、Bitrise の話題が多かったです。
Bitrise は自分にとっては使っている CI サービスの1つくらいの認識で、モバイルに強いという印象がある程度でした。
特に自分ではその強みの恩恵を受けてはいないので(iOS/Androidアプリを作っているわけじゃないので)、LT を聞いててみんな使ってるんだなーという感想。あとは Circle CI も強いんだなという感想。


Bitrise をより深く使ってみた
公演でワークフローのヒントをいろいろもらったので、やってみました。

設定の diff と restore
ワークフローとかパイプラインとか作ってるときって、結構トライアンドエラーが多いので Restore できるのはありがたい。
他のサービスよりも diff が見やすいなーと思いました。


並行実行
ワークフローを直列に実行するのではなく、2つに枝分かれさせて並行実行させる方法のブログ記事が紹介されたので、試してみました。



方法としては、別のワークフローをキックするステップが用意されているので、それを入れ込むだけです。
上記ブログで紹介されているのは、「Bitrise Start Build」を使った方法です。
(Bitrise Start Build Step でも Trigger Bitrise workflow でも、どっちでも実現できたましたが、Start Build のほうは待ちができます。)
(Start Build の方は Personal Access Token が、Trigger workflow の方は Build Trigger Token が必要になります。)

やってみた結果としては、そもそも Free プランだと 1並列 だけなので、ビルドが詰まって無理でした。。。


異なるスタックのビルドを1つのワークフローで実行したい
並行実行はできたらいいなくらいだったので、Free プランでできないのは致し方ないですが、
iutest では、iOS / Android ビルドのために、Mac と Ubuntu のスタックをそれぞれ利用しています。
そのため、これまではプロジェクト自体を分けて対応していました。
ただ、1 push に 2 ビルド消費してしまうので、1つのワークフローで iOS / Android ビルドができないかなと思ってました。

ただ単純にワークフローをつないだときに、スタックの切り替えもしてくれると良かったんですが、そううまくはいかないものです。。。



(Hybrid スタック使えばいいんでしょうが、その前に Android ビルド環境を整えねば・・・)
Workflow ごとのバッジがほしい
バッジ集めが趣味なので、ワークフローごとのバッジがほしいなーと思ってます。
(ワークフローで iOS/Android を別途書くことが多いと思うのですが、それぞれでバッジを出したい)
(今は並列実行の件もあってプロジェクト自体を2つ作ってますが・・・そうすると両方の結果を加味したバッジ表示ができないので、それもまた困っているところ)


すでにできるのかもしれないですが、やり方がわからず。
情報あればコメントいただけると嬉しいです。

(ここでワークフロー選択ができるといいんですが。。。)

最後に
Jenkins 以外で CI メインの勉強会って、たぶん初めての参加だったのですが、楽しかったです。
やっぱり CI 面白いですわ。

あとは、Bitrise のワークフローを見直すイイ機会になりました。
今まではただ使ってるって感じだったので、もっと使い倒していこうと思います!
(とりあえず、この記事で書いた未解決な件はもう少し考える)

では。またどこかで。

2018年11月8日木曜日

travis-ci.org から travis-ci.com に移行しました



Travis CI といえば travis-ci.org だったんですが、
GitHub Checks API を試してみようと思って調べていたら
(そのへんのことはこちら→「ブログズミ: GitHub Checks 対応 CI サービスを使ってみた」)
travis-ci.com のことを知りました。

.com の方は今までは public リポジトリ(OSS)が対応していなかったようですが、public リポジトリも .com を利用可能になりました。
そして、GitHub Checks API に対応しているのは .com の方なので、移行が必要でした。

すでに .org の方でビルドされているプロジェクトは、すぐには .com は使えなくマイグレーションが必要です。(新規の場合は .com で登録できる)
ただ、マイグレーションに関しては順次行われるようですが、遅延しているらしく、すぐに .com に移行したい場合はサポートにメールで依頼する必要があります。
iutest で Checks API を使いたかったので、メール依頼を出してみました。





マイグレーションにあたっての注意点
上記キャプチャにも書かれていますが、マイグレーションをすると .org の方の履歴は消えます。 Web config 部分も消えます。
マイグレーション依頼のメールを出すと、最初に本当にいいのかと?注意事項の確認がされます。

Migrating repos from travis.ci.org to travis-ci.com currently has the following caveats:

a) the build number will be reset to zero
b) the repo on travis-ci.com will start with a blank build history
c) the old build history will still be available on travis-ci.org
d) environment variables will not be migrated
e) environment variables will need to be recreated and, where necessary, re-encrypted by the customer for use in .travis.yml
f) repo settings such as enabled push or pull builds, auto-cancellation etc will not be migrated

iutest の場合、履歴に関しては、別に消えても特に問題がないので OK
Web config 系は cron 設定くらいなので、とりあえず .org の設定をキャプチャしておきました。



最初のビルドは4年以上前だったみたいですね。ほー

Hello Travis-CI ".COM"!
メールで注意事項に対して問題ないことを伝えると、ほどなく移行完了メールが来ると思います。
あとは、退避しておいた Web Config を戻すのと、 Encrypting environment variables を使っている場合は再生成が必要になります。
(再生成の際には、 travis login --pro で .com の方にログインして行います。エラーメッセージが出ると思うのでやってみればわかると思います)

これにて、無事に移行が完了しました。

GitHub Checks
さて、最後に一番の目的である GitHub Checks を見てみましょう。

https://github.com/srz-zumix/iutest/pull/118/checks


ちゃんと出てますね!
各 CI の結果が GitHub のページに集約されるのは、いろんなサービスを使っている自分としてはとても助かります。
対応サービスが今後も増えるといいですね。

今回は以上です。