Capability : git
Implémentez l’hébergement git — les credentials avec lesquels une sandbox clone, les sélecteurs de dépôt, les push au nom du membre, et le statut de la pull request à côté d’une tâche.
git, c’est là où vivent les dépôts d’un projet. Elle est résolue par dépôt : un projet peut mélanger deux forges, et c’est le propriétaire de chaque dépôt (acme dans acme/api) qui décide quelle installation répond.
Seule cloneCredential est obligatoire. Une forge qui sait cloner et rien d’autre est une app git complète ; chaque autre opération débloque une chose de plus dans le dashboard.
| Opération | Obligatoire | Débloque | Agit au nom de |
|---|---|---|---|
cloneCredential | Oui | Les sandboxes et les tâches clonent des dépôts privés | L’organisation |
listRepos | Le sélecteur de dépôt dans le formulaire du projet | L’organisation | |
listBranches | Choisir une branche, connaître celle par défaut | L’organisation | |
userCredential | Les push depuis une sandbox attribués au membre qui la possède | Le membre — exige un grant | |
registerUserSshKey | Enregistrer la clé SSH d’un membre sur son propre compte | Le membre — exige un grant | |
pullRequestForBranch | La carte de la pull request à côté du diff d’une tâche | L’organisation |
Les dépôts sont toujours nommés owner/name.
Une sandbox clone au nom de l’organisation : elle récupère donc son code même si le membre qui l’a démarrée n’a jamais rien connecté. Tout ce qui suit — fetch, push — se fait au nom du membre qui possède la sandbox : git interroge un credential helper dans la sandbox, qui interroge Spunto, qui appelle votre userCredential avec le userId de ce membre. Un push qui porte le nom de quelqu’un doit venir de sa propre autorisation ; un credential d’installation ne peut pas en tenir lieu.
C’est pourquoi userCredential et registerUserSshKey vont dans les userGrantOperations de votre manifeste, et échouent avec grant_required quand le membre n’a pas autorisé votre app.
Un credential de courte durée avec lequel une sandbox clone. Appelée une fois par propriétaire de dépôt à la mise en place d’une sandbox — le credential est réutilisé pour tous les dépôts de ce propriétaire dans le projet.
// input
{ "repo": "acme/api", "repos": ["acme/api", "acme/web"] }
// result
{ "scheme": "https-token", "username": "x-access-token", "token": "…", "expiresInSeconds": 3600 }reposliste tous les dépôts du projet qui ont le même propriétaire. Restreignez le token à ceux-là, en lecture seule, si votre forge le permet : il finit dans le setup de la sandbox, lisible par quiconque peut ouvrir cette sandbox.- Si certains sont hors de portée de l’installation, émettez-en un pour ceux qui sont accessibles plutôt que de tous les faire échouer ; n’échouez avec
not_foundque si aucun ne l’est. schemevauthttps-token— git s’authentifie avecusernameettokenen HTTPS.
// input
{}
// result
{ "repos": [{ "fullName": "acme/api", "name": "api", "private": true, "defaultBranch": "main" }] }Tous les dépôts que l’installation de l’organisation peut atteindre. Si elle a plusieurs installations et que l’une est injoignable, renvoyez les autres.
// input
{ "repo": "acme/api" }
// result
{ "branches": ["main", "feat/login"], "defaultBranch": "main" }// input — userId in the envelope is the member to act as
{ "repo": "acme/api" }
// result
{ "username": "x-oauth-token", "password": "…", "expiresAt": "2026-10-28T15:00:00Z" }Remis à git au moment où il le demande, jamais écrit sur le disque. expiresAt peut valoir null si le credential n’expire pas. Rafraîchissez vous-même l’autorisation du membre si les tokens de votre forge expirent ; si elle ne peut pas être rafraîchie, échouez avec grant_required pour qu’on lui demande d’autoriser à nouveau.
// input
{ "publicKey": "ssh-ed25519 AAAA…", "title": "Spunto" }
// result
{ "keyId": 81723 }Enregistre la clé sur le propre compte du membre. Un nouvel appel doit remplacer la clé enregistrée précédemment, pas en ajouter une de plus.
Ce que regarde d’un coup d’œil la personne qui relit avant d’ouvrir la pull request — affiché à côté du diff d’une tâche.
// input
{ "repo": "acme/api", "branch": "task/fix-login-a1b2c3" }
// result
{
"pullRequest": {
"label": "#262",
"url": "https://git.acme.dev/acme/api/pulls/262",
"title": "Fix the login redirect",
"state": "open",
"branch": "task/fix-login-a1b2c3",
"baseBranch": "main",
"checks": "passing",
"review": "pending",
"comments": 3,
"updatedAt": "2026-10-28T14:02:11Z"
}
}pullRequest vaut null quand rien n’est ouvert pour la branche. state vaut draft, open, merged ou closed ; checks, pending, passing ou failing ; review, approved, changes-requested ou pending. Chaque champ après state peut valoir null, et null signifie votre forge ne le dit pas — une forge sans CI renvoie "checks": null, que le dashboard affiche autrement que des checks qui n’ont pas encore tourné.