Les coulisses du passage en open source de Cap Collectif #3

7 min de lecture.

Si vous n'avez pas encore lu la partie 2, rendez-vous ici.

Comme nous l'avons vu, les développeurs de Cap Collectif travaillent depuis plus de 7 ans sur un dépôt Git privé sur GitHub qui s'appelle cap-collectif/platform. Nous avons désormais réécrit l'historique complet du code, donc en théorie, nous pourrions basculer en open source directement en modifiant la visibilité sur GitHub…

Cependant nous avons choisi de ne pas rendre open source le dépôt Git utilisé en interne par Cap Collectif, pour plusieurs raisons :

Premièrement celui-ci contient tout notre historique de travail (des milliers d'issues, de Pull Requests, etc.) ce qui représente une énorme quantité de données, donc à nouveau des risques de sécurité.

Deuxièmement, l'intégration continue de Cap Collectif utilise plusieurs services tiers (comme des SSO), ainsi que des bases de données (pour vérifier les migrations de données) que nous ne souhaitons pas exposer au public. L'intégration continue du dépôt privé assure également le bon fonctionnement de notre infrastructure de production, qui n'a, elle, pas vocation à être open source. De plus, ne pas exposer cette intégration continue nous permet aussi de maîtriser à 100% son coût, en limitant les risques d'exploitation par des tiers.

Enfin, nous souhaitions conserver une bonne ambiance de travail, sans que tout notre code, nos idées, réactions et commentaires de recette soient instantanéments rendus public. Cette approche nous permet aussi de limiter les risques de problèmes de sécurité, suite à une erreur humaine.

Globalement, l'objectif de Cap Collectif est de basculer en open source, en impactant le moins possible le quotidien des équipes techniques, design et QA qui contribuent majoritairement au développement du produit.

Nous avons donc fait le choix de rendre publique un second dépôt Git, qu'on a appelé cap-collectif/cap-collectif. Celui-ci sera intégralement open source et contiendra 100% du code qui permet à une plateforme Cap Collectif de fonctionner. Voyons comment nous avons mis ça en place !

La publication d'un dépôt open source

Pour publier un second dépôt Git, on va devoir automatiser un processus de synchronisation.

Il existe plusieurs outils permettant de synchroniser 2 dépôts Git. Nous avons choisi d'utiliser Copybara, un outil open source, développé et utilisé en interne par Google.

Le principe est de définir un dépôt source de vérité (origin), dont on va synchroniser la branche principale vers un autre dépôt (destination).

Notre dépôt interne sera donc la source de vérité et le dépôt open source, la destination.

Une configuration typique pour le mettre en place est similaire à celle-ci :

core.workflow(
    name = "push",
    origin = git.origin(
        url = "https://github.com/cap-collectif/platform",
        ref = "master",
    ),
    destination = git.github_destination(
        url = "https://github.com/cap-collectif/cap-collectif",
        push = "main",
    )
)

Pour faire en sorte que chaque nouveau commit sur le dépôt interne soit synchronisé automatiquement et instantanément, nous avons mis en place une Github Action qui lance Copybara.

Celle-ci nous permet de paramétrer en yaml :

# .github/workflows/oss-sync.yml
on:
  push:
    branches:
      - 'master'
jobs:
  move-code:
    runs-on: ubuntu-latest
    # initial synchronisation can take some time, so we increase timeout
    timeout-minutes: 1200
    steps:
      - uses: actions/checkout@v3
        with:
          # We only need the branch used as source of truth
          ref: master
          # We need to fetch all history of commits for copybara
          fetch-depth: 0

      - uses: olivr/copybara-[email protected]
        with:
          ssh_key: ${{ secrets.SSH_KEY }}
          access_token: ${{ secrets.GH_TOKEN }}
          sot_repo: cap-collectif/platform
          sot_branch: master
          destination_repo: cap-collectif/cap-collectif
          destination_branch: main

On configure l'action pour qu'elle s'exécute à chaque nouveau commit sur la branche principale (ici master) et qu'elle lance ensuite Copybara, il n'y a donc que les commits qui ont été mergés qui seront publiés en open source.

Pour synchroniser, notre dépôt interne doit disposer des droits d'écriture vers le dépôt open source, pour cela il faut créer une clé de déploiement avec les droits d'écriture, qu'on ajoute en secret au dépôt interne via SSH_KEY.

Synchroniser l'intégralité de l'historique Git

Lors de la synchronisation initiale, par défaut copybara ne copie que le premier parent. Cela lui permet d'aller plus vite, mais c'est dommage de perdre la trace de certains commits.

Pour plus de transparance, nous avons souhaité synchroniser l'intégralité de notre historique de commits. Pour cela, nous allons utiliser l'option first_parent = False. Elle va permettre de basculer individuellement chacun des commits de la source de vérité vers la destination :

git.origin(
    url = "https://github.com/cap-collectif/platform",
    ref = "master",
    first_parent = False,
)

Il est important de ne plus réécrire l'historique de la branche principale de la source de vérité une fois la synchronisation en place. Sinon une nouvelle synchronisation à partir de zéro sera nécessaire. C'est pour cela que nous avons bien pris le temps de préparer le passage en open source avant de le publier (comme je vous ai expliqué dans les parties 1 & 2).

Permettre des différences entre les 2 dépôts

Il est possible de configurer Copybara pour exclure certains fichiers de la synchronisationL. Par exemple nous avons exclu le README interne à destination des employés pour le remplacer par un README destiné aux utilisateurs de la version open source.

Pour cela, ajoutez un dossier .oss qui va contenir les fichiers qui seront mis en avant dans le dépôt open source:

.oss/
    README.md # readme that will be used on the oss repo
README.md # readme used on the internal repo

Il ne nous reste qu'à exclure de la synchronisation les fichiers que l'on veut voir disparaitre, puis à déplacer le dossier .oss à la racine du dépôt de destination :

- uses: olivr/copybara-[email protected]
    with:
        # existing configuration…
        # We do not sync some internal repo tools
        push_exclude: 'README.md'
        push_move: ".oss||"

C'est bon le dépôt open source a désormais son propre README !

Quel auteur pour les commits ?

Nous avons créé un compte github @cap-collectif-github-bot qui est utilisé en tant que commiter sur tous les commits synchronisés. Ainsi il est clair que chaque commit a été importé par un bot.

Malgré tout il est dommage de perdre le contributeur original, et comme nous avons synchronisé plusieurs milliers de commits, s'est posé la question d'afficher les auteurs ou non. Nous avons contacté tous les développeurs ayant déjà contribués au dépôt privé, pour leur annoncer notre futur passage en open source et leur demander s'ils souhaitent voir leurs contributions associés à leur profil GitHub ou non.

Nous avons ajoutés ceux qui souhaitaient apparaitre à une liste d'auteurs ayant consentis dans la configuration de Copybara :

COMMITTER = "cap-collectif-github-bot <[email protected]>"
AUTHORING_ALLOW_LIST = ["[email protected]","[email protected]"]

authoring = authoring.allowed(
    default = COMMITTER,
    allowlist = AUTHORING_ALLOW_LIST
),

Nous avons ajouté le support de cette option en adaptant la github action :

- uses: spyl94/copybara-action@implement-authoring-allow-list
    with:
        # existing configuration…
        committer: cap-collectif-github-bot <cap-collectif-github-bot@cap-collectif.com>
        authoring_allow_list: [email protected] [email protected]

L'auteur original est désormais correctement restauré et visible en tant que co-auteur sur le dépôt open source :

image

Et voilà, la synchronisation du dépôt interne au dépôt open source est prête !

Voir la partie 4, finaliser le passage en open source (bientôt disponible)

Publié le