はじめに
社内で運用されていた CodeClimate Quality (以下CCQ)の CLI を調査していたところ
Qlty に変わっていたのを検知したので、触ってみました。
元々 CodeClimate 社は Velocity と Quality というサービスを展開していましたが、Quality ごと Qlty Software 社へスピンアウトしていました。(びっくりしました)
参考 :https://codeclimate.com/blog/code-climate-quality-is-now-qlty-software
Qlty の概要
従来と大きくコンセプトは変わらず、複数のプログラミング言語に対応した静的コード解析ツールです。
主要機能:
参考:https://docs.qlty.sh/what-is-qlty
🐞 Linting (for every language)
🖌️ Auto-formatting
🚨 Security scanning (IaC, SAST, SCA, and more)
💩 Maintainability and duplication
🚦 Code coverage
Qlty CLI と Qlty Cloud があり、用途によって組み合わせたり、使い分けます。
Cloud が CI として連携して分析・可視化する部分、CLIはローカルでの分析に使うという位置づけのようです。
CCQ 時代の CLI では Maintainalibity and duplication がメイン(だった記憶)でしたが、上述の他の機能も使えるようになったようです。
今回はCLIを試してみました。
super-linterと比較
使用感の前に同じく社内で利用されていた super-linter とざっくり比較してみましょう。
super-linterは各言語のデファクトなLinterやAuto formatterを簡単に利用できるツールです。
2024/12 現在のサポート言語は super-linter 59種類、 Qlty 25種類です。
Qltyは完全サポートとプラグインサポートの2つの方法で利用でき、完全サポートされる言語は9種類です。
完全サポートでサポートされるのは上述の5つのメイン機能です。
Maintainablity や Code coverage まで扱うのでそのあたりは Qlty のほうがより深くサポートされているようです。
広く浅いsuper-linter、狭く深いQltyのような状況だと思います。
Qlty の運用面での特徴は調査しきれていませんが、気軽に使えるのは super-linter でしょう。
Qlty CLI を使ってみる
インストールして実際に動かして行きます。
下記がメインのコマンドです。
-
smells
: コードの悪臭(潜在的な問題)を検出する -
check
: 各種Linter (rubocop, brakemanなど) を実行し、コードの静的解析を行う -
fmt
: コードのフォーマットを自動的に修正する(Linterの機能) -
metrics
: コードの複雑度や行数などのメトリクスを出力する
まずは、名前が気になった smells
コマンドから試してみることにします。
smells
オプション無しで実行すると upstream ブランチに対する差分に対して実行されます。
例だと origin/master ブランチとの差分に対して実行されました。
差分がない場合、0 fileになっています。
qlty smells
[0/3] 🔍 Analyzing vs. origin/master... 0.04s
[1/3] 👀 Checking structure of 0 files... 0.00s
[2/3] 🤔 Looking for duplication across 0 files... 0.00s
[3/3] ✨ Reporting...
--all
オプションを指定すると、全てのファイルに対して分析を実行します。
qlty smells --all
[0/3] 🔍 Analyzing all targets... 0.08s
[1/3] 👀 Checking structure of 23 files... 0.66s
[2/3] 🤔 Looking for duplication across 23 files... 0.05s
[3/3] ✨ Reporting...
bin/webpack
Found 16 lines of similar code in 2 locations (mass = 76)
1 #!/usr/bin/env ruby
2
3 ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 ENV["NODE_ENV"] ||= ENV["NODE_ENV"] || "development"
5
6 require "pathname"
[hid 10 additional lines]
also found at bin/webpack-dev-server
bin/webpack-dev-server
Found 16 lines of similar code in 2 locations (mass = 76)
1 #!/usr/bin/env ruby
2
3 ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 ENV["NODE_ENV"] ||= ENV["NODE_ENV"] || "development"
5
6 require "pathname"
[hid 10 additional lines]
also found at bin/webpack
check
rubocop や brakeman などのデファクトな Linter が実行されます。
各種 Lint ツールはqlty init
実行時にインストールされます(これが結構便利)
qlty check
[0/1] 🤔 Planning... 0.44s
[1/1] 🔍 Analyzing vs. origin/master...
∟ brakeman ⠐
∟ rubocop app/controllers/application_controller.rb and 3 more ⠐
∟ reek app/controllers/application_controller.rb and 3 more ⡀
∟ trufflehog app/controllers/application_controller.rb and 5 more ⠐
ISSUES
app/controllers/application_controller.rb:0:0
0:0 fmt Incorrect formatting, autoformat by running `qlty fmt`. rubocop:fmt
4:5 medium Extra empty line detected at class body beginning. rubocop:Layout/EmptyLinesAroundClassBody
app/controllers/pages_controller.rb:0:0
0:0 fmt Incorrect formatting, autoformat by running `qlty fmt`. rubocop:fmt
5:6 medium Extra empty line detected at method body beginning. rubocop:Layout/EmptyLinesAroundMethodBody
app/controllers/test_reports_controller.rb:0:0
0:0 fmt Incorrect formatting, autoformat by running `qlty fmt`. rubocop:fmt
7:7 medium Trailing whitespace detected. rubocop:Layout/TrailingWhitespace
Checked 23 files
✖ 6 issues
実行時の出力を見ていたらtrivy
も実行されていました。
qlty init
コマンド実行時に自動生成される .qlty/qlty.toml
ファイルには、実行されるプラグインが明記されています。
[[plugin]]
name = "brakeman"
[[plugin]]
name = "checkov"
[[plugin]]
name = "eslint"
version = "8.57.0"
[[plugin]]
name = "golangci-lint"
[[plugin]]
name = "markdownlint"
version = "0.41.0"
[[plugin]]
name = "osv-scanner"
[[plugin]]
name = "prettier"
[[plugin]]
name = "reek"
[[plugin]]
name = "ripgrep"
[[plugin]]
name = "rubocop"
version = "1.65.1"
package_file = "Gemfile"
package_filters = ["rubocop"]
[[plugin]]
name = "stylelint"
version = "14.6.1"
[[plugin]]
name = "trivy"
drivers = [
"config",
"fs-vuln",
]
[[plugin]]
name = "trufflehog"
[[plugin]]
name = "yamllint"
metrics
コードに関する指標が出力されます。
個人的には、JSONなどのプログラマブルな出力形式が提供されると、他のツールとの連携やさらなる分析が可能になり、より便利になると思いました。
qlty metrics --all --max-depth 2
[0/3] 🤔 Planning... 0.26s
[1/3] 🔍 Analyzing files over all targets... 0.91s
[2/3] 👀 Parsing 23 files... 0.00s
[3/3] ✨ Reporting...
name | classes | funcs | fields | cyclo | complex | LCOM | lines | LOC
-----------------+---------+-------+--------+-------+---------+------+-------+-----
app | 8 | 10 | 2 | 25 | 2 | 2 | 202 | 126
app/channels | 2 | 0 | 0 | 2 | 0 | 0 | 12 | 8
app/client | 0 | 0 | 0 | 2 | 0 | 0 | 38 | 19
app/controllers | 2 | 2 | 2 | 4 | 0 | 2 | 33 | 25
app/helpers | 0 | 1 | 0 | 2 | 2 | 0 | 12 | 10
app/jobs | 1 | 0 | 0 | 1 | 0 | 0 | 4 | 2
app/models | 3 | 7 | 0 | 14 | 0 | 0 | 103 | 62
bin | 0 | 2 | 0 | 22 | 11 | 0 | 114 | 64
lib | 0 | 0 | 0 | 2 | 1 | 0 | 55 | 47
lib/tasks | 0 | 0 | 0 | 2 | 1 | 0 | 55 | 47
TOTAL | 16 | 22 | 4 | 76 | 17 | 4 | 628 | 410
fmt
plugin に基づいて自動修正するコマンド。多分 rubocop の自動修正が動いたようでした。
何による修正なのかわからないので、--filter
オプションで動作する plugin を指定するのがいいのかも。
qlty fmt
✔ Formatted app/controllers/test_reports_controller.rb
✔ Formatted app/controllers/pages_controller.rb
✔ Formatted app/controllers/application_controller.rb
Checked 4 files
--upstream
オプション
個人的には共通の --upstream
オプションが便利だと思いました。
これがないと CI とかで実行するときにファイル差分からいちいち実行対象を抽出する手間がかかります。
動きとしては指定したブランチとの差分に対して実行されます。
qlty check --upstream origin/resolve-conflicts
[0/1] 🤔 Planning... 0.15s
[1/1] 🔍 Analyzing vs. origin/resolve-conflicts...
qlty metrics --upstream origin/resolve-conflicts
[0/3] 🤔 Planning... 0.14s
[1/3] 🔍 Analyzing files vs. origin/resolve-conflicts... 0.31s
[2/3] 👀 Parsing 6 files... 0.00s
[3/3] ✨ Reporting...
name | classes | funcs | fields | cyclo | complex | LCOM | lines | LOC
-------------------------------------------+---------+-------+--------+-------+---------+------+-------+-----
Gemfile | 0 | 0 | 0 | 1 | 0 | 0 | 53 | 47
app/controllers/application_controller.rb | 1 | 1 | 0 | 1 | 0 | 1 | 16 | 11
app/controllers/pages_controller.rb | 1 | 1 | 2 | 3 | 0 | 1 | 17 | 14
app/helpers/application_helper.rb | 0 | 1 | 0 | 2 | 2 | 0 | 12 | 10
app/models/job.rb | 1 | 7 | 0 | 12 | 0 | 0 | 85 | 56
lib/tasks/auto_annotate_models.rake | 0 | 0 | 0 | 2 | 1 | 0 | 55 | 47
TOTAL | 3 | 10 | 2 | 21 | 3 | 2 | 238 | 185
migrate
あまり需要なさそうですが、CCQの設定ファイル .codeclimate.yaml
をQltyの設定ファイル qlty.toml
に移行するコマンドも用意されていました。
前からユーザーをきちんと考えてくれていて嬉しくなりました
例えば以下のような .codeclimate.yaml
がある状態で、 qlty migrate
を実行すると、
version: "2"
checks:
argument-count:
enabled: true
config:
threshold: 4
complex-logic:
enabled: true
config:
threshold: 4
file-lines:
enabled: true
config:
threshold: 250
method-complexity:
enabled: true
config:
threshold: 5
method-count:
enabled: true
config:
threshold: 25
method-lines:
enabled: true
config:
threshold: 25
nested-control-flow:
enabled: true
config:
threshold: 4
return-statements:
enabled: true
config:
threshold: 4
similar-code:
enabled: false
config:
threshold:
identical-code:
enabled: false
config:
threshold:
以下の内容が .qlty/qlty.toml
に追記されます。
[smells.boolean_logic]
threshold = 4
enabled = true
[smells.file_complexity]
threshold = 55
enabled = true
[smells.return_statements]
threshold = 4
enabled = true
[smells.nested_control_flow]
threshold = 4
enabled = true
[smells.function_parameters]
threshold = 4
enabled = true
[smells.function_complexity]
threshold = 5
enabled = true
[smells.duplication]
enabled = false
余談
試すときにインストールが上手くいかなくてサポートに問い合わせしたら、1~2日くらいで返答が来て解決できました
導入期だからかもですが、迅速で手厚いサポートも好感触でした。
機能のリクエストを行えば、取り入れてくれるかもしれませんね。
終わりに
ほぼほぼ公式ドキュメント見れば分かる話で恐縮ですが、使ってみた肌感が伝われば幸いです。
こういったツールは Copilot 系の AI によるコーディングツールで淘汰されるのかもとも思いましたが、AI は完璧ではない点もあるので多層でチェックする仕組みもありかなと思いました。
また、Qlty Cloud 側には AI による説明や自動修正の提供が予定されているようなので、ほかツールとどう差別化を図るのかとても楽しみだなと思いました。
Fin.