Soportar forks, para que alguien que no sea el dueño pueda abrir pull requests #3
Hoy nadie externo puede contribuir, y no por falta de un botón: no hay ningún lugar donde dejar una rama.
CanPush(repo_service.go:72) esviewer.ID == repo.OwnerID. Cualquier otro push da 403.- Los PRs son entre dos ramas del mismo repo:
pull_requeststienerepo_id,base_branch,head_branch, sin noción de un repo de origen distinto.
Los permisos ya son los correctos
No hay que tocar la autorización: un fork le pertenece a quien lo forkea, así que
CanPush(fork, forkeador) ya da true, y CanMergePR ya es "solo el dueño del base".
El trabajo está en el modelo de datos, git y la UI.
Las mecánicas funcionan (probado)
Todos los bare viven en el mismo filesystem, así que traer los objetos del fork es un
fetch por ruta, sin red ni auth:
git clone --bare upstream.git fork.git # el fork
git push -u origin feature # el forkeador, a SU bare
git fetch /ruta/al/fork.git feature # el upstream mergea
git merge --no-ff FETCH_HEAD && git push origin main
--shared deja el fork casi sin ocupar espacio, pero no en v1: si el upstream corre
git gc y poda objetos que solo el fork referencia, el fork se rompe.
Qué cambia
Esquema
repositories:fork_of_id INTEGER NULL.pull_requests:head_repo_id INTEGER NOT NULL, backfill= repo_id.
Código
GitReader.Compare(ports.go:49) recibe un soloowner, name. La parte más delicada: go-git necesita los dos commits en la misma base de objetos para el merge-base, así que hay que registrar el fork como alternate o traer objetos antes.GitService.Merge: demerge origin/<head>alfetchpor ruta de arriba.PullService.Open: validarheadcontra el repo de origen, no contra el base.RepoService.Fork+CloneBareenGitService.
UI
- Compare cruzado
?head=usuario:rama; hoyheades un query param plano (pull_handler.go:65). - Botón de fork, y head como
dueño:ramaen el detalle del PR.
Visibilidad: decidirlo explícito
Es donde esto filtra código privado. Un fork privado de un repo público, al abrir un PR,
le muestra su diff al dueño del base. Regla simple para v1: el origen tiene que ser al
menos tan visible como el base. Y CanView devuelve 404 y no 403 a propósito, está
fijado por tests: un PR con origen invisible no puede filtrar ni el nombre de la rama.
Bloqueante
Borrar un fork con PRs abiertos deja un head_repo_id colgando: RepoRepo.Delete es un
DELETE pelado y las FK no se aplican (ver issue de PostgreSQL). Resolver eso antes.
Aceptación
La matriz de permisos ya cubierta por tests tiene que seguir pasando sin cambios, más: el forkeador pushea a su fork pero no al base (403); el dueño del base mergea un PR de un fork y el autor no; un fork de un repo privado es 404 para terceros.
Sign in to comment.