2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AndroidプロジェクトにDetektを導入してGitHub Actionsで自動静的解析

Posted at

Androidアプリ開発でコードの品質を保つために、Kotlinの静的コード解析ツール Detekt を導入してみました。
GitHub Actionsと連携させることで、プルリクエスト時に自動でコード解析を実行し、問題があれば指摘してもらえるようになります。本記事では、その導入からGitHub Actionsでの連携までの手順を紹介します。

実際の設定例は以下のサンプルプロジェクトで確認できます:
example-detekt - DetektとGitHub Actionsの統合例

Detektとは?

DetektはKotlin用の静的コード解析ツールで、以下のような問題を検出できます:

  • コードの複雑度が高い箇所
  • 命名規則に従っていない変数・関数
  • 未使用のコードや不要なimport
  • 潜在的なバグにつながるコードパターン
  • パフォーマンスに影響する可能性のあるコード

手元の環境

  • Android Studio Meerkat Feature Drop | 2024.3.2 Patch 1
  • Kotlin 2.2.0
  • Android Gradle Plugin 8.10.1
  • Detekt 1.23.6
  • Gradle 8.11.1

導入手順

1. gradle/libs.versions.toml に Detekt を追加

Version Catalogを使って依存関係を管理している場合は、gradle/libs.versions.toml にDetektのバージョンを追加します。

[versions]
detekt = "1.23.6"

[plugins]
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }

2. build.gradle.kts (プロジェクトルート) でプラグインを適用

plugins {
    alias(libs.plugins.detekt) apply false
}

3. app/build.gradle.kts でDetektを設定

plugins {
    alias(libs.plugins.detekt)
}

// Detekt設定
detekt {
    config.setFrom(file("../detekt.yml"))
    baseline = file("detekt-baseline.xml")
    autoCorrect = true
}

// タスクレベルでレポート設定を行う(新しいAPI)
tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
    reports {
        html.required.set(true)
        xml.required.set(true)
        sarif.required.set(true)
        md.required.set(true)
    }
}

4. Detekt設定ファイルの作成

プロジェクトルートに detekt.yml を作成して、解析ルールをカスタマイズします。
初期設定ファイルを生成する場合は、以下のコマンドで作成できます:

./gradlew detektGenerateConfig

手元のプロジェクトでは、以下のような設定にしました:

build:
  maxIssues: 0
  excludeCorrectable: false

complexity:
  active: true
  LongMethod:
    active: true
    threshold: 60
  CyclomaticComplexMethod:
    active: true
    threshold: 15

style:
  active: true
  MaxLineLength:
    active: true
    maxLineLength: 120
  MagicNumber:
    active: true
    excludes: ['**/test/**', '**/androidTest/**']
    ignoreNumbers:
      - '-1'
      - '0'
      - '1'
      - '2'

naming:
  active: true
  FunctionNaming:
    active: true
    excludes: ['**/test/**', '**/androidTest/**']
    ignoreAnnotated: ['Composable']

5. ローカルでDetektを実行

設定が完了したら、ローカルでDetektを実行してみます:

./gradlew detekt

実行後、app/build/reports/detekt/ 配下に以下のレポートが生成されます:

  • detekt.html - ブラウザで見やすいHTML形式
  • detekt.xml - CIツールで利用しやすいXML形式
  • detekt.sarif - GitHub Security との連携用
  • detekt.md - Markdown形式

GitHub Actions との連携

プルリクエスト時に自動でDetektを実行するために、GitHub Actionsのワークフローを設定します。

.github/workflows/detekt.yml を作成:

name: Detekt Static Analysis

on:
  pull_request:
    branches: [ main, develop ]
    paths:
      - '**/*.kt'
      - '**/*.kts'
      - 'detekt.yml'
      - 'app/build.gradle.kts'
      - 'build.gradle.kts'

permissions:
  contents: read
  pull-requests: write
  security-events: write

jobs:
  detekt:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
        
    - name: Setup Gradle
      uses: gradle/gradle-build-action@v3
      
    - name: Run Detekt
      run: ./gradlew detekt
      
    - name: Upload SARIF to GitHub Security
      if: always()
      uses: github/codeql-action/upload-sarif@v3
      with:
        sarif_file: app/build/reports/detekt/detekt.sarif
        
    - name: Comment PR with results
      if: failure()
      uses: actions/github-script@v7
      with:
        script: |
          const fs = require('fs');
          try {
            const report = fs.readFileSync('app/build/reports/detekt/detekt.md', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## 🔍 Detekt Static Analysis Results\n\n${report}`
            });
          } catch (error) {
            console.log('No detekt report found or error reading file:', error.message);
          }

このワークフローでは以下の処理を行います:

  1. Kotlinファイルが変更されたプルリクエストでトリガー
  2. Detektを実行
  3. 結果をSARIF形式でGitHub Securityタブにアップロード
  4. 問題が見つかった場合、プルリクエストにコメントで結果を投稿

実際の使用例

設定後にプルリクエストを作成すると、以下のようにDetektが自動実行されます:

> Task :app:detekt

Detekt found 5 code quality issues:
- ComplexMethod at MainActivity.kt:45:5
- LongParameterList at UserRepository.kt:12:5
- MagicNumber at Constants.kt:8:20
- UnusedImport at LoginActivity.kt:3:1
- MaxLineLength at DataProcessor.kt:67:1

問題が見つかった場合、プルリクエストにコメントが自動投稿され、どのファイルのどの行に問題があるかが分かります。

実際の動作例は以下のプルリクエストで確認できます:
PR #2: Add Qiita documentation articles - Detekt GitHub Actionsの実行結果

カスタマイズのポイント

テストコードの除外

テストコードでは多少ルールを緩めたい場合があるので、以下のように設定できます:

style:
  MagicNumber:
    active: true
    excludes: ['**/test/**', '**/androidTest/**']

Jetpack Compose対応

Composable関数は関数名が大文字で始まることがあるので、除外設定を追加:

naming:
  FunctionNaming:
    active: true
    ignoreAnnotated: ['Composable']

閾値の調整

プロジェクトの規模に応じて閾値を調整:

complexity:
  LongMethod:
    threshold: 60  # デフォルトは60行
  CyclomaticComplexMethod:
    threshold: 15  # デフォルトは15

まとめ

Detektを導入することで、コードレビュー前に機械的にチェックできる問題を自動検出できるようになりました。
特にチーム開発では、コーディング規約の統一やコード品質の底上げに効果的だと感じています。

最初は警告が大量に出るかもしれませんが、段階的にルールを調整していけば、プロジェクトに適した設定に調整できます。

参考リンク

2
3
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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?