Skip to content

Commit

Permalink
NEW Migrate logic from workflows for reasoning about repository metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Apr 30, 2024
1 parent ea552a5 commit cf821f6
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/vendor/
composer.lock
12 changes: 12 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "silverstripe/supported-modules",
"description": "Metadata about Silverstripe CMS supported modules and other repositories maintained by Silverstripe",
"autoload": {
"psr-4": {
"SilverStripe\\SupportedModules\\": "src/"
}
},
"require": {
"composer/semver": "^3.4"
}
}
63 changes: 63 additions & 0 deletions src/BranchLogic.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace SilverStripe\SupportedModules;

use Composer\Semver\VersionParser;
use stdClass;

final class BranchLogic
{
public static function getCmsMajor(array $repoMetaData, string $branch, ?stdClass $composerJsonContent = null): string
{
$cmsMajor = self::getCmsMajorFromBranch($repoMetaData, $branch);
if ($cmsMajor == '') {
$cmsMajor = self::getCmsMajorFromComposerJson($composerJsonContent);
}
return $cmsMajor ?: MetaData::LOWEST_SUPPORTED_CMS_MAJOR;
}

private static function getCmsMajorFromBranch(array $repoMetaData, string $branch): string
{
$branchMajor = '';
if (preg_match('#^[1-9]+$#', $branch)) {
$branchMajor = $branch;
} elseif (preg_match('#^([1-9]+)\.[0-9]+$#', $branch, $matches)) {
$branchMajor = $matches[1];
}
foreach ($repoMetaData['majorVersionMapping'] ?? [] as $cmsMajor => $repoBranches) {
if (is_numeric($cmsMajor) && in_array($branchMajor, $repoBranches)) {
return $cmsMajor;
}
}
return '';
}

private static function getCmsMajorFromComposerJson(?stdClass $composerJsonContent = null): string
{
if ($composerJsonContent === null) {
return '';
}
foreach (MetaData::getAllRepositoryMetaData() as $categoryData) {
foreach ($categoryData as $repoData) {
$composerName = $repoData['packagist'] ?? null;
if ($composerName === null || !isset($composerJsonContent->require->$composerName)) {
continue;
}
$parser = new VersionParser();
$constraint = $parser->parseConstraints($composerJsonContent->require->$composerName);
$boundedVersion = explode('.', $constraint->getLowerBound()->getVersion());
$composerVersionMajor = $boundedVersion[0];
// If it's a non-numeric branch constraint or something unstable, don't use it
if ($composerVersionMajor === 0) {
continue;
}
foreach ($repoData['majorVersionMapping'] as $cmsMajor => $repoBranches) {
if (is_numeric($cmsMajor) && in_array($composerVersionMajor, $repoBranches)) {
return $cmsMajor;
}
}
}
}
return '';
}
}
94 changes: 94 additions & 0 deletions src/MetaData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

namespace SilverStripe\SupportedModules;

use RuntimeException;

final class MetaData
{
public const CATEGORY_SUPPORTED = 'supportedModules';

public const CATEGORY_WORKFLOW = 'workflow';

public const CATEGORY_TOOLING = 'tooling';

public const CATEGORY_MISC = 'misc';

public const LOWEST_SUPPORTED_CMS_MAJOR = '4';

public const HIGHEST_STABLE_CMS_MAJOR = '5';

private static array $repositoryMetaData = [];

/**
* Get metadata for a given repository, if we have any.
*
* @param string $gitHubReference The full GitHub reference for the repository
* e.g. `silverstripe/silverstripe-framework`.
* @param boolean $allowPartialMatch If no data is found for the full repository reference,
* check for repositories with the same name but a different organisation.
*/
public static function getMetaDataForRepository(
string $gitHubReference,
bool $allowPartialMatch = false
): array {
$parts = explode('/', $gitHubReference);
if (count($parts) !== 2) {
throw new RuntimeException('$gitHubReference must be a valid org/repo reference.');
}
$candidate = null;
foreach (self::getAllRepositoryMetaData() as $categoryData) {
foreach ($categoryData as $repoData) {
// Get data for the current repository
if ($repoData['github'] === $gitHubReference) {
// Exact match of org and repo name
return $repoData;
} elseif ($parts[1] === explode('/', $repoData['github'])[1]) {
// Partial match - repo name only
$candidate = $repoData;
}
}
}
if ($allowPartialMatch && $candidate !== null) {
return $candidate;
}
return [];
}

/**
* Get metadata for repositories that are released in lock-step with Silverstripe CMS minor releases.
*/
public static function getMetaDataForLocksteppedRepos(): array
{
$repos = [];
foreach (self::getAllRepositoryMetaData() as $category => $categoryData) {
// Skip anything that can't be lockstepped
if ($category !== self::CATEGORY_SUPPORTED) {
continue;
}
// Find lockstepped repos
foreach ($categoryData as $repoData) {
if (isset($repoData['lockstepped']) && $repoData['lockstepped'] && !empty($repoData['packagist'])) {
$repos[$repoData['packagist']] = $repoData['majorVersionMapping'];
}
}
}
return $repos;
}

/**
* Get all metadata about all repositories we have information about
*/
public static function getAllRepositoryMetaData(): array
{
if (empty(self::$repositoryMetaData)) {
$rawJson = file_get_contents(__DIR__ . '/../repositories.json');
$decodedJson = json_decode($rawJson, true);
if ($decodedJson === null) {
throw new RuntimeException('Could not parse repositories.json data: ' . json_last_error_msg());
}
self::$repositoryMetaData = $decodedJson;
}
return self::$repositoryMetaData;
}
}

0 comments on commit cf821f6

Please sign in to comment.