Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ReleaseChooser.php 4.05 KiB
<?php

namespace Drupal\automatic_updates;

use Composer\Semver\Semver;
use Drupal\automatic_updates\Validator\UpdateVersionValidator;
use Drupal\automatic_updates_9_3_shim\ProjectRelease;
use Drupal\Core\Extension\ExtensionVersion;

/**
 * Defines a class to choose a release of Drupal core to update to.
 */
class ReleaseChooser {

  use VersionParsingTrait;

  /**
   * The version validator service.
   *
   * @var \Drupal\automatic_updates\Validator\UpdateVersionValidator
   */
  protected $versionValidator;

  /**
   * The project information fetcher.
   *
   * @var \Drupal\automatic_updates\ProjectInfo
   */
  protected $projectInfo;

  /**
   * Constructs an ReleaseChooser object.
   *
   * @param \Drupal\automatic_updates\Validator\UpdateVersionValidator $version_validator
   *   The version validator.
   */
  public function __construct(UpdateVersionValidator $version_validator) {
    $this->versionValidator = $version_validator;
    $this->projectInfo = new ProjectInfo('drupal');
  }

  /**
   * Returns the releases that are installable.
   *
   * @return \Drupal\automatic_updates_9_3_shim\ProjectRelease[]
   *   The releases that are installable according to the version validator
   *   service.
   */
  protected function getInstallableReleases(): array {
    return array_filter(
      $this->projectInfo->getInstallableReleases(),
      [$this->versionValidator, 'isValidVersion'],
      ARRAY_FILTER_USE_KEY
    );
  }

  /**
   * Gets the most recent release in the same minor as a specified version.
   *
   * @param string $version
   *   The full semantic version number, which must include a patch version.
   *
   * @return \Drupal\automatic_updates_9_3_shim\ProjectRelease|null
   *   The most recent release in the minor if available, otherwise NULL.
   *
   * @throws \InvalidArgumentException
   *   If the given semantic version number does not contain a patch version.
   */
  protected function getMostRecentReleaseInMinor(string $version): ?ProjectRelease {
    if (static::getPatchVersion($version) === NULL) {
      throw new \InvalidArgumentException("The version number $version does not contain a patch version");
    }
    $releases = $this->getInstallableReleases();
    foreach ($releases as $release) {
      // Checks if the release is in the same minor as the currently installed
      // version. For example, if the current version is 9.8.0 then the
      // constraint ~9.8.0 (equivalent to >=9.8.0 && <9.9.0) will be used to
      // check if the release is in the same minor.
      if (Semver::satisfies($release->getVersion(), "~$version")) {
        return $release;
      }
    }
    return NULL;
  }

  /**
   * Gets the installed version of Drupal core.
   *
   * @return string
   *   The installed version of Drupal core.
   */
  protected function getInstalledVersion(): string {
    return $this->projectInfo->getInstalledVersion();
  }

  /**
   * Gets the latest release in the currently installed minor.
   *
   * This will only return a release if it passes the ::isValidVersion() method
   * of the version validator service injected into this class.
   *
   * @return \Drupal\automatic_updates_9_3_shim\ProjectRelease|null
   *   The latest release in the currently installed minor, if any, otherwise
   *   NULL.
   */
  public function getLatestInInstalledMinor(): ?ProjectRelease {
    return $this->getMostRecentReleaseInMinor($this->getInstalledVersion());
  }

  /**
   * Gets the latest release in the next minor.
   *
   * This will only return a release if it passes the ::isValidVersion() method
   * of the version validator service injected into this class.
   *
   * @return \Drupal\automatic_updates_9_3_shim\ProjectRelease|null
   *   The latest release in the next minor, if any, otherwise NULL.
   */
  public function getLatestInNextMinor(): ?ProjectRelease {
    $installed_version = ExtensionVersion::createFromVersionString($this->getInstalledVersion());
    $next_minor = $installed_version->getMajorVersion() . '.' . (((int) $installed_version->getMinorVersion()) + 1) . '.0';
    return $this->getMostRecentReleaseInMinor($next_minor);
  }

}