Skip to content

Support larger MAJOR version numbers#149

Merged
Seldaek merged 3 commits intocomposer:mainfrom
onethumb:improve-semver-major-support
Aug 30, 2023
Merged

Support larger MAJOR version numbers#149
Seldaek merged 3 commits intocomposer:mainfrom
onethumb:improve-semver-major-support

Conversation

@onethumb
Copy link
Copy Markdown
Contributor

@onethumb onethumb commented Feb 1, 2023

root@0c6964ad69d6:/var/project# COMPOSER_ROOT_VERSION=20230131.0.0 composer install

  [UnexpectedValueException]
  Invalid version string "20230131.0.0"

While we're at it, we may as well be future-proof (support & test YYYYMMDDhhmm and PHP_INT_MAX).

- We prefer to use CalVer + SemVer (YYYYMMDD as MAJOR) for versioning.
- Other software, like `npm`, supports this: https://github.com/npm/node-semver/blob/bdda212f4f6126a1b8821dc0731a17fdc2fc533f/classes/semver.js#L48
- Composer breaks with an invalid version string:

root@0c6964ad69d6:/var/project# COMPOSER_ROOT_VERSION=20230131.0.0 composer install

  [UnexpectedValueException]
  Invalid version string "20230131.0.0"

// match classical versioning
if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
if (preg_match('{^v?(\d{1,' . PHP_INT_MAX . '})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHP_INT_MAX on 64bit (9223372036854775807) is only 19 characters long so if anything it should look something like this IMO as that's the char length and not the max number:

Suggested change
if (preg_match('{^v?(\d{1,' . PHP_INT_MAX . '})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
if (preg_match('{^v?(\d{1,20})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {

The problem though is this is only meant to parse x.y.z versions <100000, and then below we have the code for datetime versions but which do already support many formats as you can see in the tests. I'm not entirely sure yet why your format isn't supported but I don't think this fix is appropriate as I believe it changes the behavior for existing formats.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point about value vs char length. Open to whatever works best... just would like to use YYYYMMDD.y.z :)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If other versions can be of any size - can they really, does composer support it fully? - then this should be simply \d++ to be consistent.

@Seldaek
Copy link
Copy Markdown
Member

Seldaek commented Jul 20, 2023

Ok I took another look at this and fixed it to avoid causing any changes to existing parsed formats, because the problem is version_compare is quite picky (e.g. version_compare('202301310000.0.0.0', '202301310000.0.0', '=') is false because of one added .0 at the end, this is the reason we normalize versions)

The tests without any changes to VersionParser fail the following new formats which were not supported before:

UnexpectedValueException: Invalid version string "20230131.0.0"
UnexpectedValueException: Invalid version string "202301310000.0.0"
UnexpectedValueException: Invalid version string "20100102.1.0"
UnexpectedValueException: Invalid version string "20100102.0.3"
UnexpectedValueException: Invalid version string "2010-01-02-10-20-30.0.3"

And with the patch those 5 are now supported but no existing one changes.

So really all this does is allow date formats with <date>.x.y where as we previously only allowed <date> or <date>.x.

I think I can live with this patch now, as it appears harmless, but I'd still like confirmation from @naderman before merging.

@naderman
Copy link
Copy Markdown
Member

I think this does cause a BC break in version comparisons though?

Previously the version string "20230131" would have been normalized to "2023.01.31.0" but now it gets normalized to "20230131.0.0.0" which means that

  • before: "20230131" < "2023-02-01" normalized to "2023.01.31.0" < "2023.02.01.0"
  • after: "20230131" > "2023-02-01" normalized to "20230131.0.0.0" > "2023.02.01.0"

I don't know if this kind of comparison ever mattered to anyone in practice though as it would really just come up if you ever switched from major version date formats without separators to ones with separators or vice versa.

@naderman
Copy link
Copy Markdown
Member

Nevermind the above, the old code never inserted separators, just replaced existing separators with dots, so that issue doesn't exist. Looks all good to me then!

@Seldaek Seldaek merged commit ce46554 into composer:main Aug 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants