From 7c48639922f9b965c620e4f16a1a26764d39eca5 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Mon, 12 Jun 2017 12:11:06 +0100
Subject: [PATCH] Issue #2769841 by edgewl2, alexpott, heddn: Prefer caret over
 tilde in composer.json

---
 composer.json                                 |  4 +-
 composer.lock                                 |  2 +-
 core/composer.json                            | 58 +++++++++----------
 .../Drupal/Component/Annotation/composer.json |  6 +-
 .../lib/Drupal/Component/Bridge/composer.json |  2 +-
 .../Drupal/Component/Datetime/composer.json   |  2 +-
 .../DependencyInjection/composer.json         |  2 +-
 core/lib/Drupal/Component/Diff/composer.json  |  2 +-
 .../Drupal/Component/Discovery/composer.json  |  4 +-
 .../Component/EventDispatcher/composer.json   |  4 +-
 .../Drupal/Component/Gettext/composer.json    |  2 +-
 .../Component/HttpFoundation/composer.json    |  2 +-
 .../lib/Drupal/Component/Plugin/composer.json |  2 +-
 .../lib/Drupal/Component/Render/composer.json |  2 +-
 .../Component/Serialization/composer.json     |  2 +-
 .../Drupal/Component/Utility/composer.json    |  2 +-
 core/lib/Drupal/Component/Uuid/composer.json  |  2 +-
 .../Drupal/Tests/ComposerIntegrationTest.php  | 40 +++++++++++++
 18 files changed, 90 insertions(+), 50 deletions(-)

diff --git a/composer.json b/composer.json
index 38078d6b06f8..b9536cfe35c6 100644
--- a/composer.json
+++ b/composer.json
@@ -5,10 +5,10 @@
     "license": "GPL-2.0+",
     "require": {
         "composer/installers": "^1.0.24",
-        "wikimedia/composer-merge-plugin": "~1.4"
+        "wikimedia/composer-merge-plugin": "^1.4"
     },
     "replace": {
-        "drupal/core": "~8.4"
+        "drupal/core": "^8.4"
     },
     "minimum-stability": "dev",
     "prefer-stable": true,
diff --git a/composer.lock b/composer.lock
index d7c3a26a81ca..6622a70a91f0 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "5264cac45d935c61a1d48a32b71c9f15",
+    "content-hash": "bec46eaaa9fa07a4cbd8c84302f0d275",
     "packages": [
         {
             "name": "asm89/stack-cors",
diff --git a/core/composer.json b/core/composer.json
index f38de18be85b..0d103002c7cd 100644
--- a/core/composer.json
+++ b/core/composer.json
@@ -5,47 +5,47 @@
     "license": "GPL-2.0+",
     "require": {
         "php": ">=5.5.9",
-        "symfony/class-loader": "~3.2",
-        "symfony/console": "~3.2",
-        "symfony/dependency-injection": "~3.2",
-        "symfony/event-dispatcher": "~3.2",
-        "symfony/http-foundation": "~3.2",
-        "symfony/http-kernel": "~3.2",
-        "symfony/routing": "~3.2",
-        "symfony/serializer": "~3.2",
-        "symfony/translation": "~3.2",
-        "symfony/validator": "~3.2",
-        "symfony/process": "~3.2",
-        "symfony/polyfill-iconv": "~1.0",
-        "symfony/yaml": "~3.2",
+        "symfony/class-loader": "^3.2",
+        "symfony/console": "^3.2",
+        "symfony/dependency-injection": "^3.2",
+        "symfony/event-dispatcher": "^3.2",
+        "symfony/http-foundation": "^3.2",
+        "symfony/http-kernel": "^3.2",
+        "symfony/routing": "^3.2",
+        "symfony/serializer": "^3.2",
+        "symfony/translation": "^3.2",
+        "symfony/validator": "^3.2",
+        "symfony/process": "^3.2",
+        "symfony/polyfill-iconv": "^1.0",
+        "symfony/yaml": "^3.2",
         "twig/twig": "^1.23.1",
         "doctrine/common": "^2.5",
-        "doctrine/annotations": "1.2.*",
+        "doctrine/annotations": "^1.2",
         "guzzlehttp/guzzle": "^6.2.1",
-        "symfony-cmf/routing": "~1.4",
-        "easyrdf/easyrdf": "0.9.*",
-        "zendframework/zend-feed": "~2.4",
-        "stack/builder": "1.0.*",
-        "egulias/email-validator": "1.2.*",
-        "masterminds/html5": "~2.1",
+        "symfony-cmf/routing": "^1.4",
+        "easyrdf/easyrdf": "^0.9",
+        "zendframework/zend-feed": "^2.4",
+        "stack/builder": "^1.0",
+        "egulias/email-validator": "^1.2",
+        "masterminds/html5": "^2.1",
         "symfony/psr-http-message-bridge": "^1.0",
-        "zendframework/zend-diactoros": "~1.1",
-        "composer/semver": "~1.0",
+        "zendframework/zend-diactoros": "^1.1",
+        "composer/semver": "^1.0",
         "paragonie/random_compat": "^1.0|^2.0",
-        "asm89/stack-cors": "~1.1"
+        "asm89/stack-cors": "^1.1"
     },
     "conflict": {
         "drush/drush": "<8.1.10"
     },
     "require-dev": {
         "behat/mink": "1.7.x-dev",
-        "behat/mink-goutte-driver": "~1.2",
-        "drupal/coder": "8.2.12",
-        "jcalderonzumba/gastonjs": "~1.0.2",
-        "jcalderonzumba/mink-phantomjs-driver": "~0.3.1",
-        "mikey179/vfsStream": "~1.2",
+        "behat/mink-goutte-driver": "^1.2",
+        "drupal/coder": "^8.2.12",
+        "jcalderonzumba/gastonjs": "^1.0.2",
+        "jcalderonzumba/mink-phantomjs-driver": "^0.3.1",
+        "mikey179/vfsStream": "^1.2",
         "phpunit/phpunit": ">=4.8.35 <5",
-        "symfony/css-selector": "~3.2",
+        "symfony/css-selector": "^3.2",
         "symfony/phpunit-bridge": "^3.2"
     },
     "replace": {
diff --git a/core/lib/Drupal/Component/Annotation/composer.json b/core/lib/Drupal/Component/Annotation/composer.json
index 76254ea7faa1..ff33d29b068c 100644
--- a/core/lib/Drupal/Component/Annotation/composer.json
+++ b/core/lib/Drupal/Component/Annotation/composer.json
@@ -8,9 +8,9 @@
     "php": ">=5.5.9",
     "doctrine/common": "2.5.*",
     "doctrine/annotations": "1.2.*",
-    "drupal/core-fileCache": "~8.2",
-    "drupal/core-plugin": "~8.2",
-    "drupal/core-utility": "~8.2"
+    "drupal/core-fileCache": "^8.2",
+    "drupal/core-plugin": "^8.2",
+    "drupal/core-utility": "^8.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Bridge/composer.json b/core/lib/Drupal/Component/Bridge/composer.json
index af6da1862ddd..928d8676d47a 100644
--- a/core/lib/Drupal/Component/Bridge/composer.json
+++ b/core/lib/Drupal/Component/Bridge/composer.json
@@ -6,7 +6,7 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "zendframework/zend-feed": "~2.4"
+    "zendframework/zend-feed": "^2.4"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Datetime/composer.json b/core/lib/Drupal/Component/Datetime/composer.json
index 04d965355a9a..1df4328f1fe7 100644
--- a/core/lib/Drupal/Component/Datetime/composer.json
+++ b/core/lib/Drupal/Component/Datetime/composer.json
@@ -6,7 +6,7 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "drupal/core-utility": "~8.2"
+    "drupal/core-utility": "^8.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/DependencyInjection/composer.json b/core/lib/Drupal/Component/DependencyInjection/composer.json
index 77013136b95e..cf2519254d4c 100644
--- a/core/lib/Drupal/Component/DependencyInjection/composer.json
+++ b/core/lib/Drupal/Component/DependencyInjection/composer.json
@@ -12,7 +12,7 @@
   },
   "require": {
     "php": ">=5.5.9",
-    "symfony/dependency-injection": "~2.8"
+    "symfony/dependency-injection": "^2.8"
   },
   "suggest": {
     "symfony/expression-language": "For using expressions in service container configuration"
diff --git a/core/lib/Drupal/Component/Diff/composer.json b/core/lib/Drupal/Component/Diff/composer.json
index 0d7f3d36f780..cc584532b6f4 100644
--- a/core/lib/Drupal/Component/Diff/composer.json
+++ b/core/lib/Drupal/Component/Diff/composer.json
@@ -6,7 +6,7 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "drupal/utility": "~8.2"
+    "drupal/utility": "^8.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Discovery/composer.json b/core/lib/Drupal/Component/Discovery/composer.json
index 1b0acb677eec..588480e8571b 100644
--- a/core/lib/Drupal/Component/Discovery/composer.json
+++ b/core/lib/Drupal/Component/Discovery/composer.json
@@ -6,8 +6,8 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "drupal/core-filecache": "~8.2",
-    "drupal/core-serialization": "~8.2"
+    "drupal/core-filecache": "^8.2",
+    "drupal/core-serialization": "^8.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/EventDispatcher/composer.json b/core/lib/Drupal/Component/EventDispatcher/composer.json
index be66232834a3..a4db6fafa4d9 100644
--- a/core/lib/Drupal/Component/EventDispatcher/composer.json
+++ b/core/lib/Drupal/Component/EventDispatcher/composer.json
@@ -6,8 +6,8 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "symfony/dependency-injection": "~2.8",
-    "symfony/event-dispatcher": "~2.7"
+    "symfony/dependency-injection": "^2.8",
+    "symfony/event-dispatcher": "^2.7"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Gettext/composer.json b/core/lib/Drupal/Component/Gettext/composer.json
index 2dab6984898f..16512345b989 100644
--- a/core/lib/Drupal/Component/Gettext/composer.json
+++ b/core/lib/Drupal/Component/Gettext/composer.json
@@ -10,7 +10,7 @@
   },
   "require": {
     "php": ">=5.5.9",
-    "drupal/core-utility": "~8.2"
+    "drupal/core-utility": "^8.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/HttpFoundation/composer.json b/core/lib/Drupal/Component/HttpFoundation/composer.json
index 1b3920bc3dfc..b86ab16ba773 100644
--- a/core/lib/Drupal/Component/HttpFoundation/composer.json
+++ b/core/lib/Drupal/Component/HttpFoundation/composer.json
@@ -6,7 +6,7 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "symfony/http-foundation": "~2.7"
+    "symfony/http-foundation": "^2.7"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Plugin/composer.json b/core/lib/Drupal/Component/Plugin/composer.json
index 4ffeeed3a274..118265715cd4 100644
--- a/core/lib/Drupal/Component/Plugin/composer.json
+++ b/core/lib/Drupal/Component/Plugin/composer.json
@@ -6,7 +6,7 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "symfony/validator": "~2.7"
+    "symfony/validator": "^2.7"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Render/composer.json b/core/lib/Drupal/Component/Render/composer.json
index 88291e91bb1a..50c2f70d90e3 100644
--- a/core/lib/Drupal/Component/Render/composer.json
+++ b/core/lib/Drupal/Component/Render/composer.json
@@ -6,7 +6,7 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "drupal/core-utility": "~8.2"
+    "drupal/core-utility": "^8.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Serialization/composer.json b/core/lib/Drupal/Component/Serialization/composer.json
index 5d629cfc1591..97fd63931969 100644
--- a/core/lib/Drupal/Component/Serialization/composer.json
+++ b/core/lib/Drupal/Component/Serialization/composer.json
@@ -6,7 +6,7 @@
   "license": "GPL-2.0+",
   "require": {
     "php": ">=5.5.9",
-    "symfony/yaml": "~2.7"
+    "symfony/yaml": "^2.7"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Utility/composer.json b/core/lib/Drupal/Component/Utility/composer.json
index 13671efef403..5fa20796ce1d 100644
--- a/core/lib/Drupal/Component/Utility/composer.json
+++ b/core/lib/Drupal/Component/Utility/composer.json
@@ -7,7 +7,7 @@
   "require": {
     "php": ">=5.5.9",
     "paragonie/random_compat": "^1.0|^2.0",
-    "drupal/core-render": "~8.2"
+    "drupal/core-render": "^8.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/lib/Drupal/Component/Uuid/composer.json b/core/lib/Drupal/Component/Uuid/composer.json
index deca54b80d42..7c43422dca64 100644
--- a/core/lib/Drupal/Component/Uuid/composer.json
+++ b/core/lib/Drupal/Component/Uuid/composer.json
@@ -10,7 +10,7 @@
   },
   "require": {
     "php": ">=5.5.9",
-    "drupal/core-utility": "~8.2"
+    "drupal/core-utility": "^8.2"
   },
   "autoload": {
     "psr-4": {
diff --git a/core/tests/Drupal/Tests/ComposerIntegrationTest.php b/core/tests/Drupal/Tests/ComposerIntegrationTest.php
index a64804cf8b8f..5619b84d04ae 100644
--- a/core/tests/Drupal/Tests/ComposerIntegrationTest.php
+++ b/core/tests/Drupal/Tests/ComposerIntegrationTest.php
@@ -88,6 +88,46 @@ public function testComposerLockHash() {
     $this->assertSame($content_hash, $lock['content-hash']);
   }
 
+  /**
+   * Tests composer.json versions.
+   *
+   * @param string $path
+   *   Path to a composer.json to test.
+   *
+   * @dataProvider providerTestComposerJson
+   */
+  public function testComposerTilde($path) {
+    $content = json_decode(file_get_contents($path), TRUE);
+    $composer_keys = array_intersect(['require', 'require-dev'], array_keys($content));
+    if (empty($composer_keys)) {
+      $this->markTestSkipped("$path has no keys to test");
+    }
+    foreach ($composer_keys as $composer_key) {
+      foreach ($content[$composer_key] as $dependency => $version) {
+        $this->assertFalse(strpos($version, '~'), "Dependency $dependency in $path contains a tilde, use a caret.");
+      }
+    }
+  }
+
+  /**
+   * Data provider for all the composer.json provided by Drupal core.
+   *
+   * @return array
+   */
+  public function providerTestComposerJson() {
+    $root = realpath(__DIR__ . '/../../../../');
+    $tests = [[$root . '/composer.json']];
+    $directory = new \RecursiveDirectoryIterator($root . '/core');
+    $iterator = new \RecursiveIteratorIterator($directory);
+    /** @var \SplFileInfo $file */
+    foreach ($iterator as $file) {
+      if ($file->getFilename() === 'composer.json' && strpos($file->getPath(), 'core/modules/system/tests/fixtures/HtaccessTest') === FALSE) {
+        $tests[] = [$file->getRealPath()];
+      }
+    }
+    return $tests;
+  }
+
   /**
    * Tests core's composer.json replace section.
    *
-- 
GitLab