diff --git a/.github/workflows/sync-icon-sets.yml b/.github/workflows/sync-icon-sets.yml index 27704b2..9afd982 100644 --- a/.github/workflows/sync-icon-sets.yml +++ b/.github/workflows/sync-icon-sets.yml @@ -73,7 +73,8 @@ jobs: # the first run after a merge passed and every run after it failed. git fetch origin "+refs/heads/$BRANCH:refs/remotes/origin/$BRANCH" || true git checkout -B "$BRANCH" - git add icon-sets.json + # The sync sets docs/installation.md's pack-table counts from the catalogue too. + git add icon-sets.json docs/installation.md git commit -m 'docs: sync icon-sets catalog' || true # Lease kept rather than dropped for --force: it still refuses to clobber a # push that arrived after the fetch above, which is the case it exists for. diff --git a/CHANGELOG.md b/CHANGELOG.md index 923a3b9..bff3fe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ All notable changes to `ichava/core` follow [Keep a Changelog](https://keepachan ### Fixed +- **The nightly catalogue sync updates the installation guide's pack table with the catalogue.** `bin/sync-icon-sets.php` rewrote `icon-sets.json` alone, so a count change opened a pull request that `InstallationPackTableTest` failed: #179 moved tabler to 6,287 and openmoji to 8,990 while `docs/installation.md` still said 6,257 and 8,568. After writing the catalogue, the script now sets each table row's count from it with `withPackTableCounts()`, and the workflow commits both files. Rows, order and repositories are left as written, so a set added or removed still fails the table test. `tests/Unit/SyncIconSetsDocTableTest.php` covers it (proven red by leaving the counts alone). - **The nightly catalogue sync no longer puts Twemoji's pre-split values back.** `bin/sync-icon-sets.php` reads each pack at its latest tag, and `icon-sets-twemoji`'s `v0.1.0` still holds OpenMoji, so #176 proposed 10,567 "Emoji Sets" over the recorded 3,435 "Twemoji". A set in `icon-sets.json` may now carry a `hold` (`tag`, `commit`, `reason`): while that tag is the latest release at that commit the sync keeps the set's snapshot, and the hold drops itself once a newer tag is cut or the tag moves. The twemoji set is held at `v0.1.0`. `tests/Unit/SyncIconSetsHoldTest.php` covers it (proven red by ignoring the commit). - **A pack listed with the application boots again.** `PackConfigCache` resolved the cache store when it was built, and a pack's constants class builds it while the providers are still registering, before the store exists, so every pack failed to boot with `Target class [cache] does not exist` (found running the packs against #172). The store is now resolved when it is used. Core's own pack tests registered their fixture after boot, which is why none saw it; `tests/Feature/PackBootsInProviderListTest.php` lists the fixture with the application. - **`InformationService::discoverPackages()` finds the installed packs.** It globbed `vendor/*/ichava-*`, which matches no pack (packs install as `vendor/ichava/icon-sets-*`), and reported `registered` through `IconRegistry::has()`, which looks up an icon, not a package, so `ichava::ichava-core.info discover` listed nothing. It now asks `Composer\InstalledVersions` for every package of type `ichava-icon-set` and reports `registered` through `IconRegistry::isRegistered()`. The signature and return shape are unchanged. A pack is identified by its composer type and nothing else (owner, 2026-11-05): the `vendor/*/ichava-*` directory glob is removed, since no pack in the estate matched it, and the `platform/ichava` scan now keeps only a directory whose composer.json declares `ichava-icon-set`, keyed by that file's `name` instead of `ichava/`. A checkout there without the type is no longer listed. `tests/Feature/InstalledPackDiscoveryTest.php`. diff --git a/bin/sync-icon-sets.php b/bin/sync-icon-sets.php index eebc103..250da9f 100755 --- a/bin/sync-icon-sets.php +++ b/bin/sync-icon-sets.php @@ -31,10 +31,10 @@ // Run only when executed as a script, so the functions below can be loaded and tested on their own. if (realpath((string) ($_SERVER['SCRIPT_FILENAME'] ?? '')) === __FILE__) { - exit(main(dirname(__DIR__) . '/icon-sets.json')); + exit(main(dirname(__DIR__) . '/icon-sets.json', dirname(__DIR__) . '/docs/installation.md')); } -function main(string $manifestPath): int +function main(string $manifestPath, ?string $docPath = null): int { $raw = @file_get_contents($manifestPath); @@ -113,9 +113,48 @@ function main(string $manifestPath): int file_put_contents($manifestPath, $encoded . "\n"); echo "Wrote {$manifestPath}\n"; + // docs/installation.md shows each set's count, and InstallationPackTableTest fails when it + // disagrees with the catalogue. Writing the catalogue alone opened a pull request that + // could never go green (core#179), so the table moves with it. + if ($docPath !== null && is_file($docPath)) { + $doc = (string) file_get_contents($docPath); + $updated = withPackTableCounts($doc, $manifest['sets']); + + if ($updated !== $doc) { + file_put_contents($docPath, $updated); + echo "Wrote {$docPath}\n"; + } + } + return 0; } +/** + * The installation guide with each pack-table row's count set from the catalogue. + * + * Only the count cell of a row whose package is in the catalogue changes; rows, order and + * repositories are left as written, so a set added or removed still fails the table test + * rather than being papered over here. + * + * @param list> $sets + */ +function withPackTableCounts(string $doc, array $sets): string +{ + $counts = []; + + foreach ($sets as $set) { + if (isset($set['package'], $set['icon_count']) && is_int($set['icon_count'])) { + $counts[(string) $set['package']] = number_format($set['icon_count']); + } + } + + return (string) preg_replace_callback( + '/^(\| `(ichava\/[\w-]+)` \| )([^|]+?)( \| `https:\/\/github\.com\/[\w\/.-]+` \|)$/m', + static fn (array $m): string => isset($counts[$m[2]]) ? $m[1] . $counts[$m[2]] . $m[4] : $m[0], + $doc, + ); +} + /** * The catalogue without its sync timestamp, for comparing two runs. * diff --git a/tests/Unit/SyncIconSetsDocTableTest.php b/tests/Unit/SyncIconSetsDocTableTest.php new file mode 100644 index 0000000..3a2101b --- /dev/null +++ b/tests/Unit/SyncIconSetsDocTableTest.php @@ -0,0 +1,42 @@ + 6,287, +// openmoji 8,568 -> 8,990). The sync now sets the guide's count cells from the +// catalogue it writes. + +require_once dirname(__DIR__, 2) . '/bin/sync-icon-sets.php'; + +function docTable(string $tabler, string $openmoji): string +{ + return "Intro.\n\n| Package | Icons | Repository |\n|---|---|---|\n" + . "| `ichava/icon-sets-tabler` | {$tabler} | `https://github.com/ichava/icon-sets-tabler` |\n" + . "| `ichava/icon-sets-openmoji` | {$openmoji} | `https://github.com/ichava/icon-sets-openmoji` |\n" + . "\nOutro mentions 6,257 icons.\n"; +} + +it('sets each row count from the catalogue', function () { + $sets = [ + ['package' => 'ichava/icon-sets-tabler', 'icon_count' => 6287], + ['package' => 'ichava/icon-sets-openmoji', 'icon_count' => 8990], + ]; + + expect(withPackTableCounts(docTable('6,257', '8,568'), $sets))->toBe(docTable('6,287', '8,990')); +}); + +it('leaves a row the catalogue does not name, and the prose around the table', function () { + $doc = docTable('6,257', '8,568'); + + expect(withPackTableCounts($doc, [['package' => 'ichava/icon-sets-tabler', 'icon_count' => 6257]]))->toBe($doc) + ->and(withPackTableCounts($doc, []))->toBe($doc); +}); + +it('keeps the real guide in step with the real catalogue', function () { + $root = dirname(__DIR__, 2); + $sets = json_decode((string) file_get_contents($root . '/icon-sets.json'), true, flags: JSON_THROW_ON_ERROR)['sets']; + $doc = (string) file_get_contents($root . '/docs/installation.md'); + + expect(withPackTableCounts($doc, $sets))->toBe($doc); +});