Skip to content

Commit 67e9bf4

Browse files
committed
Migrate core source code for v3 components
1 parent 2f9ee77 commit 67e9bf4

File tree

893 files changed

+85458
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

893 files changed

+85458
-2
lines changed

.editorconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
indent_size = 2
7+
indent_style = space
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.php]
12+
indent_size = 4
13+
max_line_length = 120
14+
15+
[*.md]
16+
trim_trailing_whitespace = false

.github/workflows/tests.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- '*.x'
8+
pull_request: ~
9+
schedule:
10+
- cron: '0 0 * * *'
11+
12+
jobs:
13+
phpunit:
14+
runs-on: ubuntu-latest
15+
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
php-versions: [ '8.2', '8.3', '8.4', '8.5' ]
20+
stability: [ 'prefer-lowest', 'prefer-stable' ]
21+
22+
name: PHPUnit on PHP ${{ matrix.php-versions }} - ${{ matrix.stability }}
23+
24+
continue-on-error: ${{ matrix.stability != 'prefer-stable' }}
25+
26+
steps:
27+
- name: 'Checkout code'
28+
uses: actions/checkout@v4
29+
30+
- name: 'Setup PHP'
31+
uses: shivammathur/setup-php@v2
32+
with:
33+
php-version: ${{ matrix.php-versions }}
34+
extensions: fileinfo, intl, mbstring, xml, pdo, pdo-mysql, yaml, amqp, redis
35+
ini-values: error_reporting=E_ALL
36+
tools: composer:v2
37+
coverage: xdebug
38+
39+
- name: 'Install dependencies'
40+
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress
41+
42+
- name: 'Execute tests'
43+
run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Change Log
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
## [3.0.0]
11+
12+
The version 3.0.0 marks the transition of the Berlioz Framework to a **Monorepo** structure.
13+
14+
Why this move?
15+
16+
- **Consistency:** Ensures all Berlioz components are tested and released together, preventing version mismatches.
17+
- **Maintenance:** Simplifies the management of issues and pull requests by centralizing them in one place.
18+
- **Better CI/CD:** Global testing ensures that a change in one package never breaks another.

bin/prepare-release.php

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
#!/usr/bin/env php
2+
<?php
3+
// Berlioz Framework – prepare-release.php
4+
// Logic:
5+
// 1. Load config.subsplit-publish.json to find packages.
6+
// 2. For each package: Merge Unreleased -> Version, collect items.
7+
// 3. For Root: Aggregate package items into root CHANGELOG.
8+
9+
declare(strict_types=1);
10+
11+
// ------- Args & Setup -----------------------------------------------------
12+
$args = array_values(array_slice($argv, 1));
13+
$dryRun = false;
14+
$filtered = [];
15+
foreach ($args as $a) {
16+
if ($a === '--dry-run') {
17+
$dryRun = true;
18+
} else {
19+
$filtered[] = $a;
20+
}
21+
}
22+
$args = $filtered;
23+
24+
if (count($args) < 2) {
25+
fwrite(STDERR, "Usage: php bin/prepare-release.php <version> <date:YYYY-MM-DD> [PackageName ...] [--dry-run]\n");
26+
exit(1);
27+
}
28+
29+
$version = $args[0];
30+
$date = $args[1];
31+
$explicitPkgs = array_slice($args, 2);
32+
33+
$rootDir = realpath(__DIR__ . '/..') ?: getcwd();
34+
$rootFile = $rootDir . '/CHANGELOG.md';
35+
$configFile = $rootDir . '/config.subsplit-publish.json';
36+
37+
// --- Loading Subsplit Config ---
38+
if (!is_file($configFile)) {
39+
fwrite(STDERR, "Error: config.subsplit-publish.json not found at $configFile\n");
40+
exit(1);
41+
}
42+
$config = json_decode(file_get_contents($configFile), true);
43+
$subsplits = $config['sub-splits'] ?? [];
44+
45+
// Standard Keep a Changelog order
46+
const CATEGORY_ORDER = ['Added', 'Changed', 'Deprecated', 'Removed', 'Fixed', 'Security', 'Docs'];
47+
const PLACEHOLDER = '_No changes in this release._';
48+
49+
// ------- Helpers (reused from your original script) -----------------------
50+
51+
function normEol(string $s): string
52+
{
53+
return str_replace(["\r\n", "\r"], "\n", $s);
54+
}
55+
56+
function extractRawSection(string $md, string $headerRegex): ?array
57+
{
58+
if (preg_match($headerRegex, $md, $m, PREG_OFFSET_CAPTURE)) {
59+
$start = (int)$m[0][1];
60+
$headerLen = strlen($m[0][0]);
61+
$bodyStart = $start + $headerLen;
62+
if (preg_match('/^##\s*\[/m', substr($md, $bodyStart), $nextM, PREG_OFFSET_CAPTURE)) {
63+
$len = $nextM[0][1];
64+
} else {
65+
$len = strlen($md) - $bodyStart;
66+
}
67+
return [
68+
'full_match' => substr($md, $start, $headerLen + $len),
69+
'body' => trim(substr($md, $bodyStart, $len)),
70+
'start' => $start,
71+
'length' => $headerLen + $len
72+
];
73+
}
74+
return null;
75+
}
76+
77+
function extractItems(string $text): array
78+
{
79+
$out = [];
80+
foreach (explode("\n", trim($text)) as $l) {
81+
if (preg_match('/^\s*[-*]\s+(.*)$/', $l, $matches)) {
82+
$out[] = trim($matches[1]);
83+
}
84+
}
85+
return $out;
86+
}
87+
88+
function parseKeepAChangelog(string $body): array
89+
{
90+
$sections = [];
91+
$current = null;
92+
$buf = '';
93+
$map = [
94+
'added' => 'Added',
95+
'new' => 'Added',
96+
'changed' => 'Changed',
97+
'updated' => 'Changed',
98+
'deprecated' => 'Deprecated',
99+
'removed' => 'Removed',
100+
'fixed' => 'Fixed',
101+
'bugfix' => 'Fixed',
102+
'security' => 'Security',
103+
'docs' => 'Docs',
104+
];
105+
foreach (explode("\n", $body) as $line) {
106+
if (preg_match('/^###\s+(.+?)\s*$/', $line, $m)) {
107+
if ($current !== null && isset($map[$current])) {
108+
$sections[$map[$current]] = array_merge($sections[$map[$current]] ?? [], extractItems($buf));
109+
}
110+
$current = strtolower(trim($m[1]));
111+
$buf = '';
112+
continue;
113+
}
114+
$buf .= $line . "\n";
115+
}
116+
if ($current !== null && isset($map[$current])) {
117+
$sections[$map[$current]] = array_merge($sections[$map[$current]] ?? [], extractItems($buf));
118+
}
119+
if (empty($sections) && trim($body) !== '' && trim($body) !== PLACEHOLDER) {
120+
$items = extractItems($body);
121+
if (!empty($items)) {
122+
$sections['Changed'] = $items;
123+
}
124+
}
125+
return $sections;
126+
}
127+
128+
function rebuildBody(array $categories): string
129+
{
130+
$output = "";
131+
foreach (CATEGORY_ORDER as $cat) {
132+
if (empty($categories[$cat])) {
133+
continue;
134+
}
135+
$sb = "### $cat\n\n";
136+
foreach ($categories[$cat] as $item) {
137+
$sb .= "- $item\n";
138+
}
139+
$output .= $sb . "\n";
140+
}
141+
return trim($output);
142+
}
143+
144+
// ------- Core Logic -------------------------------------------------------
145+
146+
echo "Preparing release $version ($date) for Berlioz Framework...\n";
147+
$packageBuckets = [];
148+
149+
foreach ($subsplits as $sub) {
150+
$pkgName = $sub['name'];
151+
$pkgDir = $rootDir . '/' . $sub['directory'];
152+
153+
// Si on a spécifié des packages en argument, on ignore les autres
154+
if (!empty($explicitPkgs) && !in_array($pkgName, $explicitPkgs)) {
155+
continue;
156+
}
157+
158+
$clPath = $pkgDir . '/CHANGELOG.md';
159+
if (!is_file($clPath)) {
160+
echo " [SKIP] $pkgName: No CHANGELOG.md found in " . $sub['directory'] . "\n";
161+
continue;
162+
}
163+
164+
$content = normEol(file_get_contents($clPath));
165+
$reUnreleased = '/^##\s*\[?Unreleased\]?\s*$/m';
166+
$reVersion = '/^##\s*\[' . preg_quote($version, '/') . '\]\s*(?:-\s*[\d-]{10})?\s*$/m';
167+
168+
$blockUnreleased = extractRawSection($content, $reUnreleased);
169+
$blockVersion = extractRawSection($content, $reVersion);
170+
171+
$finalVersionBody = '';
172+
$newPkgContent = $content;
173+
174+
if ($blockUnreleased) {
175+
$actionLog = "";
176+
// Merge or Rename logic (same as your original script)
177+
if ($blockVersion) {
178+
$unreleasedItems = parseKeepAChangelog($blockUnreleased['body']);
179+
$versionItems = parseKeepAChangelog($blockVersion['body']);
180+
$mergedItems = array_merge_recursive($versionItems, $unreleasedItems);
181+
$finalVersionBody = rebuildBody($mergedItems) ?: PLACEHOLDER;
182+
183+
$newVersionBlock = "## [$version] - $date\n\n" . $finalVersionBody . "\n\n";
184+
$newUnreleasedBlock = "## [Unreleased]\n\n";
185+
186+
$head = substr($content, 0, $blockUnreleased['start']);
187+
$between = substr($content, $blockUnreleased['start'] + $blockUnreleased['length'],
188+
$blockVersion['start'] - ($blockUnreleased['start'] + $blockUnreleased['length']));
189+
$tail = substr($content, $blockVersion['start'] + $blockVersion['length']);
190+
$newPkgContent = $head . $newUnreleasedBlock . $between . $newVersionBlock . $tail;
191+
$actionLog = "Merged into existing [$version]";
192+
} else {
193+
$finalVersionBody = $blockUnreleased['body'] ?: PLACEHOLDER;
194+
$replacement = "## [Unreleased]\n\n## [$version] - $date\n\n" . $finalVersionBody . "\n\n";
195+
$newPkgContent = substr_replace($content, $replacement, $blockUnreleased['start'],
196+
$blockUnreleased['length']);
197+
$actionLog = "Tagged as [$version]";
198+
}
199+
200+
if (!$dryRun) {
201+
file_put_contents($clPath, $newPkgContent);
202+
echo " [OK] $pkgName: $actionLog\n";
203+
} else {
204+
echo " [DRY] $pkgName: $actionLog\n";
205+
}
206+
}
207+
208+
// --- Aggregate for Root ---
209+
if ($finalVersionBody !== '' && trim($finalVersionBody) !== PLACEHOLDER) {
210+
$cats = parseKeepAChangelog($finalVersionBody);
211+
// Prefix with berlioz/ (or whatever prefix you use in config)
212+
$prefix = 'berlioz/' . $pkgName;
213+
foreach ($cats as $cat => $items) {
214+
foreach ($items as $it) {
215+
$packageBuckets[$cat][] = "**$prefix**: " . $it;
216+
}
217+
}
218+
}
219+
}
220+
221+
// --- PART 2: UPDATE ROOT CHANGELOG ---
222+
223+
if (!is_file($rootFile)) {
224+
echo "Root CHANGELOG.md not found.\n";
225+
exit(0);
226+
}
227+
228+
$rootContent = normEol(file_get_contents($rootFile));
229+
230+
// Regex for Root sections
231+
$reRootUnreleased = '/^##\s*\[?Unreleased\]?\s*$/m';
232+
$reRootVersion = '/^##\s*\[' . preg_quote($version, '/') . '\]\s*(?:-\s*[\d-]{10})?\s*$/m';
233+
234+
$blkRootUnrel = extractRawSection($rootContent, $reRootUnreleased);
235+
$blkRootVer = extractRawSection($rootContent, $reRootVersion);
236+
237+
$existingRootItems = [];
238+
$unreleasedRootItems = [];
239+
240+
if ($blkRootVer) {
241+
$existingRootItems = parseKeepAChangelog($blkRootVer['body']);
242+
}
243+
if ($blkRootUnrel) {
244+
$unreleasedRootItems = parseKeepAChangelog($blkRootUnrel['body']);
245+
}
246+
247+
// MERGE: Existing Root Version + Root Unreleased + New Package Items
248+
// array_merge_recursive peut créer des tableaux de tableaux, on aplatit et on déduplique
249+
$allRootItems = [];
250+
$categories = array_unique(array_merge(
251+
array_keys($existingRootItems),
252+
array_keys($unreleasedRootItems),
253+
array_keys($packageBuckets)
254+
));
255+
256+
foreach ($categories as $cat) {
257+
$combined = array_merge(
258+
$existingRootItems[$cat] ?? [],
259+
$unreleasedRootItems[$cat] ?? [],
260+
$packageBuckets[$cat] ?? []
261+
);
262+
263+
// Déduplication intelligente : on nettoie les espaces et on retire les doublons exacts
264+
$allRootItems[$cat] = array_values(array_unique(array_map('trim', $combined)));
265+
}
266+
267+
if (empty(array_filter($allRootItems))) {
268+
echo "No content to update in Root CHANGELOG.\n";
269+
exit(0);
270+
}
271+
272+
$newRootBody = rebuildBody($allRootItems);
273+
$newRootSection = "## [$version] - $date\n\n" . $newRootBody . "\n\n";
274+
$emptyUnreleased = "## [Unreleased]\n\n";
275+
276+
// --- RECONSTRUCTION DU FICHIER ---
277+
// Stratégie de reconstruction sécurisée pour éviter les décalages d'index
278+
if ($blkRootVer && $blkRootUnrel) {
279+
// Cas le plus courant : Unreleased est en haut, la Version cible est juste en dessous
280+
$parts = [];
281+
$parts[] = substr($rootContent, 0, $blkRootUnrel['start']);
282+
$parts[] = $emptyUnreleased;
283+
284+
// On garde ce qu'il y a entre Unreleased et la Version cible (souvent juste des sauts de ligne)
285+
$gap = substr($rootContent, $blkRootUnrel['start'] + $blkRootUnrel['length'],
286+
$blkRootVer['start'] - ($blkRootUnrel['start'] + $blkRootUnrel['length']));
287+
$parts[] = $gap;
288+
289+
$parts[] = $newRootSection;
290+
$parts[] = substr($rootContent, $blkRootVer['start'] + $blkRootVer['length']);
291+
292+
$newRootContent = implode('', $parts);
293+
$action = "Merged Unreleased & Existing Version into [$version]";
294+
295+
} elseif ($blkRootUnrel) {
296+
// Premier tag de cette version : On transforme Unreleased en Version et on recrée un Unreleased vide
297+
$replacement = $emptyUnreleased . $newRootSection;
298+
$newRootContent = substr_replace($rootContent, $replacement, $blkRootUnrel['start'], $blkRootUnrel['length']);
299+
$action = "Created [$version] from Unreleased + Packages";
300+
301+
} elseif ($blkRootVer) {
302+
// On met juste à jour le bloc de la version existante
303+
$newRootContent = substr_replace($rootContent, $newRootSection, $blkRootVer['start'], $blkRootVer['length']);
304+
$action = "Updated existing [$version] block";
305+
}
306+
307+
if ($dryRun) {
308+
echo "\n===== ROOT PREVIEW ($action) =====\n" . $newRootSection . "==================================\n";
309+
} else {
310+
file_put_contents($rootFile, $newRootContent);
311+
echo "Root CHANGELOG processed: $action.\n";
312+
}
313+
314+
echo "Done.\n";

0 commit comments

Comments
 (0)