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
7 changed files with 212 additions and 66 deletions
Showing only changes of commit a551034442 - Show all commits

No files matched your search

+100
View File
@@ -0,0 +1,100 @@
name: plugin-checks
# Plugin-agnostic: nothing below names this plugin. Name, version and paths come from composer.json.
# shopware-cli is intentionally unpinned (latest); a red build after a CLI release means fix the config.
on:
pull_request:
branches: [main]
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install shopware-cli
run: |
curl -sL https://github.com/shopware/shopware-cli/releases/latest/download/shopware-cli_Linux_x86_64.tar.gz | tar -xz -C /tmp shopware-cli
sudo install /tmp/shopware-cli /usr/local/bin/shopware-cli || install /tmp/shopware-cli /usr/local/bin/shopware-cli
- name: Validate extension
run: shopware-cli extension validate .
package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install shopware-cli
run: |
curl -sL https://github.com/shopware/shopware-cli/releases/latest/download/shopware-cli_Linux_x86_64.tar.gz | tar -xz -C /tmp shopware-cli
sudo install /tmp/shopware-cli /usr/local/bin/shopware-cli || install /tmp/shopware-cli /usr/local/bin/shopware-cli
- name: Package extension
run: shopware-cli extension package . --output-directory .build --filename package.zip --git-commit "$GITHUB_SHA"
- name: Validate packaged zip
run: shopware-cli extension validate .build/package.zip
- name: Assert built JS is in the zip
run: |
set -e
LIST=$(unzip -Z1 .build/package.zip)
if [ -f src/Resources/app/administration/src/main.js ] || [ -f src/Resources/app/administration/src/main.ts ]; then
echo "$LIST" | grep -q 'Resources/public/administration/js/' || { echo "::error::admin entry exists but the zip has no built admin JS"; exit 1; }
fi
if [ -f src/Resources/app/storefront/src/main.js ] || [ -f src/Resources/app/storefront/src/main.ts ]; then
echo "$LIST" | grep -q 'Resources/app/storefront/dist/' || { echo "::error::storefront entry exists but the zip has no built storefront JS"; exit 1; }
fi
phpunit:
runs-on: ubuntu-latest
services:
database:
image: mariadb:11.4
env:
MARIADB_ROOT_PASSWORD: root
options: >-
--health-cmd="healthcheck.sh --connect --innodb_initialized"
--health-interval=5s --health-timeout=5s --health-retries=20
env:
DATABASE_URL: mysql://root:root@database:3306/shopware
APP_ENV: test
APP_URL: http://localhost
steps:
- uses: actions/checkout@v4
with:
path: plugin-src
- uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: gd, intl, pdo_mysql, zip, curl, mbstring, dom, xml, fileinfo, sodium, bcmath
tools: composer
- name: Resolve plugin name
run: |
# plugin directory name = short class name of extra.shopware-plugin-class
CLASS=$(jq -r '.extra["shopware-plugin-class"]' plugin-src/composer.json)
echo "PLUGIN_NAME=${CLASS##*\\}" >> "$GITHUB_ENV"
- name: Create Shopware 6.6 project
run: composer create-project shopware/production:6.6.* shopware --no-interaction --no-scripts
- name: Install Shopware and the plugin
working-directory: shopware
run: |
set -e
composer require --dev phpunit/phpunit:^10 --no-interaction
bin/console system:install --basic-setup --create-database --force --no-interaction
cp -r ../plugin-src "custom/plugins/${PLUGIN_NAME}"
bin/console plugin:refresh
bin/console plugin:install --activate "${PLUGIN_NAME}"
- name: Run phpunit
working-directory: shopware
run: vendor/bin/phpunit -c "custom/plugins/${PLUGIN_NAME}/phpunit.xml"
+3
View File
@@ -4,6 +4,9 @@ on:
pull_request:
branches: [main]
permissions:
contents: read
jobs:
version-changelog:
runs-on: ubuntu-latest
+68 -60
View File
@@ -1,11 +1,16 @@
name: release
# Plugin-agnostic: owner, repo, host, package name and version come from the `github` context
# and composer.json. shopware-cli is intentionally unpinned (latest).
# RELEASE_TOKEN is the single token used for releases, assets and the Composer registry.
on:
push:
branches: [main]
env:
SERVER_URL: https://git.arthurerlich.de
permissions:
contents: write
packages: write
jobs:
release:
@@ -17,15 +22,19 @@ jobs:
token: ${{ secrets.RELEASE_TOKEN }}
- name: Determine version and guard against re-release
id: version
id: meta
run: |
set -e
VERSION=$(grep -m1 '"version"' composer.json | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')
PACKAGE_NAME=$(grep -m1 '"name"' composer.json | sed -E 's/.*"name"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')
VERSION=$(jq -r .version composer.json)
PACKAGE_NAME=$(jq -r .name composer.json)
REPO_NAME="${GITHUB_REPOSITORY#*/}"
TAG="v${VERSION}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "package_name=${PACKAGE_NAME}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
{
echo "version=${VERSION}"
echo "package_name=${PACKAGE_NAME}"
echo "tag=${TAG}"
echo "zip=${REPO_NAME}-${TAG}.zip"
} >> "$GITHUB_OUTPUT"
if git ls-remote --tags origin "refs/tags/${TAG}" | grep -q "${TAG}"; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "Tag ${TAG} already exists, nothing to release."
@@ -33,68 +42,66 @@ jobs:
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Extract changelog section
if: steps.version.outputs.skip == 'false'
- uses: actions/setup-node@v4
if: steps.meta.outputs.skip == 'false'
with:
node-version: '20'
- name: Install shopware-cli
if: steps.meta.outputs.skip == 'false'
run: |
awk -v ver="${{ steps.version.outputs.version }}" '
curl -sL https://github.com/shopware/shopware-cli/releases/latest/download/shopware-cli_Linux_x86_64.tar.gz | tar -xz -C /tmp shopware-cli
sudo install /tmp/shopware-cli /usr/local/bin/shopware-cli || install /tmp/shopware-cli /usr/local/bin/shopware-cli
- name: Validate extension
if: steps.meta.outputs.skip == 'false'
run: shopware-cli extension validate .
- name: Package extension (prebuilt admin/storefront assets)
if: steps.meta.outputs.skip == 'false'
run: |
shopware-cli extension package . --output-directory .build \
--filename "${{ steps.meta.outputs.zip }}" --git-commit "$GITHUB_SHA"
- name: Validate packaged zip
if: steps.meta.outputs.skip == 'false'
run: shopware-cli extension validate ".build/${{ steps.meta.outputs.zip }}"
- name: Extract changelog section
if: steps.meta.outputs.skip == 'false'
run: |
awk -v ver="${{ steps.meta.outputs.version }}" '
BEGIN { found=0 }
/^## \[/ {
if (found) exit
if ($0 ~ "\[" ver "\]") { found=1; next }
if ($0 ~ "\\[" ver "\\]") { found=1; next }
}
found { print }
' CHANGELOG.md > release-notes.md
cat release-notes.md
- name: Create and push tag
if: steps.version.outputs.skip == 'false'
- name: Create Gitea release (creates the tag) and upload the zip
if: steps.meta.outputs.skip == 'false'
env:
TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
git config user.name "gitea-actions"
git config user.email "actions@git.arthurerlich.de"
git tag "${{ steps.version.outputs.tag }}"
git push origin "${{ steps.version.outputs.tag }}"
set -e
API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
BODY=$(jq -n --arg tag "${{ steps.meta.outputs.tag }}" --arg sha "$GITHUB_SHA" --rawfile notes release-notes.md \
'{tag_name:$tag, target_commitish:$sha, name:$tag, body:$notes}')
RELEASE_ID=$(curl -sf -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" -d "$BODY" "${API}/releases" | jq -r .id)
echo "release id: ${RELEASE_ID}"
curl -sf -H "Authorization: token ${TOKEN}" \
-F "attachment=@.build/${{ steps.meta.outputs.zip }}" \
"${API}/releases/${RELEASE_ID}/assets?name=${{ steps.meta.outputs.zip }}" > /dev/null
- name: Install shopware-cli
if: steps.version.outputs.skip == 'false'
run: |
curl -sL -o /tmp/shopware-cli.tar.gz \
https://github.com/shopware/shopware-cli/releases/latest/download/shopware-cli_Linux_x86_64.tar.gz
mkdir -p /tmp/swcli-extract
tar -xzf /tmp/shopware-cli.tar.gz -C /tmp/swcli-extract
cp /tmp/swcli-extract/shopware-cli /usr/local/bin/shopware-cli
- name: Validate extension (informational only, does not gate the release)
if: steps.version.outputs.skip == 'false'
run: shopware-cli extension validate . || true
- name: Package Store-style zip for the Gitea Release asset
if: steps.version.outputs.skip == 'false'
run: |
shopware-cli extension package . --output-directory .build \
--filename "AeonDumpManager-${{ steps.version.outputs.tag }}.zip"
- name: Build root-level zip for the Composer registry
if: steps.version.outputs.skip == 'false'
run: git archive --format=zip -o "composer-package-${{ steps.version.outputs.tag }}.zip" "${{ steps.version.outputs.tag }}"
- name: Create Gitea Release
if: steps.version.outputs.skip == 'false'
uses: akkuman/gitea-release-action@v1
with:
server_url: ${{ env.SERVER_URL }}
token: ${{ secrets.RELEASE_TOKEN }}
tag_name: ${{ steps.version.outputs.tag }}
name: ${{ steps.version.outputs.tag }}
body_path: release-notes.md
files: .build/AeonDumpManager-${{ steps.version.outputs.tag }}.zip
- name: Publish to Composer registry
if: steps.version.outputs.skip == 'false'
- name: Publish the same zip to the Composer registry
if: steps.meta.outputs.skip == 'false'
run: |
STATUS=$(curl -s -o /tmp/composer-publish.log -w "%{http_code}" \
-u "haylan:${{ secrets.RELEASE_TOKEN }}" \
-T "composer-package-${{ steps.version.outputs.tag }}.zip" \
"https://git.arthurerlich.de/api/packages/haylan/composer")
-u "${GITHUB_REPOSITORY_OWNER}:${{ secrets.RELEASE_TOKEN }}" \
-T ".build/${{ 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"
@@ -102,10 +109,11 @@ jobs:
fi
- name: Link Composer package to this repository
if: steps.version.outputs.skip == 'false'
if: steps.meta.outputs.skip == 'false'
run: |
ENCODED_NAME=$(printf '%s' "${{ steps.version.outputs.package_name }}" | sed 's#/#%2F#g')
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -u "haylan:${{ secrets.RELEASE_TOKEN }}" -X POST "https://git.arthurerlich.de/api/v1/packages/haylan/composer/${ENCODED_NAME}/-/link/AeonDumpManager")
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"
+17
View File
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.1.0] - 2026-10-03
### Changed
- Services and routes are now configured in YAML; the plugin requires PHP `^8.2`.
- Release pipeline: the packaged `shopware-cli` zip (with prebuilt assets) is validated and used for both the Gitea Release and the Composer registry; the release is created through the Gitea API after packaging, so a failed build no longer leaves an orphan tag.
- New PR checks: `shopware-cli` validate, package build and phpunit.
### Added
- Dedicated `aeon_dump_manager` monolog channel; dump jobs, deletions and purges are logged.
- Extension icon and `.config/shopware-extension.yml`.
### Removed
- Empty plugin lifecycle overrides.
## [0.0.5] - 2026-09-21
### Fixed
+1 -1
View File
@@ -3,7 +3,7 @@
"description": "Export database dumps for Shopware 6 environments.",
"type": "shopware-platform-plugin",
"license": "MIT",
"version": "0.0.5",
"version": "0.1.0",
"keywords": [
"shopware",
"shopware6",
+6 -5
View File
@@ -31,13 +31,14 @@ on branches `research/shopware-guideline-checklist`, `research/shopware-cli-ci-b
## 3. Pipeline
### PR workflow (`.gitea/workflows/pr.yml`, replaces `pr-version-check.yml`)
### PR workflows
Jobs (all required checks on `main`):
1. `version-changelog` - unchanged logic (version bump + changelog heading). Keep this job/workflow name so the existing required context `version-changelog / version-changelog (pull_request)` keeps working, or update protection when renamed.
2. `validate` - install `shopware-cli`, `extension validate .` (hard gate, no `|| true`).
3. `package` - `extension package` with `--git-commit "$GITHUB_SHA"`, then assert the zip contains built admin JS (`Resources/public/administration/js`) when an admin entry exists.
4. `phpunit` - `composer create-project shopware/production` (6.6.x) + MariaDB service, symlink plugin, install/activate, run phpunit. PHP 8.3.
`pr-version-check.yml` (job `version-changelog`) is unchanged apart from `permissions:`; its name keeps the existing required context. New `plugin-checks.yml`:
1. `validate` - install `shopware-cli`, `extension validate .` (hard gate, no `|| true`).
2. `package` - `extension package` with `--git-commit "$GITHUB_SHA"`, then assert the zip contains built admin JS (`Resources/public/administration/js`) when an admin entry exists.
3. `phpunit` - `composer create-project shopware/production` (6.6.x) + MariaDB service, copy the plugin into `custom/plugins`, install/activate, run phpunit. PHP 8.3.
### Release workflow (`.gitea/workflows/release.yml`)
+17
View File
@@ -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": [
"version-changelog / version-changelog (pull_request)",
"plugin-checks / validate (pull_request)",
"plugin-checks / package (pull_request)",
"plugin-checks / phpunit (pull_request)"
]
}'