From 887903781c97c9ce6906642f456a57ae630df92a Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Tue, 17 Apr 2018 17:41:11 -0700 Subject: [PATCH] VersionCheck - Get more nuanced messages from latest.civicrm.org Overview ---------------------------------------- Get fully-formed upgrade messages from `latest.civicrm.org`. This allows us to convey more nuanced information about available upgrades. It also allows us to iterate more quickly on how releases are presented (e.g. adding hyperlinks to the blog/changelog, highlighting important changes, introducing the in-between status `deprecated`). Before ---------------------------------------- The `VersionCheck` helper sends a request to `latest.civicrm.org` with `format=json` to get a list of all available versions. Then it digests the information and presents any messages in the `CRM_Utils_Check` layer. After ---------------------------------------- The `VersionCheck` helper sends a request to `latest.civicrm.org` with `format=summary` to get a list of displayable messages. Then it presents any messages in the `CRM_Utils_Check` layer. Technical Details ---------------------------------------- * Because patch-releases are allowed mid-month, this patch also reduces the TTL from 7 days to 3 days. * Test coverage is reduced here (`civicrm-core`), but it's improved a lot elsewhere (`latest.civicrm.org`). * In `VersionCheck`, it makes a few contract changes (which have been evaluated by grepping for stale references circa 4.7.31). Specifically: * Add `getVersionMessages()` * Remove unnecessary members `$localMajorVersion`, `getMajorVersion()`, `isNewerVersionAvailable()`, `checkBranchForNewVersion()` * Change the content of `versionInfo`. It's still a cache of the web-service response, but now it's a list of displayable messages (rather than a list of all versions). --- CRM/Utils/Check/Component/Env.php | 59 ++------ CRM/Utils/VersionCheck.php | 150 ++----------------- tests/phpunit/CRM/Utils/versionCheckTest.php | 109 +------------- 3 files changed, 27 insertions(+), 291 deletions(-) diff --git a/CRM/Utils/Check/Component/Env.php b/CRM/Utils/Check/Component/Env.php index 75532be049..31b92afa3d 100644 --- a/CRM/Utils/Check/Component/Env.php +++ b/CRM/Utils/Check/Component/Env.php @@ -484,56 +484,15 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component { } if ($vc->isInfoAvailable) { - $newerVersion = $vc->isNewerVersionAvailable(); - if ($newerVersion['version']) { - $vInfo = array( - 1 => $newerVersion['version'], - 2 => $vc->localVersion, - ); - // LTS = long-term support version - if ($newerVersion['status'] == 'lts') { - $vInfo[1] .= ' ' . ts('(long-term support)'); - } - - if ($newerVersion['upgrade'] == 'security') { - // Security - $severity = \Psr\Log\LogLevel::CRITICAL; - $title = ts('CiviCRM Security Update Required'); - $message = ts('New security release %1 is available. The site is currently running %2.', $vInfo); - } - elseif ($newerVersion['status'] == 'eol') { - // Warn about EOL - $severity = \Psr\Log\LogLevel::WARNING; - $title = ts('CiviCRM Update Needed'); - $message = ts('New version %1 is available. The site is currently running %2, which has reached its end of life.', $vInfo); - } - else { - // For most new versions, just make them notice - $severity = \Psr\Log\LogLevel::NOTICE; - $title = ts('CiviCRM Update Available'); - $message = ts('New version %1 is available. The site is currently running %2.', $vInfo); - } - } - elseif (!empty($vc->cronJob['is_active'])) { - $vNum = $vc->localVersion; - // LTS = long-term support version - if ($newerVersion['status'] == 'lts') { - $vNum .= ' ' . ts('(long-term support)'); - } - - $severity = \Psr\Log\LogLevel::INFO; - $title = ts('CiviCRM Up-to-Date'); - $message = ts('CiviCRM version %1 is up-to-date.', array(1 => $vNum)); - } - - if (!empty($message)) { - $messages[] = new CRM_Utils_Check_Message( - __FUNCTION__, - $message, - $title, - $severity, - 'fa-cloud-upload' - ); + $severities = array( + 'info' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::INFO), + 'notice' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::NOTICE) , + 'warning' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::WARNING) , + 'critical' => CRM_Utils_Check::severityMap(\Psr\Log\LogLevel::CRITICAL), + ); + foreach ($vc->getVersionMessages() as $msg) { + $messages[] = new CRM_Utils_Check_Message(__FUNCTION__ . '_' . $msg['name'], + $msg['message'], $msg['title'], $severities[$msg['severity']], 'fa-cloud-upload'); } } diff --git a/CRM/Utils/VersionCheck.php b/CRM/Utils/VersionCheck.php index ce14ef4a12..740dd2f04e 100644 --- a/CRM/Utils/VersionCheck.php +++ b/CRM/Utils/VersionCheck.php @@ -32,9 +32,9 @@ */ class CRM_Utils_VersionCheck { const - CACHEFILE_NAME = 'version-info-cache.json', - // After which length of time we expire the cached version info (7+ days). - CACHEFILE_EXPIRE = 605000; + CACHEFILE_NAME = 'version-msgs-cache.json', + // After which length of time we expire the cached version info (3 days). + CACHEFILE_EXPIRE = 259200; /** * The version of the current (local) installation @@ -43,13 +43,6 @@ class CRM_Utils_VersionCheck { */ public $localVersion = NULL; - /** - * The major version (branch name) of the local version - * - * @var string - */ - public $localMajorVersion; - /** * Info about available versions * @@ -70,7 +63,7 @@ class CRM_Utils_VersionCheck { /** * @var string */ - public $pingbackUrl = 'https://latest.civicrm.org/stable.php?format=json'; + public $pingbackUrl = 'https://latest.civicrm.org/stable.php?format=summary'; /** * Pingback params @@ -91,7 +84,6 @@ class CRM_Utils_VersionCheck { */ public function __construct() { $this->localVersion = CRM_Utils_System::version(); - $this->localMajorVersion = $this->getMajorVersion($this->localVersion); $this->cacheFile = CRM_Core_Config::singleton()->uploadDir . self::CACHEFILE_NAME; } @@ -126,113 +118,19 @@ class CRM_Utils_VersionCheck { * * @param $info */ - public function setVersionInfo($info) { - $this->versionInfo = (array) $info; - // Sort version info in ascending order for easier comparisons - ksort($this->versionInfo, SORT_NUMERIC); - } - - /** - * Finds the release info for a minor version. - * @param string $version - * @return array|null - */ - public function getReleaseInfo($version) { - $majorVersion = $this->getMajorVersion($version); - if (isset($this->versionInfo[$majorVersion])) { - foreach ($this->versionInfo[$majorVersion]['releases'] as $info) { - if ($info['version'] == $version) { - return $info; - } - } - } - return NULL; + protected function setVersionInfo($info) { + $this->versionInfo = $info; } /** - * @param $minorVersion - * @return string + * @return array|NULL + * message: string + * title: string + * severity: string + * Ex: 'info', 'notice', 'warning', 'critical'. */ - public function getMajorVersion($minorVersion) { - if (!$minorVersion) { - return NULL; - } - list($a, $b) = explode('.', $minorVersion); - return "$a.$b"; - } - - - /** - * Get the latest version number if it's newer than the local one - * - * @return array - * Returns version number of the latest release if it is greater than the local version, - * along with the type of upgrade (regular/security) needed and the status of the major - * version - */ - public function isNewerVersionAvailable() { - $return = array( - 'version' => NULL, - 'upgrade' => NULL, - 'status' => NULL, - ); - - if ($this->versionInfo && $this->localVersion) { - if (isset($this->versionInfo[$this->localMajorVersion])) { - switch (CRM_Utils_Array::value('status', $this->versionInfo[$this->localMajorVersion])) { - case 'stable': - case 'lts': - case 'testing': - // look for latest version in this major version - $releases = $this->checkBranchForNewVersion($this->versionInfo[$this->localMajorVersion]); - if ($releases['newest']) { - $return['version'] = $releases['newest']; - - // check for intervening security releases - $return['upgrade'] = ($releases['security']) ? 'security' : 'regular'; - } - break; - - case 'eol': - default: - // look for latest version ever - foreach ($this->versionInfo as $majorVersionNumber => $majorVersion) { - if ($majorVersionNumber < $this->localMajorVersion || $majorVersion['status'] == 'testing') { - continue; - } - $releases = $this->checkBranchForNewVersion($this->versionInfo[$majorVersionNumber]); - - if ($releases['newest']) { - $return['version'] = $releases['newest']; - - // check for intervening security releases - $return['upgrade'] = ($releases['security'] || $return['upgrade'] == 'security') ? 'security' : 'regular'; - } - } - } - $return['status'] = $this->versionInfo[$this->localMajorVersion]['status']; - } - else { - // Figure if the version is really old or really new - $wayOld = TRUE; - - foreach ($this->versionInfo as $majorVersionNumber => $majorVersion) { - $wayOld = ($this->localMajorVersion < $majorVersionNumber); - } - - if ($wayOld) { - $releases = $this->checkBranchForNewVersion($majorVersion); - - $return = array( - 'version' => $releases['newest'], - 'upgrade' => 'security', - 'status' => 'eol', - ); - } - } - } - - return $return; + public function getVersionMessages() { + return $this->isInfoAvailable ? $this->versionInfo : NULL; } /** @@ -243,28 +141,6 @@ class CRM_Utils_VersionCheck { $this->pingBack(); } - /** - * @param $majorVersion - * @return null|string - */ - private function checkBranchForNewVersion($majorVersion) { - $newerVersion = array( - 'newest' => NULL, - 'security' => NULL, - ); - if (!empty($majorVersion['releases'])) { - foreach ($majorVersion['releases'] as $release) { - if (version_compare($this->localVersion, $release['version']) < 0) { - $newerVersion['newest'] = $release['version']; - if (CRM_Utils_Array::value('security', $release)) { - $newerVersion['security'] = $release['version']; - } - } - } - } - return $newerVersion; - } - /** * Collect info about the site to be sent as pingback data. */ diff --git a/tests/phpunit/CRM/Utils/versionCheckTest.php b/tests/phpunit/CRM/Utils/versionCheckTest.php index eb8980cb82..70096389ee 100644 --- a/tests/phpunit/CRM/Utils/versionCheckTest.php +++ b/tests/phpunit/CRM/Utils/versionCheckTest.php @@ -6,17 +6,6 @@ */ class CRM_Utils_versionCheckTest extends CiviUnitTestCase { - /** - * @return array - */ - public function get_info() { - return array( - 'name' => 'VersionCheck Test', - 'description' => 'Test versionCheck functionality', - 'group' => 'CiviCRM BAO Tests', - ); - } - public function setUp() { parent::setUp(); } @@ -100,100 +89,12 @@ class CRM_Utils_versionCheckTest extends CiviUnitTestCase { ), ); - /** - * @dataProvider newerVersionDataProvider - * @param string $localVersion - * @param array $versionInfo - * @param mixed $expectedResult - */ - public function testNewerVersion($localVersion, $versionInfo, $expectedResult) { - $vc = new CRM_Utils_VersionCheck(); - // These values are set by the constructor but for testing we override them - $vc->localVersion = $localVersion; - $vc->localMajorVersion = $vc->getMajorVersion($localVersion); - $vc->setVersionInfo($versionInfo); - $available = $vc->isNewerVersionAvailable(); - $this->assertEquals($available['version'], $expectedResult); - } - - /** - * @return array - * (localVersion, versionInfo, expectedResult) - */ - public function newerVersionDataProvider() { - $data = array(); - - // Make sure we do not get unstable release updates for a stable localVersion - $data[] = array('4.5.5', $this->sampleVersionInfo, NULL); - - // Make sure we do get unstable release updates for unstable localVersion - $data[] = array('4.6.alpha1', $this->sampleVersionInfo, '4.6.beta1'); - - // Make sure we get nothing (and no errors) if no versionInfo available - $data[] = array('4.7.beta1', array(), NULL); - - // Make sure alerts prioritize the localMajorVersion - $data[] = array('4.4.1', $this->sampleVersionInfo, '4.4.11'); - - // Make sure new security release on newest version doesn't trigger security - // notice on site running LTS version that doesn't have a security release - $data[] = array('4.3.9', $this->sampleVersionInfo, NULL); - - // Make sure new security release on newest version DOES trigger security - // notice on site running EOL version that doesn't have a security release - $data[] = array('4.2.19', $this->sampleVersionInfo, '4.5.5'); - - return $data; - } - - /** - * @dataProvider securityUpdateDataProvider - * @param string $localVersion - * @param array $versionInfo - * @param bool $expectedResult - */ - public function testSecurityUpdate($localVersion, $versionInfo, $expectedResult) { + public function tearDown() { + parent::tearDown(); $vc = new CRM_Utils_VersionCheck(); - // These values are set by the constructor but for testing we override them - $vc->localVersion = $localVersion; - $vc->localMajorVersion = $vc->getMajorVersion($localVersion); - $vc->setVersionInfo($versionInfo); - $available = $vc->isNewerVersionAvailable(); - $this->assertEquals($available['upgrade'], $expectedResult); - } - - /** - * @return array - * (localVersion, versionInfo, expectedResult) - */ - public function securityUpdateDataProvider() { - $data = array(); - - // Make sure we get alerted if a security release is available - $data[] = array('4.5.1', $this->sampleVersionInfo, 'security'); - - // Make sure we do not get alerted if a security release is not available - $data[] = array('4.5.5', $this->sampleVersionInfo, NULL); - - // Make sure we get false (and no errors) if no versionInfo available (this will be the case for pre-alphas) - $data[] = array('4.7.alpha1', array(), NULL); - - // If there are 2 security updates on the same day (e.g. lts and stable majorVersions) - // we should not get alerted to one if we are using the other - $data[] = array('4.4.11', $this->sampleVersionInfo, FALSE); - - // This version predates the ones in the info array, it should be assumed to be EOL and insecure - $data[] = array('4.0.1', $this->sampleVersionInfo, 'security'); - - // Make sure new security release on newest version doesn't trigger security - // notice on site running LTS version that doesn't have a security release - $data[] = array('4.3.9', $this->sampleVersionInfo, NULL); - - // Make sure new security release on newest version DOES trigger security - // notice on site running EOL version that doesn't have a security release - $data[] = array('4.2.19', $this->sampleVersionInfo, 'security'); - - return $data; + if (file_exists($vc->cacheFile)) { + unlink($vc->cacheFile); + } } public function testCronFallback() { -- 2.25.1