5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LIFULLAdvent Calendar 2024

Day 20

CodeClimate Quality の後継 "Qlty" を触ってみた

Last updated at Posted at 2024-12-19

はじめに

社内で運用されていた 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 に移行するコマンドも用意されていました。
前からユーザーをきちんと考えてくれていて嬉しくなりました :smiley:

例えば以下のような .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日くらいで返答が来て解決できました :clap:

導入期だからかもですが、迅速で手厚いサポートも好感触でした。

機能のリクエストを行えば、取り入れてくれるかもしれませんね。

終わりに

ほぼほぼ公式ドキュメント見れば分かる話で恐縮ですが、使ってみた肌感が伝われば幸いです。

こういったツールは Copilot 系の AI によるコーディングツールで淘汰されるのかもとも思いましたが、AI は完璧ではない点もあるので多層でチェックする仕組みもありかなと思いました。

また、Qlty Cloud 側には AI による説明自動修正の提供が予定されているようなので、ほかツールとどう差別化を図るのかとても楽しみだなと思いました。

Fin.

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?