2019年3月27日水曜日

git gc --aggressive するそのまえに

Git が遅い!!
そんなときに検索をするとだいたい
「git gc しましょう」だったり、「git gc --aggressive --prune=now」だったりします。

が、試してみても劇的に速くなることってあんまりなくないですか?
特に --aggressive オプションを付けると git gc 自体がくそ長く、その割に効果は感じられなくて残念な結果になることが多いです。
※個人的な感想です

なんか遅い。もう少し深掘りしてみませんか?

GIT_TRACE=1 GIT_TRACE_PERFORMANCE=1
git コマンドは GIT_TRACE を有効にすると、中で何をしているのか追跡できるようになります。
GIT_TRACE=1 git st


git st はエイリアスなので、git status コマンドが呼ばれている様子がわかりますね。
さらに、GIT_TRACE_PERFORMANCE=1 をしておくと、処理時間の計測までしてくれます。

GIT_TRACE=1 GIT_TRACE_PERFORMANCE=1 git st


処理を追えるようになったので、あとはボトルネックになってる部分を見ていけばいいわけです。
(TRACE には他にも項目があります。詳細はこちら→ Git - 環境変数

事例
上に載せたスクリーンショットは、サブモジュールがあるリポジトリでの git status コマンドの計測なのですが、見ていただくとサブモジュールに対してもステータスを確認しにいっているのがわかります。普段なにげなく使っていたコマンドですが、サブモジュールを見に行ってるとは知りませんでした。

サブモジュールの使い方にもよると思いますが、
データ(アセット)をサブモジュールにしているリポジトリでの git status がすごく遅くなっていたため、TRACE するとサブモジュールの status に時間がかかってました。(でかいからな)

自分の場合は、そのサブモジュールで作業することはなく興味のない情報だったので、以下の設定で無視するようにしました。
git config diff.ignoreSubmodule dirty

これで 90% くらい速くなりました。

最後に
速度を求めるなら、ボトルネックを知らなければ効率的な解決はできませんよね!

2019年3月20日水曜日

[CI] 帰ってきたクラウド版 Drone



以前サービスされていた Drone.io のクラウド版が帰ってきてました。
というわけで、(ちょうどとある CI からジョブを引っ越しさせたいと思っていたので)
早速使ってみました。

セットアップ
まずはサインナップからですが省略します。

ダッシュボードにリポジトリがリストアップされているので、CI したいリポジトリを選んで「ACTIVATE」を押します。


リポジトリの「SETTINGS」が開くので、もう一度「ACTIVATE」を押します。


すぐに ACTIVATE は完了し、設定が表示されます。
いくつか設定できる項目がありますが、最初に気にしておくところは「Project visibility」くらいだと思います。


Drone は YAML config のみのようなので、つづいて yaml を作成をしていきます。

パイプライン作成
それでは、.drone.yml ファイルを書いていきましょう。
フォーマットは公式ドキュメントを見るのが一番良いのでそちらを参照してください。
Pipeline

iutest では以下のように書いてみました。
kind: pipeline
name: benchmark_test

steps:
- name: bench
  image: gcc
  commands:
    - cd test
    - make -C benchmark
    - make bench

steps に配列で処理を定義できる感じですね。簡単!

これをリポジトリルートに置いたら commit/push しましょう。
自動でビルドが開始されます。(反応もいい感じ)




複数のパイプライン
Drone では複数のパイプラインを定義できます。

kind: pipeline
name: test1

※1つ目のパイプラインの処理

---
kind: pipeline
name: test2

※2つ目のパイプラインの処理


このように --- で区切ることで複数のパイプラインが作成できます
それぞれのパイプラインの書き方は特に変わらずそのままです。
(※YAML anchor/alias はこれを越えられないみたいです)




Plugin を使う
Drone ではプラグインを使うことで、複雑な処理を書くことなくパラメータの設定だけでツールやサービスを簡単に利用できる仕組みになっています。
どんなプラグインがあるかはこちらにまとまっています。
http://plugins.drone.io/

今回は Slack Plugin を使ってステータス通知をしてみました。

steps:
- name: slack
  image: plugins/slack
  settings:
    webhook:
      from_secret: SLACK_WEBHOOK
    channel: ci
    username: drone
    icon_url: https://raw.githubusercontent.com/drone/brand/master/logos/png/drone-logo-dark_256.png
  when:
    status: [ success, failure ]


Webhook URL は見えないように from_secret: SLACK_WEBHOOK にしています。
こちらは「SETTINGS」ページの「Secrets」のところで生成できます。


動かしてみるとこのように通知が飛んできました!

簡単ですね。

skip コメント
つづいて、CI のスキップコメントメッセージについてまとめているので、そちらの更新も行いました。
https://github.com/srz-zumix/ci-skip


ドキュメントは見当たらなかったのですが、他の CI サービスと同様に [ci skip] [skip ci] が使えます。
また、***no_ci*** も使えるようです。

Badge
シメは、お決まりのバッジですね。
「SETTINGS」 タブを開くと最下部に「Badges」があるのでそこから取得できます。




一点だけ注意があって、ブランチ指定をした場合に生成される URL が ?ref=/refs/heads/develop のようにパラメータが付きますが、執筆時にはこの URL だと「build: none」と表示されてしまってました。

https://0-8-0.docs.drone.io/badges/
0.8.0 のドキュメントですが、こちらを参考に ?branch=develop に変えたところ、イメージが取得できました。


最後に
クラウド版は一度閉じてはいましたが、その間もオンプレミスで進化を続けていただけあって、簡単にかつ素早く動いたので良かったです。
(いつから戻ってきたんだろ)

最近、他の CI サービスの・・・で苦労してたので、シンプルに使える Drone がまた使えるようになったのはすごく助かりますね。
オンプレミス版を Jenkins の代わりとして使ってる企業も多いようなので、ぜひ一度使ってみてください。

ではでは。

2019年3月11日月曜日

Codacy は Dockerfile の検証もしてくれてた

Codacy
Python とか Ruby とかの静的解析をしてくれるサービスは多いですが、Dockerfile も見てくれているとは!
Codacy というか Hadolint



1.13以降はMAINTAINERの代わりにLABELを使うようにしよう - Qiita
MAINTAINER じゃなくて LABEL maintainer "srz_zumix <...>" のようにするとイイらしいっす!









あ、 Visual Studio Code でも出てた


Dockerfile の書き方でこうしたほうがいいよってのがわかるので便利ですね!

2019年3月5日火曜日

EditorConfig の設定に従っているかをテストしてみた

どうも、先日 .editorconfig の記述に typo をずっと放置していて驚愕した僕です。
ブログズミ: .editorconfig ファイル自体の Lint を CI で回す

.editorconfig "自体"の Lint ができたので、今回は .editorconfig に従っているかチェックしたいと思います。
こんな方にオススメ
.editorconfig を開発途中から導入した場合
iutest もそうですが、仕事のプロジェクトでも最初から .editorconfig が用意されているケースがなく、あとから .editorconfig を追加するケースをよく目にしています。
.editorconfig を導入したあとは、対応しているエディタで作業していれば、.editorconfig に従っていない記述が混入することはないはずですが、開発途中に導入された場合は変更が加わらない限り補完されません。

従ってないことでクリティカルな問題が出ることは少ないと思いますが、作業者が変更したところ以外に差分が出るとレビューの際にじゃまになったりするので、やる意味はあるかなと思います。

.editorconfig に対応していないエディタからのコミッターがいる
このケースは存在するのだろうか?という疑問は置いておいて…
git の pre-commit とかに仕込んでおくと、対応している人と対応してない人が無駄に差分を出し合うことがなくなるかなーと思います。

使った Lint ツール
今回の検証では、2 つの Lint ツールを使いました。
使ってみた結果、一長一短あったため 2 つとも採用しています。
Editorconfig Checker
最初に見つけたツールが、Editorconfig Checker です。
https://github.com/editorconfig-checker
複数の言語に対応しているようで、JavaScript/Go/PHP/Java のリポジトリがありました。
今回は最初に見つけたのが npm package だったのでそちらを使うことにしました。

eclint
もう1つは eclint です。
https://github.com/jedmao/eclint
こちらも npm package があり、Editorconfig checker を npm で取ってきたこともあり、すぐに使えそうだったので試してみました。


Editorconfig Checker の使い方と注意
npm install などセットアップについては省略します。

使い方は単純で、解析したいパスを渡すだけです。
オプションで除外パスの指定もできるので、エディタで編集しないようなファイルを除外しつつチェックができます。
また、デフォルトで .git ディレクトリ以下や画像ファイルの拡張子は除外してくれるのと、--dotfiles or -d オプションで dotfiles を除外できるので、単純にルートディレクトリを解析するでも問題ないかもしれません。

以下は、iutest でのオプションの抜粋です。
Visual Studio のソリューション・プロジェクトファイルだけ除外しました。
CI サービス上で実行する想定なので、git 管理外のファイル除外には対応してません。

"scripts": {
    "eccheck": "editorconfig-checker --exclude-regexp \"\\.sln|\\..*proj\" ."
  },

これで npm run eccheck を実行すれば検証してくれます。
このような形でレポートされます。


注意点
Editorconfig Checker は、文字コード(charset)の検出ができないです。
BOM のつけ忘れを検出したいなーと思ったのですが、これができなかったのがもう1つツールを使うことにした理由です。

eclint の使い方と注意
続いて eclint です。
こちらも npm install などのセットアップについては省略します。
eclint も基本的には検証したいパスを引数に渡すだけで使用できます。
Editorconfig Checker とは違い除外オプションはないので、ワイルドカードでの指定や、find コマンドなどを使ってファイルのリストを渡すなどの工夫が必要です。

以下は、iutest でのオプションの抜粋です。
"scripts": {
    "eclint": "npm-run-all eclint:*",
    "eclint:src": "eclint check ./src",
    "eclint:include": "find ./include -type f -not -name iutest_ver.hpp | xargs eclint check -s 2",
    "eclint:root": "find . -maxdepth 1 -type f | xargs eclint check"
  },

これで npm run eclint を実行すれば検証されます。
(除外指定をしつつワンライナーで書くのが手間だったので npm-run-all を使いました)
このような形でレポートされます。


Editorconfig Checker ではできなかった charset の検出ができました。

注意点
さて、charset の検出はできましたが、いいことだけではありません。
eclint はインデント判定もちゃんとしてくれるのですが、これがちょっとノイズになってしまいました。
「インデント」ではなく「整列」のために空白を入れたものまで警告されるためです。

具体的には以下のようなコードです。
enum Level
    {
          LOG_INFO
        , LOG_WARNING
        , LOG_ERROR
        , LOG_FATAL
        , LOG_LEVEL_NUM
    };
私は列挙や関数引数を改行して書く場合、「,」を行末ではなく行頭に書くようにしています。
そして、視認性の観点から最初の「,」のいらない要素に関しては、名前の先頭が揃うように空白を挿入しています。

これがインデント幅 4 の設定に適合せず警告されるのです。
個人的に、これは許容したいため 「-s 2」 オプションをつけて、インデント幅 2 として検証をしています。

また、コメント中の整形であれば以下の設定(もしくはオプション指定)で無視することができます。


ただ、それでも無視しきれないケースがあったため、iutest_ver.hpp だけ検証対象から除外しています。
(Editorconfig Checker は幸か不幸か、インデントの検証がされないようなので iutest_ver.hpp は Editorconfig Checker で検証するって感じです)

おまけ: GitHub Actions
GitHub Actions の使い方が少しわかってきたので、こちらの検証は GitHub Actions で行うようにしました。今回は、特に自分ではアクションを作らず、既存の npm アクションを使ってます。

action "lint:editorconfig" {
  uses = "actions/npm@master"
  args = ["apt-get update && apt-get install -y git && npm install && npm run lint:editorconfig"]
  runs = "bash -c"
}

最初に git をインストールしているのは npm アクションのコンテナに git がインストールされていないため、git 依存のあるパッケージを取ってこれないためです。
npm の ENTRYPOINT は npm コマンドになっているので、runs に bash を指定して install から npm run までするようにしました。
この点だけ手間取りましたが、あとは簡単に組めました。



まとめ



自動化しましょう!