Skip to content

Commit

Permalink
feat(config): introduce configuration builder
Browse files Browse the repository at this point in the history
Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
  • Loading branch information
Altahrim committed May 16, 2024
1 parent 589f549 commit 68d8594
Show file tree
Hide file tree
Showing 10 changed files with 573 additions and 377 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
config/config.php: config/major_versions.json config/releases.json $(wildcard config/entreprise_releases.json)
@echo '🏗 Build configuration file $(@)…'
build/config_builder > $(@)

.ONESHELL:
29 changes: 29 additions & 0 deletions build/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Configuration builder

Generates the `config/config.php` file

### Configuration files
#### `major_versions.json`
List all major versions
```json
"29": {
"eol": "2025-04", // End of life as YYYY-mm. Optional, default to no end of life
"minPHP": "8.0" // Minimal PHP version
},
```

#### `releases.json`
```json
"29.0.0": {
"internalVersion": "29.0.0.19", // Internal version number
"signature": "<Base64 signature>", // Signature on one line
"deploy": 70 // Deploy percentage. Optional, default to 100%
}
```

### Build
Check if the `config.php` needs update and update it:
```bash
make config/config.php
```
Can be forced with `make -B config/config.php`
87 changes: 87 additions & 0 deletions build/config_builder
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);

require_once __DIR__.'/utils.php';

// Configuration
$docUrl = 'https://docs.nextcloud.com/server/%s/admin_manual/maintenance/upgrade.html';
$changelogServerUrl = 'https://updates.nextcloud.com/changelog_server/';
$majorVersions = loadJson('major_versions');
$releases = loadJson('releases');

try {
$enterpriseReleases = loadJson('enterprise');
$releases = array_merge($releases, $enterpriseReleases);
$latestReleases = $generatedConfig = ['enterprise' => [], 'stable' => [], 'beta' => []];
} catch (\Exception) {
$latestReleases = $generatedConfig = ['stable' => [], 'beta' => []];
}

// Search latest release for each major/stability
foreach ($releases as $releaseName => $ignored) {
$major = parseVersionName($releaseName)['major'];
$stability = getStabilityFromName($releaseName);
if (!isset($latestReleases[$stability][$major])) {
$latestReleases[$stability][$major] = $releaseName;
continue;
}
if (version_compare($latestReleases[$stability][$major], $releaseName, '<')) {
$latestReleases[$stability][$major] = $releaseName;
}
}

// Generate previous configuration
$now = date('Y-m');
foreach ($releases as $releaseName => $info) {
preg_match('/(\d+)\.(\d+).(\d+)(?: (.+))?/A', $releaseName, $matches);
[, $major, $minor, $patch] = $matches;
$stability = getStabilityFromName($releaseName);
$isEol = isset($majorVersions[$major]['eol']) ? ($majorVersions[$major]['eol'] < $now) : false;
$deployPercent = $info['deploy'] ?? 100;
$generatedConfig[$stability][$major]['100'] = [
'latest' => $releaseName,
'internalVersion' => $info['internalVersion'],
'downloadUrl' => buildDownloadUrl($releaseName, $info),
'web' => sprintf($docUrl, $major),
'eol' => $isEol,
'minPHPVersion' => $majorVersions[$major]['minPHP'] ?? '',
'signature' => isset($info['signature']) ? wordwrap($info['signature'], 64, cut_long_words: true) : '',
];

if (isset($latestReleases[$stability][$major - 1])) {
$upgradeFrom = $latestReleases[$stability][$major - 1];
$generatedConfig[$stability][$upgradeFrom][$deployPercent] = $generatedConfig[$stability][$major]['100'];
} elseif (isset($latestReleases['stable'][$major -1])) {
$upgradeFrom = $latestReleases['stable'][$major - 1];
$generatedConfig[$stability][$upgradeFrom][$deployPercent] = $generatedConfig[$stability][$major]['100'];
}
}

// Keep order like original config.php
foreach($generatedConfig as $stability => $ignored) {
uksort($generatedConfig[$stability], fn($a, $b) => version_compare((string) $b, (string) $a));
}

// Daily updates
$maxMajor = (int) max(array_keys($majorVersions));
foreach ($majorVersions as $majorVersion => $info) {
if ($majorVersion < 20) {
break;
}
$generatedConfig['daily'][$majorVersion] = [
'downloadUrl' => sprintf('https://download.nextcloud.com/server/daily/latest-%s.zip', $maxMajor === $majorVersion ? 'master' : 'stable'.$majorVersion),
'web' => sprintf($docUrl, $maxMajor === $majorVersion ? 'latest' : $majorVersion),
'eol' => isset($info['eol']) ? ($info['eol'] < $now) : false,
'minPHPVersion' => $info['minPHP'] ?? '7.2',
];
}

// Display result
echo '<?php',PHP_EOL,'return ';
echo preg_replace(
['/array\s*\(/', '/\)/', "/=>\s*\n\s*\[/", '/ /'],
['[', ']', '=> [', "\t"],
var_export($generatedConfig, true)
);
echo ';',PHP_EOL;
79 changes: 79 additions & 0 deletions build/utils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);

if (file_exists(__DIR__.'/enterprise_utils.php')) {
require_once __DIR__.'/enterprise_utils.php';
}

/**
* Load JSON from configuration file
*/
function loadJson(string $name): array {
$filepath = dirname(__DIR__).'/config/'.$name.'.json';
if (!is_file($filepath)) {
throw new \Exception('JSON file '.$filepath.' not found');
}

return json_decode(file_get_contents($filepath), true, flags: JSON_THROW_ON_ERROR);
}

/**
* Extract stability from release name
*
* @return string enterprise, stable or beta
*/
function getStabilityFromName(string $releaseName): string {
if (preg_match('/alpha|beta|rc/i', $releaseName)) {
return 'beta';
}
if (preg_match('/enterprise$/i', $releaseName)) {
return 'enterprise';
}

return 'stable';
}

/**
* Extract version info from release name
*/
function parseVersionName(string $releaseName): array {
preg_match('/(\d+)\.(\d+).(\d+)(?: (.*))?/', $releaseName, $matches);
[, $major, $minor, $patch] = $matches;
$stability = getStabilityFromName($releaseName);
return [
'major' => $major,
'minor' => $minor,
'patch' => $patch,
'modifier' => isset($matches[4]) ? $matches[4] : '',
'stability' => $stability,
];
}

function displayAsFile(array $generatedConfig) {
echo '<?php',PHP_EOL,'declare(strict_types=1);',PHP_EOL,PHP_EOL,'return ';
echo preg_replace(
['/array\s*\(/', '/\)/', "/=>\s*\n\s*\[/", '/ /'],
['[', ']', '=> [', "\t"],
var_export($generatedConfig, true)
);
echo ';',PHP_EOL;
}

function buildDownloadUrl(string $releaseName, array $info): string {
if (function_exists('buildEnterpriseDownloadUrl')) {
$url = buildEnterpriseDownloadUrl($releaseName, $info);
if ($url !== null) {
return $url;
}
}

$release = parseVersionName($releaseName);
$downloadUrl = 'https://download.nextcloud.com/server/%s/nextcloud-%d.%d.%d%s.zip';
return sprintf($downloadUrl,
$release['modifier'] === '' ? 'releases' : 'prereleases',
$release['major'],
$release['minor'],
$release['patch'],
$release['modifier'] === '' ? '' : str_replace(' ', '', strtolower('-'. $release['modifier'])),
);
}

0 comments on commit 68d8594

Please sign in to comment.