2021年12月23日木曜日

GitHub で草生やさないようにする

 GitHub で「草を生やす」方法はすぐ出てくるのですが、「草を生やさない」方法がすぐに見つからなくて困っていたので備忘録。

というのも、GitHub Actions で定期的に commit をするワークフローがあるのですが、そのコミットが contribution に含まれてしまってました。 
問題の workflow => https://github.com/srz-zumix/wandbox-status/actions(今は修正済み)
このワークフローでは、修正前は自分の GitHub アカウントの noreply メールアドレスを使ってました。

git config --local user.name ${{ github.actor }}
git config --local user.email ${{ github.actor }}@users.noreply.github.com
筆者は noreply ではなく個人のメールアドレスを登録してるのでカウントされないと思ってたのですが、そうではなかったみたいです。
コントリビューションがプロフィールに表示されないのはなぜですか? - GitHub Docs
※「草が生えない」で困ってる人は↑の公式ドキュメントを読むのをおすすめします。

というわけで、user.email をなんかテキトーなメールアドレスにしたら良いのですが、ちょうど良さげな記事があったのでこれにしました。

GitHub Actionsのボットがコミットしたようにアイコンをつけるにはメールに「github-actions[bot]@users.noreply.github.com」を指定すれば良い - nwtgck / Ryo Ota

git config --local user.name github-actions[bot]
git config --local user.email github-actions[bot]@users.noreply.github.com
これで無事、定期ジョブの自動コミットで草を生やさないようにできました。
(濃い草が自動コミットも含まれていた時期)


めでたしめでたし。

2021年12月16日木曜日

Visual Studio でライブラリなど外部コードの警告を出さないようにする方法

これは「C++のカレンダー | Advent Calendar 2021 - Qiita」の16日目の記事です。

はじめに

警告はときにプログラムの問題を教えてくれます。
警告は基本的にないのが望ましいです。なぜなら、野原から四葉のクローバーを探し出すのは大変だからです。(見つけた四葉は幸運をもたらすか、不幸をもたらすか。。見つけるなら早いほうがいいですよ)

CI/CD 担当をやっていると警告を直してもらうための対応とかしたりします。
警告出てたらステータスを変えて通知とか、ちょっとずつ警告をエラーにしていくとか。
ここで問題になるのは、自分たちが改変することができない SDK やライブラリの警告です。
通知で頑張ってる場合はフィルターでなんとかなるかもしれません。
as Error にしている場合は困ります。

そんな場合は自分たちのコード以外をシステムインクルード(#include <...>)し別途警告レベルを制御することで解決できます。

Visual Studio で外部コードの警告を制御する

Visual Studio では 2017 (15.6) からシステムインクルードの警告レベルを別途設定できるようになりました。「/external (外部ヘッダー診断) | Microsoft Docs」こちらの公式ドキュメントにもありますが 2017 では試験機能となっています。/external オプションに加えて /experimental:external オプションも必要になるので注意してください。2019 からは正式機能となっており、設定も専用のページができました。

さて、これを利用すれば外部コードはシステムインクルードとすることで警告がでないようにできます。試しに以下のコードで試してみました。


/external の設定

プロジェクトプロパティの「C/C++」→「外部インクルード」を開き、 /external:W0 を設定します。コード分析も外部インクルードに対して別途制御可能なので、有効にしている場合は設定しましょう。

外部インクルードディレクトリにパスを追加している場合は、システムインクルードすれば外部インクルードとして認識されます。もしただのインクルードディレクトリにパスを追加している場合は、/external:anglebracket オプションを有効にすることで外部インクルードとみなされます。(システムインクルードすれば警告でなくなると逃げ口として意図しない対応をされる可能性があるので、インクルードディレクトリの設定を変更するのをオススメします)

システムインクルードではない場合

C4390 と C4456 が出ます。

システムインクルードの場合

システムインクルードにすると警告が消えました!

消えない警告もある?

たまたま見つけたのですが、システムインクルードしたファイルの警告でも /external:W0 が効かずに警告されるケースがありました。(こういう書き方をすることはない気もしますが)
コードはこちらです。gcc/clang では警告されませんでした。(https://wandbox.org/permlink/kPn2z1MLCAvbOBny

↑は C4390/C4702 の2つ。↓は C4390 は消えるが、C4702 は消えない。

Visual Studio でシステムインクルードヘッダーの警告を厳しくする

逆にシステムインクルードの警告レベルを上げるとどうなるのでしょうか?
標準ライブラリはシステムインクルードしていると思いますが、それらのコードに警告はあるのか・・? /external:W4 にして試してみました。


結果としては警告は出ない、が警告があるのかないのかはわからない。でした。
というのも VS2017 より前から標準ライブラリの警告って見た記憶がないため(たぶん)、別途制御されているのでは?と思ったからです。
ちなみに後述してますが gcc/clang では(とあるコンパイルオプションをつけると)標準ライブラリからも警告が出ていたこともあります。
MSVC の STL は公開されているので、暇なときにビルドしてみて確認してみようかと思います。
https://github.com/microsoft/STL

gcc/clang の場合

gcc/clang の場合は古くからシステムインクルードの警告は除外されていました。
(Visual Studio が今までできてなくて 2017 でようやくという感じでした)
Wandbox で試してみたのでリンクを貼っておきます。
コードは Gist にも置いてあります。

システムインクルードではない場合

警告でます。
gcc: https://wandbox.org/permlink/MLrLASaM5o5A3UWm
clang: https://wandbox.org/permlink/x6TT2NFROSmyLhV4


システムインクルードの場合

警告でません。
gcc: https://wandbox.org/permlink/XVHXnWIMyOfDMjl3
clang: https://wandbox.org/permlink/strTYwduT4ZLH5NK

gcc/clang でシステムインクルードヘッダーの警告を有効にする

gcc/clang でもシステムインクルードの警告を有効にできます。-Wsystem-headers オプションを使います。
試しにしてみると・・

新しいコンパイラーと標準ライブラリの組み合わせだと警告でませんでした。
古いとそこそこ出ます。

gcc 9.1.0: https://wandbox.org/permlink/lhXWuNvWEJdKwJNh
gcc 8.3.0: https://wandbox.org/permlink/4dHKZKtdqmDGmXNU 
clang 6.0.0: https://wandbox.org/permlink/MaVYzrGDeT79eMZa
clang 5.0.0: https://wandbox.org/permlink/qjbmV9U2c8MxHe6A

まとめ

システムインクルードを使って外部コードの警告を除外、自身のコードの警告を取り除く/取り除いてもらうように自動化/自働化しましょう。

2021年12月9日木曜日

Facebook 改め Meta 社の静的解析ツール Infer を GitHub Actions でかける

この記事は「C++のカレンダー | Advent Calendar 2021 - Qiita」の9日目です。

Infer とは

Infer は Facebook 社改め Meta 社が作った静的解析ツールです。
今回は C++ Advent Calendar ということで C++ の静的解析ツールとして紹介しますが、Infer 自体は OCaml で書かれています。
また、C++ の他に Java/C/Objective-C の解析も可能です。

C++ の静的解析ツールというと Cppcheck や Coverity 、コンパイラ付属のものがあったりします。筆者はこれまでこれらのツールを使ってきました。
Infer は 2015 年にOSS化して公開されたのですが、ずっと使ってみたいと思いつつ機会がありませんでした。

今回こうして記事にしているのは、仕事で必要になったからとか趣味でやる気になったからではなく、社名が変わったからネタとして触ることにしました。
理由はともあれ、以下で紹介していきます!

ローカル環境で使う場合

本記事は表題どおり「GitHub Actions」で Infer を使う手順を紹介しますが、ローカル環境で実行する場合も軽く触れておきます。
まず大事なこととして、Windows 非対応です!
Mac の場合は brew install infer でインストールできます。Linux の場合はビルド済みバイナリをダウンロードするか、ソースコードビルドで使うことができます。Docker という手もあります。
詳しいことは公式の「Getting Started with Infer」を見てください。

セットアップできたら「infer run -- ビルドコマンド」のようにコマンド実行すると以下のように結果が出ます。

ビルドコマンドは対象によって変わると思いますが、コンパイラー以外にも cmake や make 、mvn などのビルドツールにも対応しています。

ビルドコマンドが bash script になっているような場合はキャプチャーするコマンドを認識できないので、--force-integration オプションで教えてあげてください。
対応している integration は --force-integration オプションのヘルプで確認できます。
e.g. infer run --force-integration clang -- build.sh

GitHub Actions で使う

では、ここから本題です。
GitHub Actions で Infer を使うために、Setup Infer action (srz-zumix/setup-infer) と Infer reviewdog action (srz-zumix/reviewdog-action-infer) を作成しました。

setup-infer

Infer を現在の環境にセットアップするアクションです。
当然ですが Windows は非対応です。また Mac の場合はバージョン指定はできず、 brew install で取得できるバージョンがインストールされます。
(要望あれば対応しようかと思いますので、issues へどうぞ)

reviewdog-action-infer

Infer の結果を reviewdog を使って PR にコメントするアクションです。
Infer の実行結果が入っている infer-out から result.txt を参照し、reviewdog を使って PR に問題をコメントします。


なぜ action を分けたのか

最初は Infer インストールや解析込みの action を書こうと思ったのですが、ビルドツールや環境はユーザーによってバラバラで、action 側ですべてに対応するのは難しいと考えてこのようになりました。

Infer の実行

上記2つの action は infer での解析処理をしませんので、ワークフローで適宜呼び出してください。
個人開発してるテストフレームワーク(iutest)の例を記載しておきます。

  infer:
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - uses: actions/checkout@v2
      - uses: srz-zumix/setup-infer@v1
      - name: infer
        run: |
          infer -- make -C test IUTEST_USE_PYTHON=0
      - name: Check Infer report
        uses: srz-zumix/reviewdog-action-infer@v1
        with:
          reporter: github-pr-review
   
結果

iutest のワークフローの結果はこちらです。
静的解析なしだと 10 分くらいのテストが、Infer ありだと 25 分弱と少し時間がかかってますが、まぁ趣味開発なので許容範囲です。

速度向上

Recommended flow for CI | Infer」こちらで CI 向けのおすすめ実行方法が書いてあります。うまくキャッシュできるのであれば --reactive オプションでキャプチャーした情報を再利用すれば早くなると思います。
reportdiff は reviewdog で同等のことができるのでどちらでも。

また --changed-files-index オプションで差分ファイルのリストを指定すれば、そのファイルの解析だけが行われるため、速度向上可能です。
ただし、C++ の場合はヘッダーファイルを指定しても解析されません。.cpp ファイルを指定しないとダメです。(※ --changed-files-index は analyze 時に有効なので capture 時間の短縮にはならない)

Infer capture/analyze TIPS
capture/analyze 中にクラッシュする場合

--skip-analysis-in-path で除外指定できるのでそれをおすすめします。
-g オプションでデバッグモードになるので原因調査ができるかもしれませんが、ストレージを圧迫するかもしれません。
(3,000 弱のソースコードファイル数からなるプロジェクトでやったら 600GB 越えたあたりでディスクフルになって PC 自体が落ちました。。)

解析途中でエラーが出る場合

--keep-going オプションを付けると続行可能です。

compile_commands.json の場合 --clang-blacklisted-flags/--clang-blacklisted-flags-with-arg は効かない

そのまんまです。特に xcodebuild の場合 infer が使う clang が知らないオプションを使ってることがあり、「error: unknown argument: '-index-store-path'」のように失敗していまいます。 infer はデフォルトで  --clang-blacklisted-flags-with-arg に -index-store-path が入ってますが、 compile_commands.json から capture をする場合は --clang-blacklisted-flags(-with-arg) オプションは考慮されないので、json ファイルの command から削除してください。

--continue-analyz

仕事のプロジェクトに Infer 掛けてみたら analyze でクラッシュするわ、エラー起こるわ、なんか応答なくなるわ、そもそも解析時間がクソ長いわ、で辛かったんですが、--continue-analyz オプションつけると続きから解析してくれるので作業が無駄になりません。
(最初に知りたかった)

.inferconfig にオプションを書ける

infer のコマンドラインオプションは .inferconfig ファイルに書いておくことができます。
ファイルの中身は JSON 形式でオプションから -- を除いた名前をキーに設定をします。

例えば、上記で紹介した --skip-analysis-in-path や、 infer の clang にインクルードパスを追加する場合は以下のように書けます。

{
    "skip-analysis-in-path": [
        "path/to/lib/xxx/src",
    ],
    "Xclang": [
        "-I /path/to/dir/include",
    ]
}
まとめ

静的解析ツールは1つかければ十分というものではないので、ぜひ試してみてください。

以上。

2021年12月6日月曜日

CircleCI の Concurrency と Parallelism

この記事は「CircleCI Advent Calendar 2021のカレンダー | Advent Calendar 2021 - Qiita」の6日目です。

CircleCI が無料プランで 30 同時実行可能になったので、Parallelism との関係を調べてみました。

Parallelism とは?

CircleCI ではワークフローのジョブとジョブはそれぞれ並行実行されます。
参考:ワークフローを使用したジョブのスケジュール - CircleCI#ワークフローの構成例 

一方、Parallelism はジョブの中の処理を並列実行する仕組みです。
参考:テストの並列実行 - CircleCI

Parallelism はジョブの steps をそれぞれのワーカーで同じように実行されますが、各ワーカーに付与される CIRCLE_NODE_INDEX 環境変数の値(0,1,2...)でテストを分割したり条件分岐できます。
この Parallelism はプランによって使用できる上限が決まっています。
筆者の場合は今月頭の時点で 16 でした。

さて、ここで少し疑問がわきました。
16 parallelism のジョブを 2 つ使ったら 30 同時実行されるのでしょうか?

Parallelism を含むジョブを 30 以上実行したらどうなるか?

筆者が CI サービスのまとめをしてるリポジトリで検証してみました。

まとめルートリポジトリ:https://github.com/srz-zumix/ci-specs
同時実行の関連まとめ:https://github.com/srz-zumix/ci-parallel

ジョブの開始・終了時刻を記録、その情報から json を生成して chrome://tracing で可視化しています。
この方法は以前「ブログズミ: chrome://tracing で並列処理の可視化をしてみたらすごく便利だった話」で詳細に書いてますので、そちらを参照してください。
ジョブ設定はこちらを参照してください。
https://github.com/srz-zumix/ci-parallel/blob/master/.circleci/config.yml

16 parallelism x 2 job

16 -> 16 という感じでジョブは同時実行されませんでした。
続いて Parallelism を減らし、ジョブ数を増やしてみます。

4 parallelism x 8 job

今度は 28 -> 4 という感じで実行されました。
組み合わせたらダメとうわけではないようです。

(1 parallelism x ) 31 job

最後に Parallelism なし(1)を 31 job です。

当然ですが、30 -> 1 のように実行されました。

まとめ

Parallelism の数分だけ空きがないとそのジョブはキュー待ちする
同時実行数に収まるように Parallelism 数を決めると良さそうですね。
※この挙動に関しては 2021/12/05 時点での結果であり将来的に変わる可能性はあります。

以上。

2021年11月24日水曜日

master/main 混在している git submodule すべてをデフォルトブランチ最新にする

Git - サブモジュール

git submodule update --remote

以上!


下書き終えて、清書したら公開できる状態にしてあったのですが、git コマンド一発で解決することがわかったのでこの記事の↓↓の方の内容は読まなくて OK です。
でも、この過程ももったいないので残しつつ公開することにしました。
こういうときに Zenn のスクラップが便利なんだろうなーと思いました。



 GitHub のデフォルトブランチが master から main に変わって大分経ちました。
筆者も切り替わってから設定を master に戻すことはせず使ってきましたが、たまーに GitHub Actions の branches 指定を master/main で間違うくらいで特に困ってはいませんでした。

筆者の場合は、既存のリポジトリは今までのまま master としており、新規は main がメインブランチ(デフォルトブランチ)という感じになっています。
この状態の方も結構多いのではないでしょうか。

今までは特に困ってなかったのですが、ついに面倒くさい状態になったので備忘録を残しておきます。

なにが起きた

master がデフォルトブランチのリポジトリに複数のサブモジュールがぶら下がっているリポジトリがありました。
サブモジュールも含めてすべてデフォルトブランチが master でした。
ところが、ここに新規作成した新しいリポジトリをサブモジュールに追加したことで、main がデフォルトブランチのサブモジュールが増え、master/main 混在状態になりました。

でも、これだけであれば、まぁ git 操作時にうち間違えて面倒くさいってくらいだと思います。

サブモジュールの自動更新ジョブが止まった・・

問題が起きたのはサブモジュールの自動更新ジョブでした。
このジョブは毎日サブモジュールをデフォルトブランチ最新にし、commit/push するというものでした。
このジョブを作成した当時はデフォルトブランチは master だけだったので、特に気にせず master から pull してきてました。
はい。そうです。
main がデフォルトブランチのサブモジュールができたことで失敗するようになってしまいました。。

どうしたか

まず main → master を考えましたが、時代に逆行するのでやめました。(サブモジュール増えるたびに踏み抜きそうだったし)
次に master → main を考えましたが、これも面倒くさいのでやめました。

デフォルトブランチは検出することが可能なので、検出する action を書いたりもしましたがサブモジュールだと使いづらいというか、無理な感じだったので最終的にはデフォルトブランチを git submodule foreach 時に検出するようにしました。

コマンドはこんな感じです。

git submodule foreach "git remote show origin | grep 'HEAD branch' | awk '{print \$NF}' | xargs -I{} git pull origin {}"

デフォルトブランチを知る方法は他にもあるので調べてみてください。

では、今回は以上。



2021年11月17日水曜日

xcpretty で compile_commands.json を出力しても空になってしまう理由がわかった!

 1年以上前に非 CMake プロジェクトからなんとか CMake にできないかなーと思って compile_commands.json を仲介させる方法をやろうとしたけど、そもそもうまく出力できなかった理由が今日わかったんで備忘録!

原因は ccache

そのプロジェクトは ccache を利用しており、CC/CXX に ccache_wrapper.sh みたいなのを設定していました。最近 infer を試してて xcodebuild capture じゃうまくできなかったので、compile_commands.json でやろうとしたら1年ぶりに同じ罠にハマったのですが、今度は乗り越えた!圧倒的成長!!

xcpretty の parser.rb を見れば一目瞭然でした
https://github.com/xcpretty/xcpretty/blob/master/lib/xcpretty/parser.rb#L63

コンパイラー検出用の正規表現的に clang で終わるような CC じゃないと認識しれくれないかったのです。
ccache_wrapper.sh じゃなくて ccach_wrapper_clang だったらセーフだった・・

対応方法

CC/CXX はプロジェクトで設定されているので、xcconfig を食わせて CC/CXX を上書きするようにしました。

cxx.xcconfig

CC = clang
CXX = clang++
export XCODE_XCCONFIG_FILE=/path/to/dir/cxx.xcconfig 
xcodebuild -scheme XXX -project XXX.xcodeproj -configuration Debug -dry-run build | tee ./build.log | xcpretty  --report json-compilation-database --output ./compile_commands.json

ちょーすっきりした


2021年11月5日金曜日

【OSS】Miro 風ホワイトボード ourboard を立ててみる

 Miro はオンラインで共同編集可能なホワイトボードツールです。
リモートワークが増えた昨今、こういった共同編集ツールの需要が増えたのではないかと思います。私も仕事で Miro を使う機会が何度かありました。

こういったサービスはとても便利なのですが、仕事で使うには社内手続きが面倒だったり、そもそもクラウド NG などで使えないってケースもあると思います。

そういうときは OSS な類似ツールがないか探して使ってみることが多いです。
「ホワイトボード OSS」とかで検索すればいくつか候補が出てきます。
今回はその中でも Miro っぽい ourboard を使ってみることにしましたので、docker でサービスを立ててみました。

リポジトリはこちらです。
https://github.com/srz-zumix/docker-ourboard
git clone して docker-compose up すれば立ち上がります。
他の ourboard 紹介記事が db だけ docker 、ourboad はホストに立てていたのですが、こちらは ourboard も docker コンテナにしています。
(パスワードとかデフォルトのまま決め打ちになってるので適宜変えてください)

起動したら localhost:1337 をブラウザで開きます。
付箋・エリア・テキスト・矢印が使え、Undo/Redo にも対応しています。
↓の画像ではフレーム分割して薄いピンクの枠で囲ったところで同じページを開いて共同編集している様子です。相手のカーソル位置が表示されているのがわかります。
フレーム分割はこちら(TampermonkeyUserScripts)の iframe-splitter を使っています。


Miro は↓のような感じです。ourboard のほうが機能は少ないですが使い方は大分似ていると思いました。


ourboard は https://www.ourboard.io/ で試しに使ってみることもできますので、そちらで試してみてから検討しても良いと思います。

今回は以上。では。

2021年10月29日金曜日

Docker な Jenkins でプラグインインストール済みイメージを作る

 表題の件は検索すればすぐ見つかる内容ですが、古い方法のほうが検索上位に来ることが多いのでこの記事を書きました。

旧方式(install-plugins.sh)

プラグイン名や、プラグインが列挙されたテキストファイルを渡すとインストールしてくれる shell スクリプトが Jenkins のベースイメージに入っているのでそれを使います。

COPY JenkinsPlugins.txt plugins.txt
RUN /usr/local/bin/install-plugins.sh < plugins.txt

plugins.txt の中身は以下のように「プラグイン名:バージョン」となっています。

analysis-model-api:10.3.0
ansicolor:1.0.0
antisamy-markup-formatter:2.1
apache-httpcomponents-client-4-api:4.5.13-1.0
authentication-tokens:1.4
authorize-project:1.4.0
badge:1.8

この方法は既に Deprecated です。
https://github.com/jenkinsci/docker/blob/master/README.md#install-plugins-script-deprecated

一部プラグインがインストールできないなくて、調べたことがきっかけで新方式を知りました。
実際にはツールの問題じゃなく、lts イメージを使ってたのが直接の原因でしたが。
Some plugins failed to download! Not downloaded とエラーになる場合は、lts-jdk11 のイメージを使いましょう。

新方式(jenkins-plugin-cli)

新しい方法は CLI を使います。CLI を使って操作するのが現在の主流のようです。
https://github.com/jenkinsci/docker/blob/master/README.md#plugin-installation-manager-cli
この CLI はベースイメージに入っているので追加インストールとかは不要です。

COPY JenkinsPlugins.txt plugins.txt
RUN jenkins-plugin-cli --plugin-file plugins.txt

plugins.txt の中身は install-plugins.sh のときと同じで大丈夫です。
プラグイン列挙ファイルを渡す場合は --plugin-file(-f) を使います。
オプションの詳細は README を参照してください。
https://github.com/jenkinsci/plugin-installation-manager-tool#cli-options

インストールされているプラグインリストを取得するには以下のようにすれば可能なので、イメージを起動後に手動でプラグインをインストール後、docker exec とかでコンテナに入ってコマンドを実行してください。

$ jenkins-plugin-cli --list

Installed plugins:
ace-editor 1.1
analysis-model-api 10.3.0
ansicolor 1.0.0
antisamy-markup-formatter 2.1
apache-httpcomponents-client-4-api 4.5.13-1.0
authentication-tokens 1.4
authorize-project 1.4.0
.
.
.
workflow-job 2.41
workflow-multibranch 2.24
workflow-scm-step 2.13
workflow-step-api 2.24
workflow-support 3.8
ws-cleanup 0.39

Bundled plugins:

All requested plugins:

Plugins that will be downloaded:

Resulting plugin list:
ace-editor 1.1
analysis-model-api 10.3.0
ansicolor 1.0.0
antisamy-markup-formatter 2.1
apache-httpcomponents-client-4-api 4.5.13-1.0
authentication-tokens 1.4
authorize-project 1.4.0
.
.
.
workflow-job 2.41
workflow-multibranch 2.24
workflow-scm-step 2.13
workflow-step-api 2.24
workflow-support 3.8
ws-cleanup 0.39
Done

ただ、この出力をそのまま --plugin-file として渡せないのでスクリプトコンソールで出力したほうが手っ取り早いかもしれません。
その場合は下記のようなスクリプトを実行することになると思います。

def plugins = jenkins.model.Jenkins.instance.getPluginManager().getPlugins()
plugins.each {
    println ("${it.getShortName()}:${it.getVersion()}")
} 
最後に

今回はプラグインの事前インストールでしたが、Jenkins の Docker イメージ使ってちょっとやってみたいことがあるので進展がありましたら、またブログにしたいと思います。
では。

2021年10月22日金曜日

npm-groovy-lint + reviewdog で Jenkins Shared Library の PR チェック

 reviewdog は様々なツールの出力から PR に対してレビューをつけてくれるとても便利なツールです。私も GitHub Actions で reviewdog 使って shellcheck とか lint とかをよくかけています。

今回は Jenkins Shared Library の groovy スクリプトの lint をしたいと思い、npm-groovy-lint + reviewdog の GitHub Actions を用意したので紹介します。

reviewdog とツールがセットになったアクションがたくさんありますが、
npm-groovy-lint のアクションはなかったので作るか、アクション側で書くかのどちらかになります。
今回はアクション側で対応したいと思います。

.reviewdog.yml

reviewdog は .reviewdog.yml に runner 情報(実行コマンドや出力フォーマット)を書いておくと、-runners オプション指定で簡単に実行できるようになるので、その方法を使います。

作成した .reviewdog.yml がこちらです。

runner:
  npm-groovy-lint:
    # cmd: npm-groovy-lint # (required)
    cmd: npm-groovy-lint -o log.txt && cat log.txt
    errorformat: # (optional if you use `format`)
      - '%-P%f'
      - '%*\s%l%*\s%tnfo%*\s%m'
      - '%*\s%l%*\s%tarning%*\s%m'
      - '%*\s%l%*\s%trror%*\s%m'
      - '%-Q'

コマンド指定のところで一度ログファイルに出力しているのは、色付き出力されたものを reviewdog に認識させるのが面倒だったためです。

github/workflows/reviewdog.yml

続いて、GitHub Actions のワークフローです。
こちらは npm-groovy-lint を実行する環境を整えつつ、reviewdog を実行するワークフローになっています。

name: GitHub Actions - reviewdog
on:
  pull_request:

jobs:
  groovylint:
    runs-on: ubuntu-latest
    container:
      image: docker://nvuillam/npm-groovy-lint
      credentials:
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_TOKEN }}
    steps:
      - run: apk add curl git
      - uses: reviewdog/action-setup@v1
      - uses: actions/checkout@v2
      - name: Run reviewdog
        env:
          REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          reviewdog -reporter=github-pr-review -runners=npm-groovy-lint

npm-groovy-lint を実行するのに、公式のコンテナ上で実行するのが楽だったのでそのようになっています。このコンテナには reviewdog が実行するために必要になる curl と git が入ってなかったので、はじめに追加をしてます。

結果

これでセットアップ完了です。
以下のように npm-groovy-lint の結果をレビューコメントしてくれるようになりました。



2021年10月14日木曜日

「自分リリースノート」を一年書いてみた

 GitHub のユーザープロフィールページで自分リリースノートを書いています。
毎月リリースでその月にやったこととかをまとめているのですが、それが書き始めて一年以上経ったので振り返り。

KPT
Keep

継続した
あのころに何をしていたのか振り返られるのが良い

Problem

当初ほどの情熱がない
定形的な情報の入力が面倒くさい

Try

ある程度の自動化をしたい
マンネリ化してるのでその他の欄をもう少し書きたい

最後に

このブログももうすぐ10年ですが、それと同じくらい続けられたいいですね。
ではでは。

2021年10月8日金曜日

2021年10月1日金曜日

Tails of Words v0.3.0 リリース

シルバーウィークに久しぶりに連休を取ったので Tales of ARISE をやってました。まだクリアしてません。もうちょいでクリアだと思うのですが。なので最近はゲームばっかりしてます。

はい。では本題です。

tails-of-words 0.3.0 をリリースしました。
tails-of-words は「ブログズミ: CEDEC でやってた表記ゆれ検出をお試し実装してみた」で作成した表記ゆれ検出ツールです。
(なんだか某ゲームっぽいツール名ですね)

今回は前回ブログ時点からの差分を紹介したいと思います。

変更履歴
knp 対応

まず大きな変更点として knp(pyknp) に対応しました。
knp は juman の出力を入力に係り受けとかを解析してくれるものですが、
tails-of-words では knp の固有表現検出機能を使いました。

固有表現検出機能を使うと以下のように「奈良先端科学技術大学院大学」を1つの単語として検出できるようになります。


knp を有効にするには --knp オプションを付けます。実行環境に knp がインストールされている必要があるので、knp インストール済みの tails-of-words の docker container を使うのが楽だと思います。

コンフィグファイル対応

tails-of-words のオプション及び評価関数のパラメータをファイル指定できるようにしました。

log: DEBUG
html2test: True
exclude_ascii: True
exclude_alphabet: True
jaro_winkler: True
knp: False

# スコア計算の設定値
score_config:
  # 読みが同じ時にかける値
  same_yomi_scale: 1.2
  # 出現数の差の正規化数([0,1])にかける値
  occurrences_sacle: 1.0
  # 読みが同じかつ、長音が消えてる場合にかける値
  same_yomi_with_remove_long_vowel_scale: 0.8
  # 片方を内包し、末尾の長音の差分のみの場合にかける値
  diff_only_long_vowel_scale: 1.2
  # 片方を内包している場合にかける値
  inclue_other_one: 0.5
  
形態素解析のための正規化による表記ゆれ吸収問題を解決

pyknp で knp/jumanpp の出力する際に特定の文字列が出力フォーマットと衝突し、正しくパースできないので(たとえば半角スペースや @ などの記号)、解析前に全角文字に変換したりしているのですが、これにより当該文字の半角・全角の表記ゆれ検出ができないようになっていました。

これに対応するために、pyknp の結果の形態素の見出し(midasi)から正規化した文字をもとに戻す処理をいれました。
また固有表現検出に対応したことで「2021 年秋」と「2021 年秋」のようなスペースのゆれも検出できるようになりました。(スペース含んだ固有表現と認識されればの話)

jaro_winkler 編集距離に対応
レーベンシュタイン距離がデフォルトですが、ジャロ・ウィンクラー距離にも対応しました。
--jw,--jaro-winkler オプションを付けると切り替わります。
tails-of-words では編集距離を 0-1 の値に正規化して評価していますが、この値が変わるので表記ゆれの検出結果にも変化がでます。
0=不一致 1=一致


XML入力に対応
Blogger のバックアップ出力が xml だったので、このブログを解析するために対応しました。
xml ファイルの場合は text が解析対象になります。

標準入力に対応
パイプでつなげて処理したい。curl で html 取ってきて解析させたい。ということで対応。
以下のように --stdin-type で html を指定すれば html2text した文字列で解析できます。
curl -fsSL https://srz-zumix.blogspot.com/2021/09/cedec.html | tails-of-words --stdin-type html swing --exclude-alphabet --exclude-ascii -t 1 -
ASCII のみやアルファベットのみを除外するオプションを追加
記号のみやアルファベットのみの形態素は未定義語の hinsi_id になるようなので、
tails-of-words swing -i 6 hoge.txt のように -i オプションで解析対象の品詞を名詞(6)のみにすることで除外できます。(デフォルトは 名詞(6) と 未定義語(15))

GET と Get や get など大文字小文字の揺れを除外したい場合、これで実現可能だったのですが、未定義語にはカタカナ語なども入ることがあるため、このユースケースに対応するために --exclude-alphabet (--no-alpha) と --exclude-ascii (--no-ascii) オプションを追加しました。
最後に
とりあえず実装してみた前回バージョンからだいぶパワーアップしました。
実際に拙著やこのブログの表記ゆれを検出しようと使ってみたら、こうなりました。
編集距離にはまだ他の手法もあるようなので、そのうち対応してみたいです。

今回は以上。



2021年9月14日火曜日

GitHub Actions Composite Action で uses が使えるようになった!

GitHub Actions: Reduce duplication with action composition | GitHub Changelog

GitHub Actions では Composite Action でワークフローの一部を1つのアクションとしてまとめ共有できることができます。
複合実行ステップ アクションの作成 - GitHub Docs

GitHub Actions は YAML のアンカー・エイリアスに対応しておらず、 Azure Pipelines のような Templates 機能もありませんが、この機能で Action に切り出すことで似たようなことができます。
Composite Action は Docker や Javascript Action と違い、通常のワークフローの記述と近いかたちで書くことができますので、よりアンカー・エイリアスや Templates と近い感覚で記述ができます。

**近い**としたのは Composite Action で書けることは通常のワークフローよりも制限がされているからです。
uses もその1つでした。
今回のアップデートで uses が使えるようになり、checkout アクションや python / node / ruby などの setup 系アクションを含んだ Composite Action を書けるようになったので、かなり便利になりました!

(個人的には shell を動的に解決したいとか conditional (if) を使いたいとかはありますが、uses が対応されたことで大分使い勝手が良くなったので嬉しい)


2021年9月8日水曜日

CEDEC でやってた表記ゆれ検出をお試し実装してみた

CEDEC2021: ゲーム制作効率化のためのAIによる画像認識・自然言語処理への取り組み
ゲーム制作効率化のためのAIによる画像認識・自然言語処理への取り組み - Speaker Deck

こちらの講演の中であった表記ゆれ検出の実装実験をしてみました。
ポイントとなるのは「形態素解析」と「編集距離」です。

形態素解析はこのブログでもたまに扱ってました。
ブログズミ: TreeTagger を使ってソースコード中の単語をリストアップしてみた
ブログズミ: ソースコード中の単語からの略語/スペルミス検出に挑戦

↑これらは TreeTagger 使ったものでした。

実は、前職でも同じような表記ゆれ検出はしたことがあって、そのときは MeCab で形態素解析し、単語の出現数をカウントしてソート出力するだけのものでした。
出現数の少ない単語から見ていくと、「あ、これは揺れてそう」ってのがわかったのでそれなりに有用でした。
なので、CEDEC の方法であった「出現数の差が大きいほどスコアが上がる」は良いと思いました。

で、今回は形態素解析には Jumanpp を編集距離はレーベンシュタイン距離を使いました。
実装はこちら。
講演の内容そのものの実装ではないです。スコア計算の部分はテスト対象の入力に合わせて書いたので万能ではないと思いますが、なるべく一般化したルールにしてるつもり。

https://github.com/srz-zumix/tails-of-words

PyPI でも公開してるので pip でインストールできます。
https://pypi.org/project/tails-of-words/0.1.2/
また Dockerhub にイメージもおいてるのでそれ使っても実行できます。
https://hub.docker.com/r/srzzumix/tails-of-words

実装メモ

実装上のポイントをメモしてます。

  • yomi がひらがなの場合とカタカナの場合がある
  • yomi に長音(ー)が追加される場合がある
  • 総当りで調べるのですべての単語差分を記録すると killed される
  • 半角スペース、"、@、# を含んでると pknp で例外出るので全角にする
  • 「えー!?」のように全角!・?があると、つながった状態で1単語になるので、分解するため半角にする

テスト

試しに拙著をチェックしてみました。

拙著の場合、未定義語(15)まで集計対象にするとアルファベットのみの単語の大文字・小文字違いがスコアが高くなり、ノイズだったので -i 6 で名詞のみに制限。
-t 1 で 1.0 以上のスコアのものを表示してます。

画像をご覧いただくと、「コンパイラー vs コンパイラ」の表記ゆれを検出してるのが見つかります。それ以外は表記ゆれではないと思いますが、書き損じの可能性はあるかもしれませんね。

最後に

実装自体は1日、スコア計算の部分とかの調整で1日。
あとは周辺機能の整理とかで1日くらいですかね。
(仕事じゃなくて夜中に書いてたやつなので工数じゃないよ)

とりあえず最低限のものを作るだけなら、めちゃくちゃ簡単にできます。
ただし、精度はいまいちだと思います。
リストアップされたものを人間がチェックする必要性がありますが、リストアップする部分まで人間がやるよりはかなりマシでしょう。

ここから検出精度を上げるのはとても大変だと思います。
トライアンドエラーで色々評価軸を追加したり、スコア計算の調整したりすることになると思いますが、コスパがどんどん悪くなっていくと思います。
(業務外だったら関係ないのかもしれないけど・・)
流行りの機械学習で精度アップできるかもしれないですが、どうなんでしょうね?
(この辺は詳しくないのでわかりません)

実はこの手の話をすると、似たようなこと昔やったことあるって人が結構います。
みんなサクッと実装できたといいますが、精度・コスパの話も同じような感想でした。

これは完全な余談なんですが、
Jumanpp の出力をいい感じに print したいなーと思って Power-Assert みたいな出力にしようと(すぐ道草をする悪い癖が出そうになったのを我慢)して、適当に作った print が割といい感じにできたのが良かった :D


対して難しいことはしてませんが、この実装が役に立てば幸いです。
では。

2021年9月3日金曜日

GitHub Actions でペアな値のマトリックスを組む

 CI でパラメタライズドなテストを実行するときに、マトリックスを組むことがあると思います。
GitHub Actions でも strategy.matrix でマトリックスを組めます。

例えば、上記公式ドキュメントのサンプルの

strategy:
  matrix:
    node: [10, 12, 14]
steps:
  # Configures the node version used on GitHub-hosted runners
  - uses: actions/setup-node@v2
    with:
      # The Node.js version to configure
      node-version: ${{ matrix.node }}

↑こちらは node-version が 10,12,14 のステップがそれぞれ実行されます。合計で 3 回です。

さらに、因子を追加して例えば

strategy:
  matrix:
    node: [10, 12, 14]
    expect: [ "dubnium",  "erbium", "fermium" ] 

とすると、以下のような組み合わせになります。

101214
dubnium10,dubnium12,dubnium14,dubnium
erbium10,erbium12,erbium14,erbium
fermium10,fermium12,fermium14,fermium

node と expect の因子の直行になります。合計は 3x3 の 9 回です。
ただ、このような組み合わせではなく、ペアな因子1つを作りたい場合もあります。
上の例では [10, dubnium], [12, erbium], [14, fermium] という組み合わせにしたいです。
その場合は、以下のように include を使って書くとスマートそうです。

strategy:
  matrix:
    include:
      - node: 10
        expect: dubnium
      - node: 12
        expect: erbium
      - node: 14
        expect: fermium      
strategy:
  matrix:
    node: [10]
    expect: ["dubnium"] 
    include:
      - node: 12
        expect: erbium
      - node: 14
        expect: fermium
 

前者は include のみで記述、後者は matrix に include で組み合わせを追加しています。
この例では前者のほうがきれいに見えますが、一部の組み合わせだけ値が異なる場合は後者の方法で書いたほうがきれい書けける場合もあります。

実例

今まで1つの値に複数の値をもたせたりしてたのですが、とてもきれいに書き直せました。


こちらはサンプルの前者の方法と同じで、include で必要な組み合わせを書いています。


https://github.com/srz-zumix/ci-yaml/blob/e1e1d6d15bb75f9682bc05304e7ec61162de094b/.github/workflows/search.yml
こちらはサンプルの後者と同じ方法で、 path が "" の場合は matrix で、空白以外の場合は include で組み合わせを追加しています。


今回は以上です。では。

2021年8月24日火曜日

ゲーム開発者のための SRE

はじめに

 まずはじめに SRE について軽く触れておきます。
SRE は Site Reliability Engineer(ing) の略です。
Google が提唱しているロール(役割)で、運用に関わります。
50% ルールというのがあり、主たる業務はエンジニアリングによる開発・自動化(Dev)でこれを必ず50%以上確保するルールです。
残りは運用業務(Ops)に割り当てます。

SRE については書籍「Google - Site Reliability Engineering」を読むといいと思います。
私も日本語版を勝手読みました。英語版は無料で読めます。
英語版「Google - Site Reliability Engineering」
日本語版「SRE サイトリライアビリティエンジニアリング――Googleの信頼性を支えるエンジニアリングチーム」

最初読んだときは「ふーん Google ではそうなのね。うちとはマッチしない部分もあるなぁ」って感じだったのですが、実践し始めたらちょくちょく参考にしているので、普通にオススメ。まずはこれを読むのがいいです。
SRE は Google が提唱しているものであり、それが日本でも普及し始めていますが、SRE が実務でなにをしているかは企業によってそれぞれだと思います。
なにをしているかはその現場によって求められるものが違ってくるので当然です。
SRE がどういう思想のもと活動しているのかに着目するのが良いです。

少しそれましたが、詳しいことは書籍や検索して調べてみてください。

ゲーム会社における SRE について

さて、ここからが本ブログで今後扱っていきたい話題です。
最初に述べたように Google の SRE はサービス運用に対して活動をしています。
スマホゲームや家庭用ゲームでも、売り切りではなくサービスなゲームが主流となった今、
ゲーム会社でも SRE の活躍の場があります。

ゲーム会社でも SRE 人材欲しいってのはまぁ普通の話で、めちゃ欲しいです。
でも私が語りたいのはちょっと違う話です。

ゲーム開発者のための SRE

ここで考えたいのは、ゲーム「運用」における SRE ではなく、
ゲーム「開発」における SRE です。

私個人の想いとして、
ゲーム開発における開発環境、ツールや CI/CD などを「開発者向けのサービス」として捉え、「ゲーム開発者のための SRE」が必要であると感じています。
特に私は CI/CD に関わることが多かったのですが、この辺は誰かの片手間で提供されていることが多いように感じています。
(そもそもゲーム作りたくて入ってる人がほとんどなんだからゲーム作ってたいのは当然だよねーとかこの辺はまたいろいろ話したい)
ゲーム開発はやることが多いです。そのため優先度つけてやっていかないとゲームをリリースできません。ゲームをリリースすることが必須になってしまうと、ゲーム開発者のための改善は片手間の片手間でまぁ回りません。課題を感じつつ、手が空いたらやる。そんなのばかりになります。

そのために「ゲーム開発者のための SRE」が必要なんじゃないかと。
SRE は開発期から関わっていくので「?」な方もいるかもしれません。
Google の SRE は対象のサービスがリリース前の開発時から関わると書籍にも書いてあります。ただ、これはサービスのための活動と言えます。
「ゲーム開発者のための SRE」はサービスを作っている人たちのための活動です。
(最終的にはゲームを届けるお客様のためになることなので、同じと言えるかもしれませんが)

SRE とはこうで、こうあるべきだという話ではなく、
SRE の思想を持ち込みたいと考えてるので、名前は正直どうでもいいですが、名前があることもまた大事なので。。


まとまりなく書き連ねたので、今日はこのへんで締めます。
とりあえず、私が想いが伝わればいいかなと思ってます。
最近会社では SRE を自称してて、実践し始めてます。
他の会社の方とかとも話してみたいので興味ある方は SNS などお声がけ頂けると嬉しいです。

ではでは。





2021年8月11日水曜日

DockerHub Automated Build の Webhook の代わりに GitHub Actions workflow_dispatch を使う

DockerHub の料金改訂により Automated Build が無料プランでは使えなくなりました。
Changes to Docker Hub Autobuilds - Docker Blog

DockerHub に image push するのに一番楽で良かったのですが、しょうがないですね。
今は GitHub Actions があるのでそこから build して push するのが簡単だと思うので、そちらに移行しました。

移行したリポジトリたち

build と push は  アクションを使えばとても簡単です。
下記、もしくは上記リポジトリの workflows を参考にしてみてください。

さて、定期的なビルドは GitHub Actions の cron トリガーを使えばすぐに対応できます。
また hook の post_push も必要な環境変数を与えたうえで run すれば問題ないでしょう。

問題は Webhook トリガーで、私の場合は PyPI や gems のリリース RSS をトリガーに Webhook を叩いてビルドしていました。
例:「ブログズミ: PyPI のリリースを検知して Dockerhub の image を更新する

これを GitHub Actions でやる場合は「workflow_dispatch」を使うことになると思います。
actions 側は特に難しいことはなくて、on のところに workflow_dispatch を追加するだけです。
一方 Webhook を送信してた側は dispatch イベントを API で送信することになります。
API ドキュメントは↓
Actions - GitHub Docs

以下は、Integromat で dispatch イベントを送る設定方法です。
repo 権限のついた GitHub の Personal Access Token が必要なので発行しておきましょう。


まず、ただの Make request モジュールから Make a Basic Auth request モジュールに変更しています。
Credentials が必要になるので Add ボタンから先程作成したトークンを入力します。
Username は「token」です。

URL には下記の {} で囲まれた部分を適宜変更して入力します。
/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches
workflow_id は Action を開いたときの URL でわかるとは思いますが、面倒なのでファイル名指定がおすすめです。(ファイル名には拡張子も含める必要があるので注意してください)

Method は「POST」、
Headers には「Name: Accept, Value: application/vnd.github.v3+json」を追加します。

Body type を「Raw」にし、Content type は「JSON (application/json)」にします。
Request content には「{ "ref": "master" }」(今は main の場合もあるでしょう)を入力します。workflow_dispatch には任意の input パラメータを設定できますが、それらの設定はここにつけ足すことになります。

設定できたらモジュールを右クリックし、「Run this module only」を実行して、トリガーできるか確認しましょう。
Integromat での設定例を紹介しましたが、他の場合でも対応方法は同じような流れになると思います。


今回は以上。では。


2021年8月3日火曜日

【JFrog Pipelines】Cron Trigger を設定する

 しばらく活動してなかったら Subscription キャンセルされてしまったので Cron Trigger で何もしないジョブを定期実行するようにしました。

ちなみにキャンセルされるとその環境を継続利用するにはプランのアップグレードをするしかないようです。
もし、無料プランで使い続けたい場合は同じメールアドレスでの登録はできないので、別のメールアドレスを用意して新規登録する必要があります。

本題に戻りましょう。
Cron Trigger はリソースに cron 定義を追加し、それを input にすることで設定できます。
CronTrigger - JFrog - JFrog Documentation

とっても簡単です。
今回の内容は以上ですが、環境が使えなくなると1から Integration/Pipelines Source/Node Pool などなどを構築しなおしになるので、この設定をしておくと良いと思います。

では。

2021年7月27日火曜日

技術書典11お疲れ様でした&ブログのこれから

技術書典11お疲れ様でした。
技術書典では虎空棘魚というサークル名で活動しておりますが、
こちらでは個人活動で得た知見をまとめて本にしています。
なのでこのブログの内容がベースにあったりします。

今後も本やブログの執筆活動は続けていこうかなーと思ってはいるのですが、
ブログの更新の方が最近滞りぎみな状況なのが現実。

年齢的なパフォーマンス低下だったり、生活スタイルの変化だったり、
いろいろと原因はあったり?なかったり?するのですが。
なんだかここ数年は、仕事場での知識・技術のインプット、そして仕事場でのアウトプットが充実しているから、な気がしています。
簡単にいうと仕事楽しくてそっちのけって感じです。

まぁそれはそれでいいことだとは思うんですがね。
業務上得た知見・技術を取り扱ってもいいんですが、
会社依存の部分を削ぎ落としたり、公開用にまとめる時間を明確に取れなくなった(取らなくなった)ので、あんまりワークしていないです。
(リモートワーク前は出社前に時間作って朝活してました。今は境界がなくなってイマイチ集中できない感じ)

結構書けるネタはあったりするんですよね。
Jenkins おじさんとまた戯れだしたので、そのへんとか。

言い訳並べてもしょうもないので、そろそろ結論書こうかなと思いますが、
ブログはやめません。もうちょいで 10 年なんでそこまでは頑張ります
ただ、ちょこちょここういった「思い」を書くことが増える、かも、しれません。

とりあえず、ここ1,2年で思ってるキャリア・働き方について書く、かも、しれません。

まぁ、ちょっと肩の力を抜いてやっていこうと思います。ではでは。

2021年7月21日水曜日

Re:VIEW Starter から Re:VIEW のプロジェクトに戻すツール review-retrovert 0.9.9 リリース

ブログズミ: [Re:VIEW Starter][Re:VIEW] 訳あって Starter から素の Re:VIEW に戻すツールをリリースしました

こちらの最新版 0.9.9 をリリースしました。
https://rubygems.org/gems/review-retrovert

以下、今年2月にリリースした 0.9.7 からの更新内容です。

  • Re:VIEW Starter 2021/06/30 版に対応
    • Re:VIEW Starter のサンプルプロジェクトの変換が可能な状態
    • talklist や desclist 、単語展開、用語・索引、CSV テーブルなどサンプルで使われている表現には対応しています
    • 7月の Starter の更新にも対応していると思います
  • Starter でのみキャプションが付けられるコマンドのキャプション部分を代替コマンドの前に文章として出力
  • file パラメータによる埋め込みに対応
  • キャプションなし image は indepimage が出力されるように修正
  • Starter 独自コマンド中の文章が出力されてなかった問題を修正
  • %指定の width 指定を scale に変換
  • Re:VIEW 5.1 以降および 3.2 未満のバージョンでエラーになっていたのを修正
  • その他、めっちゃバグ修正

自分が欲しくて作ったものですが、同じような境遇の方に届けば幸いです。

2021年7月15日木曜日

【技術書典11】 CI サービス本の増補・改訂版をリリースしました

 7/10(土)から技術書典11が始まってます
弊サークル虎空棘魚からオンラインマーケットにて、「あつまれCIサービス」の増補・改訂版である「2021夏」を販売してます。
また、既刊「詳解Integromat」も販売中です。
よろしくおねがいします!




2021年7月7日水曜日

[Azure Pipelines] DockerHub pull rate limit に対応する

これらのつづき

Azure Pipelines の場合は以下を参考に「Project Settings」の「Service connections」を開き、「Docker Registry」を追加すれば OK です。
Registry Type に DockerHub があるので、それを選択して、ID/パスワード(トークン)をセットします。
Service connections in Azure Pipelines - Azure Pipelines | Microsoft Docs

今回は以上。

2021年6月28日月曜日

JFrog Pipelines はじめました

 Shippable はだいぶ前に JFrog 傘下になり JFrog Pipelines と Shippable の2つのサービスが提供されていました。
Shippable のサービス提供も続けていくよとされていましたが、とうとう終了となりました。
(マイニングの影響もあったのかはわからないけど、あれは困ったものですな)
The Next Step in the Evolution of Shippable: JFrog Pipelines

いつまで見られるかわからないですが、こちらは引越し前の Shippable ビルド履歴です。
https://app.shippable.com/github/srz-zumix/iutest/dashboard/history
5/3 まで元気に動いてました。お疲れ様でした。

さて、Shippable は終了となりましたが、JFrog Pipelines に移行できるようなのでやってみました。
移行するのは以下のリポジトリです。
https://github.com/srz-zumix/iutest

Pricing

その前に気になるのはお値段ですよね。
Shippable のときは↓な感じでしたが、

Unlimited builds for public projects
150 builds/month for private projects
Forum support

(Shippable がどんなのだったかは拙著「あつまれCIサービス」を読んで頂くのもありですよ)

JFrog Pipelines はこんな感じ。

ビルド時間無制限はこのご時世ではもう無理なんでしょうねぇ
それでも2000分/月使えるのはありがたいです。(Travis CI も毎月付与にならないかなぁ)

プランの確認ができたので、早速登録して使ってみましょう。

Get Started

Start for free などからリンク開くと以下のようなページが開きます。

日本語ページもあるのでそちらからも登録できます。
クラウドプロバイダー(Select your cloud provider)
クラウドプロバイダーの選択が出てきて、ちょっと本当に無料の範囲でできるのかな?と不安になりますが、No Credit Card だし大丈夫だと信じて進みます。
(実際問題ない)
自分はどれもあまり詳しくないのですが、まだ多少知ってるという理由で Google Cloud を選択しました Google 選んだつもりでしたが AWS を選んでました(2021/08/02 追記)。

サーバーの詳細(Server Details)

お客様詳細情報(Create your Credentials)
メールアドレスとパスワードを記入します。
パスワードは大文字・小文字、数字、記号を含める必要があります。

ユーザー詳細(User Details)
氏名を入力します。英語(アルファベット)で記入する必要があるようです。

PROCCED して完了。

問題がなければ「JFrog Free Subscription Activation」というタイトルでメールが来ます。
「Click here to activate your JFrog subscription」のリンクを開いてアクティベートします。

待ちます。

完了したらログインできるようになるので Login しましょう。
ログインしたら↓のようなダッシュボードが開くと思います。
セットアップ

JFrog には Pipelines の他にもプロダクトがありますが、今回使うのは Pipelines です。

まずは左側メニューから「Pipelines」を選択。「Clik to Activate」をクリック。

待ちます。

君はそのページ見れないよ。とエラーっぽいメッセージが出ますが、admin なはずなのでそんなわけはありません。
おそらくまだセットアップ中なのでしょう。待ちます。

・・・zzz

一晩寝かせたことでアクセスできるようになってました。(少し時間がかかると思ったほうがよさそうですね)
※一度ログアウトしてログインし直すと見えるようです(2021/08/02 追記)
Pipelines が使えるようになったので設定の続きをしていきます。


JFrog のドキュメントに「QuickStart Guide: JFrog Cloud - JFrog - JFrog Documentation」があるのでそちらを参考に進めます。
今回は Pipelines だけまずは使いたいので Step 2/3 はスキップして「Step 4: Define a pipeline」から始めます。
Artifactory を Integrations に追加
※成果物を特に扱わない、パイプラインを試してみるだけ、という場合は飛ばして OK

先に、Artifactory 用の API Token を JFrog の User Profile から払い出しておきます。
右上のユーザーメニューから「Edit Profile」を開き、ログインパスワードを入力して Unlock します。
Unlock すると操作できるようになるので「Authentication Settings」の「Generate API Key」をクリックします。
API キーが生成されたら、コピーしておきましょう。

つづいて、「Administraion」タブの「Pipelines」から「Integrations」を開き、右上の「+ Add an Integration」をクリックします。
Pipeline から利用するので「Usage」は Pipelines を選択。
名前は任意、「Integration Type」に Artifactory を選択します。
URL と User はデフォルトのままで良いと思います。
API Key に先程コピーしたものをペーストし、「Create」をクリックして完了です。

「Assign Pipelines to this Integration」はとりあえず Any で OK です。制限かけたい場合はチェックを外すと許可する source を選択できます。(画像にはいくつか source がありますが、現時点ではまだ source 登録してないので空っぽだと思います)
GitHub を Integrations に追加

次に GitHub を Integrations に追加します。
Artifactory と同様に、右上の「+ Add an Integration」をクリックします。
Pipeline から利用したいので「Usage」は Pipelines を選択。
名前は任意、「Integration Type」に GitHub を選択します。
最後に GitHub のパーソナルアクセストークンを作成して入力したら「Create」ボタンを押します。

Node Pool にノード追加

次に実行環境を用意しておく必要があるので登録します。
「Administraion」タブの「Pipelines」から「Node Pools」を開き、右上の「+ Add Node Pool」をクリックします。
下記画面のようになるので、名前の入力とイメージを選択します。
選択可能なイメージは Ubuntu/CentOS/Windows があります。

Node Limits は同時に起動可能なノード数の制限です。1 にした場合、このノードを使うジョブは 1 つずつ順番に実行されます。

Node Idle Interval はノードが停止するまでの時間です。
ノードは常に起動しているのではなく必要なときに起動します。
commit でジョブを実行する場合、インターバルが短いと都度都度ノードを起動することになるので、使い方に合わせて時間を調整しましょう。
ちなみに、有料プランでは静的ノードが使えます。


Pipeline source を追加

ノードの準備ができたらパイプラインを登録しましょう。
「Administraion」タブの「Pipelines」から「Node Pools」を開き、右上の「+ Add Pipeline Source」をクリック、「From YAML」を選択します。

パイプライン YAML を PR で追加したいので、「Multi Branch」を選択します。
「SCM Provider」は上で追加した GitHub のインテグレーションを選びます。
ほどなくリポジトリが選択可能になるので、目的のものを選択。
「Exclude/Include Branch Pattern」で YAML の Sync をするブランチの対象を制御できます。
最後に、YAML ファイルのパスを入力して「Create Source」しましょう。
(JFrog では YAML ファイルは任意の場所におけます。)

この時点ではまだ YAML がないので Sync は失敗します。

Pipeline を記述

パイプラインを記述します。
ドキュメントや、サンプルプロジェクトがあるのでそちらを参考にすると良いと思います。

移行後の iutest の YAML はこちら
https://github.com/srz-zumix/iutest/blob/master/jfrog-pipelines.yml


他の CI サービスとちょっと使い方に特徴があるので、その点だけ説明します。

チェックアウトパス

他の CI サービスではソースとなるリポジトリがカレントディレクトリにチェックアウトされることが多いと思いますが、JFrog Pipelines は複数リポジトリをソースにできるので、それぞれのワークスペースにチェックアウトされます。
このパスは「res_{{ resource_name }}_resourcePath」環境変数で取得できるので、ディレクトリを移動してからビルドやテストを行いましょう。

シークレット環境変数

環境変数は「Generic Integration」を追加することで使用できます。
こちらも上記チェックアウトパスと同様に「int_{{ integration_name }}_{{ env_name }}」のような環境変数になっているので注意してください。

例:https://github.com/srz-zumix/ci-specs/blob/1f64ac66f635b6ffeee06db45ae1210bf0fd1c64/jfrog-pipelines.yml#L28

GitHub ステータス更新もパイプライン記述が必要

他の CI サービスでは自動的に GitHub のコミットステータスを更新してくれますが、JFrog Pipelines ではパイプラインに明記しないといけません。(仕組み上しかたがないですが)
やり方は簡単で、「update_commit_status {{ resource_name }}」で現在の execution の状態に合わせてステータスを更新してくれます。
より細かな制御も可能です。詳しくはドキュメントを参照してください。
Sending Build Status to Source Control - JFrog - JFrog Documentation

Sync

パイプラインをコミットしたら Pipeline Sources で Sync が成功するか確認しましょう。
「Pipelines」>「Pipeline Sources」を開き、Status を確認してください。
パイプラインの記述に不備がなければ「Success」になっているはずです。
問題がある場合は一番右のログボタンから何が原因か確認して修正しましょう。

パイプライン実行

Sync できたらいよいよ実行可能です。
PR トリガーは Sync が成功したあとから有効になるので、最初は手動でトリガーするか、空コミットを push するかで起動しましょう。
(パイプライン修正 PR をして修正されたパイプラインで動作を見たいときも同様。改善したい)

手動でトリガーする場合は、「My Pipelines」から実行したいパイプラインを選択し、そこからトリガーするステップを開いて実行するだけです。

結果は履歴から確認できます。

Next

ここまでで JFrog Pipelines でジョブを実行できるようになったと思います。
JFrog Pipelines は他の CI サービスと使い勝手が少し違います。
Jenkins など他の CI と連携したり、複雑なジョブを構築したりしていくことができるようです。ドキュメントがまとまっているのでそちらを参考に挑戦してみてください。
https://www.jfrog.com/confluence/display/JFROG/Get+Started

バッジ

CI サービス恒例のバッジですが、残念ながら見つけられませんでした。
バッジを付ける方法が見つかったら、このブログで紹介します。

最後に

Shippable が終了したのは残念でしたが、JFrog Pipelines で同じように CI できそうです。
また、Shippable のころに使いこなせなかった Assembly Line が使えるようになって、ドキュメントって大事だと改めて気付かされました。

今回は以上。ではでは。