Skip to content

Commit

Permalink
Merge pull request #1053 from nextcloud-releases/feat/config-builder
Browse files Browse the repository at this point in the history
  • Loading branch information
Altahrim committed May 27, 2024
2 parents ce0a029 + 639a566 commit 30963a5
Show file tree
Hide file tree
Showing 11 changed files with 610 additions and 368 deletions.
13 changes: 7 additions & 6 deletions .github/workflows/prerelease-dir-check.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
name: Check directory for packages
name: Check config.php is up-to-date with JSON configuration files

on: pull_request

permissions:
contents: read

concurrency:
group: prerelease-dir-check-${{ github.head_ref || github.run_id }}
group: config-up-to-date-check-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
prerelease-dir-check:
config-up-to-date-check:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6

- name: Make sure all releases are stable and all prereleases are unstable
- name: Make sure config.php is up-to-date with JSON files
run: |
grep '/releases/' config/config.php | grep "'downloadUrl'" | grep -E '(rc|beta|alpha)' | wc -l | grep '^0$'
grep '/prereleases/' config/config.php | grep "'downloadUrl'" | grep -v -E '(rc|beta|alpha)' | wc -l | grep '^0$'
mv config/config.php config/config_pr.php
make config/config.php
diff config/config_pr.php config/config.php
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/enterprise_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`
97 changes: 97 additions & 0 deletions build/config_builder
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/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 => $info) {
$major = parseVersionName($releaseName)['major'];
$stability = getStabilityFromName($releaseName);
if (!isset($latestReleases[$stability][$major])) {
$latestReleases[$stability][$major] = $info['internalVersion'];
continue;
}
if (version_compare($latestReleases[$stability][$major], $releaseName, '<')) {
$latestReleases[$stability][$major] = $info['internalVersion'];
}
}

// 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;
$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) : '',
];

// Check if we can upgrade from a previous major version
$previousMajor = $major - 1;
$deployPercent = $info['deploy'] ?? 100;
if (isset($latestReleases[$stability][$previousMajor])) {
$upgradeFrom = $latestReleases[$stability][$previousMajor];
$generatedConfig[$stability][$upgradeFrom][$deployPercent] = $generatedConfig[$stability][$major]['100'];
} elseif (isset($latestReleases['stable'][$major -1])) {
$upgradeFrom = $latestReleases['stable'][$previousMajor];
$generatedConfig[$stability][$upgradeFrom][$deployPercent] = $generatedConfig[$stability][$major]['100'];
}

// For stable versions, check if we can upgrade from a beta version
if ($stability === 'stable') {
if (isset($latestReleases['beta'][$previousMajor])) {
$upgradeFrom = $latestReleases['beta'][$previousMajor];
$generatedConfig['beta'][$upgradeFrom][100] = $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, 30, 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'])),
);
}
Loading

0 comments on commit 30963a5

Please sign in to comment.