Composer, Composer.lock, vendor et versioning sont dans un bateau

Composer

À la suite d’une discussion avec Clément (@shikiryu) sur le la mise sous gestion de version ou « versionnement » du composer.lock, j’ai posé la question sur twitter :

Dans le cadre d'un site ou d'une application web (pour une librairie, c'est différent), pour moi la question ne se posait pas :

  • Le fichier composer.json contient la liste des dépendances nécessaires à notre projet, ce fichier doit être versionné.
  • Le dossier vendor contient lui les sources de ces dépendances, ce dossier ne doit pas être versionné.
  • Le fichier composer.lock contient l'état exact (la version) de nos dépendances au moment où l'on travaille sur le projet, pour moi il doit être versionné.

Comment marche composer ?

Pour comprendre comment marche composer, nous allons utiliser un nouveau projet silex (mini framework utilisant des briques de Symfony).

Pour cela je me place dans un dossier vide et je lance la commande suivante dans un terminal : 

composer require silex/silex

Vu que le dossier est vide, et que donc aucun fichier composer.json contenant la liste de dépendances de mon projet n'est pas présent, ce fichier va être créé par la commande composer require, en voici son contenu :

{
    "require": {
        "silex/silex": "^2.0"
    }
}

Après avoir créé ce fichier, composer lance automatiquement la commande composer install, afin d'installer les dépendances. "Composer install" commence par regarder s'il existe un fichier composer.lock, qui contient donc la version exacte des dépendances qui doivent être utilisées. Dans notre cas il n'existe pas, donc il va le créer en utilisant le fichier composer.json.

Dans notre cas le fichier est assez simple, il dit qu'il n'a besoin que de la librairie silex/silex dans une version supérieure à 2.0 (on pourrait très bien demander une version spécifique de silex avec la ligne suivante : "silex/silex": "2.0.1")

Composer va alors faire une requête sur packagist.org (qui est le dépôt par défaut de composer, une sorte d'annuaire de l'ensemble des librairies installables) pour connaître la version la plus récente de notre paquet correspondant à nos contraintes.

À noter, packagist peut s'utiliser "manuellement", voici par exemple la page concernant silex : https://packagist.org/packages/silex/silex.

À ce jour la version la plus récente de silex est la 2.0.4, c'est celle qui sera donc récupérée et installée par composer.

Une fois silex est téléchargé et installé, alors composer va en enregistrer le numéro de version exact dans le fichier composer.lock.

Si on l'inspect on trouvera bien la section définissant silex/silex :

"name": "silex/silex",
"version": "v2.0.4",
"source": {
    "type": "git",
    "url": "https://github.com/silexphp/Silex.git",
    "reference": "49ca08d853731d1635374e5019c8696cfd53c161"
},

Mais le fichier est beaucoup plus long que cela et contient des références à d'autres libraries, par exemple pimple/pimple, que l'on avait pas demandé.

En effet,Silex a lui aussi besoin de librairies tierces, on le voit durant le "composer require" :

composer require silex/silex  
Using version ^2.0 for silex/silex
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing symfony/routing (v3.2.1)
    Loading from cache

  - Installing psr/log (1.0.2)
    Loading from cache

  - Installing symfony/debug (v3.2.1)
    Loading from cache

  - Installing symfony/polyfill-mbstring (v1.3.0)
    Loading from cache
...

Et les versions de ces dépendances seront elles aussi enregistrées dans le fichier composer.lock.

Voici maintenant l'architecture de notre projet :

composer architecture dossier

Nous allons maintenant créer un dossier "app" qui contiendra nos développements personnalisés (ici un simple fichier index.php) :

On va maintenant utiliser git pour versionner tout ça, mais quoi versionner au juste ?

  • Le dossier app : oui, car on ne pourra le retrouver nulle part
  • le dossier vendor : non, c'est inutile, car il est généré automatiquement par composer
  • le fichier composer.json : oui, il contient la liste des dépendances nécessaires.
  • le fichier composer.lock : pour moi oui, car il contient la version exacte des dépendances utilisées.

Le fichier .gitignore sera utilisé pour ne pas versionner le dossier vendor, en voici son contenu :

/vendor

À noter, le fichier gitignore doit lui aussi être versionné.

Installation du projet par un tiers

Maintenant si quelqu'un veut installer mon application sur son système, il n'a qu'à cloner mon dépôt et installer les dépendances via composer install :

git clone git@github.com:kgaut/silex-composer-example.git
cd silex-composer-example
composer install

Contrairement au moment où l'on avait fait "composer require", maintenant le composer.lock existe et donc composer sait exactement quelle version il doit récupérer pour chaque dépendance.

Si l'on n'avait pas eu de fichier composer.lock, alors composer aurait requété le site packagist pour connaître la version la plus récente de nos dépendances, et potentiellement le tiers se serait retrouvé avec une version plus récente que nous au moment du développement. Dans la plupart des cas, cela n'aurait pas posé de soucis, mais on n'est pas l'abri d'une nouvelle version d'une dépendance d'une de nos dépendance qui soit bogué.

Sur le point de la dépendance boguée, certains m'ont opposé le fait que l'on ne devrait pas utiliser une dépendance "foireuse", mais bon sortir une version boguée d'une application arrive à tout le monde, je ne vais pas me priver d'une dépendance car une de leur version a connu un bug...

D'autres m'ont dit que les tests unitaires étaient là pour ça. Pour moi non, ils ne sont pas là pour tester l'ensemble des fonctionnalités de nos dépendances.

Gestion des mises à jour

Pour mettre à jour nos dépendances, on utilise la commande "composer update" pour tout mettre à jour ou bien "composer update dépendance" pour ne faire les mises à jour que d'une dépendance.

Dans ce cas, composer va lire le fichier composer.json afin de se remémorer les contraintes de version que nous avions posées, interroger packagist.org, et s'il trouve de nouvelles versions, alors il modifiera le fichier composer.lock avec les nouvelles informations. Il lancera ensuite automatiquement la commande "composer install" pour télécharger ces nouvelles versions.

Conclusion

Quand on développe une libraire (une dépendance) alors la question ne se pose pas, le fichier composer.lock ne doit pas être versionné, si l'on a besoin d'une dépendance dans une version très particulière alors il faudra le spécifier dans le fichier composer.json.

Par contre quand on développe une application web / un site web, je ne vois pas l'intérêt de ne pas versionner le fichier composer.lock, pour moi cela ne peut apporter que des problèmes. C'est ce qui est confirmé sur le site de composer d'ailleurs :

Commit your application's composer.lock (along with composer.json) into version control.

https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-fi…

Pourtant sur le sondage twitter (qui ne vaut pas plus qu'un sondage) près d'un tiers des votants sont pour le non commit du composer.lock... Je ne demande qu'à comprendre pourquoi, peut-être que je manque quelque chose ? Mais pour l'instant je ne vois pas.

Contenus en rapport

Drupal & Composer - Appliquer un patch dans le fichier composer.json

Si vous utilisez composer pour gérer votre instance de Drupal, vous avez parfois besoin d'appliquer un patch (de votre conception ou depuis drupal.org) que ce soit pour un module tiers ou pour le core.

Si on est "à l'ancienne" on a le core et les module sous gestionnaire de version (git par exemple), cela reste simple, vous appliquez le patch et commitez le tout.

Commentaires

Je suis d'accord avec toi. Pour un projet il faut commit le composer.lock car c'est la seule garantie que, lors du build d'un des environnements, il soit ISO avec les autres du côté des dépendances.
Sans ce fichier, si une librairie à été mis à jour entre le moment où tu as build ton environnement de tests et celui où tu as build ton environnement de production, tu peux aller au devant de surprises.

Je versionne aussi, je prefere que le composer install soit predictible (et doncidentique ) a chaque fois.

Pour avoir connu cette situation, la question pourrait aussi etre posée ainsi : qui est censé commiter le composer.lock ? Chaque développeur ? Uniquement le responsable intégration / devops ?

Le composer.lock "ne sert que" à garantir le déploiement d'une version précise de l'application à un instant T.
Cette question est plutot superflue pour un dev qui doit implémenter une nouvelle fonctionnalité (par exemple dans sa branche feature)

Par contre, elle devient indispensable au moment de la livraison de l'appli.

Je tombe sur ce post suite à une recherche (indirecte) sur des lenteurs lors de déploiements avec l'utilisation de composer.
J'ajouterais donc à ton billet, que le fait d'inclure composer.lock dans ton dépôt évite une charge mémoire importante sur le serveur. Le projet que nous développons est de plus en plus important et à chaque déploiement, le temps est de plus en plus long à cause de l'écriture de ce fichier.lock

Source Reddit.com

wubblewobble 3 points il y a 3 ans

As far as I figure, composer uses lots of memory when calculating dependencies, but not when just installing packages.

So what I'm saying is that I think that you haven't copied your composer.lock over? If you copied that from your local box, then the dependencies would already have been calculated and doing a composer install would just literally be downloading/unpacking files and so wouldn't use a ton of memory?

c'est utile merci

attention, dans la conclusion " je ne vois pas l'intérêt de ne pas versionner le fichier composer.json" alors que l'on parle ici du composer.lock

Sinon super artcile

Merci ! C'est corrigé !

merci infiniment pour ces explications, c'était clair net et précis, j'ai enfin compris le fonctionnement de composer, merci merci merci

Ajouter un commentaire

Ne sera pas publié
CAPTCHA
Désolé, pour ça, mais c'est le seul moyen pour éviter le spam...