Skip to content

Commit

Permalink
[BUGFIX] Render correct version information in Core Updater and repor…
Browse files Browse the repository at this point in the history
…ts module

Currently, the TYPO3 backend shows incomplete version information
regarding updates in the Core Updater and the reports. Both take
community-supported releases into account only and ignore the fact that
certain versions are covered by the ELTS program and thus render messages
about unsupported or invalid versions, which are false statements.

We now use the full information from get.typo3.org, and added lengthy
tests to avoid any further issues. The internally used
CoreVersionService is now able to handle ELTS releases as well and give
proper information to admins.

Resolves: #94745
Releases: master, 10.4, 9.5
Change-Id: I6485d36ded943acba723d55e23275554484e4f82
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/70311
Tested-by: core-ci <typo3@b13.com>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
  • Loading branch information
andreaskienast committed Aug 9, 2021
1 parent a02928f commit 4d4c37b
Show file tree
Hide file tree
Showing 10 changed files with 900 additions and 215 deletions.
149 changes: 109 additions & 40 deletions typo3/sysext/install/Classes/Controller/UpgradeController.php
Expand Up @@ -37,6 +37,7 @@
use TYPO3\CMS\Core\Service\OpcodeCacheService;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Install\CoreVersion\CoreRelease;
use TYPO3\CMS\Install\ExtensionScanner\Php\CodeStatistics;
use TYPO3\CMS\Install\ExtensionScanner\Php\GeneratorClassesResolver;
use TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\ArrayDimensionMatcher;
Expand Down Expand Up @@ -276,43 +277,116 @@ public function coreUpdateGetDataAction(ServerRequestInterface $request): Respon
*/
public function coreUpdateIsUpdateAvailableAction(): ResponseInterface
{
$action = null;
$this->coreUpdateInitialize();
$messageQueue = new FlashMessageQueue('install');

$messages = [];

if ($this->coreVersionService->isInstalledVersionAReleasedVersion()) {
$isDevelopmentUpdateAvailable = $this->coreVersionService->isYoungerPatchDevelopmentReleaseAvailable();
$isUpdateAvailable = $this->coreVersionService->isYoungerPatchReleaseAvailable();
$isUpdateSecurityRelevant = $this->coreVersionService->isUpdateSecurityRelevant();
if (!$isUpdateAvailable && !$isDevelopmentUpdateAvailable) {
$messageQueue->enqueue(new FlashMessage(
'',
'No regular update available',
FlashMessage::NOTICE
));
} elseif ($isUpdateAvailable) {
$newVersion = $this->coreVersionService->getYoungestPatchRelease();
if ($isUpdateSecurityRelevant) {
$messageQueue->enqueue(new FlashMessage(
'',
'Update to security relevant released version ' . $newVersion . ' is available!',
FlashMessage::WARNING
));
$action = ['title' => 'Update now', 'action' => 'updateRegular'];
$versionMaintenanceWindow = $this->coreVersionService->getMaintenanceWindow();
$renderVersionInformation = false;

if (!$versionMaintenanceWindow->isSupportedByCommunity() && !$versionMaintenanceWindow->isSupportedByElts()) {
$messages[] = [
'title' => 'Outdated version',
'message' => 'The currently installed TYPO3 version ' . $this->coreVersionService->getInstalledVersion() . ' does not receive any further updates, please consider upgrading to a supported version!',
'severity' => FlashMessage::ERROR,
];
$renderVersionInformation = true;
} else {
$currentVersion = $this->coreVersionService->getInstalledVersion();
$isCurrentVersionElts = $this->coreVersionService->isCurrentInstalledVersionElts();
$latestRelease = $this->coreVersionService->getYoungestPatchRelease();

$availableReleases = [];
if ($this->coreVersionService->isPatchReleaseSuitableForUpdate($latestRelease)) {
$availableReleases[] = $latestRelease;
}
if (!$versionMaintenanceWindow->isSupportedByCommunity()) {
if ($latestRelease->isElts()) {
// Check if there's a public release left that's not installed yet
$latestCommunityDrivenRelease = $this->coreVersionService->getYoungestCommunityPatchRelease();
if ($this->coreVersionService->isPatchReleaseSuitableForUpdate($latestCommunityDrivenRelease)) {
$availableReleases[] = $latestCommunityDrivenRelease;
$action = ['title' => 'Update now to version ' . $latestCommunityDrivenRelease->getVersion(), 'action' => 'updateRegular'];
}
} elseif (!$isCurrentVersionElts) {
// Inform user about ELTS being available soon if:
// - regular support ran out
// - the current installed version is no ELTS
// - no ELTS update was released, yet
$messages[] = [
'title' => 'ELTS will be available soon',
'message' => sprintf('The currently installed TYPO3 version %s doesn\'t receive any community-driven updates anymore, consider subscribing to Extended Long Term Support (ELTS) releases. Please read the information below.', $currentVersion),
'severity' => FlashMessage::WARNING,
];
$renderVersionInformation = true;
}
}

if ($availableReleases === []) {
$messages[] = [
'title' => 'Up to date',
'message' => 'There are no TYPO3 updates available.',
'severity' => FlashMessage::NOTICE,
];
} else {
$messageQueue->enqueue(new FlashMessage(
'',
'Update to regular released version ' . $newVersion . ' is available!',
FlashMessage::INFO
));
$action = ['title' => 'Update now', 'action' => 'updateRegular'];
foreach ($availableReleases as $availableRelease) {
$isUpdateSecurityRelevant = $this->coreVersionService->isUpdateSecurityRelevant($availableRelease);
$versionString = $availableRelease->getVersion();
if ($availableRelease->isElts()) {
$versionString .= ' ELTS';
}

if ($isUpdateSecurityRelevant) {
$title = ($availableRelease->isElts() ? 'ELTS ' : '') . 'Security update available!';
$message = sprintf('The currently installed version is %s, update to security relevant released version %s is available.', $currentVersion, $versionString);
$severity = FlashMessage::ERROR;
} else {
$title = ($availableRelease->isElts() ? 'ELTS ' : '') . 'Update available!';
$message = sprintf('Currently installed version is %s, update to regular released version %s is available.', $currentVersion, $versionString);
$severity = FlashMessage::WARNING;
}

if ($availableRelease->isElts()) {
if ($isCurrentVersionElts) {
$message .= ' Please visit my.typo3.org to download the release in your ELTS area.';
} else {
$message .= ' ' . sprintf('The currently installed TYPO3 version %s doesn\'t receive any community-driven updates anymore, consider subscribing to Extended Long Term Support (ELTS) releases. Please read the information below.', $currentVersion);
}

$renderVersionInformation = true;
}

$messages[] = [
'title' => $title,
'message' => $message,
'severity' => $severity,
];
}
}
} elseif ($isDevelopmentUpdateAvailable) {
$newVersion = $this->coreVersionService->getYoungestPatchDevelopmentRelease();
$messageQueue->enqueue(new FlashMessage(
'',
'Update to development release ' . $newVersion . ' is available!',
FlashMessage::INFO
));
$action = ['title' => 'Update now', 'action' => 'updateDevelopment'];
}

if ($renderVersionInformation) {
$supportedMajorReleases = $this->coreVersionService->getSupportedMajorReleases();
$supportMessages = [];
if (!empty($supportedMajorReleases['community'])) {
$supportMessages[] = sprintf('Currently community-supported TYPO3 versions: %s (more information at https://get.typo3.org).', implode(', ', $supportedMajorReleases['community']));
}
if (!empty($supportedMajorReleases['elts'])) {
$supportMessages[] = sprintf('Currently supported TYPO3 ELTS versions: %s (more information at https://typo3.com/elts).', implode(', ', $supportedMajorReleases['elts']));
}

$messages[] = [
'title' => 'TYPO3 Version information',
'message' => implode(' ', $supportMessages),
'severity' => FlashMessage::INFO,
];
}

foreach ($messages as $message) {
$messageQueue->enqueue(new FlashMessage($message['message'], $message['title'], $message['severity']));
}
} else {
$messageQueue->enqueue(new FlashMessage(
Expand Down Expand Up @@ -1117,9 +1191,9 @@ protected function coreUpdateInitialize()
*
* @param ServerRequestInterface $request
* @throws \RuntimeException
* @return string Version to handle, eg. 6.2.2
* @return CoreRelease
*/
protected function coreUpdateGetVersionToHandle(ServerRequestInterface $request): string
protected function coreUpdateGetVersionToHandle(ServerRequestInterface $request): CoreRelease
{
$type = $request->getQueryParams()['install']['type'];
if (!isset($type) || empty($type)) {
Expand All @@ -1128,12 +1202,7 @@ protected function coreUpdateGetVersionToHandle(ServerRequestInterface $request)
1380975303
);
}
if ($type === 'development') {
$versionToHandle = $this->coreVersionService->getYoungestPatchDevelopmentRelease();
} else {
$versionToHandle = $this->coreVersionService->getYoungestPatchRelease();
}
return $versionToHandle;
return $this->coreVersionService->getYoungestCommunityPatchRelease();
}

/**
Expand Down
69 changes: 69 additions & 0 deletions typo3/sysext/install/Classes/CoreVersion/CoreRelease.php
@@ -0,0 +1,69 @@
<?php

declare(strict_types = 1);

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

namespace TYPO3\CMS\Install\CoreVersion;

class CoreRelease
{
protected const RELEASE_TYPE_REGULAR = 'regular';
protected const RELEASE_TYPE_SECURITY = 'security';

protected $version;
protected $date;
protected $type;
protected $checksum;
protected $isElts;

public function __construct(string $version, \DateTimeInterface $date, string $type, string $checksum, bool $isElts = false)
{
$this->version = $version;
$this->date = $date;
$this->type = $type;
$this->checksum = $checksum;
$this->isElts = $isElts;
}

public static function fromApiResponse(array $response): self
{
return new self($response['version'], new \DateTimeImmutable($response['date']), $response['type'], $response['tar_package']['sha1sum'], $response['elts'] ?? false);
}

public function getVersion(): string
{
return $this->version;
}

public function getDate(): \DateTimeInterface
{
return $this->date;
}

public function isSecurityUpdate(): bool
{
return $this->type === self::RELEASE_TYPE_SECURITY;
}

public function getChecksum(): string
{
return $this->checksum;
}

public function isElts(): bool
{
return $this->isElts;
}
}
57 changes: 57 additions & 0 deletions typo3/sysext/install/Classes/CoreVersion/MaintenanceWindow.php
@@ -0,0 +1,57 @@
<?php

declare(strict_types = 1);

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

namespace TYPO3\CMS\Install\CoreVersion;

class MaintenanceWindow
{
protected $communitySupport;
protected $eltsSupport;

public function __construct(?\DateTimeInterface $communitySupport, ?\DateTimeInterface $eltsSupport)
{
$this->communitySupport = $communitySupport;
$this->eltsSupport = $eltsSupport;
}

public static function fromApiResponse(array $response): self
{
$maintainedUntil = isset($response['maintained_until']) ? new \DateTimeImmutable($response['maintained_until']) : null;
$eltsUntil = isset($response['elts_until']) ? new \DateTimeImmutable($response['elts_until']) : null;

return new self($maintainedUntil, $eltsUntil);
}

public function isSupportedByCommunity(): bool
{
return $this->isSupported($this->communitySupport);
}

public function isSupportedByElts(): bool
{
return $this->isSupported($this->eltsSupport);
}

protected function isSupported(?\DateTimeInterface $supportedUntil): bool
{
return $supportedUntil !== null
&& (
$supportedUntil >=
new \DateTimeImmutable('now', new \DateTimeZone('UTC'))
);
}
}
62 changes: 62 additions & 0 deletions typo3/sysext/install/Classes/CoreVersion/MajorRelease.php
@@ -0,0 +1,62 @@
<?php

declare(strict_types = 1);

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

namespace TYPO3\CMS\Install\CoreVersion;

class MajorRelease
{
protected $version;
protected $lts;
protected $title;
protected $maintenanceWindow;

public function __construct(string $version, ?string $lts, string $title, MaintenanceWindow $maintenanceWindow)
{
$this->version = $version;
$this->lts = $lts;
$this->title = $title;
$this->maintenanceWindow = $maintenanceWindow;
}

public static function fromApiResponse(array $response): self
{
$maintenanceWindow = MaintenanceWindow::fromApiResponse($response);
$ltsVersion = isset($response['lts']) ? (string)$response['lts'] : null;

return new self((string)$response['version'], $ltsVersion, $response['title'], $maintenanceWindow);
}

public function getVersion(): string
{
return $this->version;
}

public function getLts(): ?string
{
return $this->lts;
}

public function getTitle(): string
{
return $this->title;
}

public function getMaintenanceWindow(): MaintenanceWindow
{
return $this->maintenanceWindow;
}
}

0 comments on commit 4d4c37b

Please sign in to comment.