# Git et déploiement automatique

Bastide construit à partir d'un dépôt Git. Cette page explique comment raccorder vos comptes GitHub à une organisation, quelle branche part en production, comment une poussée se met en ligne d'elle-même, comment déclencher un déploiement depuis un autre outil par un crochet, et ce que le fichier `glowsoft.json` de votre dépôt peut déclarer.

## Les concepts

- **Dépôt du projet** : l'adresse Git que le projet construit, en `https://`, `ssh://` ou `git://`. Elle se règle à la création, ou plus tard dans **Réglages** du projet, section « Source et construction », champ « Dépôt Git ».
- **Raccordement GitHub** : l'installation de l'application GitHub de Bastide sur un compte GitHub (personnel ou organisation), rattachée à votre organisation Bastide. Elle ouvre les dépôts privés que vous lui avez choisis et fait arriver les poussées.
- **Branche de production** : la seule branche dont une poussée part en production.
- **Crochet de déploiement** : une adresse signée qu'un autre outil appelle pour déployer une branche dans un environnement.

## Raccorder GitHub

Le raccordement se fait au niveau de l'organisation, au rang Administrateur (`admin`).

1. Ouvrez **Réglages** de l'organisation, carte « GitHub », ou cliquez « + Raccorder un compte GitHub » sur **Nouveau projet**.
2. Cliquez « Installer l'application ». GitHub vous demande sur quel compte l'installer, et quels dépôts lui ouvrir.
3. GitHub vous ramène à la console avec un code à usage unique (valable dix minutes). La console l'émet une seule fois, puis l'efface de l'adresse. Si vous êtes parti de **Nouveau projet**, vous y revenez.

La carte liste ensuite chaque compte raccordé, son genre (« Organisation GitHub » ou « Compte personnel »), sa date et son état. Sur **Nouveau projet**, les dépôts que vos raccordements ouvrent s'affichent du dernier poussé au plus ancien (300 au plus) : vous choisissez au lieu de recopier une adresse.

Ce que fait le raccordement :

- Chaque construction d'un dépôt privé reçoit un jeton frappé pour elle, limité à ce dépôt et à la lecture. Aucun jeton n'est conservé.
- Les poussées et les demandes de fusion du dépôt arrivent à la plateforme, signées par GitHub.
- La plateforme publie l'état de chaque déploiement sur son commit, et tient un commentaire unique sur chaque demande de fusion.

« Retirer » défait un raccordement : il reste à la liste, daté et signé, et les constructions suivantes des dépôts de ce compte se font sans identifiants, si bien qu'un dépôt privé ne se récupère plus. L'application reste installée chez GitHub : la désinstaller se fait là-bas.

Les opérations correspondantes, réservées à une personne et absentes du catalogue MCP, sont [`organization.github_connection.list`](../reference/operations/organization.github_connection.list.md), [`organization.github_connection.create`](../reference/operations/organization.github_connection.create.md), [`organization.github_connection.revoke`](../reference/operations/organization.github_connection.revoke.md) et [`organization.github_repository.list`](../reference/operations/organization.github_repository.list.md).

### Ce que l'application peut faire chez vous

Le périmètre est publié et ne demande aucune administration de dépôt :

| Droit | Niveau | Pourquoi |
| --- | --- | --- |
| Métadonnées | lecture | Connaître le dépôt : nom, branche par défaut, visibilité. |
| Contenus | lecture | Cloner le commit à construire. Rien n'est poussé. |
| Demandes de fusion | écriture | Poser puis tenir à jour le commentaire unique d'une demande. |
| Statuts de commit | écriture | Publier l'état de chaque déploiement sur son commit. |
| Crochets | écriture | Recevoir les poussées et les demandes de fusion. |

Un droit sur option s'y ajoute seulement pour un projet qui l'active : pousser, sur une branche `bastide/…` créée par la plateforme, la migration qui corrige la posture de sécurité de la base, puis en ouvrir la demande de fusion. Jamais la branche principale ; vous relisez et fusionnez.

### Les autres forges

Un dépôt GitLab, Forgejo, Gitea ou tout serveur Git joignable se construit par son adresse. Pour un dépôt privé, l'adresse peut porter ses identifiants : ils ne sont jamais réaffichés, et il faut les ressaisir si vous changez l'adresse. En revanche, le crochet qui annonce les poussées de ces forges ne se pose encore ni depuis la console ni par l'API : pour déployer à chaque poussée depuis elles, appelez un crochet de déploiement (plus bas) depuis votre intégration continue.

## La branche de production et le déploiement à chaque poussée

Sans configuration, la branche par défaut du projet part en production à chaque poussée, et aucune autre branche ne déploie. La branche par défaut se règle dans **Réglages** du projet, section « Source et construction », champ « Branche de production ». La changer décide de la prochaine poussée ; la version en service ne change pas.

Pour envoyer d'autres branches ailleurs, déclarez-le dans `glowsoft.json` (voir plus bas). À la réception d'une poussée :

1. La plateforme lit `glowsoft.json` à la pointe de la branche par défaut, jamais au commit poussé : une branche ne décide pas de son propre sort.
2. Elle cherche où la branche atterrit : la branche de production d'abord, par égalité exacte ; puis les motifs, dans l'ordre, le premier qui correspond gagnant.
3. Une branche qui n'atterrit nulle part ne déploie rien.
4. Sinon, un déploiement est mis en file sur l'environnement visé. Deux livraisons du même commit retombent sur le même déploiement.

Une demande de fusion ouverte depuis une branche qu'aucune règle ne nomme reçoit sa [prévisualisation](previews.md). Une demande issue d'une bifurcation ne se construit qu'après l'autorisation d'un membre.

### Les monorepos

Dans **Réglages** du projet, section « Source et construction » :

- « Racine du projet » : le dossier du dépôt à construire, relatif à sa racine. Vide, la racine du dépôt.
- « Chemins inclus » : les chemins hors de la racine à faire entrer dans la construction, un par ligne.

Avec `"build": { "skipUnaffected": true }` dans `glowsoft.json`, une poussée qui ne touche pas le projet est « Sauté » : ni place de construction, ni minute consommée.

## Crochets de déploiement

Un crochet est une adresse que vous appelez pour déployer, depuis un gestionnaire de contenu, une tâche planifiée ou une autre chaîne d'intégration. Il ne demande ni compte ni jeton : chaque appel est signé.

- Il est lié à un couple branche-environnement, choisi à sa création, et n'en déploie aucun autre.
- Un projet en porte vingt en vigueur au plus.
- Son secret (`dhsec_…`) n'est montré qu'une fois, à la création.
- Il se révoque seul, sans toucher aux autres.

### Créer et révoquer un crochet

Dans la console, la carte « Crochets de déploiement » se trouve sur **Webhooks** et dans **Réglages** du projet, section « Crochets et cache ». Choisissez l'environnement, la branche et « À quoi il sert », puis copiez le secret affiché. La création demande le rang mainteneur (`maintainer`) et une personne : c'est l'opération [`deployment.hook.create`](../reference/operations/deployment.hook.create.md), hors du catalogue MCP. Un agent lit les crochets par `webhook_list` et en révoque un par `deployment_hook_revoke`.

### Appeler un crochet

`POST https://api.bastide.app/v1/deploy-hooks/<identifiant dhk_…>`, avec l'en-tête `Bastide-Signature: t=<secondes Unix>,v1=<hex>`, où `v1` est le HMAC-SHA256 du secret sur `<t>.<corps>`. Le corps est vide ou un objet JSON ; `branch` et `environmentId`, s'ils y sont, doivent désigner le couple du crochet.

```sh
t=$(date +%s)
corps='{}'
sig=$(printf '%s.%s' "$t" "$corps" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')
curl -X POST "https://api.bastide.app/v1/deploy-hooks/$CROCHET" \
  -H "Bastide-Signature: t=$t,v1=$sig" -H 'content-type: application/json' -d "$corps"
```

Un appel accepté rend `202` et `deploymentId`. Si un déploiement de la même branche, avec les mêmes variables, est déjà en cours, c'est lui qui est rendu (`deduplicated: true`).

| Statut | Code | Sens |
| --- | --- | --- |
| 403 | `signature_invalide` | Signature fausse, ou crochet inconnu, révoqué, ou environnement disparu : la réponse est la même. |
| 403 | `horodatage_perime` | `t` est à plus de cinq minutes de l'horloge de la plateforme. |
| 403 | `couple_refuse` | Le corps vise une autre branche ou un autre environnement. |
| 429 | `plafond_de_declenchements` | Soixante déclenchements dans l'heure glissante, pour le projet. Lire `Retry-After`. |
| 409 | `quota_de_construction_atteint` | Le quota mensuel de minutes est atteint. |

## Configurer dans le dépôt : glowsoft.json

Un fichier `glowsoft.json` à la racine du dépôt décrit ce que le dépôt décide lui-même. Il est facultatif, lu à la pointe de la branche par défaut, et pèse 64 Kio au plus. Un champ inconnu ou non appliqué est refusé en le nommant, jamais ignoré.

```json
{
  "version": 1,
  "branches": {
    "production": "main",
    "patterns": [
      { "pattern": "develop", "environment": "staging" },
      { "pattern": "feat/**", "environment": "preview" }
    ]
  },
  "probe": { "path": "/sante", "startupBudgetSeconds": 90 },
  "build": { "skipUnaffected": true }
}
```

| Champ | Ce qu'il déclare |
| --- | --- |
| `version` | Requis, vaut `1`. |
| `branches` | `production`, une chaîne unique ; `patterns`, 32 règles au plus, chacune un motif et un environnement. `preview` donne une prévisualisation par branche. |
| `probe`, `port` | La sonde de santé et le port d'un `Dockerfile` fourni : voir [Cadriciels](frameworks.md). |
| `services`, `crons` | Les services et les tâches planifiées : voir [Cadriciels](frameworks.md) et [Tâches planifiées](cron.md). |
| `requests` | Délai de garde d'une requête (30 à 3 600 s, 300 par défaut) et corps maximal (jusqu'à 5 120 Mio, 100 par défaut). |
| `redirects`, `headers`, `rewrites` | Les règles de l'edge, sous la forme de `vercel.json`, 2 048 au plus par bloc : voir [Routage](routing.md). |
| `comments` | `enabled: false` retire le commentaire des demandes de fusion ; `exclude` le retire pour certaines branches. |
| `build` | `skipUnaffected` pour un monorepo. |
| `linkedProjects` | Jusqu'à dix projets de la même organisation, dont l'adresse est injectée dans une variable. |

Les règles des motifs : caractères `A-Z a-z 0-9 . _ / * + -` ; `*` dans un segment, `**` sur un segment entier ; quatre jokers au plus. Un motif ne peut pas viser `production`, deux motifs ne peuvent pas viser le même environnement durable (seul `preview` l'admet), et un motif placé après `**` est refusé car jamais atteint.

Sont refusés en se nommant : `rootDirectory`, `outputDirectory`, `installCommand`, `buildCommand`, `framework`, `nodeVersion`, `volumes` et `env`. Les variables d'environnement ne se déclarent jamais dans un fichier versionné : voir [Environnements et variables](environments.md).

## Erreurs fréquentes

| Code | Remède |
| --- | --- |
| `declaration_refusee` | `glowsoft.json` est invalide ou déclare plus de services ou de tâches que le palier n'en permet. Corriger le fichier sur la branche par défaut. |
| `config_illisible` | Le fichier n'a pas pu être lu à la pointe de la branche par défaut : vérifier que le dépôt répond. |
| `reference_introuvable` | La branche, l'étiquette ou le commit demandé n'existe pas au dépôt. |
| `fetch_failed` | Le dépôt n'a pas pu être récupéré : dépôt privé auquel le raccordement GitHub n'ouvre pas l'accès, ou adresse fausse. Cochez le dépôt dans l'application GitHub, puis redéployez. |
| `remote_host_refused` | L'hôte du dépôt ne résout pas, ou vers une adresse privée : la plateforme ne joint que des hôtes publics. |
| `root_directory_missing` | La « Racine du projet » n'existe pas dans le dépôt à ce commit. |

Un raccordement dont l'installation a été retirée chez GitHub apparaît comme injoignable : refaites-le depuis la carte « GitHub ».

Voir aussi : [Déployer](deploy.md), [Prévisualisations](previews.md), [Cadriciels](frameworks.md), [Routage](routing.md), [Webhooks](webhooks.md), [Organisations](organizations.md).
