Integracje
View on GitHubIntegracja z GitHubem
W przeciwieństwie do integracji typu notify (webhook) i import (pull) opisanych w innych przewodnikach z tej kategorii, GitHub to trzeci rodzaj: instalacja GitHub App, połączona przez mały publiczny serwis relay, która łączy pull request z issue w Orbicie. Ten przewodnik dokumentuje faktyczną funkcję — architekturę, jak połączyć projekt, składnię znacznika i rozwiązywanie problemów — a nie "jak dodać kolejną", ponieważ GitHub jest jedyną integracją tego rodzaju.
Po co relay
Orbit jest self-hosted, więc typowa instancja Orbit Local nie jest
publicznie dostępna — GitHub nie może dostarczyć webhooka bezpośrednio
do niej. orbit-api (mały, osobno hostowany serwis Netlify Functions,
domyślnie api.orbit-dev.app) istnieje po to, żeby połączyć tę lukę:
GitHub --webhook--> orbit-api <--poll-- Orbit Local --żądanie komentarza--> orbit-api --API GitHub App--> GitHub
- GitHub wysyła webhook
pull_requestdo orbit-api, gdy PR zostaje otwarty. - orbit-api weryfikuje podpis webhooka i zapisuje go jako oczekujący "event relay", przypisany do połączenia danego projektu.
- Orbit Local odpytuje orbit-api raz na minutę (
PollGithubRelayEvents, zaplanowane wroutes/console.php) o oczekujące eventy. - Dla każdego eventu Orbit Local parsuje treść PR-a w poszukiwaniu
znacznika
<!-- orbit-issue:ID -->, rozwiązuje issue i zapisuje powiązanie. - Orbit Local prosi orbit-api o dodanie komentarza potwierdzającego na PR-ze, używając tokenu instalacji GitHub App należącego do orbit-api — Orbit Local nigdy sam nie posiada tokenu GitHuba ani klucza prywatnego GitHub App.
- Orbit Local potwierdza (ACK) event, co usuwa go z kolejki oczekujących.
Autorytatywnym źródłem kontraktu API jest sam kod orbit-api; ten przewodnik opisuje wyłącznie stronę Orbit Local.
Przechowywanie lokalne
Nie ma dedykowanej tabeli dla połączenia z GitHubem — rozszerza ono
ten sam wiersz project_integrations, którego używa każda inna
integracja (zobacz zasadę "nigdy nie dodawaj schematu specyficznego
dla integracji" z przewodnika 05IntegracjeDodaj integrację typu importPrzećwiczony przykład: zamiana Linear z zablokowanej karty "coming soon" w katalogu w w pełni działającą integrację typu import, dokładnie tak, jak dziś dz…),
z kolumnami specyficznymi dla GitHuba (github_status,
github_relay_token, github_installation_id,
github_repository_owner/github_repository_name itd.) dodanymi przez
migrację. github_relay_token jest szyfrowany at rest (cast
'encrypted' na App\Models\ProjectIntegration) i nigdy nie trafia do
żadnego propsa Inertii — strona ustawień otrzymuje wyłącznie mały DTO
statusu (GithubIntegrationService::getConnectStatus()).
Samo powiązanie PR ↔ issue korzysta z external_issue_links (tej samej
tabeli, której używa integracja importu z Jiry do deduplikacji),
oznaczonej external_type = 'github_pull_request'. Jej unikalny
constraint na (project_integration_id, external_id) — gdzie
external_id to własny numeryczny identyfikator pull requesta z
GitHuba — sprawia, że ponowne połączenie tego samego PR-a (np. przy
ponowionym evencie relay) jest idempotentne zamiast tworzyć duplikat
wiersza.
Zmienne środowiskowe
ORBIT_API_URL=https://api.orbit-dev.app
Ustawiane w .env/.env.example i odczytywane przez
config('services.orbit_api.url') (config/services.php) — nigdy nie
zaszywaj tego URL-a na sztywno w serwisie. Wskaż tutaj self-hostowaną
instancję orbit-api, jeśli nie korzystasz z domyślnej.
Łączenie projektu
- Ustawienia projektu → Integracje → GitHub → Connect with GitHub.
- Orbit Local prosi orbit-api o utworzenie połączenia
(
GithubIntegrationService::connect()), zapisuje identyfikator połączenia i token relay (zaszyfrowany) oraz otwiera zwrócony URL instalacji GitHub App w nowej karcie. - Strona ustawień odpytuje w tle (
WorkspaceSettingsIntegrationsTab, co ~2 sekundy, rezygnując po 5 minutach), dopóki połączenie jest w staniepending. - Gdy instalacja GitHub App zakończy się i wybrane zostanie dokładnie
jedno repozytorium, orbit-api oznacza połączenie jako
connected; kolejne odpytanie to wychwytuje i UI pokazuje połączone repozytorium.
Disconnect unieważnia połączenie w orbit-api i oznacza lokalny
wiersz jako revoked — nie odinstalowuje GitHub App z organizacji na
GitHubie (zobacz ograniczenia).
Składnia znacznika
Jedynym wspieranym sposobem powiązania pull requesta z issue w Orbicie jest ukryty znacznik w opisie PR-a:
<!-- orbit-issue:213769 -->
- Brak znacznika → event jest ignorowany (potwierdzany, bez ponawiania).
- Dokładnie jeden znacznik → dane issue jest rozwiązywane i łączone, o ile należy do tego samego projektu w Orbicie, z którym połączona jest integracja GitHub. Issue z innego projektu nigdy nie zostanie powiązane.
- Dwa lub więcej znaczników → traktowane jako niejednoznaczne. Nic nie zostaje powiązane, a niejednoznaczność jest logowana diagnostycznie. To wynik trwały, a nie przejściowy błąd — event i tak zostaje potwierdzony (ACK).
Nie ma żadnego fallbacku: brak parsowania tytułu, brancha czy
wiadomości commitów. Zobacz
App\Services\Integrations\Github\GithubMarkerParser.
Semantyka potwierdzania (ACK)
Event zostaje potwierdzony (usunięty z kolejki oczekujących), gdy
GithubRelayEventProcessor::process() zwróci wynik bez rzucenia
wyjątku — obejmuje to zarówno udane powiązanie, jak i każdy z
powyższych trwale-nieprawidłowych przypadków (brak znacznika,
niejednoznaczność, brak issue, zły projekt, nieobsługiwany
event/akcja). Błąd przejściowy — niedostępne orbit-api, nieudane
żądanie komentarza, błąd bazy danych — powoduje, że process() rzuca
wyjątek, a PollGithubRelayEvents celowo nie potwierdza w takim
przypadku eventu: pozostaje on oczekujący i zostanie ponowiony przy
kolejnym odpytaniu. Nie ma osobnej infrastruktury kolejki ponowień —
mechanizmem ponawiania jest sam stan "oczekujący" po stronie relay.
Ograniczenia MVP
- Obsługiwany jest wyłącznie
pull_request.opened— edycje, zamknięcia, merge'e, review'y i CI/check runs nie są synchronizowane. - Jedno połączenie z GitHubem na projekt w Orbicie, jedno repozytorium na połączenie i jedno issue w Orbicie na pull request.
- Brak automatyzacji statusu: powiązanie PR-a nigdy nie zmienia statusu issue ani go nie zamyka.
- Brak synchronizacji komentarzy w żadną stronę poza pojedynczym komentarzem potwierdzającym, który orbit-api publikuje raz.
- Rozłączenie w Orbicie nie odinstalowuje GitHub App z GitHuba — tylko sprawia, że Orbit Local przestaje ufać temu połączeniu.
Rozwiązywanie problemów
Połączenie utknęło na "pending" — instalacja GitHub App nigdy nie została ukończona albo ukończono ją z zerem lub więcej niż jednym wybranym repozytorium (orbit-api wymaga dokładnie jednego). Otwórz ponownie stronę instalacji z panelu integracji i spróbuj jeszcze raz.
Połączenie pokazuje "revoked" i nie da się połączyć ponownie — kliknij ponownie Connect with GitHub; zawsze tworzy to zupełnie nowe połączenie w orbit-api zamiast próbować wznowić stare.
PR nie zostaje powiązany — sprawdź, czy znacznik ma dokładnie
postać <!-- orbit-issue:ID --> z numerycznym id, występuje dokładnie
raz w opisie PR-a, a identyfikator issue należy do tego samego
projektu w Orbicie, co połączone repozytorium. Sprawdź też, czy status
połączenia to connected, a nie pending.
Eventy się nie przetwarzają — upewnij się, że scheduler faktycznie
działa (procesy queue/schedule z composer dev albo wpis crona w
produkcji dla php artisan schedule:run); PollGithubRelayEvents
uruchamia się raz na minutę tylko wtedy, gdy coś wywołuje scheduler
Laravela.
Uwagi bezpieczeństwa
- Orbit Local posiada wyłącznie token relay orbit-api — nigdy nie otrzymuje ani nie przechowuje tokenu GitHuba ani klucza prywatnego GitHub App. Te sekrety żyją wyłącznie w orbit-api.
- Orbit Local nigdy nie wywołuje bezpośrednio REST API GitHuba; wszystkie akcje wymagające uwierzytelnienia w GitHubie (publikacja komentarza potwierdzającego) są proxowane przez orbit-api przy użyciu jego własnego tokenu instalacji GitHub App.
github_relay_tokenjest szyfrowany at rest i nigdy nie jest logowany ani wysyłany na frontend.
