Add extension compatibility list
authorColeman Watts <coleman@civicrm.org>
Mon, 17 Dec 2018 17:01:50 +0000 (12:01 -0500)
committerColeman Watts <coleman@civicrm.org>
Sat, 29 Dec 2018 01:04:17 +0000 (20:04 -0500)
CRM/Admin/Page/Extensions.php
CRM/Extension/Info.php
CRM/Extension/System.php
CRM/Upgrade/Form.php
distmaker/dists/common.sh
extension-compatibility.json [new file with mode: 0644]
tests/phpunit/CRM/Extension/InfoTest.php

index 966c1a195d19ed4b7697ac51168dd6183b86338c..97da3d1755a3ef3245a2d43d70b65e2d8df9f07f 100644 (file)
@@ -221,7 +221,7 @@ class CRM_Admin_Page_Extensions extends CRM_Core_Page_Basic {
   }
 
   /**
-   * Get the list of local extensions and format them as a table with
+   * Get the list of remote extensions and format them as a table with
    * status and action data.
    *
    * @param array $localExtensionRows
@@ -238,7 +238,12 @@ class CRM_Admin_Page_Extensions extends CRM_Core_Page_Basic {
 
     // build list of available downloads
     $remoteExtensionRows = array();
+    $compat = CRM_Extension_System::getCompatibilityInfo();
+
     foreach ($remoteExtensions as $info) {
+      if (!empty($compat[$info->key]['obsolete'])) {
+        continue;
+      }
       $row = (array) $info;
       $row['id'] = $info->key;
       $action = CRM_Core_Action::UPDATE;
index 4302f775005d92ae1300352045cb0dcaa1fcf050..aa8e4ba7a95c7133f1894eadff44af556fb141a3 100644 (file)
@@ -169,10 +169,7 @@ class CRM_Extension_Info {
         }
       }
       elseif ($attr === 'requires') {
-        $this->requires = array();
-        foreach ($val->ext as $ext) {
-          $this->requires[] = (string) $ext;
-        }
+        $this->requires = $this->filterRequirements($val);
       }
       else {
         $this->$attr = CRM_Utils_XML::xmlObjToArray($val);
@@ -180,4 +177,22 @@ class CRM_Extension_Info {
     }
   }
 
+  /**
+   * Filter out invalid requirements, e.g. extensions that have been moved to core.
+   *
+   * @param SimpleXMLElement $requirements
+   * @return array
+   */
+  public function filterRequirements($requirements) {
+    $filtered = [];
+    $compatInfo = CRM_Extension_System::getCompatibilityInfo();
+    foreach ($requirements->ext as $ext) {
+      $ext = (string) $ext;
+      if (empty($compatInfo[$ext]['obsolete'])) {
+        $filtered[] = $ext;
+      }
+    }
+    return $filtered;
+  }
+
 }
index 20d171d131573a276fdd92b986a06ac28bdaef79..e1b0b0852db61eb5eaebdfa9de5ef3903d9c499b 100644 (file)
@@ -286,6 +286,18 @@ class CRM_Extension_System {
     return $this->_repoUrl;
   }
 
+  /**
+   * Returns a list keyed by extension key
+   *
+   * @return array
+   */
+  public static function getCompatibilityInfo() {
+    if (!isset(Civi::$statics[__CLASS__]['compatibility'])) {
+      Civi::$statics[__CLASS__]['compatibility'] = json_decode(file_get_contents(Civi::paths()->getPath('[civicrm.root]/extension-compatibility.json')), TRUE);
+    }
+    return Civi::$statics[__CLASS__]['compatibility'];
+  }
+
   /**
    * Take an extension's raw XML info and add information about the
    * extension's status on the local system.
index 16a2740d6741f11dea885fd5e9202af3ffa455b2..b13361347cc851e1c98e270d21b95afb635565dd 100644 (file)
@@ -547,6 +547,13 @@ SET    version = '$version'
     );
     $queue->createItem($task);
 
+    $task = new CRM_Queue_Task(
+      array('CRM_Upgrade_Form', 'disableOldExtensions'),
+      array($postUpgradeMessageFile),
+      "Checking extensions"
+    );
+    $queue->createItem($task);
+
     $revisions = $upgrade->getRevisionSequence();
     foreach ($revisions as $rev) {
       // proceed only if $currentVer < $rev
@@ -624,6 +631,33 @@ SET    version = '$version'
     return TRUE;
   }
 
+  /**
+   * Disable any extensions not compatible with this new version.
+   *
+   * @param \CRM_Queue_TaskContext $ctx
+   * @param string $postUpgradeMessageFile
+   * @return bool
+   */
+  public static function disableOldExtensions(CRM_Queue_TaskContext $ctx, $postUpgradeMessageFile) {
+    $compatInfo = CRM_Extension_System::getCompatibilityInfo();
+    $disabled = [];
+    $manager = CRM_Extension_System::singleton()->getManager();
+    foreach ($compatInfo as $key => $ext) {
+      if (!empty($ext['obsolete']) && $manager->getStatus($key) == $manager::STATUS_INSTALLED) {
+        $disabled[$key] = sprintf("<li>%s</li>", ts('The extension %1 is now obsolete and has been disabled.', [1 => $key]));
+      }
+    }
+    if ($disabled) {
+      $manager->disable(array_keys($disabled));
+      file_put_contents($postUpgradeMessageFile,
+        '<br/><br/><ul>' . implode("\n", $disabled) . '</ul>',
+        FILE_APPEND
+      );
+    }
+
+    return TRUE;
+  }
+
   /**
    * Perform an incremental version update.
    *
index e760bf593054d3dd6b2269a706e7fb2e216c950b..1ad546ef5b21ca25164aa2c0d1a032b393c229f3 100644 (file)
@@ -70,7 +70,7 @@ function dm_install_core() {
   done
 
   dm_install_files "$repo" "$to" {agpl-3.0,agpl-3.0.exception,gpl,CONTRIBUTORS}.txt
-  dm_install_files "$repo" "$to" composer.json composer.lock bower.json package.json Civi.php README.md release-notes.md
+  dm_install_files "$repo" "$to" composer.json composer.lock bower.json package.json Civi.php README.md release-notes.md extension-compatibility.json
 
   mkdir -p "$to/sql"
   pushd "$repo" >> /dev/null
diff --git a/extension-compatibility.json b/extension-compatibility.json
new file mode 100644 (file)
index 0000000..2f8bd4b
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "com.ixiam.modules.quicksearch": {
+    "obsolete": "5.8"
+  }
+}
index 0ae7fba1c0a40946122162c44cead94a6c0e9706..879cb76288c7ca7d979665727c06088d69ebf697 100644 (file)
@@ -81,4 +81,12 @@ class CRM_Extension_InfoTest extends CiviUnitTestCase {
     $this->assertTrue(is_object($exc));
   }
 
+  public function test_requirements() {
+    // Quicksearch requirement should get filtered out per extension-compatibility.json
+    $data = "<extension key='test.foo' type='module'><file>foo</file><requires><ext>example.test</ext><ext>com.ixiam.modules.quicksearch</ext></requires></extension>";
+
+    $info = CRM_Extension_Info::loadFromString($data);
+    $this->assertEquals(['example.test'], $info->requires);
+  }
+
 }