Bot do wstępnego przeglądu pull requestów z OpenAI i Vercel

30 stycznia 2025

Przegląd kodu wymaga skupienia, ale jego pierwszą, powtarzalną część można wspomóc automatyzacją. W tym poradniku zbudujemy prostego asystenta, który pobiera różnicę z GitHub, analizuje ją przez OpenAI Responses API i dodaje komentarz do pull requesta.

To narzędzie nie zatwierdza zmian i nie zastępuje reviewera. Model nie zna całego kontekstu produktu, dlatego każda uwaga wymaga weryfikacji przez człowieka.

Zakres

Bot będzie:

  • odbierał zdarzenia GitHub,
  • pobierał zmienione pliki,
  • szukał konkretnych ryzyk poprawności, bezpieczeństwa i utrzymania,
  • publikował jeden zbiorczy komentarz.

Konfiguracja projektu

1mkdir github-pr-reviewer
2cd github-pr-reviewer
3npm init -y
4npm install @octokit/rest openai dotenv express

Potrzebujesz GITHUB_TOKEN, OPENAI_API_KEY, OPENAI_MODEL oraz WEBHOOK_SECRET. Token GitHub powinien mieć tylko uprawnienia niezbędne do odczytu pull requesta i publikacji komentarza.

Handler webhooka

1const express = require('express');
2const { Octokit } = require('@octokit/rest');
3const OpenAI = require('openai');
4
5const router = express.Router();
6const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
7const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
8
9router.post('/webhook', async (req, res) => {
10 verifyWebhookSignature(req);
11
12 const { action, pull_request, repository } = req.body;
13 if (!pull_request || !['opened', 'synchronize', 'ready_for_review'].includes(action)) {
14 return res.status(200).send('Event ignored');
15 }
16
17 const owner = repository.owner.login;
18 const repo = repository.name;
19 const pullNumber = pull_request.number;
20
21 const { data: files } = await octokit.pulls.listFiles({
22 owner,
23 repo,
24 pull_number: pullNumber,
25 });
26
27 const diff = files
28 .filter((file) => file.patch)
29 .map((file) => `${file.filename}:\n${file.patch}`)
30 .join('\n\n');
31
32 const response = await openai.responses.create({
33 model: process.env.OPENAI_MODEL || 'gpt-5.6-sol',
34 instructions: `
35 Przeanalizuj diff pod kątem konkretnych błędów poprawności,
36 bezpieczeństwa i utrzymania. Wskaż plik i fragment, którego dotyczy uwaga.
37 Nie zgłaszaj problemów opartych wyłącznie na brakującym kontekście.
38 Jeśli nie widzisz istotnego problemu, napisz to wprost.
39 `,
40 input: diff,
41 max_output_tokens: 700,
42 });
43
44 await octokit.issues.createComment({
45 owner,
46 repo,
47 issue_number: pullNumber,
48 body: `## Automatyczny przegląd — szkic\n\n${response.output_text}`,
49 });
50
51 return res.status(200).send('Review added');
52});

Weryfikacja webhooka

GitHub podpisuje żądania nagłówkiem x-hub-signature-256. Podpis należy obliczać z surowego ciała żądania, nie z ponownie zserializowanego obiektu JSON. Do porównania użyj crypto.timingSafeEqual, a błędnie podpisane żądanie odrzuć przed wykonaniem jakiejkolwiek operacji.

Jak ograniczać fałszywe alarmy

Najlepszy efekt daje wąski zakres. Zamiast prosić model o „pełny code review”, określ rodzaje problemów i wymagaj wskazania dowodu w diffie. Warto też:

  • pomijać pliki wygenerowane i lockfile,
  • ograniczać wielkość pojedynczego wejścia,
  • nie publikować komentarza, jeśli model nie znalazł konkretnego problemu,
  • oznaczać wynik jako szkic,
  • mierzyć, ile uwag zostało zaakceptowanych przez reviewerów.

Wdrożenie

Po wdrożeniu funkcji na Vercel dodaj adres /api/webhook w ustawieniach repozytorium GitHub, wybierz zdarzenia pull requestów i ustaw ten sam sekret po obu stronach. Najpierw przetestuj rozwiązanie na repozytorium demonstracyjnym, bez kodu klienta i danych wrażliwych.

Automatyczny przegląd ma największą wartość jako filtr przed właściwą rozmową o kodzie. Powinien kierować uwagę reviewera, a nie udawać, że podjął za niego decyzję.

Michał Winiarski

Michał Winiarski

Founder of Devbrains and senior software developer

Najnowsze artykuły