composer-normalize icon indicating copy to clipboard operation
composer-normalize copied to clipboard

Make "paths that should not be sorted" configurable

Open TravisCarden opened this issue 5 years ago • 12 comments

Some elements of composer.json are highly sensitive to order, such as extra.patches with https://github.com/cweagans/composer-patches, which applies patches in the order specified and can therefore fail if it changes. See another example #699. I need a way to exclude arbitrary paths from sorting. I see that the current exclusions are hardcoded in \Ergebnis\Json\Normalizer\Vendor\Composer\ConfigHashNormalizer::PROPERTY_PATHS_THAT_SHOULD_NOT_BE_SORTED. I would like this value to be configurable like the other options. I could take a stab at a PR. Alternatively, a few specific additions to the current hardcoded list would temporarily unblock my customers. I would gladly send a PR for that, too.

TravisCarden avatar Mar 05 '21 15:03 TravisCarden

@TravisCarden

Which property paths are these?

localheinz avatar Mar 06 '21 13:03 localheinz

@localheinz Which property paths should be added to the hardcoded exclusions? Off the top of my head I know of the following order-dependent paths:

  • extra.patches is the one specifically blocking my customers.
  • extra.installer-paths was mentioned in https://github.com/ergebnis/composer-normalize/issues/699.
  • repositories already seems to be excluded.

TravisCarden avatar Mar 08 '21 16:03 TravisCarden

Also using https://github.com/cweagans/composer-patches and experiencing the same issue: patches are re-ordered, but some of them need to be applied in a specific order. I'm currently working around this issue by defining my patches in a separate file (explained @ https://github.com/cweagans/composer-patches#using-an-external-patch-file).

rafatwork avatar May 17 '21 20:05 rafatwork

Hello,

About composer-patches, a workaround is to use put number at the beginning of the description like in

            "drupal/core": {
                "1 - BrowserTestBase::setUp() must be compatible with PHPUnit\\Framework\\TestCase::setUp() - https://www.drupal.org/project/drupal/issues/3182103": "https://git.drupalcode.org/project/drupal/-/merge_requests/28.patch"
            }

Best regards,

FlorentTorregrosa avatar Sep 01 '21 15:09 FlorentTorregrosa

I also am experiencing problems with this in the "scripts" section - I define various commands to be run via the install and update hooks (via the "auto-scripts" block shown below), but these commands need to be in a specific order, whereas when normalized they are placed in alphabetical order which is not what we want!

"scripts": {
    "post-install-cmd": [
      "@auto-scripts"
    ],
    "post-update-cmd": [
      "@auto-scripts"
    ],
    "auto-scripts": {
      "cache:clear": "symfony-cmd",
      "doctrine:migrations:migrate -v": "symfony-cmd",
      "bazinga:js-translation:dump assets --merge-domains --format=json": "symfony-cmd",
      "assets:install %PUBLIC_DIR%": "symfony-cmd"
    }
  }

When normalized changes the order and becomes:

"scripts": {
    "post-install-cmd": [
      "@auto-scripts"
    ],
    "post-update-cmd": [
      "@auto-scripts"
    ],
    "auto-scripts": {
      "assets:install %PUBLIC_DIR%": "symfony-cmd",
      "bazinga:js-translation:dump assets --merge-domains --format=json": "symfony-cmd",
      "cache:clear": "symfony-cmd",
      "doctrine:migrations:migrate -v": "symfony-cmd"
    }
  }

benr77 avatar Jan 28 '22 16:01 benr77

@benr77 Working on this!

localheinz avatar Jan 30 '22 16:01 localheinz

@benr77

I am releasing a temporary fix (see #875) as ergebnis/composer-normalize:2.23.1.

Let's keep this issue open until I have solved the problem!

I apologize for any problems I have caused, and I thank you for opening these issues! Without your help, I would never even know about how different projects use composer.json, and I am learning a lot!

localheinz avatar Jan 31 '22 06:01 localheinz

Thanks for your efforts - it really is appreciated a lot!

One point to consider - I see in the PR you are referring to auto-scripts but this is just what I have called the group - I think you can call it anything (this is just a Symfony convention IIRC).

In the scripts block at least, it is OK to sort the first level of children, but anything past that should not be sorted.

Cheers!

benr77 avatar Jan 31 '22 07:01 benr77

Thank you, @benr77!

localheinz avatar Jan 31 '22 07:01 localheinz

Hi,

@localheinz don't blame yourself, this tool is amazing! Thanks for providing it in open source with free usage possible!

FlorentTorregrosa avatar Feb 12 '22 18:02 FlorentTorregrosa

Since this issue has not had any activity within the last 180 days, I have marked it as stale.

I will close it if no further activity occurs within the next 14 days.

ergebnis-bot avatar Aug 12 '22 12:08 ergebnis-bot

I believe this issue is still unresolved, at least in the correct manner. Can we not close it please.

benr77 avatar Aug 12 '22 14:08 benr77

I also cannot use this until scripts order normalization can be disabled.

Bilge avatar Nov 08 '22 19:11 Bilge

@Bilge

Can you share an example composer.json where you are experiencing issues with the scripts section, please?

  • orginal
  • normalized
  • expected normalized

Thank you!

localheinz avatar Dec 12 '22 07:12 localheinz

@benr77

Fixing scripts.auto-scripts with https://github.com/ergebnis/json-normalizer/pull/776.

localheinz avatar Dec 12 '22 07:12 localheinz

@TravisCarden

Fixing extra.installer-paths with https://github.com/ergebnis/json-normalizer/pull/777.

localheinz avatar Dec 12 '22 07:12 localheinz

@localheinz I just don't want the scripts section "normalized" (alphabetized) at all. I would like to except the scripts section altogether. Same for scripts-descriptions.

Bilge avatar Dec 12 '22 10:12 Bilge

@TravisCarden

Regarding extra.patches, can the direct children of extra.patches safely be sorted, or is that also an issue?

Original composer.json

{
  "extra": {
    "patches": {
      "drupal/foo": {
        "foo": "https://www.drupal.org/files/issues/2022-01-01/bar.patch",
        "bar": "https://www.drupal.org/files/issues/2020-12-13/foo.patch"
      },
      "drupal/bar": {
        "bar": "https://www.drupal.org/files/issues/2022-01-01/bar.patch",
        "baz": "https://www.drupal.org/files/issues/2019-01-01/baz.patch"
      }
    }
  }
}

Normalized composer.json

{
  "extra": {
    "patches": {
      "drupal/bar": {
        "bar": "https://www.drupal.org/files/issues/2022-01-01/bar.patch",
        "baz": "https://www.drupal.org/files/issues/2019-01-01/baz.patch"
      },
      "drupal/foo": {
        "foo": "https://www.drupal.org/files/issues/2022-01-01/bar.patch",
        "bar": "https://www.drupal.org/files/issues/2020-12-13/foo.patch"
      }
    }
  }
}

localheinz avatar Dec 12 '22 16:12 localheinz

@FlorentTorregrosa @rafatwork @TravisCarden

Fixing extra.patches with https://github.com/ergebnis/json-normalizer/pull/780.

Does that make sense?

localheinz avatar Dec 12 '22 16:12 localheinz

Yes, it's safe to sort children of extra.patches, but not their children. That's to say that grandchildren of extra.patches should retain their order.

fredden avatar Dec 12 '22 17:12 fredden

extra is arbitrary data that can be "virtually anything". I don't think a generic tool can make assumptions about its structure. At most, sort direct subkeys.

Regarding scripts, my own use case is like:

    "scripts": {
        "start": [
            "Composer\\Config::disableProcessTimeout",
            "php -S localhost:8080 -t public public/index.php"
        ],
        "phpstan": "phpstan analyse .",
        "phpcs": "phpcs",
        "phpcbf": "phpcbf",
        "rector-lint": "vendor/bin/rector process --dry-run",
        "rector-fix": "vendor/bin/rector process"
    },

Scripts are listed in logical blocks (build actions first, linters last). Linters are shown in order of importance/preference for the project. Each linter displays lint command first, fix command second. Order conveys information, I'm not fond of having it discarded blindly.

On the other side, composer list itself couldn't care less and alphabetises scripts nonetheless.

Would some generic opt-in/opt-out setting be a solution? Can it be flexible enough without adding too much complexity?

{
  "extra": {
    "composer-normalize": {
      "skip-keys": ["scripts", "scripts-descriptions", "extra.patches"]
    }
  }
}

kAlvaro avatar Dec 12 '22 17:12 kAlvaro

@kAlvaro

From my point of view, JSON objects are objects or maps - if the order of properties or keys matter in an object or a map, then something is broken by design.

I am not judging, but I think it is a bad idea.

ergebnis/json-normalizer only sorts properties of objects, it never sorts lists.

localheinz avatar Dec 12 '22 22:12 localheinz

Hi,

@localheinz, about https://github.com/ergebnis/composer-normalize/issues/704#issuecomment-1346841515, I confirm, direct children of extra.patches can be sorted (and I like to sort it) but not their own children.

So ok with you comment result.

FlorentTorregrosa avatar Dec 13 '22 08:12 FlorentTorregrosa

JSON objects are objects or maps - if the order of properties or keys matter in an object or a map, then something is broken by design

You have a point here. Original json.org page says:

An object is an unordered set of name/value pairs".

ECMA-404 says:

The JSON syntax does not impose any restrictions on the strings used as names, does not require that name strings be unique, and does not assign any significance to the ordering of name/value pairs. These are all semantic considerations that may be defined by JSON processors or in specifications defining specific uses of JSON for data interchange

And I don't think Composer has anything to say about order.

I'd still appreciate a generic setting to customise behaviour for custom keys, but it's out of scope.

kAlvaro avatar Dec 13 '22 16:12 kAlvaro

@localheinz++ 😄

TravisCarden avatar Dec 13 '22 16:12 TravisCarden