Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BC: Composer 2.5.0 introduces new dependency resolution that may cause issues #11264

Closed
nunomaduro opened this issue Jan 10, 2023 · 12 comments · Fixed by #11270
Closed

BC: Composer 2.5.0 introduces new dependency resolution that may cause issues #11264

nunomaduro opened this issue Jan 10, 2023 · 12 comments · Fixed by #11270
Labels
Milestone

Comments

@nunomaduro
Copy link

nunomaduro commented Jan 10, 2023

As of Composer ^2.5.0 (#11160), it is now possible to resolve dependencies in a new way that was not previously possible. Here's an example assuming the following:

  • The user is working within a Laravel 9 application.
  • The user wants to require a third-party/package that does not currently support Laravel 9.
  • The package developer has started a branch (feat/laravel-9-support) to add support for Laravel 9, but the work is not yet complete.

By running the command:

> composer require third-party/package

The user will get:

Using version dev-feat/laravel-9-support for third-party/package

It is crucial to keep in mind that this functionality may result in confusion for the user in specific scenarios, and there is a high likelihood that it will disrupt existing CI processes that take actions — such as deployments, testing results, automatic releases — based on the resolution of those dependencies.

EDIT 1: It's worth noting that in the example given, as well as in all Laravel applications, the following settings are typically set in the composer.json file:

"minimum-stability": "dev",
"prefer-stable": true

It is a topic of debate whether these settings should be present in Laravel applications, however, it is important to note that the example provided earlier (the third-party/package) would not have been possible when using Composer 2.4.4.

EDIT 2: Just pointing out, that even if the dev-feat/laravel-9-support gets merged on master - the branch used to tag releases - previously composer would never resolve dev-master while now, it installs dev-master with the following message: Using version ^1.0@dev for third-party/package for example.

@nunomaduro nunomaduro changed the title BC introduced by #11160 BC: Composer 2.5.0 introduces new dependency resolution that may cause issues Jan 10, 2023
@mallardduck
Copy link

Might be a silly question, but I think that it probably would be important context for this behaviour.
Within this Laravel project, what are the values of minimum-stability and prefer-stable?

Curious because I could see this behaviour being expected if you have minimum-stability: dev. If so, composer did resolve to a version that fits your other dependencies and is "dev" stability. In that case this might be a changed behaviour, but one that fixes a scenario that was previously uncovered.

However, if the stability is set to stable then this certainly feels like a naughty breaking change. As it's clearly providing an unstable package version when the user requests stable packages only. So that's why I'm curious about those values and why I think the context here could matter.

@nunomaduro
Copy link
Author

@mallardduck I've edited the issue description specifying that Laravel applications use the "minimum-stability": "dev", and "prefer-stable": true.

@Seldaek
Copy link
Member

Seldaek commented Jan 11, 2023

@nunomaduro and with Composer 2.4.4 what happens? It would pick third-party/package ^1.2 for ex and then fail to resolve because that does not support Laravel 9? Is that a better outcome? Or what do you expect to happen?

As far as I understand it, if it picks the dev version despite having prefer-stable true it is because there is no other choice than the dev version, so it's still preferable to not being able to require at all IMO..

@nunomaduro
Copy link
Author

@nunomaduro and with Composer 2.4.4 what happens?

You would get something like this:

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - third-party/package require Laravel 9, ...

As far as I understand it, if it picks the dev version despite having prefer-stable true it is because there is no other choice than the dev version, so it's still preferable to not being able to require at all IMO..

I acknowledge your viewpoint and likely concur with it. However, the concern at hand is not whether the new behavior is better or worst, but rather that there is an unexpected change in behavior for those who trusted that specifying "minimum-stability": "dev" would not result in the installation of branches in draft or early stages of development.

To provide context, there are currently millions of Laravel applications utilizing "minimum-stability": "dev". This means that when Laravel 10 is released in February, developers may run composer update and receive versions of their dependencies that they believe are compatible with Laravel 10, but may not be due to the new behavior potentially installing branches in draft or early stages of development.

@Seldaek
Copy link
Member

Seldaek commented Jan 11, 2023

for those who trusted that specifying "minimum-stability": "dev" would not result in the installation of branches in draft or early stages of development.

Sorry but nobody here ever said that. That's a misunderstanding on your/Laravel's end IMO. dev is dev, and if you set * as constraint with a min stability dev you will get any kind of dev branch.

I disagree this as anywhere near a BC break, it's a convenience feature which actually resolves issues for many users. For example people on Laravel 8 right now where previously Composer would have guessed a version of the new dependency that may be too high and might require Laravel 9 already, now with Composer 2.5 it will get to the correct one.

So one question is can we do anything to help? And I am not sure what would be an appropriate solution yet..

The other question is why are you still shipping with this default of min stability dev? Can that go away somehow? It's fine to opt-in to this on a per project basis if you know what you are doing but as a default it seems like it's bound to hurt people by forcing them on to the bleeding edge.

@nunomaduro
Copy link
Author

The other question is why are you still shipping with this default of min stability dev?

We ship with the default of min-stability:dev because it allows users to specify development versions, such as 2.0-dev or dev-feat/wtv, in their composer.json file without being blocked by the "minimum-stability": "stable" setting.

seems like it's bound to hurt people by forcing them on to the bleeding edge.

We were not forcing them. Users still had to specify those draft or early stages of development in their composer.json file. In the past, composer require would only resolve to branches in draft or early stages of development if they were explicitly required in the composer.json file. This ensured that these branches were only used when explicitly requested by the user.

So one question is can we do anything to help?

The optimal outcome for us, and for the numerous Laravel applications with minimum-stability": "dev" in their composer.json file, would be to reverse this change and implement a new minimum-stability": "wtv" for this new behavior.

@nicolas-grekas
Copy link
Contributor

Please don't revert to the previous behavior as the new one makes using composer require way better for deps with complex requirements.

I suppose we could add some logic to reject auto-selecting a dev-stability dep. That would fix the use case for Laravel without breaking the improvement.

Dunno if it's worth the added logic.

@Seldaek
Copy link
Member

Seldaek commented Jan 11, 2023

We ship with the default of min-stability:dev because it allows users to specify development versions, such as 2.0-dev or dev-feat/wtv, in their composer.json file without being blocked by the "minimum-stability": "stable" setting.

That's another misunderstanding IMO. If you explicitly require a dev version of something Composer will implicitly add a flag for that dependency allowing it to be installed in dev (e.g. requiring 1.x-dev is same as requiring ^1.0@dev, and both will get you 1.x-dev if that exists and regardless of min-stability). The only benefit of changing the minimum-stability is if you have transitive dependencies that you need in dev as well for it to resolve.

The optimal outcome for us, and for the numerous Laravel applications with minimum-stability": "dev" in their composer.json file, would be to reverse this change and implement a new minimum-stability": "wtv" for this new behavior.

That sounds like a giant BC break/change of assumptions.

I think yes as @nicolas-grekas says maybe we could reject what seems like feature branches (or just reject any non-numeric dev versions) for the purposes of the require command. I am not sure how feasible this is though.

It still sounds to me like the problem is slightly overstated.. As you go from Composer 2.4 "cannot find a package that works" to 2.5 "here we found this dev package.. it may be WIP but you asked for dev so you get what you ask for". Sure it may lead to breakage if people don't test anything, but is it worse than not being able to install a package at all?

@mallardduck
Copy link

I have an idea however it would require changes to Packagist and subsequent opt-in setting changes for projects. If projects had the ability to exclude branches from being discovered by Packagist - then they could opt-in to blocking all feat/* or draft/* branches. After all if the branch isn't indexed by packagist, then there's no way to "accidentally" let users discover it.

This option still leaves the possibility that someone who does want unstable code for testing can use the repositories field to load directly from GH and require the dev-draft/* to get the code. Sure it adds an extra step to get the Dev code, but it also protects users from unstable code. So that trade-off seems like a decent compromise that gives maintainers the control to protect end-users from their development workflows.

@nunomaduro
Copy link
Author

Regardless of the outcome in this issue, we are currently updating our Laravel skeletons to have a minimum-stability of "stable". Additionally, we are writing a blog post that recommends our users to change their minimum-stability from "dev" to "stable" to prevent potential issues in the future.

@Seldaek
Copy link
Member

Seldaek commented Jan 13, 2023

Ok this is the best I got to mitigate the issue please take a look :) #11270

@Seldaek Seldaek added the Bug label Jan 13, 2023
@nunomaduro
Copy link
Author

@Seldaek That's indeed an improvement already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants