As revisões de código sempre foram cruciais para manter um padrão e enfatizar as melhores práticas de código em um projeto. Este não é um post sobre como os desenvolvedores devem revisar o código, é mais sobre delegar uma parte dele à IA.
Como Michael Lynch menciona em sua postagem - "Como fazer revisões de código como um humano" - deveríamos deixar os computadores cuidarem das partes chatas da revisão de código. Embora Michael enfatize uma ferramenta de formatação, eu gostaria de dar um passo adiante e deixar a inteligência artificial descobrir isso. Quero dizer, por que não aproveitar a vantagem do boom da IA na indústria?
Agora, não estou dizendo que a IA deva ser usada no lugar de ferramentas de formatação e linters. Em vez disso, deve ser usado além disso, para capturar coisas triviais que podem passar despercebidas a um humano.
É por isso que decidi criar uma ação no github cujo código analisa uma comparação de pull request e gera sugestões usando IA. Deixe-me explicar isso.
? Observação
- Esta ação do GitHub já está disponível no mercado GitHub.
- É uma ação javascript - saiba mais sobre como criar ações javascript no github.
Para interagir com a API do github, usei o octokit, que é uma espécie de SDK ou biblioteca cliente para interagir com a API do github de forma idiomática.
Para obter o diff da solicitação pull levantada, você precisa passar o cabeçalho Accept com o valor application/vnd.github.diff junto com os parâmetros necessários.
async function getPullRequestDetails(octokit, { mode }) { let AcceptFormat = "application/vnd.github.raw json"; if (mode === "diff") AcceptFormat = "application/vnd.github.diff"; if (mode === "json") AcceptFormat = "application/vnd.github.raw json"; return await octokit.rest.pulls.get({ owner: github.context.repo.owner, repo: github.context.repo.repo, pull_number: github.context.payload.pull_request.number, headers: { accept: AcceptFormat, }, }); }
Se você não está familiarizado com as ações do github, aqui está uma série 101 de ações do github de Victoria Lo e é um bom começo.
Depois de obter a comparação, eu a analiso e removo as alterações indesejadas e, em seguida, a retorno em um esquema mostrado abaixo:
/** using zod */ schema = z.object({ path: z.string(), position: z.number(), line: z.number(), change: z.object({ type: z.string(), add: z.boolean(), ln: z.number(), content: z.string(), relativePosition: z.number(), }), previously: z.string().optional(), suggestions: z.string().optional(), })
Ignorar arquivos é bastante simples. A lista de entrada do usuário requer uma sequência de padrões glob separados por ponto e vírgula. Em seguida, ele é analisado, concatenado com a lista padrão de arquivos ignorados e desduplicado.
**/*.md; **/*.env; **/*.lock;
const filesToIgnoreList = [ ...new Set( filesToIgnore .split(";") .map(file => file.trim()) .filter(file => file !== "") .concat(FILES_IGNORED_BY_DEFAULT) ), ];
A lista de arquivos ignorados é então usada para remover as alterações de comparação que se referem a esses arquivos ignorados. Isso fornece uma carga útil bruta contendo apenas as alterações desejadas.
Depois de obter a carga útil bruta após analisar a diferença, eu a passo para a API da plataforma. Aqui está uma implementação da API OpenAI.
async function useOpenAI({ rawComments, openAI, rules, modelName, pullRequestContext }) { const result = await openAI.beta.chat.completions.parse({ model: getModelName(modelName, "openai"), messages: [ { role: "system", content: COMMON_SYSTEM_PROMPT, }, { role: "user", content: getUserPrompt(rules, rawComments, pullRequestContext), }, ], response_format: zodResponseFormat(diffPayloadSchema, "json_diff_response"), }); const { message } = result.choices[0]; if (message.refusal) { throw new Error(`the model refused to generate suggestions - ${message.refusal}`); } return message.parsed; }
Você pode notar o uso do formato de resposta na implementação da API. Este é um recurso fornecido por muitas plataformas LLM, que permite dizer ao modelo para gerar a resposta em um esquema/formato específico. É especialmente útil neste caso, pois não quero que o modelo tenha alucinações e gere sugestões para arquivos ou posições incorretas na solicitação pull, ou adicione novas propriedades à carga útil da resposta.
O prompt do sistema existe para fornecer ao modelo mais contexto sobre como ele deve fazer a revisão do código e quais são algumas coisas a serem lembradas. Você pode ver o prompt do sistema aqui github.com/murtuzaalisurti/better.
O prompt do usuário contém a comparação real, as regras e o contexto da solicitação pull. É o que dá início à revisão do código.
Esta ação do github oferece suporte aos modelos OpenAI e Anthropic. Veja como ele implementa a API Antrópica:
async function useAnthropic({ rawComments, anthropic, rules, modelName, pullRequestContext }) { const { definitions } = zodToJsonSchema(diffPayloadSchema, "diffPayloadSchema"); const result = await anthropic.messages.create({ max_tokens: 8192, model: getModelName(modelName, "anthropic"), system: COMMON_SYSTEM_PROMPT, tools: [ { name: "structuredOutput", description: "Structured Output", input_schema: definitions["diffPayloadSchema"], }, ], tool_choice: { type: "tool", name: "structuredOutput", }, messages: [ { role: "user", content: getUserPrompt(rules, rawComments, pullRequestContext), }, ], }); let parsed = null; for (const block of result.content) { if (block.type === "tool_use") { parsed = block.input; break; } } return parsed; }
Finalmente, depois de recuperar as sugestões, eu as limpo e as passo para a API do github para adicionar comentários como parte da revisão.
Escolhi a forma abaixo para adicionar comentários porque, ao criar uma nova avaliação, você pode adicionar todos os comentários de uma vez, em vez de adicionar um único comentário de cada vez. Adicionar comentários um por um também pode acionar a limitação de taxa porque adicionar comentários aciona notificações e você não deseja enviar notificações para os usuários.
function filterPositionsNotPresentInRawPayload(rawComments, comments) { return comments.filter(comment => rawComments.some(rawComment => rawComment.path === comment.path && rawComment.line === comment.line) ); } async function addReviewComments(suggestions, octokit, rawComments, modelName) { const { info } = log({ withTimestamp: true }); // eslint-disable-line no-use-before-define const comments = filterPositionsNotPresentInRawPayload(rawComments, extractComments().comments(suggestions)); try { await octokit.rest.pulls.createReview({ owner: github.context.repo.owner, repo: github.context.repo.repo, pull_number: github.context.payload.pull_request.number, body: `Code Review by ${modelName}`, event: "COMMENT", comments, }); } catch (error) { info(`Failed to add review comments: ${JSON.stringify(comments, null, 2)}`); throw error; } }
Eu queria manter a ação do github aberta e aberta a integrações e é por isso que você pode usar qualquer modelo de sua escolha (veja a lista de modelos suportados), ou você pode ajustar e construir seu próprio modelo personalizado sobre os modelos básicos suportados e use-o com esta ação do github.
Se você encontrar algum problema de token ou limitação de taxa, você pode atualizar os limites do seu modelo consultando a documentação da respectiva plataforma.
Então, o que você está esperando? Se você tiver um repositório no github, experimente a ação agora - está no mercado de ações do github.
Uma ação do github de revisor de código com tecnologia de IA, pronta para ser usada em seu fluxo de trabalho.
Crie um arquivo de fluxo de trabalho dentro da pasta .github/workflows (crie se não existir) do seu repositório com o seguinte conteúdo:
name: Code Review
on
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
branches:
- main # change this to your target branch
workflow_dispatch: # Allows you to run the workflow manually from the Actions tab
permissions: # necessary permissions
pull-requests: write
contents: read
jobs:
your-job-name:
runs-on: ubuntu-latest
name: your-job-name
steps:
- name: step-name
id: step-id
uses: murtuzaalisurti/better@v2 # this is
…Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3