Skip to main content
A API do Devin é uma ferramenta poderosa. Leia o artigo a seguir antes de continuar com este guia.

1. Visão geral do processo

  1. Pull request é aberto: Um pull request (PR) é enviado ao repositório com alterações que podem conter problemas identificados por uma ferramenta de análise de código.
  2. GitLab Action é acionado: A abertura do PR aciona automaticamente um workflow do GitHub Actions.
  3. GitLab Action chama a Devin API: O GitHub Actions envia uma solicitação para a Devin API, repassando os problemas identificados para resolução automatizada.
  4. Sessão do Devin é inicializada: Uma sessão do Devin é iniciada, recebendo o contexto do problema e tentando resolvê-lo com base nos dados fornecidos.
  5. Devin propõe PR para revisão humana: Quando o problema é resolvido, o Devin gera um PR com as alterações propostas e o envia para revisão humana.

2. Passos para Realizar Isso

  1. Configure o ambiente do GitLab para armazenar os secrets necessários:
    • Configure o ambiente do GitLab para armazenar com segurança os secrets necessários, como tokens de autenticação e chaves de configuração, para interagir com a API do Devin e outras ferramentas integradas.
Após concluir esses passos, seu pipeline estará pronto para resolver problemas automaticamente usando a API do Devin, acelerando o processo e reduzindo a necessidade de intervenção manual.
  1. Teste a Integração
Após concluir a configuração, você pode testar a integração acionando manualmente uma GitLab Action. Isso permitirá verificar se a action chama corretamente a API do Devin e resolve os problemas identificados.
  1. Visualize a Página de Sessões do Devin
Após o GitLab Build ser acionado e o Devin processar os problemas, você pode visualizar o status e os resultados na página de sessões do Devin. Esta página fornece insights detalhados sobre os problemas resolvidos e as alterações propostas. Como mencionado anteriormente, os valores necessários do SonarQube são: Para configurar a integração, você precisará obter os seguintes três valores da sua instância do SonarQube: Você precisará de três_valores do SonarQube: {SONAR_TOKEN, SONAR_ORG, SONAR_PROJECT_KEY} Após obter todos os valores necessários, você estará pronto para configurar a GitLab Action.
Isso pressupõe que você tenha um arquivo de propriedades local do SonarCloud sonar-project.properties que especifica:
sonar.projectKey={PROJECT_KEY}
sonar.sources=FILE_PATH (geralmente ".")
A GitLab Action possui o seguinte código-fonte
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 "[email protected]"
    - python3 $CI_PROJECT_DIR/.gitlab/scripts/devin_remediation.py
  only:
    - branches
    - merge_requests
Relembrando, devin_remediation.py é o seguinte:
python
import asyncio
import aiohttp
import os
from datetime import datetime

# Variáveis de ambiente
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():
    """Busca vulnerabilidades abertas no 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"Erro ao obter issues do SonarCloud: {await response.text()}")
                return []
            result = await response.json()
            print(f"Encontradas {len(result.get('issues', []))} issues")
            return result.get('issues', [])

async def delegate_task_to_devin(issue):
    """Delega toda a tarefa de corrigir, fazer commit e push para o Devin AI."""
    async with aiohttp.ClientSession() as session:
        headers = {"Authorization": f"Bearer {DEVIN_API_KEY}"}
        prompt = f"""
        Corrija a seguinte vulnerabilidade em {GITHUB_REPOSITORY}: {issue['message']} no arquivo {issue['component']}.
        1. Crie uma nova branch chamada 'devin/{issue['key']}-fix-vulnerability'.
        2. Implemente a correção.
        3. Escreva uma mensagem de commit detalhada explicando as alterações:
            - Chave da Issue: {issue['key']}
            - Componente: {issue['component']}
            - Corrigido pelo Devin AI em {datetime.now().isoformat()}
            - Inclua 'Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>'.
        4. Faça push da branch para o repositório remoto.
        5. Abra um pull request com uma descrição da correção.
        """

        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"Erro ao delegar tarefa ao Devin: {await response.text()}")
                return None
            result = await response.json()
            print(f"Sessão do Devin criada: {result}")
            return result

async def monitor_devin_session(session_id):
    """Monitora o progresso do Devin até que ele conclua a tarefa."""
    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"Erro ao monitorar sessão do Devin: {await response.text()}")
                    return None

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

                if status in ["completed", "stopped"]:
                    print(f"Devin concluiu a tarefa: {result}")
                    return result
                elif status == "blocked":
                    print("Devin encontrou um problema. Verifique manualmente.")
                    return None

                await asyncio.sleep(5)

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

        for issue in issues:
            print(f"Processando issue: {issue['key']}")

            # Delega tarefa ao Devin AI
            session_data = await delegate_task_to_devin(issue)

            if session_data:
                session_id = session_data["session_id"]

                # Monitora o progresso do Devin
                await monitor_devin_session(session_id)

    except Exception as e:
        print(f"Erro ocorrido: {str(e)}")
        raise

if __name__ == "__main__":
    asyncio.run(main())
Para garantir que a GitLab Action defina as variáveis de ambiente corretas, adicione-as em GitLab CI/CD Secrets. Encontrar as configurações corretas pode ser complicado. Acesse Settings e edite Secrets. Adicione SONAR_TOKEN e DEVINS_API em Repository Secrets.
SonarQube
Se você usar o GitLab em modo auto-hospedado (self-hosted), a única diferença será: Depois de tudo configurado, você pode monitorar a execução da sua GitLab Action. Se ela for executada com sucesso, aparecerá da seguinte forma:
SonarQube
Você pode visualizar sessões do Devin no Session Manager.
SonarQube
Quando terminar, o Devin abrirá pull requests automaticamente. Para usuários do GitLab, consulte o guia indicado.