
Automatyczne opisy pull requestów z OpenAI i Vercel
W tym poradniku zbudujemy generator opisów pull requestów oparty na OpenAI Responses API i wdrożymy go na Vercel. Narzędzie przygotuje szkic opisu po otwarciu pull requesta lub oznaczeniu go jako gotowego do przeglądu. Wygenerowany tekst powinien zawsze zostać sprawdzony przez autora zmian.
Co robi narzędzie
Bot:
- odbiera zdarzenia GitHub przez webhook,
- pobiera listę zmienionych plików i ich różnice,
- tworzy zwięzłe podsumowanie zmian,
- aktualizuje opis pull requesta.
Założenia
Potrzebujesz kont GitHub, Vercel i OpenAI, tokenu GitHub, klucza API OpenAI oraz środowiska Node.js. Sekrety przechowuj w zmiennych środowiskowych, nigdy w repozytorium.
Dobry prompt
Instrukcja powinna wymagać informacji, które da się potwierdzić na podstawie różnicy w kodzie. Warto poprosić o:
- krótki opis celu zmian,
- listę najważniejszych modyfikacji,
- informację o zmianach niekompatybilnych wstecz,
- wskazanie obszarów, których nie da się ocenić bez dodatkowego kontekstu.
Unikaj polecenia „opisz wszystko”. Zachęca ono model do wypełniania braków domysłami.
Wywołanie OpenAI
Dla nowych integracji OpenAI rekomenduje Responses API. Model trzymamy w zmiennej środowiskowej, aby można było zmienić go bez modyfikowania kodu.
1const aiResponse = await openai.responses.create({2 model: process.env.OPENAI_MODEL || "gpt-5.6-sol",3 instructions: `4 Przygotuj zwięzły i rzeczowy opis pull requesta.5 Opieraj się wyłącznie na widocznych zmianach.6 Nie wymyślaj zachowania, którego nie da się potwierdzić w diffie.7 `,8 input: fileDiffs,9 max_output_tokens: 300,10});1112const description = aiResponse.output_text;
Obsługa webhooka
Po odebraniu zdarzenia sprawdzamy jego typ, pobieramy zmienione pliki i przekazujemy ich zawartość do modelu.
1router.post('/webhook', async (req, res) => {2 verifyWebhookSignature(req);34 const { pull_request, repository, action } = req.body;5 if (!pull_request || !['opened', 'ready_for_review'].includes(action)) {6 return res.status(200).send('Event ignored');7 }89 const owner = repository.owner.login;10 const repo = repository.name;11 const pullNumber = pull_request.number;1213 const { data: files } = await octokit.pulls.listFiles({14 owner,15 repo,16 pull_number: pullNumber,17 });1819 const fileDiffs = files20 .map((file) => `${file.filename}:\n${file.patch || '[binary or truncated]'}`)21 .join('\n\n');2223 const aiResponse = await openai.responses.create({24 model: process.env.OPENAI_MODEL || 'gpt-5.6-sol',25 instructions: prompt,26 input: fileDiffs,27 max_output_tokens: 300,28 });2930 await octokit.pulls.update({31 owner,32 repo,33 pull_number: pullNumber,34 body: aiResponse.output_text,35 });3637 return res.status(200).send('Description updated');38});
Bezpieczeństwo i ograniczenia
Podpis webhooka trzeba sprawdzać na podstawie surowego ciała żądania i porównywać w sposób odporny na analizę czasu wykonania. Warto też ograniczyć maksymalną wielkość wejścia, obsłużyć brak diffu dla plików binarnych oraz nie wysyłać do zewnętrznego API sekretów lub danych klienta.
Duży pull request może przekroczyć rozsądny limit kontekstu. W takim przypadku najpierw odfiltruj pliki generowane, lockfile i artefakty, a pozostałe zmiany podsumuj partiami.
Co dalej
Najbardziej praktyczne rozszerzenia to etykietowanie wygenerowanego opisu jako szkicu, dodanie sekcji z planem testów oraz zapisywanie informacji o tym, które pliki zostały pominięte. Dzięki temu automatyzacja oszczędza czas, ale nie ukrywa swoich ograniczeń.

Michał Winiarski
Founder of Devbrains and senior software developer


