How Composer handles local changes - php

Suppose I install package for CKEditor through Composer and manually add new skins and plugins to it. How Composer will handle this, when next update to base package will be released?
Will it overwrite entire package directory (deleting local changes) or update only listed files?
Also, I'm having problems updating one package to newest version and made that update locally, manually. Yet, composer status shows No local changes. Does this mean, that Composer itself does not check contents of each package's folder for local changes, only operates on differences between composer.json and composer.lock?

Composer will updated to newest version matched to version what you've added in composer.json and yes - it will overwrite existing package (including all of yours changes) but it will omit files which not exist in packages.
Command: "composer status" shows all changes in files what belongs to specified package. If you will change some file then it will be shown in that list, but if you will add a new one then of course not.
Generally, your approach might work in some cases but I strongly DO NOT recommend it. Problem will be when you create some file, and then will be added into package (for example in newer version).
You should just use all packages "as is" directly in your application, and within it add new stuff, or another configuration, etc.

Will it overwrite entire package directory (deleting local changes) or update only listed files?
Yes. When updating a package Composer removes the current version of the package and installs the new one.
Also, I'm having problems updating one package to newest version and made that update locally, manually. Yet, composer status shows No local changes. Does this mean, that Composer itself does not check contents of each package's folder for local changes, only operates on differences between composer.json and composer.lock?
The 1.* part in your composer.json tells Composer to only update when there is a new release available in the 1.* version range. New commits are not a new release. A new update will be available when the package owner creates a new release with a higher version number. If you want to update after each new commit you should change "1.*" to "dev-master".

Related

How to get the exact version of included packages in my private repository

I'm currently experimenting with the Satis. I would like to be able to get the exact version of my private packages somewhere, so everything that is normally in the composer.lock. I always commit the composer.lock via Git.
But if I understand that correctly, the Satis in its packages.json always only includes the require parts, i.e. the sections from my composer.json and thus of course only version ranges.
Is there a way to configure the Satis so that the composer.locks are also stored or how do I get the exact "snapshot" of my packages?
+++ Example +++
Ok, I try to explain a bit more.
Let's say I have a package my/package. Here I add several files, including a composer.json, in which I define that symfony/console should be installed in a version greater than or equal to 4. Now I do a "composer install" and Symfony is installed in version 4.4. I commit all files, including composer.lock and create a release 1.0.
Now I'm going to the Satis. Here I add my/package and the corresponding repository URL for my/package to satis.json and update it. The Satis checks out my package correctly and in packages.json or more precisely the all*.json my package is listed with version 1.0. So far everything is fine.
But if I now take a look at the metadata that Satis stores for my package in all*.json, I see here practically my specified requirements, i.e. that symfony/console should be installed in a version greater than or equal to 4. So Satis takes a snapshot of the composer.json and apparently ignores the composer.lock. So I have no chance to see that my release 1.0 works with the exact version 4.4 of Symfony, while for example a release 1.1 works with symfony/console 4.5. But this information is interesting for me.
When installing a package, Composer recalculates all dependencies on the fly. This is based on the composer.json of your application and the composer.json files of all dependencies.
A composer.lock should not be part of any package, and it is not taken into account when a package is installed.
So, I've now built a workaround. The whole thing is not quite perfect, since the runtime for large repositories is relatively long, which is why I have to run it as a cron once a day. But it works fine.
I have created a new Satis console command.
This command uses the PackageSelection class to determine all existing packages.
I iterate over the package list and look for the paths and names to the dist files.
I extract the ZIP files in memory and look for the composer.lock. If there is one, I parse it and read the exact version numbers of the dependent packages.
I summarize the information in a separate JSON file and store it in parallel to packages.json under htdocs. From there I can call it up and integrate it into my own application or process it further.

Why "composer.json" is not updated when updating packages?

Comparing to other package managers like npm, I find that composer has a strange behaviour when updating packages related to a given project.
According also to the documentation, update and upgrade options
Upgrades your dependencies to the latest version according to composer.json, and updates the composer.lock file.
And indeed, composer.lock is correctly updated with new packages version numbers. But composer.json instead is not modified, and lists packages with their old, outdated version numbers.
Why does this happen? Am I doing something wrong, or this is indeed how this is supposed to work? And if this is the case, what is the reasoning behind having one of thw two files up-to-date while the other is not?
That's the normal behavior.
Composer update looks for updates based on your composer.json file, so here it will look for 4.2 and above (^4.2)
If you want your composer.json to require 4.3 and above (^4.3), you can either modify it manually or call composer require once again.

How to rename a PHP package in Packagist

I changed a PHP package name in composer file from "name": "author/author-php" to "name": "author/author" then did composer install & composer update, merged my changes with master then created a release.
But after updating the library on Packagist, the new name did not work and composer could not find it at composer require author/author and I could not even download this new release.
Note: the repo name is still author-php so is this the reason Packagist did not renamed it?
As of now, you cannot update a package name, I believe for security reasons (if renaming was allowed, harmful code could be put as the old name, and then dependent projects that haven't updated their composer.json would pull the harmful code). It has been discussed on Packagist's Github page, and the process in place for this kind of operation is this one (copypasted from the above link) :
Update the name in composer.json on the master branch or whatever the default branch is
Resubmitting the package to packagist using the new name
Mark the old package as "Abandoned" on packagist, and use the new name in the form so that people get pointed to it when they install with the old name
And no you can't keep your download stats

Is there a PHP/Composer tool which works like npm version?

Is there an automated way of updating the version number in composer.json and adding the necessary tags before publishing, like the way npm version does?
I mean, if you had a composer.json with the line "version": "2.1.3", and executed:
composer version minor
It would do the following:
Updating the version number in composer.json to 2.2.0
Triggering composer update to update composer.lock
Making a new git commit
Making a new git tag v2.2.0
I know that the composer version command doesn't exist, but is there an equivalent tool?
npm version does stuff that you very likely do not need for Composer:
The version number is not recorded in composer.json if there are other means available - and because you are referring to Git later on, they are available.
Updating dependencies in the lock file is unnecessary. The lock file will be ignored when the project you are dealing with is included somewhere else.
Because nothing has changed in the project, a git commit wouldn't do anything.
All this leaves you with creating a new tag in the Git repository. Putting this into Composer would mean you'd exchange one command with another, without any big benefit besides you won't have to lookup the current version number you are dealing with if you use some of the relative version parameters.
All in all I'd say that simply tagging your new version is enough for Composer. You'd probably need to have some infrastructure in place and configured to make the world aware of the new version:
If your package is open source and on packagist.org, you should have a post-commit hook to notify them as soon as a new version is available. This is a standard option on Github, I don't know about other source code hosts.
Otherwise if you have to feed closed source code, you'd probably start a new update cycle of whatever system is used to create an alternative package information source (be it Satis, locally hosted Packagist, Toran Proxy or Private Packagist)
This however depends on how you set up things.
If for some reason and despite all voices against it you still want to use a tool like the OP asked for, https://www.npmjs.com/package/composer-version works quite well.

Suggestions on how to use version control and composer with symfony2

I'm already half way done with a project in Symfony2.
I need to install a couple of new vendor bundles using composer.
I already have everything (minus logs, cache and parameters.yml) in version control (including the vendor folder).
Problem is when using composer update, it deletes the .svn folders in the vendor folders that where updated. So it's basically impossible to commit now (gives me not a working copy error).
Additional information: I'm working locally and committing to a dev server and then once approved an application server. Therefore it has to be perfect (cannot just run php composer install or php composer update on the dev/application server after commit).
I also tried exporting everything and copying and pasting them back into the repo but that also didn't work (index page broke locally).
Regarding to vendor versioning the best way is not version vendors at all.
The only things you need to version are composer.json and composer.lock. This may cause a problem with vendors which doesn't have stable versions or with that for which you need not stable one (eg. master with particular commit).
As a solution you should create your own (private) vendor repository (let's say your own packagist). Composer has a tool for that, which is called Satis.
https://github.com/composer/satis
So my suggestion would be:
Create a private repository with Satis. You place every package you need in satis.json and whenever you need to update a version of vendor, or add new one, you only modify satis.json and rebuild repository.
In your project's composer.json you set your new private repository as the only repository and set option: packagist to false.
Now, every time you run composer install it will use only your private repository, so it's fast and you always sure that every environemnt has the same versions
-
I was in similar situation two years ago.
The hard lesson I learned was never to edit files within vendor. At first I totally rejected using composer and manually cloned everything I needed. Later on, I decided to fork projects I needed to edit and referenced my forks instead.
Composer supports private GitHub repos - you don't need to register it to Packagist in order to work.
You should not keep your vendor directory in your version control. This is how it is done in Symfony Standard Edition and you should follow this. Running composer install command should be a part of your deployment process
Including vendor packages in your codebase is not recommended, so if you need to maintain the same version of the packages you use on your local machine, the best way is to keep composer.lock in the VCS and running only composer install on other environments.
Additionally, if you want the prod deployment to be instant, without depending on the composer process, you could run composer install on the dev server, and once it's validated you can make your prod deployment script copy the vendor folder from the dev env.

Categories