> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# GitLab 上で SonarQube の課題を自動解決する

> Devin に GitLab 経由で SonarQube の課題を解決させる

Devin の API は強力なツールです。このガイドを読み進める前に、まず次の[記事](/ja/enterprise/use-cases/sonarqube/guide)をお読みください。

<div id="1-process-overview">
  ### 1. プロセス概要
</div>

1. **Pull Request が作成される**: コードスキャンツールによって問題が検出された可能性のある変更を含む Pull Request (PR) がリポジトリに送信されます。

2. **GitLab Action がトリガーされる**: PR のオープンによって、自動的に GitLab Action ワークフローがトリガーされます。

3. **GitLab Action が Devin API を呼び出す**: GitLab Action が Devin API にリクエストを送り、検出された問題を自動解決のために渡します。

4. **Devin セッションが初期化される**: Devin セッションが起動し、問題のコンテキストを受け取り、提供されたデータに基づいて解決を試みます。

5. **Devin が人間によるレビュー用の PR を提案する**: 問題が解決されると、Devin は提案された変更を含む PR を作成し、人間によるレビューのために送信します。

<div id="2-steps-to-accomplish-this">
  ### 2. この手順を完了するためのステップ
</div>

1. **必要なシークレットを保持するために GitLab 環境を構成する**:
   * Devin の API やその他の連携ツールとやり取りするために必要な認証トークンや設定キーなどのシークレットを安全に保存できるよう、GitLab 環境を設定します。

これらの手順が完了すると、パイプラインは Devin の API を使用して問題を自動的に解決できるようになり、処理の高速化と手動対応の削減につながります。

2. **連携をテストする**

セットアップが完了したら、GitLab Action を手動でトリガーして連携をテストできます。これにより、Action が正しく Devin API を呼び出し、検出された問題を解決できているかを検証できます。

3. **Devin Sessions ページを参照する**

GitLab Build がトリガーされ、Devin が問題を処理した後は、Devin の Sessions ページでステータスと結果を確認できます。このページでは、解決された問題の詳細や、提案された変更内容を確認できます。

前述のとおり、SonarQube から取得する必要がある値は次のとおりです。
連携を構成するには、SonarQube インスタンスから次の 3 つの値を取得する必要があります:
`SONAR_TOKEN`, `SONAR_ORG`, `SONAR_PROJECT_KEY`

すべての必要な値がそろったら、GitLab Action を構成する準備が整います。

<Note>
  これは、`sonar-project.properties` というローカルの SonarCloud プロパティファイルがあり、そこで次の内容が指定されていることを前提としています:

  ```
  sonar.projectKey={PROJECT_KEY}
  sonar.sources=FILE_PATH (usually ".")
  ```
</Note>

GitLab Action のソースコードは次のとおりです。

```
stages:
  - analyze
  - remediate

variables:
  SONAR_TOKEN: "$SONAR_TOKEN"
  SONAR_ORG: "$SONAR_ORG"
  SONAR_PROJECT_KEY: "Colhodm_juice-shop"
  DEVIN_API_KEY: "$DEVIN_API_KEY"
  GIT_STRATEGY: clone

analyze:
  stage: analyze
  image: sonarsource/sonar-scanner-cli:latest
  script:
    - sonar-scanner -Dsonar.organization=$SONAR_ORG
  only:
    - branches
    - merge_requests

setup_python:
  stage: remediate
  image: python:3.9
  before_script:
    - python --version
    - pip install aiohttp
  script:
    - git config --global user.name "GitLab Runner"
    - git config --global user.email "runner@gitlab.com"
    - python3 $CI_PROJECT_DIR/.gitlab/scripts/devin_remediation.py
  only:
    - branches
    - merge_requests
```

おさらいとして、devin\_remediation.py は次のとおりです。

```
python
import asyncio
import aiohttp
import os
from datetime import datetime

# 環境変数
GITHUB_REPOSITORY = os.getenv("GITHUB_REPOSITORY")
SONAR_TOKEN = os.getenv("SONAR_TOKEN")
DEVIN_API_KEY = os.getenv("DEVIN_API_KEY")
SONAR_ORG = os.getenv("SONAR_ORG")
SONAR_PROJECT_KEY = os.getenv("SONAR_PROJECT_KEY")
DEVIN_API_BASE = "https://api.devin.ai/v1"

async def get_sonarcloud_issues():
    """SonarCloudから未解決の脆弱性を取得します。"""
    url = "https://sonarcloud.io/api/issues/search"
    headers = {"Authorization": f"Bearer {SONAR_TOKEN}"}
    params = {
        "organization": SONAR_ORG,
        "projectKeys": SONAR_PROJECT_KEY,
        "types": "VULNERABILITY",
        "statuses": "OPEN"
    }

    async with aiohttp.ClientSession() as session:
        async with session.get(url, headers=headers, params=params) as response:
            if response.status != 200:
                print(f"SonarCloudの問題取得エラー: {await response.text()}")
                return []
            result = await response.json()
            print(f"{len(result.get('issues', []))}件の問題を検出しました")
            return result.get('issues', [])

async def delegate_task_to_devin(issue):
    """修正、コミット、プッシュの全タスクをDevin AIに委任します。"""
    async with aiohttp.ClientSession() as session:
        headers = {"Authorization": f"Bearer {DEVIN_API_KEY}"}
        prompt = f"""
        {GITHUB_REPOSITORY}の以下の脆弱性を修正してください: ファイル{issue['component']}内の{issue['message']}。
        1. 'devin/{issue['key']}-fix-vulnerability'という名前の新しいブランチを作成してください。
        2. 修正を実装してください。
        3. 変更内容を説明する詳細なコミットメッセージを記述してください:
            - Issue Key: {issue['key']}
            - Component: {issue['component']}
            - Fixed by Devin AI at {datetime.now().isoformat()}
            - 'Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>'を含めてください。
        4. ブランチをリモートリポジトリにプッシュしてください。
        5. 修正内容の説明を含むプルリクエストを開いてください。
        """

        data = {"prompt": prompt, "idempotent": True}

        async with session.post(f"{DEVIN_API_BASE}/sessions", json=data, headers=headers) as response:
            if response.status != 200:
                print(f"Devinへのタスク委任エラー: {await response.text()}")
                return None
            result = await response.json()
            print(f"Devinセッションを作成しました: {result}")
            return result

async def monitor_devin_session(session_id):
    """タスク完了までDevinの進捗を監視します。"""
    async with aiohttp.ClientSession() as session:
        headers = {"Authorization": f"Bearer {DEVIN_API_KEY}"}

        while True:
            async with session.get(f"{DEVIN_API_BASE}/sessions/{session_id}", headers=headers) as response:
                if response.status != 200:
                    print(f"Devinセッション監視エラー: {await response.text()}")
                    return None

                result = await response.json()
                status = result.get("status_enum")

                if status in ["completed", "stopped"]:
                    print(f"Devinがタスクを完了しました: {result}")
                    return result
                elif status == "blocked":
                    print("Devinが問題を検出しました。手動で確認してください。")
                    return None

                await asyncio.sleep(5)

async def main():
    try:
        issues = await get_sonarcloud_issues()

        for issue in issues:
            print(f"問題を処理中: {issue['key']}")

            # Devin AIにタスクを委任
            session_data = await delegate_task_to_devin(issue)

            if session_data:
                session_id = session_data["session_id"]

                # Devinの進捗を監視
                await monitor_devin_session(session_id)

    except Exception as e:
        print(f"エラーが発生しました: {str(e)}")
        raise

if __name__ == "__main__":
    asyncio.run(main())
```

GitLab Action が正しい環境変数を設定できるようにするには、それらを **GitLab CI/CD Secrets** に追加します。

目的の設定画面へ移動するのは少し分かりにくい場合があります。**Settings** に移動し、**Secrets** を編集します。**Repository Secrets** のセクションに **SONAR\_TOKEN** と **DEVINS\_API** を追加します。

<Frame>
  <img src="https://mintcdn.com/cognitionai/a0js040y87FuBerW/images/SonarQubeImages/Onboarding-Gitlab-Repository-Secret.png?fit=max&auto=format&n=a0js040y87FuBerW&q=85&s=be67c9cd5c063c73137fb2e396fa05b6" alt="SonarQube" width="3406" height="1846" data-path="images/SonarQubeImages/Onboarding-Gitlab-Repository-Secret.png" />
</Frame>

セルフホスト型の GitLab を使用している場合、異なる点は次のとおりです。

設定が完了すると、実行中の GitLab Action を監視できます。正常に実行されると、次のように表示されます。

<Frame>
  <img src="https://mintcdn.com/cognitionai/a0js040y87FuBerW/images/SonarQubeImages/Sonarqube-Gitlab-Build.png?fit=max&auto=format&n=a0js040y87FuBerW&q=85&s=0ff5d149380ee984ad75edd3df3dc8e5" alt="SonarQube" width="2904" height="1708" data-path="images/SonarQubeImages/Sonarqube-Gitlab-Build.png" />
</Frame>

**Session Manager** で Devin セッションを確認できます。

<Frame>
  <img src="https://mintcdn.com/cognitionai/a0js040y87FuBerW/images/SonarQubeImages/Devin-API-SonarQube.png?fit=max&auto=format&n=a0js040y87FuBerW&q=85&s=c7c9eedf1ba0e78d0ce5000b4eecb2e6" alt="SonarQube" width="1648" height="1688" data-path="images/SonarQubeImages/Devin-API-SonarQube.png" />
</Frame>

完了すると、Devin は自動的にプルリクエスト（PR）を作成します。GitLab ユーザーは、リンク先の[ガイド](/ja/enterprise/use-cases/sonarqube/gitlab)を参照してください。
