Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be549d4a51 |
No files matched your search
@@ -0,0 +1,22 @@
|
|||||||
|
compatibility_date: 2026-02-11
|
||||||
|
# shopware-cli extension configuration (build/package/validate)
|
||||||
|
build:
|
||||||
|
zip:
|
||||||
|
pack:
|
||||||
|
excludes:
|
||||||
|
paths:
|
||||||
|
- tests
|
||||||
|
- docs
|
||||||
|
- scripts
|
||||||
|
- phpunit.xml
|
||||||
|
- docker-compose.yml
|
||||||
|
- skills-lock.json
|
||||||
|
- AGENTS.md
|
||||||
|
- CLAUDE.md
|
||||||
|
- QWEN.md
|
||||||
|
- .config
|
||||||
|
- .gitea
|
||||||
|
- .claude
|
||||||
|
- .scratch
|
||||||
|
validation:
|
||||||
|
ignore: []
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: package-extension
|
||||||
|
description: >-
|
||||||
|
Package the Shopware extension with shopware-cli (builds admin/storefront assets), validate the
|
||||||
|
zip and assert it contains the built JS. Shared by the PR checks and the release workflow.
|
||||||
|
Must run in the ghcr.io/shopware/shopware-cli image, after actions/checkout.
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
filename:
|
||||||
|
description: Name of the zip written to .build/
|
||||||
|
default: package.zip
|
||||||
|
build:
|
||||||
|
description: "'false' skips packaging (a prebuilt zip is already in .build/) and only validates it"
|
||||||
|
default: 'true'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
if: inputs.build == 'true'
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.npm
|
||||||
|
~/.cache/shopware-cli
|
||||||
|
key: swcli-${{ runner.os }}-${{ hashFiles('composer.json', 'src/Resources/app/**/package*.json') }}
|
||||||
|
restore-keys: swcli-${{ runner.os }}-
|
||||||
|
- name: Package extension
|
||||||
|
if: inputs.build == 'true'
|
||||||
|
shell: bash
|
||||||
|
run: shopware-cli extension package . --output-directory .build --filename "${{ inputs.filename }}" --git-commit "$GITHUB_SHA"
|
||||||
|
- name: Validate packaged zip
|
||||||
|
shell: bash
|
||||||
|
run: shopware-cli extension validate ".build/${{ inputs.filename }}"
|
||||||
|
- name: Assert built JS is in the zip
|
||||||
|
shell: bash
|
||||||
|
run: scripts/ci/assert-built-assets.sh ".build/${{ inputs.filename }}"
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
# The version must be higher than the latest *published release* (not just higher than main), so main can
|
||||||
|
# carry a version whose release failed or was withdrawn without blocking the next PR.
|
||||||
|
- name: Check version is unreleased and changelog entry exists
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
PR_VERSION=$(grep -m1 '"version"' composer.json | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')
|
||||||
|
LATEST=$(curl -sf -H "Authorization: token ${TOKEN}" "${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases?limit=100" \
|
||||||
|
| jq -r '.[].tag_name' | sed 's/^v//' | sort -V | tail -n1)
|
||||||
|
LATEST="${LATEST:-0.0.0}"
|
||||||
|
|
||||||
|
echo "latest release: $LATEST"
|
||||||
|
echo "PR version: $PR_VERSION"
|
||||||
|
|
||||||
|
if [ "$PR_VERSION" = "$LATEST" ] || [ "$(printf '%s\n%s\n' "$LATEST" "$PR_VERSION" | sort -V | tail -n1)" != "$PR_VERSION" ]; then
|
||||||
|
echo "::error::composer.json version ($PR_VERSION) is not greater than the latest release ($LATEST)"
|
||||||
|
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: $PR_VERSION is unreleased 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 }}
|
||||||
|
|
||||||
|
# One run per supported Shopware minor (keep in sync with require.shopware/core in composer.json).
|
||||||
|
phpunit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
shopware: ['6.6', '6.7']
|
||||||
|
# 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 and 6.7 both support MariaDB 10.11; 11.4 broke 6.6'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 matrix minor (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="~${{ matrix.shopware }}.0"
|
||||||
|
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"
|
||||||
|
echo "constraint=${CONSTRAINT}" >> "$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
|
||||||
|
# shopware/production pins one exact core version and is not tagged for every core patch
|
||||||
|
# (e.g. core 6.6.10.31, template only up to 6.6.10.30): take the newest template inside the
|
||||||
|
# constraint, then require the resolved core version on top of it.
|
||||||
|
composer create-project "shopware/production:${{ steps.sw.outputs.constraint }}" shopware --no-interaction --no-scripts --no-install
|
||||||
|
composer require "shopware/core:${{ steps.sw.outputs.version }}" --no-update -d shopware
|
||||||
|
composer require --dev phpunit/phpunit:^10 --no-update -d shopware
|
||||||
|
composer update -W --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"
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
name: release
|
||||||
|
|
||||||
|
# Plugin-agnostic: owner, repo, host, package name and version come from the `github` context
|
||||||
|
# and composer.json. shopware-cli runs from its official Docker image, intentionally unpinned (latest).
|
||||||
|
# RELEASE_TOKEN is the single token used for releases, assets and the Composer registry.
|
||||||
|
#
|
||||||
|
# Every step is idempotent (release/asset reuse, registry 409 = already published), so a failed run can
|
||||||
|
# simply be re-run and picks up where it stopped. There is deliberately no "tag exists -> skip" guard:
|
||||||
|
# it made a half-finished release (tag + release but no registry package) impossible to heal.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
# Never run two releases at once; a second push waits instead of racing on the tag.
|
||||||
|
concurrency:
|
||||||
|
group: release
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ghcr.io/shopware/shopware-cli:latest
|
||||||
|
steps:
|
||||||
|
- name: Ensure helper tools (jq, curl, unzip, zip, git)
|
||||||
|
run: |
|
||||||
|
command -v jq >/dev/null && command -v curl >/dev/null && command -v unzip >/dev/null && command -v zip >/dev/null && command -v git >/dev/null && exit 0
|
||||||
|
(apt-get update -q && apt-get install -y -q --no-install-recommends jq curl unzip zip git) || apk add --no-cache jq curl unzip zip git
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
- name: Determine version, tag and file names
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
VERSION=$(jq -r .version composer.json)
|
||||||
|
PACKAGE_NAME=$(jq -r .name composer.json)
|
||||||
|
REPO_NAME="${GITHUB_REPOSITORY#*/}"
|
||||||
|
TAG="v${VERSION}"
|
||||||
|
{
|
||||||
|
echo "version=${VERSION}"
|
||||||
|
echo "package_name=${PACKAGE_NAME}"
|
||||||
|
echo "tag=${TAG}"
|
||||||
|
echo "zip=${REPO_NAME}-${TAG}.zip"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# Reuse the zip the PR workflow already built and tested for this exact tree.
|
||||||
|
- name: Tree hash of this commit
|
||||||
|
id: tree
|
||||||
|
run: echo "hash=$(git rev-parse "${GITHUB_SHA}^{tree}")" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Restore the tested zip from the PR run
|
||||||
|
id: prebuilt
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
with:
|
||||||
|
path: .build/package.zip
|
||||||
|
key: plugin-zip-${{ steps.tree.outputs.hash }}
|
||||||
|
|
||||||
|
- name: Name the prebuilt zip
|
||||||
|
if: steps.prebuilt.outputs.cache-hit == 'true'
|
||||||
|
run: mv .build/package.zip ".build/${{ steps.meta.outputs.zip }}"
|
||||||
|
|
||||||
|
# Packages only on a cache miss; always validates and asserts what ships (guards a bad cache entry).
|
||||||
|
- uses: ./.gitea/actions/package
|
||||||
|
with:
|
||||||
|
filename: ${{ steps.meta.outputs.zip }}
|
||||||
|
build: ${{ steps.prebuilt.outputs.cache-hit != 'true' }}
|
||||||
|
|
||||||
|
- name: Extract changelog section
|
||||||
|
run: |
|
||||||
|
awk -v ver="${{ steps.meta.outputs.version }}" '
|
||||||
|
BEGIN { found=0 }
|
||||||
|
/^## \[/ {
|
||||||
|
if (found) exit
|
||||||
|
if ($0 ~ "\\[" ver "\\]") { found=1; next }
|
||||||
|
}
|
||||||
|
found { print }
|
||||||
|
' CHANGELOG.md > release-notes.md
|
||||||
|
cat release-notes.md
|
||||||
|
|
||||||
|
- name: Create Gitea release (creates the tag) and upload the zip
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
|
||||||
|
TAG="${{ steps.meta.outputs.tag }}"
|
||||||
|
ZIP="${{ steps.meta.outputs.zip }}"
|
||||||
|
CODE=$(curl -s -o /tmp/release.json -w "%{http_code}" -H "Authorization: token ${TOKEN}" "${API}/releases/tags/${TAG}")
|
||||||
|
if [ "$CODE" = "200" ]; then
|
||||||
|
echo "Release ${TAG} already exists, reusing it."
|
||||||
|
else
|
||||||
|
BODY=$(jq -n --arg tag "$TAG" --arg sha "$GITHUB_SHA" --rawfile notes release-notes.md \
|
||||||
|
'{tag_name:$tag, target_commitish:$sha, name:$tag, body:$notes}')
|
||||||
|
curl -sf -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" -d "$BODY" "${API}/releases" > /tmp/release.json
|
||||||
|
fi
|
||||||
|
RELEASE_ID=$(jq -r .id /tmp/release.json)
|
||||||
|
echo "release id: ${RELEASE_ID}"
|
||||||
|
if jq -e --arg n "$ZIP" '.assets[]? | select(.name == $n)' /tmp/release.json > /dev/null; then
|
||||||
|
echo "Asset ${ZIP} already uploaded."
|
||||||
|
else
|
||||||
|
curl -sf -H "Authorization: token ${TOKEN}" -F "attachment=@.build/${ZIP}" \
|
||||||
|
"${API}/releases/${RELEASE_ID}/assets?name=${ZIP}" > /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Gitea's Composer registry needs composer.json at the zip root, but shopware-cli zips wrap
|
||||||
|
# everything in one top-level folder (the registry answers 400 "composer.json file is missing").
|
||||||
|
# Same prebuilt content, repacked root-level.
|
||||||
|
- name: Repack the zip for the Composer registry
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
rm -rf /tmp/repack && mkdir /tmp/repack
|
||||||
|
unzip -q ".build/${{ steps.meta.outputs.zip }}" -d /tmp/repack
|
||||||
|
if [ -f /tmp/repack/composer.json ]; then
|
||||||
|
ROOT=/tmp/repack
|
||||||
|
else
|
||||||
|
ROOT=$(find /tmp/repack -mindepth 1 -maxdepth 1 -type d | head -1)
|
||||||
|
fi
|
||||||
|
test -f "$ROOT/composer.json" || { echo "::error::no composer.json found in the packaged zip"; exit 1; }
|
||||||
|
OUT="$PWD/.build/composer-${{ steps.meta.outputs.zip }}"
|
||||||
|
# explicit file list with the leading "./" stripped, so entries are stored as "composer.json", "src/..."
|
||||||
|
(cd "$ROOT" && find . -mindepth 1 | sed 's|^\./||' | zip -q "$OUT" -@)
|
||||||
|
unzip -l "$OUT" | grep -E ' composer\.json$' > /dev/null || { echo "::error::repacked zip has no root-level composer.json"; exit 1; }
|
||||||
|
echo "repacked: $OUT"
|
||||||
|
|
||||||
|
- name: Publish to the Composer registry
|
||||||
|
run: |
|
||||||
|
STATUS=$(curl -s -o /tmp/composer-publish.log -w "%{http_code}" \
|
||||||
|
-u "${GITHUB_REPOSITORY_OWNER}:${{ secrets.RELEASE_TOKEN }}" \
|
||||||
|
-T ".build/composer-${{ steps.meta.outputs.zip }}" \
|
||||||
|
"${GITHUB_SERVER_URL}/api/packages/${GITHUB_REPOSITORY_OWNER}/composer")
|
||||||
|
cat /tmp/composer-publish.log
|
||||||
|
if [ "$STATUS" != "201" ] && [ "$STATUS" != "409" ]; then
|
||||||
|
echo "Unexpected HTTP status $STATUS publishing to the Composer registry"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Link Composer package to this repository
|
||||||
|
run: |
|
||||||
|
ENCODED_NAME=$(printf '%s' "${{ steps.meta.outputs.package_name }}" | sed 's#/#%2F#g')
|
||||||
|
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -u "${GITHUB_REPOSITORY_OWNER}:${{ secrets.RELEASE_TOKEN }}" -X POST \
|
||||||
|
"${GITHUB_SERVER_URL}/api/v1/packages/${GITHUB_REPOSITORY_OWNER}/composer/${ENCODED_NAME}/-/link/${GITHUB_REPOSITORY#*/}")
|
||||||
|
echo "link status: $STATUS"
|
||||||
|
if [ "$STATUS" != "201" ] && [ "$STATUS" != "400" ]; then
|
||||||
|
echo "::warning::Unexpected status linking the Composer package to this repository (HTTP $STATUS) - not fatal, release already published"
|
||||||
|
fi
|
||||||
+33
-48
@@ -1,54 +1,39 @@
|
|||||||
# ---> Symfony
|
# PHP
|
||||||
# Cache and logs (Symfony2)
|
vendor/
|
||||||
/app/cache/*
|
composer.phar
|
||||||
/app/logs/*
|
.phpunit.result.cache
|
||||||
!app/cache/.gitkeep
|
.phpunit.cache/
|
||||||
!app/logs/.gitkeep
|
.php-cs-fixer.cache
|
||||||
|
|
||||||
# Email spool folder
|
# Symfony / Shopware
|
||||||
/app/spool/*
|
/var/
|
||||||
|
/public/bundles/
|
||||||
|
/public/assets/
|
||||||
|
/custom/
|
||||||
|
/src/Shopware/Platform
|
||||||
|
|
||||||
# Cache, session files and logs (Symfony3)
|
# Frontend
|
||||||
/var/cache/*
|
*.vite/
|
||||||
/var/logs/*
|
**/public/administration/assets/
|
||||||
/var/sessions/*
|
**/public/static/js/
|
||||||
!var/cache/.gitkeep
|
|
||||||
!var/logs/.gitkeep
|
|
||||||
!var/sessions/.gitkeep
|
|
||||||
|
|
||||||
# Logs (Symfony4)
|
# Environment
|
||||||
/var/log/*
|
.env
|
||||||
!var/log/.gitkeep
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
# Parameters
|
# Agent skills (symlinked via skills.sh, tracked through skills-lock.json)
|
||||||
/app/config/parameters.yml
|
/.agents/
|
||||||
/app/config/parameters.ini
|
/.claude/
|
||||||
|
/.qwen/
|
||||||
|
/.opencode/
|
||||||
|
/.scratch/
|
||||||
|
|
||||||
# Managed by Composer
|
# IDE
|
||||||
/app/bootstrap.php.cache
|
.idea/
|
||||||
/var/bootstrap.php.cache
|
.vscode/
|
||||||
/bin/*
|
*.swp
|
||||||
!bin/console
|
|
||||||
!bin/symfony_requirements
|
|
||||||
/vendor/
|
|
||||||
|
|
||||||
# Assets and user uploads
|
|
||||||
/web/bundles/
|
|
||||||
/web/uploads/
|
|
||||||
|
|
||||||
# PHPUnit
|
|
||||||
/app/phpunit.xml
|
|
||||||
/phpunit.xml
|
|
||||||
|
|
||||||
# Build data
|
|
||||||
/build/
|
|
||||||
|
|
||||||
# Composer PHAR
|
|
||||||
/composer.phar
|
|
||||||
|
|
||||||
# Backup entities generated with doctrine:generate:entities command
|
|
||||||
**/Entity/*~
|
|
||||||
|
|
||||||
# Embedded web-server pid file
|
|
||||||
/.web-server-pid
|
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to AeonShopwareTools will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.0.1] - 2026-11-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Plugin skeleton for Shopware 6.6 and 6.7 (`shopware/core ~6.6.0 || ~6.7.0`, PHP `^8.2`).
|
||||||
|
- PR checks (version/changelog, package + validate, phpunit against the latest 6.6 and 6.7) and the release pipeline (Gitea Release + Composer registry), taken over from AeonDumpManager.
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## What this is
|
||||||
|
|
||||||
|
AeonShopwareTools is a public Shopware 6 plugin (`shopware-platform-plugin`, MIT) that bundles scripting
|
||||||
|
and developer tooling. It supports **Shopware 6.6 and 6.7 from one codebase**
|
||||||
|
(`shopware/core ~6.6.0 || ~6.7.0`, PHP `^8.2`): only use APIs that exist in both, and test against both.
|
||||||
|
|
||||||
|
- Plugin bootstrap class: `src/AeonShopwareTools.php` (wired via `composer.json` → `extra.shopware-plugin-class`).
|
||||||
|
- Services, commands and scheduled tasks are registered explicitly in `src/Resources/config/services.yaml`
|
||||||
|
(create it with the first service; no autowiring), each with its tag (`console.command`,
|
||||||
|
`shopware.scheduled.task`, ...).
|
||||||
|
|
||||||
|
## Running the plugin
|
||||||
|
|
||||||
|
There is no standalone runtime. `docker-compose.yml` mounts the repo into a `dockware/shopware` container at
|
||||||
|
`custom/plugins/AeonShopwareTools`; install with `bin/console plugin:refresh` and
|
||||||
|
`bin/console plugin:install --activate AeonShopwareTools` inside the container.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
PHPUnit through Shopware's `TestBootstrapper` (`tests/TestBootstrap.php`), so tests need a real Shopware
|
||||||
|
installation and database.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vendor/bin/phpunit -c custom/plugins/AeonShopwareTools/phpunit.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
## CI / release pipeline
|
||||||
|
|
||||||
|
Same Gitea pipeline as AeonDumpManager, plugin-agnostic (name/version come from `composer.json`):
|
||||||
|
|
||||||
|
- `workflows/plugin-checks.yml` (PRs into `main`): `version-changelog` (version greater than the latest
|
||||||
|
release, matching `## [x.y.z]` heading in CHANGELOG.md), `package` (`shopware-cli` package + validate,
|
||||||
|
`scripts/ci/assert-built-assets.sh`) and `phpunit`, a matrix over the latest 6.6 and 6.7. Keep the matrix
|
||||||
|
in sync with `require.shopware/core`.
|
||||||
|
- `workflows/release.yml` (push to `main`): Gitea Release with the zip, Composer registry publish. Uses `RELEASE_TOKEN`.
|
||||||
|
- Required checks on `main` are set with `scripts/protect-main.sh` (`tea api`).
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Arthur Erlich
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,2 +1,23 @@
|
|||||||
# AeonShopwareTools
|
# AeonShopwareTools
|
||||||
|
|
||||||
|
Scripting and developer tooling for Shopware 6.6 and 6.7.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require arthurerlich/aeon-shopware-tools
|
||||||
|
bin/console plugin:refresh
|
||||||
|
bin/console plugin:install --activate AeonShopwareTools
|
||||||
|
```
|
||||||
|
|
||||||
|
Or drop the release zip into `custom/plugins/` and install it from the admin.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
| Shopware | PHP |
|
||||||
|
|----------|--------|
|
||||||
|
| 6.6, 6.7 | ^8.2 |
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT, see [LICENSE](LICENSE). Changes are listed in [CHANGELOG.md](CHANGELOG.md).
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"name": "arthurerlich/aeon-shopware-tools",
|
||||||
|
"description": "Scripting and developer tooling for Shopware 6.6 and 6.7.",
|
||||||
|
"type": "shopware-platform-plugin",
|
||||||
|
"license": "MIT",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"keywords": [
|
||||||
|
"shopware",
|
||||||
|
"shopware6",
|
||||||
|
"plugin",
|
||||||
|
"tooling",
|
||||||
|
"scripting",
|
||||||
|
"developer-tools"
|
||||||
|
],
|
||||||
|
"homepage": "https://git.arthurerlich.de/haylan/AeonShopwareTools",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Arthur Erlich",
|
||||||
|
"homepage": "https://arthurerlich.de",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://git.arthurerlich.de/haylan/AeonShopwareTools/issues",
|
||||||
|
"source": "https://git.arthurerlich.de/haylan/AeonShopwareTools"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.2",
|
||||||
|
"shopware/core": "~6.6.0 || ~6.7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^10.0"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"shopware-plugin-class": "AeonShopwareTools\\AeonShopwareTools",
|
||||||
|
"copyright": "(c) by Arthur Erlich",
|
||||||
|
"label": {
|
||||||
|
"de-DE": "Shopware Tools",
|
||||||
|
"en-GB": "Shopware Tools"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"de-DE": "Für Entwickler und Betreiber von Shopware 6.6 und 6.7 bündelt Shopware Tools Skripte und Konsolenwerkzeuge, die wiederkehrende Aufgaben im Shop automatisieren.",
|
||||||
|
"en-GB": "For developers and operators of Shopware 6.6 and 6.7, Shopware Tools bundles scripts and console tooling that automate recurring maintenance tasks in the shop."
|
||||||
|
},
|
||||||
|
"manufacturerLink": {
|
||||||
|
"de-DE": "https://arthurerlich.de",
|
||||||
|
"en-GB": "https://arthurerlich.de"
|
||||||
|
},
|
||||||
|
"supportLink": {
|
||||||
|
"de-DE": "https://git.arthurerlich.de/haylan/AeonShopwareTools/issues",
|
||||||
|
"en-GB": "https://git.arthurerlich.de/haylan/AeonShopwareTools/issues"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"AeonShopwareTools\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"AeonShopwareTools\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimum-stability": "stable"
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
services:
|
||||||
|
shopware:
|
||||||
|
image: dockware/shopware:6.7.14.2
|
||||||
|
container_name: shopware
|
||||||
|
ports:
|
||||||
|
- "80:80" # Shop / Admin / Adminer / Mailcatcher (all served via path on this port)
|
||||||
|
- "443:443" # HTTPS
|
||||||
|
#- "3306:3306" # MySQL (exposed for external DB clients, e.g. TablePlus/DBeaver)
|
||||||
|
- "22:22" # SSH into the container
|
||||||
|
- "8888:8888" # Admin watcher (bin/build-administration.sh --watch)
|
||||||
|
- "9998:9998" # Storefront watcher proxy
|
||||||
|
- "9999:9999" # Storefront watcher
|
||||||
|
volumes:
|
||||||
|
- "db_volume:/var/lib/mysql"
|
||||||
|
- "shop_volume:/var/www/html"
|
||||||
|
- "./:/var/www/html/custom/plugins/AeonShopwareTools"
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
environment:
|
||||||
|
- PHP_VERSION=8.3
|
||||||
|
- XDEBUG_ENABLED=1
|
||||||
|
- SW_CURRENCY=EUR
|
||||||
|
- SSH_USER=shopware
|
||||||
|
- SSH_PWD=shopware
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_volume:
|
||||||
|
shop_volume:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
|
||||||
|
bootstrap="tests/TestBootstrap.php"
|
||||||
|
executionOrder="random">
|
||||||
|
<coverage>
|
||||||
|
<include>
|
||||||
|
<directory>./src/</directory>
|
||||||
|
</include>
|
||||||
|
</coverage>
|
||||||
|
<php>
|
||||||
|
<ini name="error_reporting" value="-1"/>
|
||||||
|
<server name="KERNEL_CLASS" value="Shopware\Core\Kernel"/>
|
||||||
|
<env name="APP_ENV" value="test"/>
|
||||||
|
<env name="APP_DEBUG" value="1"/>
|
||||||
|
<env name="SYMFONY_DEPRECATIONS_HELPER" value="weak"/>
|
||||||
|
</php>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="AeonShopwareTools Testsuite">
|
||||||
|
<directory>tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
</phpunit>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Assert that a packaged extension zip contains the built admin/storefront JS when the sources exist.
|
||||||
|
# Usage: scripts/ci/assert-built-assets.sh <zip> (run from the repo root; BusyBox-safe: uses unzip -l)
|
||||||
|
set -euo pipefail
|
||||||
|
ZIP="${1:?usage: assert-built-assets.sh <zip>}"
|
||||||
|
LIST=$(unzip -l "$ZIP")
|
||||||
|
|
||||||
|
check() { # <label> <entry-glob-prefix> <expected path in zip>
|
||||||
|
local label="$1" entry="$2" expected="$3"
|
||||||
|
if [ -f "${entry}/main.js" ] || [ -f "${entry}/main.ts" ]; then
|
||||||
|
echo "$LIST" | grep -q "$expected" || { echo "::error::${label} entry exists but the zip has no built ${label} JS (${expected})"; exit 1; }
|
||||||
|
echo "ok: ${label} JS is in the zip"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check admin src/Resources/app/administration/src "Resources/public/administration/assets/"
|
||||||
|
check storefront src/Resources/app/storefront/src "Resources/app/storefront/dist/"
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# One-time (re-runnable) setup: require the PR checks on `main` using the Gitea `tea` CLI.
|
||||||
|
# `tea branches protect` cannot set status-check contexts, hence `tea api`.
|
||||||
|
# Usage: scripts/protect-main.sh [owner/repo] (default: derived from the git remote)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO="${1:-$(git config --get remote.origin.url | sed -E 's#^.*[:/]([^/]+/[^/]+)$#\1#; s#\.git$##')}"
|
||||||
|
|
||||||
|
tea api -X PATCH "repos/${REPO}/branch_protections/main" -d '{
|
||||||
|
"enable_status_check": true,
|
||||||
|
"status_check_contexts": [
|
||||||
|
"plugin-checks / version-changelog (pull_request)",
|
||||||
|
"plugin-checks / package (pull_request)",
|
||||||
|
"plugin-checks / phpunit (6.6) (pull_request)",
|
||||||
|
"plugin-checks / phpunit (6.7) (pull_request)"
|
||||||
|
]
|
||||||
|
}'
|
||||||
@@ -0,0 +1,269 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"skills": {
|
||||||
|
"symfony:api-platform-dto-resources": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/api-platform-dto-resources/SKILL.md",
|
||||||
|
"computedHash": "0b5a49ef3b26381320570fc65262fe60f467869af7e9f34ea4b0f48762af2512"
|
||||||
|
},
|
||||||
|
"symfony:api-platform-filters": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/api-platform-filters/SKILL.md",
|
||||||
|
"computedHash": "b0a911aeb39f7e9788470356ebbab960d2a025da92452ee508e67192a387d020"
|
||||||
|
},
|
||||||
|
"symfony:api-platform-resources": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/api-platform-resources/SKILL.md",
|
||||||
|
"computedHash": "5d313ce0217ef198c5543728c4d0672c48fe1e9f0f0ffe8ae89e07c5c3cf30fb"
|
||||||
|
},
|
||||||
|
"symfony:api-platform-security": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/api-platform-security/SKILL.md",
|
||||||
|
"computedHash": "0c7a91b33c470450a699940c083cccea5256ea28a83b4a0acffd8575fedee4ec"
|
||||||
|
},
|
||||||
|
"symfony:api-platform-serialization": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/api-platform-serialization/SKILL.md",
|
||||||
|
"computedHash": "658ead8e467c493e429e39f4ff5465ecece42fdb49a2abbba708fd42535d4223"
|
||||||
|
},
|
||||||
|
"symfony:api-platform-state-providers": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/api-platform-state-providers/SKILL.md",
|
||||||
|
"computedHash": "2ef06b1eba9cc3619d3d50bb5c48f313d0d864d1cd18fef3767d5e3e705a8706"
|
||||||
|
},
|
||||||
|
"symfony:api-platform-tests": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/api-platform-tests/SKILL.md",
|
||||||
|
"computedHash": "351654fffb8b216acca349ff18053f4fdfba630f1678f8827a7ab3faeea258c8"
|
||||||
|
},
|
||||||
|
"symfony:api-platform-versioning": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/api-platform-versioning/SKILL.md",
|
||||||
|
"computedHash": "0249c23a63075fb29bea006561b873f56530838505cc6c2d56c6c75b0630271a"
|
||||||
|
},
|
||||||
|
"symfony:bootstrap-check": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/bootstrap-check/SKILL.md",
|
||||||
|
"computedHash": "b0770d00e974d3077f0dbab3aaab5b644a67cce72f099a9363fd68a6e7262b43"
|
||||||
|
},
|
||||||
|
"symfony:brainstorming": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/brainstorming/SKILL.md",
|
||||||
|
"computedHash": "33d085759b6c70252df183c9589e86d1819807b371d3cbc08a7629469dc5b024"
|
||||||
|
},
|
||||||
|
"symfony:config-env-parameters": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/config-env-parameters/SKILL.md",
|
||||||
|
"computedHash": "29c30ab73cf591f6940991e1e297836499e1760d390d0fea4faffbf9bc0d42d0"
|
||||||
|
},
|
||||||
|
"symfony:controller-cleanup": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/controller-cleanup/SKILL.md",
|
||||||
|
"computedHash": "e581ac4fa9f7e59035e17a96cdb306ae6fb4c1fe2bb2ddea75fbc8b3c61b7a7f"
|
||||||
|
},
|
||||||
|
"symfony:cqrs-and-handlers": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/cqrs-and-handlers/SKILL.md",
|
||||||
|
"computedHash": "eae9fd4fb0ba0e470e460c5bd5c64064a4a06b64b52398d199c54eb58fe283bc"
|
||||||
|
},
|
||||||
|
"symfony:daily-workflow": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/daily-workflow/SKILL.md",
|
||||||
|
"computedHash": "de275687dca8eaec1c7f28f395494585a6ebb56dd2fcadfce16ccd9730db3ab2"
|
||||||
|
},
|
||||||
|
"symfony:doctrine-batch-processing": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/doctrine-batch-processing/SKILL.md",
|
||||||
|
"computedHash": "1c25ad982501efe1e1284f94e89661e83eaf67e60f6e9a86e021c2c8b8c65885"
|
||||||
|
},
|
||||||
|
"symfony:doctrine-events": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/doctrine-events/SKILL.md",
|
||||||
|
"computedHash": "0543f6b3a9077b53624fb034cf88a5aadc57e14b37138c82beaa13fdad155fe9"
|
||||||
|
},
|
||||||
|
"symfony:doctrine-fetch-modes": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/doctrine-fetch-modes/SKILL.md",
|
||||||
|
"computedHash": "8020117b42ddc00e9165ca9cf9cd7e1e2d0cf688fb5fdd10a82b05a91bd0fe5e"
|
||||||
|
},
|
||||||
|
"symfony:doctrine-fixtures-foundry": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/doctrine-fixtures-foundry/SKILL.md",
|
||||||
|
"computedHash": "dbaa95893400a1be733ff779539986ba52fdd8431e9c5298fcaad1d69c9053a7"
|
||||||
|
},
|
||||||
|
"symfony:doctrine-migrations": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/doctrine-migrations/SKILL.md",
|
||||||
|
"computedHash": "f567cc35a98fe8ac6e6632d4da5990f974d4028c9517672586c42a3528861425"
|
||||||
|
},
|
||||||
|
"symfony:doctrine-relations": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/doctrine-relations/SKILL.md",
|
||||||
|
"computedHash": "cecba41492de5efed7b2b0d53c3d198c79c063d5232e18e3ce7b6342cecac69d"
|
||||||
|
},
|
||||||
|
"symfony:doctrine-transactions": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/doctrine-transactions/SKILL.md",
|
||||||
|
"computedHash": "1682b0b3fa1dc53db39471751467528d132bd72842b9d9e5d4c1dcb28bfcd1a2"
|
||||||
|
},
|
||||||
|
"symfony:e2e-panther-playwright": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/e2e-panther-playwright/SKILL.md",
|
||||||
|
"computedHash": "37071992ee5e27b3c0922f509d1ff0708912ec17f9149e81f4befd2f7d246284"
|
||||||
|
},
|
||||||
|
"symfony:effective-context": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/effective-context/SKILL.md",
|
||||||
|
"computedHash": "1e5fa157148bde5a3e48b7f2c275880e915781e43667d8b621cc1acdcafd04d9"
|
||||||
|
},
|
||||||
|
"symfony:executing-plans": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/executing-plans/SKILL.md",
|
||||||
|
"computedHash": "deff91ba8c9c68e7f1b63ae9c91638ebe14e63e9503cb48303a5e1aa0edea288"
|
||||||
|
},
|
||||||
|
"symfony:form-types-validation": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/form-types-validation/SKILL.md",
|
||||||
|
"computedHash": "3c1264ac1883e8d332181128b9bf620ed32ddd443ade6c42abc35eee178dfd03"
|
||||||
|
},
|
||||||
|
"symfony:functional-tests": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/functional-tests/SKILL.md",
|
||||||
|
"computedHash": "fe487c7a86acc172e4d2d9130d04f7377f3950ce654d095f64a25829b9811435"
|
||||||
|
},
|
||||||
|
"symfony:interfaces-and-autowiring": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/interfaces-and-autowiring/SKILL.md",
|
||||||
|
"computedHash": "18efd79e2b99806aaf7e3311391191e3041fede2e347d474a3c592af5b6e43e7"
|
||||||
|
},
|
||||||
|
"symfony:messenger-retry-failures": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/messenger-retry-failures/SKILL.md",
|
||||||
|
"computedHash": "760b7115b9c1c7c4ec0042b21d91bdd6a58ba9b451452485eae71e5057332e29"
|
||||||
|
},
|
||||||
|
"symfony:ports-and-adapters": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/ports-and-adapters/SKILL.md",
|
||||||
|
"computedHash": "e426df4395f29814ab6e89b703cd961c303958c4a832a575550e563d1cf8300c"
|
||||||
|
},
|
||||||
|
"symfony:quality-checks": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/quality-checks/SKILL.md",
|
||||||
|
"computedHash": "603a2a61a4515727f2de2a93d5ef7fcc6bb24da6b3d096f58724b81f18b437a4"
|
||||||
|
},
|
||||||
|
"symfony:rate-limiting": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/rate-limiting/SKILL.md",
|
||||||
|
"computedHash": "061cdadeb1e21fb322712c9951a2dc09acc8613376faf1002951b151d7369862"
|
||||||
|
},
|
||||||
|
"symfony:runner-selection": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/runner-selection/SKILL.md",
|
||||||
|
"computedHash": "238744ad7e55f67f29e3e0de838e8d675e4cf51a58fddc2056b0bf27b43c2b5d"
|
||||||
|
},
|
||||||
|
"symfony:strategy-pattern": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/strategy-pattern/SKILL.md",
|
||||||
|
"computedHash": "fe487cd678da11650e325c8f28b29a81e84b4938cfe4e42641b68c7bb622d377"
|
||||||
|
},
|
||||||
|
"symfony:symfony-cache": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/symfony-cache/SKILL.md",
|
||||||
|
"computedHash": "92bfade421c2190100ba603b9d0d05d260594be3b4725ba98a9c8963433d7a97"
|
||||||
|
},
|
||||||
|
"symfony:symfony-messenger": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/symfony-messenger/SKILL.md",
|
||||||
|
"computedHash": "4f7d3772433a2a03d570a3957d0a84f7f3d86782b273c14a8a75dae3aceb1e4d"
|
||||||
|
},
|
||||||
|
"symfony:symfony-scheduler": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/symfony-scheduler/SKILL.md",
|
||||||
|
"computedHash": "8978979cf09c166b3a68dc6f64f47f38ce805ef654f55c3e913e41fbee502096"
|
||||||
|
},
|
||||||
|
"symfony:symfony-voters": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/symfony-voters/SKILL.md",
|
||||||
|
"computedHash": "c9e782244caedf9787041d001ba90383b02a6a0e03f4645a699f6cbc204637f6"
|
||||||
|
},
|
||||||
|
"symfony:tdd-with-pest": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/tdd-with-pest/SKILL.md",
|
||||||
|
"computedHash": "c5eb112bf920982639a4ad5b5eec8341a97c31fa6d693b94cc28eb5ed01e6667"
|
||||||
|
},
|
||||||
|
"symfony:tdd-with-phpunit": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/tdd-with-phpunit/SKILL.md",
|
||||||
|
"computedHash": "484f05f7a16bf1e161eb4d2770b693526eb156f2a7502ea5833f64f5ef83e233"
|
||||||
|
},
|
||||||
|
"symfony:test-doubles-mocking": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/test-doubles-mocking/SKILL.md",
|
||||||
|
"computedHash": "943d6a81a333d1a3a454510cf972c38181428a6d6186d1a19cfbe99ea7ffe3e1"
|
||||||
|
},
|
||||||
|
"symfony:twig-components": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/twig-components/SKILL.md",
|
||||||
|
"computedHash": "ee7c1f99558ff8d28bbbb92fe47c41abc772ac76ef512ce645dbb88956cc20e5"
|
||||||
|
},
|
||||||
|
"symfony:using-symfony-superpowers": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/using-symfony-superpowers/SKILL.md",
|
||||||
|
"computedHash": "8666a5b730f5cd8d1b66d07bfdf2afee3bdf0b41acc2a3d699a2bcff55c4151b"
|
||||||
|
},
|
||||||
|
"symfony:value-objects-and-dtos": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/value-objects-and-dtos/SKILL.md",
|
||||||
|
"computedHash": "6db6bab1d41959b7e31ca3f5793548e057765b0bd1768b3f584357f49b7a92bb"
|
||||||
|
},
|
||||||
|
"symfony:writing-plans": {
|
||||||
|
"source": "dev-toolings/superpowers-symfony",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/writing-plans/SKILL.md",
|
||||||
|
"computedHash": "13387e37e27958478548530a78d130b8cc31fddc9f2903525e07ae1d3c7e80c0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace AeonShopwareTools;
|
||||||
|
|
||||||
|
use Shopware\Core\Framework\Plugin;
|
||||||
|
|
||||||
|
class AeonShopwareTools extends Plugin
|
||||||
|
{
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 569 B |
@@ -0,0 +1,16 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace AeonShopwareTools\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Shopware\Core\Framework\Test\TestCaseBase\KernelTestBehaviour;
|
||||||
|
|
||||||
|
class PluginBootTest extends TestCase
|
||||||
|
{
|
||||||
|
use KernelTestBehaviour;
|
||||||
|
|
||||||
|
public function testPluginIsActiveInTheKernel(): void
|
||||||
|
{
|
||||||
|
static::assertArrayHasKey('AeonShopwareTools', static::getKernel()->getBundles());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
use Shopware\Core\TestBootstrapper;
|
||||||
|
|
||||||
|
$loader = (new TestBootstrapper())
|
||||||
|
->addCallingPlugin()
|
||||||
|
->addActivePlugins('AeonShopwareTools')
|
||||||
|
->setForceInstallPlugins(true)
|
||||||
|
->bootstrap()
|
||||||
|
->getClassLoader();
|
||||||
|
|
||||||
|
$loader->addPsr4('AeonShopwareTools\\Tests\\', __DIR__);
|
||||||
Reference in new issue
Block a user