feat: align plugin and pipeline with Shopware guidelines #13

Merged
haylan merged 13 commits from ci/shopware-guideline-compliance into main 2026-10-03 22:46:18 +00:00
Owner

Summary

Aligns the plugin and its build/release pipeline with Shopware's plugin guidelines and Gitea 28. Spec: docs/spec/shopware-guideline-compliance.md.

  • Plugin: dedicated aeon_dump_manager monolog channel and logging; services.xml/routes.php migrated to YAML; PHP ^8.2; extension icon; .config/shopware-extension.yml; empty lifecycle overrides removed.
  • PR checks (plugin-checks.yml): shopware-cli validate (hard gate), package + built-JS assertion, phpunit on shopware/production 6.6.
  • Release: validate, package from the merge commit, validate the zip, create the release via the Gitea API (creates the tag), publish the same zip to the Composer registry, link the package. No orphan tag on failed builds. Workflows are plugin-agnostic (derived from composer.json and the github context).
  • scripts/protect-main.sh sets the required status checks via tea api (run once after the first CI run shows the real check names).
  • Version bumped to 0.1.0 with changelog entry.

Not verified (first CI run is the test)

  • phpunit job setup (best-guess Shopware project bootstrap)
  • hand-converted YAML services/routes loading under Shopware 6.6
  • Composer registry accepting the zip with a top-level folder
  • status-check context names, release POST creating a missing tag, runner Node availability

🤖 Generated with Claude Code

## Summary Aligns the plugin and its build/release pipeline with Shopware's plugin guidelines and Gitea 28. Spec: `docs/spec/shopware-guideline-compliance.md`. - **Plugin:** dedicated `aeon_dump_manager` monolog channel and logging; `services.xml`/`routes.php` migrated to YAML; PHP `^8.2`; extension icon; `.config/shopware-extension.yml`; empty lifecycle overrides removed. - **PR checks (`plugin-checks.yml`):** `shopware-cli` validate (hard gate), package + built-JS assertion, phpunit on `shopware/production` 6.6. - **Release:** validate, package from the merge commit, validate the zip, create the release via the Gitea API (creates the tag), publish the same zip to the Composer registry, link the package. No orphan tag on failed builds. Workflows are plugin-agnostic (derived from `composer.json` and the `github` context). - `scripts/protect-main.sh` sets the required status checks via `tea api` (run once after the first CI run shows the real check names). - Version bumped to 0.1.0 with changelog entry. ## Not verified (first CI run is the test) - phpunit job setup (best-guess Shopware project bootstrap) - hand-converted YAML services/routes loading under Shopware 6.6 - Composer registry accepting the zip with a top-level folder - status-check context names, release POST creating a missing tag, runner Node availability 🤖 Generated with [Claude Code](https://claude.com/claude-code)
haylan added 3 commits 2026-10-03 21:29:23 +00:00
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- add dedicated monolog channel aeon_dump_manager and log dump jobs
- migrate services.xml/routes.php to YAML
- require PHP ^8.2
- add extension icon and .config/shopware-extension.yml
- drop empty lifecycle overrides

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci: plugin-agnostic PR checks and package-then-release pipeline
version-changelog / version-changelog (pull_request) Successful in 50s
plugin-checks / package (pull_request) Failing after 1m50s
plugin-checks / validate (pull_request) Failing after 31m29s
plugin-checks / phpunit (pull_request) Canceled after 33m2s
a551034442
- plugin-checks workflow: shopware-cli validate, package + built-JS assertion, phpunit
- release: validate, package from the merge commit, validate the zip, create the release
  via the Gitea API, publish the same zip to the Composer registry
- scripts/protect-main.sh sets required status checks via tea api
- bump to 0.1.0

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
haylan added 1 commit 2026-10-03 21:37:06 +00:00
fix: satisfy shopware-cli validate (description length, icon under 30kb)
version-changelog / version-changelog (pull_request) Successful in 38s
plugin-checks / package (pull_request) Successful in 1m35s
plugin-checks / phpunit (pull_request) Failing after 2m1s
plugin-checks / validate (pull_request) Successful in 15m51s
89a445f900
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
haylan added 1 commit 2026-10-03 21:46:16 +00:00
fix(plugin): reword descriptions, add transparent icon variant
version-changelog / version-changelog (pull_request) Successful in 42s
plugin-checks / package (pull_request) Successful in 1m38s
plugin-checks / phpunit (pull_request) Failing after 1m59s
plugin-checks / validate (pull_request) Canceled after 16m9s
54eeab70aa
haylan added 1 commit 2026-10-03 21:51:13 +00:00
ci: fix hanging setup-php, wait for DB manually, add compatibility_date
version-changelog / version-changelog (pull_request) Successful in 26s
plugin-checks / validate (pull_request) Failing after 1m45s
plugin-checks / package (pull_request) Failing after 1m45s
plugin-checks / phpunit (pull_request) Canceled after 11m9s
221ffece3f
- validate job needs no PHP (the package job already validates without it)
- phpunit: runner=self-hosted so setup-php does not hang under act; replace the
  unhealthy service healthcheck with a TCP wait loop
- .config/shopware-extension.yml: set compatibility_date

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
haylan added 1 commit 2026-10-03 22:03:15 +00:00
ci: PHP via apt in a bookworm container, retry shopware-cli download
plugin-checks / validate (pull_request) Successful in 1m49s
version-changelog / version-changelog (pull_request) Successful in 1m55s
plugin-checks / package (pull_request) Successful in 2m15s
plugin-checks / phpunit (pull_request) Failing after 10m31s
1ec194b464
setup-php hangs on the runner even with runner=self-hosted; the CLI download
returned a non-gzip body once under concurrent load.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
haylan added 1 commit 2026-10-03 22:07:09 +00:00
ci: run shopware-cli jobs in the official Docker image
version-changelog / version-changelog (pull_request) Successful in 59s
plugin-checks / validate (pull_request) Successful in 3m1s
plugin-checks / package (pull_request) Failing after 3m47s
plugin-checks / phpunit (pull_request) Failing after 6m38s
c3b242675e
Replaces the curl/tar install and setup-node steps; the image ships the
CLI plus its PHP/Node toolchain.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
haylan added 1 commit 2026-10-03 22:15:27 +00:00
ci: dedupe validate into package, add caches, run phpunit in the shopware-cli image
version-changelog / version-changelog (pull_request) Successful in 51s
plugin-checks / package (pull_request) Failing after 1m26s
plugin-checks / phpunit (pull_request) Failing after 3m3s
ff69377749
- drop the separate validate job (the zip is validated after packaging); same in release
- shared scripts/ci/assert-built-assets.sh (BusyBox-safe), now also used by release
- actions/cache for npm, shopware-cli and composer
- phpunit: shopware-cli image instead of a 4.5 min apt install; MariaDB 10.11
  (11.4 broke Shopware's migrations: Duplicate column 'sorter_key')
- protect-main.sh: drop the removed validate context

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
haylan added 1 commit 2026-10-03 22:15:36 +00:00
chore: mark CI scripts executable
version-changelog / version-changelog (pull_request) Successful in 53s
plugin-checks / package (pull_request) Successful in 1m43s
plugin-checks / phpunit (pull_request) Failing after 14m43s
9f760cb6b0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Owner

/review

/review
haylan added 1 commit 2026-10-03 22:29:20 +00:00
ci: cache the Shopware project, drop duplicate install, reuse the tested zip in release
version-changelog / version-changelog (pull_request) Successful in 24s
plugin-checks / package (pull_request) Successful in 1m18s
plugin-checks / phpunit (pull_request) Failing after 1m33s
37aba5d2f0
- phpunit: cache the prepared project (vendor + phpunit) monthly via cache restore/save;
  drop system:install/plugin:install (TestBootstrapper installs into its own test DB, so
  every migration ran twice, ~5.5 min each); relax InnoDB durability on the CI database
- package: save the tested zip keyed by the commit's tree hash; release restores it and
  only re-packages on a miss, but always validates and asserts the zip
- cancel superseded PR runs (concurrency)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
haylan added 1 commit 2026-10-03 22:32:19 +00:00
ci: merge version check into plugin-checks, share packaging as a composite action
plugin-checks / version-changelog (pull_request) Successful in 22s
plugin-checks / package (pull_request) Successful in 1m8s
plugin-checks / phpunit (pull_request) Failing after 1m53s
233f3eb17f
- one PR workflow (plugin-checks) with version-changelog, package, phpunit jobs
- .gitea/actions/package: package + validate + assert, used by PR and release
- phpunit: FORCE_INSTALL so the TestBootstrapper installs its own test DB
- protect-main.sh: required context is now plugin-checks / version-changelog

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Missing service

The new services.yaml references @aeon_dump_manager.filesystem.private for DumpLister and DumpService, but the file does not define that service. If the definition was in the deleted services.xml and was not migrated, the container will fail to compile when these services are resolved.

aeon_dump_manager.dump_lister:
    class: AeonDumpManager\Service\DumpLister
    arguments:
        - '@aeon_dump_manager.filesystem.private'
        - '@aeon_dump_manager.dump_filename_parser'

aeon_dump_manager.dump_service:
    class: AeonDumpManager\Service\DumpService
    arguments:
        - '@aeon_dump_manager.dump_lister'
        - '@aeon_dump_manager.filesystem.private'
        - '@aeon_dump_manager.dump_binary_locator'
        - '@Doctrine\DBAL\Connection'
        - '@Shopware\Core\System\SystemConfig\SystemConfigService'
        - '@aeon_dump_manager.dump_filename_parser'
        - '@monolog.logger.aeon_dump_manager'
Invalid loader

build() loads Resources/config/packages/monolog.yaml with Symfony's DI YamlFileLoader. That loader only accepts service-definition keys such as services, parameters, and imports; a top-level monolog key is bundle configuration and will likely cause a LoaderLoadException during container build. Use $container->loadFromExtension('monolog', ['channels' => ['aeon_dump_manager']]) or Shopware's supported plugin package loading mechanism.

public function build(ContainerBuilder $container): void
{
    parent::build($container);

    // Registers the dedicated monolog channel (Resources/config/packages/monolog.yaml)
    $locator = new FileLocator('Resources/config');
    $resolver = new LoaderResolver([
        new YamlFileLoader($container, $locator),
        new GlobFileLoader($container, $locator),
        new DirectoryLoader($container, $locator),
    ]);

    (new DelegatingLoader($resolver))->load(
        \rtrim($this->getPath(), '/') . '/Resources/config/packages/*.yaml',
        'glob'
    );
}
## PR Reviewer Guide 🔍 <!-- pr-agent:review:full --> Here are some key observations to aid the review process: <table> <tr><td>⏱️&nbsp;<strong>Estimated effort to review</strong>: 3 🔵🔵🔵⚪⚪</td></tr> <tr><td>🧪&nbsp;<strong>No relevant tests</strong></td></tr> <tr><td>🔒&nbsp;<strong>No security concerns identified</strong></td></tr> <tr><td>⚡&nbsp;<strong>Recommended focus areas for review</strong><br><br> <details><summary><a href='https://git.arthurerlich.de/haylan/AeonDumpManager/src/branch/ci/shopware-guideline-compliance/src/Resources/config/services.yaml#L19-L34'><strong>Missing service</strong></a> The new services.yaml references `@aeon_dump_manager.filesystem.private` for `DumpLister` and `DumpService`, but the file does not define that service. If the definition was in the deleted services.xml and was not migrated, the container will fail to compile when these services are resolved. </summary> ```yaml aeon_dump_manager.dump_lister: class: AeonDumpManager\Service\DumpLister arguments: - '@aeon_dump_manager.filesystem.private' - '@aeon_dump_manager.dump_filename_parser' aeon_dump_manager.dump_service: class: AeonDumpManager\Service\DumpService arguments: - '@aeon_dump_manager.dump_lister' - '@aeon_dump_manager.filesystem.private' - '@aeon_dump_manager.dump_binary_locator' - '@Doctrine\DBAL\Connection' - '@Shopware\Core\System\SystemConfig\SystemConfigService' - '@aeon_dump_manager.dump_filename_parser' - '@monolog.logger.aeon_dump_manager' ``` </details> <details><summary><a href='https://git.arthurerlich.de/haylan/AeonDumpManager/src/branch/ci/shopware-guideline-compliance/src/AeonDumpManager.php#L18-L34'><strong>Invalid loader</strong></a> `build()` loads `Resources/config/packages/monolog.yaml` with Symfony's DI `YamlFileLoader`. That loader only accepts service-definition keys such as `services`, `parameters`, and `imports`; a top-level `monolog` key is bundle configuration and will likely cause a `LoaderLoadException` during container build. Use `$container->loadFromExtension('monolog', ['channels' => ['aeon_dump_manager']])` or Shopware's supported plugin package loading mechanism. </summary> ```php public function build(ContainerBuilder $container): void { parent::build($container); // Registers the dedicated monolog channel (Resources/config/packages/monolog.yaml) $locator = new FileLocator('Resources/config'); $resolver = new LoaderResolver([ new YamlFileLoader($container, $locator), new GlobFileLoader($container, $locator), new DirectoryLoader($container, $locator), ]); (new DelegatingLoader($resolver))->load( \rtrim($this->getPath(), '/') . '/Resources/config/packages/*.yaml', 'glob' ); } ``` </details> </td></tr> </table>
haylan added 1 commit 2026-10-03 22:36:24 +00:00
ci: single Shopware install into shopware_test; serialize releases
plugin-checks / version-changelog (pull_request) Successful in 16s
plugin-checks / package (pull_request) Successful in 1m1s
plugin-checks / phpunit (pull_request) Successful in 6m2s
8a72751a14
DATABASE_URL already ends in _test so the TestBootstrapper finds an installed DB and
skips its own migration run; FORCE_INSTALL (which failed with an unknown database) removed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Owner

Reply from Claude (an AI assistant working on this PR for @haylan). I checked both findings against the CI logs and the Shopware docs and believe neither needs a code change.

1. @aeon_dump_manager.filesystem.private "missing"
Shopware registers <plugin_snake>.filesystem.private itself when it loads a plugin; it is not defined in the plugin's own config. The deleted services.xml referenced the same id without defining it. CI evidence: the run installed and activated the plugin with the YAML services (Plugin "AeonDumpManager" has been installed and activated successfully), and a missing service would have failed the container compile.

2. build() and the monolog loader
This is the pattern from Shopware's logging guide (plugin-fundamentals/logging): YamlFileLoader + GlobFileLoader + DirectoryLoader over Resources/config/packages/*.yaml. Symfony's YamlFileLoader hands unknown top-level keys such as monolog to the matching extension as configuration, so a top-level monolog key is valid. DumpService and the handlers are injected with @monolog.logger.aeon_dump_manager, which only exists if the channel loaded, and the container compiled in the same run.

Not covered: no test asserts that records reach the aeon_dump_manager channel at runtime.

Reply from Claude (an AI assistant working on this PR for @haylan). I checked both findings against the CI logs and the Shopware docs and believe neither needs a code change. **1. `@aeon_dump_manager.filesystem.private` "missing"** Shopware registers `<plugin_snake>.filesystem.private` itself when it loads a plugin; it is not defined in the plugin's own config. The deleted `services.xml` referenced the same id without defining it. CI evidence: the run installed and activated the plugin with the YAML services (`Plugin "AeonDumpManager" has been installed and activated successfully`), and a missing service would have failed the container compile. **2. `build()` and the monolog loader** This is the pattern from Shopware's logging guide (`plugin-fundamentals/logging`): `YamlFileLoader` + `GlobFileLoader` + `DirectoryLoader` over `Resources/config/packages/*.yaml`. Symfony's `YamlFileLoader` hands unknown top-level keys such as `monolog` to the matching extension as configuration, so a top-level `monolog` key is valid. `DumpService` and the handlers are injected with `@monolog.logger.aeon_dump_manager`, which only exists if the channel loaded, and the container compiled in the same run. Not covered: no test asserts that records reach the `aeon_dump_manager` channel at runtime.
haylan merged commit 85980ee3bf into main 2026-10-03 22:46:18 +00:00
haylan deleted branch ci/shopware-guideline-compliance 2026-10-03 22:46:18 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: haylan/AeonDumpManager#13