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/searchde 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 renvoie200pour 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/migratede Gitea interroge d'abord l'API Gogs et récupère sonclone_urlpublic, 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_LOCALNETWORKSdoit ê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_atd'un dépôt existant.fix_creation_dates.pycompare 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 gitinstallé- 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é :
- Vérifier le nom des colonnes (
DESCRIBE repository;) —created_unix/updated_unixsont les noms standards des versions récentes de Gitea, mais à confirmer sur la version en place. - Faire une sauvegarde de la table
repository(ou de la base entière). - Exécuter avec le nom de la base en argument :
(le script valide lui-même avec un
mysql -u USER -pMOTDEPASSE NOM_BASE < fix_dates.sqlCOMMIT;en fin de fichier)