Testen, Bauen, und Veröffentlichen von Shopware 6 Plugin mit GitLab CI - Teil 1 - Veröffentlichen

Insider Blog

Es gibt viele Möglichkeiten, Shopware 6 Plugins zu installieren. Sie können sie direkt im Admin-Panel herunterladen oder mit Composer installieren.

Einen detaillierten Vergleich finden Sie in der offiziellen Dokumentation.

Als Entwickler und Betreuer von Themes, Anpassungen, Drittanbieter-APIs usw. konzentriere ich mich auf statische Plugins.

Der Workflow ist einfach:

  1. Erstelle ein Plugin mit bin/console plugin:create --static
  2. Installiere es mit Composer
  3. Baue das Projekt mit shopware-cli

Wenn wir dasselbe Plugin in mehr als einem Shop benötigen, könnten wir dasselbe Plugin mehrfach erstellen, das wäre aber für die Wartung nicht optimal.

Das Plugin extrahieren

Wir fangen damit an, dass wir den Quellcode unseres Plugins in ein separates Repository verschieben. Um die Sache vorerst einfach zu machen, machen wir das Repository öffentlich.

Download mit Git

Wir müssen composer nur mitteilen, wo unser Plugin zu finden ist.

<project-root>/composer.json
{
  "name": "shopware/production",
  "license": "MIT",
  "type": "project",
  "require": {
    "composer-runtime-api": "^2.0",
    "acme/sample-plugin": "^1.0",
    "shopware/administration": "*",
    "shopware/core": "6.6.10.2",
    "shopware/elasticsearch": "*",
    "shopware/storefront": "*",
    "symfony/flex": "~2"
  },
  "repositories": [
    {
      "type": "path",
      "url": "custom/plugins/*",
      "options": {
        "symlink": true
      }
    },
    {
      "type": "path",
      "url": "custom/plugins/*/packages/*",
      "options": {
        "symlink": true
      }
    },
    {
      "type": "path",
      "url": "custom/static-plugins/*",
      "options": {
        "symlink": true
      }
    },
    {
      "type": "git",
      "url": "https://<DOMAIN-NAME>/<group>/<repo>.git"
    }
  ],
  "autoload": {
    "psr-4": {
      "App\\": "src/"
    }
  },
  "prefer-stable": true,
  "config": {
    "allow-plugins": {
      "symfony/flex": true,
      "symfony/runtime": true
    },
    "optimize-autoloader": true,
    "sort-packages": true
  },
  "scripts": {
    "auto-scripts": {
      "assets:install": "symfony-cmd"
    },
    "post-install-cmd": [
      "@auto-scripts"
    ],
    "post-update-cmd": [
      "@auto-scripts"
    ]
  },
  "extra": {
    "symfony": {
      "allow-contrib": true,
      "endpoint": [
        "https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json",
        "flex://defaults"
      ]
    }
  }
}

und installieren es mit

composer req acme/sample-plugin

Ja... das ist der Nachteil. Wir müssen dev-master als Version verwenden

composer req acme/sample-plugin:dev-master
./composer.json has been updated
Running composer update acme/sample-plugin
Loading composer repositories with package information                                                                
Updating dependencies                                 
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking acme/sample-plugin (dev-master 294414d)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Syncing acme/sample-plugin (dev-master 294414d) into cache
  - Installing acme/sample-plugin (dev-master 294414d): Cloning 294414deb2 from cache
Generating optimized autoload files

Run composer recipes at any time to see the status of your Symfony recipes.

Executing script assets:install [OK]

Composer wird git verwenden, um unser Repository zu klonen, und den Standard-Branch sowie den Commit-Hash verwenden, um den Release zu verfolgen.

Das funktioniert, aber wir können es besser machen.

Git Tags

Wir taggen nun unser Plugin als v1.0.0.

Bitte beachten, dass Sie die version in der composer.json gesetzt ist.

<plugin-root>/composer.json
{
    "name": "acme/sample-plugin",
    "description": "acme/sample-plugin",
    "type": "shopware-platform-plugin",
    "version": "1.0.0",
    "license": "MIT",
    "require": {
        "shopware/core": "~6.6.0"
    },
    "extra": {
        "shopware-plugin-class": "Acme\\SamplePlugin",
        "label": {
            "de-DE": "Skeleton plugin",
            "en-GB": "Skeleton plugin"
        }
    },
    "autoload": {
        "psr-4": {
            "Acme\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Acme\\Tests\\": "tests/"
        }
    }
}
git tag v1.0.0
git push --tags

Nun wird dies funktionieren:

composer req acme/sample-plugin
./composer.json has been updated                                                                                                            
Running composer update acme/sample-plugin
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking acme/sample-plugin (1.0.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Syncing acme/sample-plugin (1.0.0) into cache
  - Installing acme/sample-plugin (1.0.0): Cloning 294414deb2 from cache
Generating optimized autoload files

Run composer recipes at any time to see the status of your Symfony recipes.

Executing script assets:install [OK]

Using version ^1.0 for acme/sample-plugin

Das ist besser, aber wir verwenden immer noch git, um das Plugin abzurufen. Wir können es noch besser machen.

GitLab Package Registry

Hier beginnt der GitLab-Teil. Weitere Details sind in der offiziellen Dokumentation zu finden.

An dieser Stelle spielt es keine Rolle, ob unser Projekt öffentlich ist oder nicht, da wir uns ohnehin gegenüber der Package Registry authentifizieren müssen.

Wir veröffentlichen unseren v1.0.0-Tag als Composer-Paket.

curl --fail-with-body --data tag=v1.0.0 "https://__token__:<personal-access-token>@<DOMAIN-NAME>/api/v4/projects/<project_id>/packages/composer"

Nun müssen wir die Repository-Informationen aktualisieren:

<project-root>/composer.json
{
  "name": "shopware/production",
  "license": "MIT",
  "type": "project",
  "require": {
    "composer-runtime-api": "^2.0",
    "acme/sample-plugin": "^1.0",
    "shopware/administration": "*",
    "shopware/core": "6.6.10.2",
    "shopware/elasticsearch": "*",
    "shopware/storefront": "*",
    "symfony/flex": "~2"
  },
  "repositories": [
    {
      "type": "path",
      "url": "custom/plugins/*",
      "options": {
        "symlink": true
      }
    },
    {
      "type": "path",
      "url": "custom/plugins/*/packages/*",
      "options": {
        "symlink": true
      }
    },
    {
      "type": "path",
      "url": "custom/static-plugins/*",
      "options": {
        "symlink": true
      }
    },
    {
      "type": "composer",
      "url": "https://<DOMAIN-NAME>/api/v4/api/v4/group/<group_id>/-/packages/composer/packages.json"
    }
  ],
  "autoload": {
    "psr-4": {
      "App\\": "src/"
    }
  },
  "prefer-stable": true,
  "config": {
    "allow-plugins": {
      "symfony/flex": true,
      "symfony/runtime": true
    },
    "optimize-autoloader": true,
    "sort-packages": true
  },
  "scripts": {
    "auto-scripts": {
      "assets:install": "symfony-cmd"
    },
    "post-install-cmd": [
      "@auto-scripts"
    ],
    "post-update-cmd": [
      "@auto-scripts"
    ]
  },
  "extra": {
    "symfony": {
      "allow-contrib": true,
      "endpoint": [
        "https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json",
        "flex://defaults"
      ]
    }
  }
}

oder über das CLI:

composer config repositories.<group_id> composer https://<DOMAIN-NAME>/api/v4/group/<group_id>/-/packages/composer/packages.json

Und die GitLab-Anmeldeinformationen einrichten:

composer config gitlab-token.<DOMAIN-NAME> <personal_access_token>

Mehr über diesen Prozess in der offiziellen Dokumentation zu finden.

Jetzt installieren wir unser Paket wie gewohnt:

composer req acme/sample-plugin
./composer.json has been updated
Running composer update acme/sample-plugin
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking acme/sample-plugin (1.0.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Downloading acme/sample-plugin (1.0.0)
  - Installing acme/sample-plugin (1.0.0): Extracting archive
Generating optimized autoload files

Run composer recipes at any time to see the status of your Symfony recipes.

Executing script assets:install [OK]

Using version ^1.0 for acme/sample-plugin

Großartig. Direkter Paket-Download!

Warum die Mühe?

Das ist eine sehr gute Frage. Der Hauptgrund ist das Paket-Caching. Bei der Ausführung in einer CI/CD-Umgebung oder einem docker build kann das Caching von Paketen einen massiven Leistungsschub bewirken.



Release-Pipeline

Mit manuellem Tagging

Dies ist eine einfache Pipeline, in der ein Git-Tag manuell erstellt und pushen wird.

Bitte sicherstellen, dass Sie die version in der composer.json immer aktualisiert wird.

git tag <version>
git push --tags
.gitlab-ci.yml
stages:
  - release

deploy:
  image: alpine/curl
  stage: release
  script:
    - 'curl --fail-with-body --header "Job-Token: $CI_JOB_TOKEN" --data tag=$CI_COMMIT_TAG "${CI_API_V4_URL}/projects/$CI_PROJECT_ID/packages/composer"'
  environment: production
  rules:
    if: $CI_COMMIT_TAG

Mit semantic-release

Es wäre viel einfacher, wenn wir unsere Änderungen einfach pushen könnten und uns nicht um Versionierung und Tagging kümmern müssten.

semantic-release automatisiert den gesamten Workflow für Paket-Releases.

Bitte befolgen Sie der Anleitung zur GitLab-Authentifizierung, bevor Sie weiterlesen.

<plugin-root>/.gitlab-ci.yml
stages:
  - release

release:
  stage: release
  image:
    name: ghcr.io/voxpupuli/semantic-release:25.0.0-latest
    entrypoint: [""]
  interruptible: true
  script:
    - /container-entrypoint.sh
  rules:
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
      when: never
    - if: $CI_COMMIT_BRANCH
<plugin-root>/.releaserc.json
{
  "plugins": [
    "@semantic-release/commit-analyzer",
    [
      "semantic-release-replace-plugin",
      {
        "replacements": [
          {
            "files": ["composer.json"],
            "from": "version\": \".*\"",
            "to": "version\": \"${nextRelease.version}\""
          }
        ]
      }
    ],
    [
      "@semantic-release/git",
      {
        "assets": ["composer.json"],
        "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
      }
    ],
    [
      "@semantic-release/exec",
      {
        "publishCmd": "curl --fail-with-body --header \"Job-Token: ${process.env.CI_JOB_TOKEN}\" --data tag=${nextRelease.gitTag} ${process.env.CI_API_V4_URL}/projects/${process.env.CI_PROJECT_ID}/packages/composer"
      }
    ]
  ]
}

Dies wird:

  1. Die Commits seit dem letzten Release analysieren, um zu entscheiden, ob eine neue Version veröffentlicht werden soll
  2. Die Version in der composer.json aktualisieren
  3. Die composer.json zurück in das Repository committen
  4. Einen Tag erstellen
  5. Ein Composer-Paket von diesem Tag releasen

Autor

Steckbrief

Veröffentlicht:

26. März 2026

Kategorien:

Was uns bewegt, DevOps

Tags:

DevOps, Open Source, Shopware
Vorheriger Artikel