name: plugin-checks # Plugin-agnostic: nothing below names this plugin. Name, version and paths come from composer.json. # shopware-cli runs from its official Docker image, intentionally unpinned (latest); a red build # after a CLI release means fix the config. on: pull_request: branches: [main] permissions: contents: read # A new push to the PR cancels the superseded run. concurrency: group: plugin-checks-${{ github.ref }} cancel-in-progress: true jobs: # Every PR into main must bump the version and document it in CHANGELOG.md. version-changelog: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check version bump and changelog entry run: | set -e PR_VERSION=$(grep -m1 '"version"' composer.json | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/') MAIN_VERSION=$(git show origin/main:composer.json | grep -m1 '"version"' | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/') echo "main version: $MAIN_VERSION" echo "PR version: $PR_VERSION" if [ "$MAIN_VERSION" = "$PR_VERSION" ]; then echo "::error::composer.json version ($PR_VERSION) was not bumped from main ($MAIN_VERSION)" exit 1 fi HIGHEST=$(printf '%s\n%s\n' "$MAIN_VERSION" "$PR_VERSION" | sort -V | tail -n1) if [ "$HIGHEST" != "$PR_VERSION" ]; then echo "::error::composer.json version ($PR_VERSION) is not greater than main's ($MAIN_VERSION)" exit 1 fi if ! grep -qF "## [$PR_VERSION]" CHANGELOG.md; then echo "::error::CHANGELOG.md is missing a '## [$PR_VERSION]' heading" exit 1 fi echo "OK: version bumped to $PR_VERSION and documented in CHANGELOG.md" # Packages the extension (builds admin/storefront assets) and validates the resulting zip, # which is the artifact that ships. A separate directory validate would only repeat these checks. package: runs-on: ubuntu-latest container: image: ghcr.io/shopware/shopware-cli:latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: ./.gitea/actions/package # The release workflow reuses this tested zip when main ends up with the same tree # (it falls back to packaging again otherwise). - name: Tree hash of the packaged commit id: tree run: echo "hash=$(git rev-parse "${GITHUB_SHA}^{tree}")" >> "$GITHUB_OUTPUT" - name: Save tested zip for the release uses: actions/cache/save@v4 with: path: .build/package.zip key: plugin-zip-${{ steps.tree.outputs.hash }} phpunit: runs-on: ubuntu-latest # Same image as above: it already ships PHP, Composer and Node, so no apt install. container: image: ghcr.io/shopware/shopware-cli:latest services: database: # Shopware 6.6 supports MariaDB 10.11 / MySQL 8; 11.4 broke Shopware's own migrations. image: mariadb:10.11 env: MARIADB_ROOT_PASSWORD: root env: # Already the *_test name: Shopware's TestBootstrapper would otherwise append _test and run every migration a second time. DATABASE_URL: mysql://root:root@database:3306/shopware_test APP_ENV: test APP_URL: http://localhost APP_SECRET: ci-secret-not-for-production INSTANCE_ID: ci COMPOSER_MEMORY_LIMIT: '-1' COMPOSER_ALLOW_SUPERUSER: '1' steps: - uses: actions/checkout@v4 with: path: plugin-src # The cache key follows the Shopware version: a new release inside the plugin's supported range changes # the key, so the old project + database are never reused. Bump -v1 to force a refresh by hand. - name: Resolve the latest Shopware Version id: sw run: | set -e # The plugin's own constraint (require.shopware/core, e.g. ~6.6.0) decides which versions are acceptable; # Composer lists the matching ones newest first, the first stable one is the latest. CONSTRAINT=$(php -r 'echo json_decode(file_get_contents("plugin-src/composer.json"), true)["require"]["shopware/core"];') VERSION=$(composer show shopware/core "$CONSTRAINT" --all --format=json --no-interaction 2>/dev/null \ | php -r '$d = json_decode(stream_get_contents(STDIN), true); foreach ($d["versions"] as $v) { if (preg_match("/^v?\d+(\.\d+)+$/", $v)) { echo ltrim($v, "v"); exit; } }') test -n "$VERSION" || { echo "::error::could not resolve a Shopware version for ${CONSTRAINT}"; exit 1; } echo "Shopware ${VERSION} (constraint ${CONSTRAINT})" echo "version=${VERSION}" >> "$GITHUB_OUTPUT" # Project (vendor/, phpunit, config) and the installed database as a SQL dump. Neither depends on the plugin. - name: Restore Shopware project and database id: shopware uses: actions/cache/restore@v4 with: path: | shopware !shopware/var/cache !shopware/var/log shopware-db.sql.gz key: shopware-${{ steps.sw.outputs.version }}-installed-v1 - name: Create Shopware project if: steps.shopware.outputs.cache-hit != 'true' run: | set -e composer create-project "shopware/production:${{ steps.sw.outputs.version }}" shopware --no-interaction --no-scripts composer require --dev phpunit/phpunit:^10 --no-interaction --no-scripts -d shopware - name: Ensure the MariaDB client run: | command -v mariadb-dump >/dev/null || command -v mysqldump >/dev/null && exit 0 (apt-get update -q && apt-get install -y -q --no-install-recommends mariadb-client) || apk add --no-cache mariadb-client - name: Wait for the database run: | for i in $(seq 60); do (echo > /dev/tcp/database/3306) 2>/dev/null && exit 0 sleep 2 done echo "::error::database service did not come up"; exit 1 - name: Relax database durability (throwaway CI database, speeds up the install and the restore) run: | php -r '$p = new PDO("mysql:host=database;port=3306", "root", "root"); $p->exec("SET GLOBAL innodb_flush_log_at_trx_commit=0"); $p->exec("SET GLOBAL sync_binlog=0");' # One install into shopware_test; the bootstrapper then sees an installed DB, skips its own install and # only activates the plugin (tests/TestBootstrap.php forces plugin installation). - name: Install Shopware if: steps.shopware.outputs.cache-hit != 'true' working-directory: shopware run: bin/console system:install --basic-setup --create-database --force --no-interaction - name: Dump the installed database if: steps.shopware.outputs.cache-hit != 'true' run: | set -e DUMP=$(command -v mariadb-dump || command -v mysqldump) "$DUMP" -h database -P 3306 -u root -proot --skip-ssl --single-transaction --routines --triggers \ --databases shopware_test | gzip > shopware-db.sql.gz ls -l shopware-db.sql.gz - name: Save Shopware project and database if: steps.shopware.outputs.cache-hit != 'true' uses: actions/cache/save@v4 with: path: | shopware !shopware/var/cache !shopware/var/log shopware-db.sql.gz key: shopware-${{ steps.sw.outputs.version }}-installed-v1 - name: Restore the database from the cache if: steps.shopware.outputs.cache-hit == 'true' run: | set -e CLIENT=$(command -v mariadb || command -v mysql) gunzip -c shopware-db.sql.gz | "$CLIENT" -h database -P 3306 -u root -proot --skip-ssl - name: Resolve plugin name and install the plugin sources run: | # plugin directory name = short class name of extra.shopware-plugin-class CLASS=$(php -r 'echo json_decode(file_get_contents("plugin-src/composer.json"), true)["extra"]["shopware-plugin-class"];') PLUGIN_NAME="${CLASS##*\\}" echo "PLUGIN_NAME=${PLUGIN_NAME}" >> "$GITHUB_ENV" rm -rf "shopware/custom/plugins/${PLUGIN_NAME}" cp -r plugin-src "shopware/custom/plugins/${PLUGIN_NAME}" - name: Run phpunit working-directory: shopware run: vendor/bin/phpunit -c "custom/plugins/${PLUGIN_NAME}/phpunit.xml"