Files

5.7 KiB

Migration Gogs → Gitea (figureslibres.io)

Scripts utilisés pour migrer les dépôts d'une instance Gogs vers une instance Gitea sur le même serveur (YunoHost), en conservant les propriétaires d'origine.

Portée volontairement limitée à :

  • les dépôts git (branches, tags, historique complet) ;
  • les collaborateurs (contributeurs) de chaque dépôt ;
  • les webhooks ;
  • les dates de création/mise à jour affichées.

Explicitement hors scope : issues, wiki, labels, milestones, releases, pull requests. Les webhooks pointant vers des services internes avec secret non exposé par l'API (ex: Kanboard) sont exclus par défaut.

Contexte

Gogs et Gitea tournent tous les deux en local sur le même serveur (loopback, 127.0.0.1), ce qui permet de scripter la migration sans jamais passer par les domaines publics ni par le SSO. Le script part du principe que les comptes utilisateurs (individus) sont déjà identiques des deux côtés (ex: synchronisés via un LDAP commun) — il ne crée jamais de compte utilisateur automatiquement. Les organisations, en revanche, peuvent être créées automatiquement si absentes.

Pièges rencontrés (et déjà gérés par le script)

  • L'authentification HTTP Basic Auth de l'API Gogs est cassée sur cette instance (401 identique avec de bons ou de mauvais identifiants) → l'API Gogs s'utilise donc avec un token, jamais avec login/mot de passe.
  • GET /api/v1/repos/search de Gogs ne fait pas une vraie recherche site-wide, même avec un compte admin : il ne renvoie que les dépôts publics + ceux du compte du token. La découverte se fait donc propriétaire par propriétaire (/users|orgs/{login}/repos), en partant de la liste des comptes connus côté Gitea.
  • Les dépôts privés d'un propriétaire n'apparaissent dans cette liste que si le compte utilisé par le script a explicitement accès au dépôt (ajouté comme collaborateur) — l'admin ne "voit" pas tout par magie via cet endpoint.
  • GET /api/v1/orgs/{login} de Gogs ne vérifie pas le type : il renvoie 200 pour n'importe quel login existant, user ou org. La détection des vraies organisations se fait donc en scrapant /explore/organizations, pas via cet endpoint.
  • Le service "gogs" de l'API /repos/migrate de Gitea interroge d'abord l'API Gogs et récupère son clone_url public, qui repasse par le mur SSO et fait échouer le clonage. Le script utilise le service générique "git" à la place, qui clone brutalement l'adresse fournie (le loopback), sans ce détour.
  • ALLOW_LOCALNETWORKS doit être activé côté Gitea (app.ini, section [migrations]) pour autoriser une migration dont la source est une adresse locale/loopback (protection anti-SSRF activée par défaut).
  • Un compte de service synchronisé LDAP se fait périodiquement réécraser son statut admin par la resynchronisation. Utiliser un compte local (pas LDAP) pour le compte de service du script, des deux côtés (Gogs et Gitea).
  • L'API Gitea n'expose aucun moyen d'éditer created_at/updated_at d'un dépôt existant. fix_creation_dates.py compare les dates via les deux API (lecture seule) et génère un script SQL à exécuter soi-même après vérification du schéma et sauvegarde de la base.

Prérequis

  • Python 3 + pip install requests
  • git installé
  • Un token API Gogs admin (Gogs → Settings → Applications → Generate New Token)
  • Un compte Gitea admin local (pas LDAP) avec mot de passe

Configuration

cp config.env.example config.env
# éditer config.env et renseigner les valeurs -- ce fichier ne doit JAMAIS être commité

Utilisation

migrate_gogs_to_gitea.py — dépôts, collaborateurs, webhooks

Toujours en dry-run par défaut (rien n'est écrit) :

python3 migrate_gogs_to_gitea.py                          # dry-run, tous les dépôts
python3 migrate_gogs_to_gitea.py --only owner/repo         # dry-run, un seul dépôt
python3 migrate_gogs_to_gitea.py --limit 3                 # dry-run, 3 premiers dépôts
python3 migrate_gogs_to_gitea.py --apply --only owner/repo # exécution réelle, ciblée
python3 migrate_gogs_to_gitea.py --apply                   # exécution réelle, tout

Un dépôt déjà présent côté Gitea n'est jamais recréé ni écrasé — seuls les collaborateurs, webhooks et le topic migrated-from-gogs peuvent être complétés.

Vérifier l'historique git des dépôts déjà migrés à la main

Compare les branches/tags Gogs vs Gitea des dépôts déjà présents (lecture seule) :

python3 migrate_gogs_to_gitea.py --verify-existing

Ajoute les refs totalement absentes côté Gitea (jamais les branches divergentes, jamais de --force) :

python3 migrate_gogs_to_gitea.py --verify-existing --apply

fix_creation_dates.py — dates de création/mise à jour

Ne se connecte jamais à la base de données. Compare via les deux API (lecture seule) et génère un script SQL à vérifier puis exécuter soi-même :

python3 fix_creation_dates.py                       # tous les dépôts communs
python3 fix_creation_dates.py --only owner/repo      # un seul dépôt (test)

Avant d'exécuter le fix_dates.sql généré :

  1. Vérifier le nom des colonnes (DESCRIBE repository;) — created_unix / updated_unix sont les noms standards des versions récentes de Gitea, mais à confirmer sur la version en place.
  2. Faire une sauvegarde de la table repository (ou de la base entière).
  3. Exécuter avec le nom de la base en argument :
    mysql -u USER -pMOTDEPASSE NOM_BASE < fix_dates.sql
    
    (le script valide lui-même avec un COMMIT; en fin de fichier)