Add interactive project upgrade wizard#1063
Draft
Soner (shyim) wants to merge 10 commits into
Draft
Conversation
Mirrors the shopware/web-installer Update flow so projects can be upgraded from the command line: - Reads the current Shopware version from composer.lock - Filters available releases the same way as ReleaseInfoProvider (next major + remaining patches of the current major, no RCs) - Prompts for the target version (or `--to` flag), then runs the existing extension compatibility check before continuing - Backs up composer.json, cleans up recipe-managed stale files by MD5, removes incompatible symlinked custom plugins, rewrites composer.json (shopware/core + administration/storefront/elasticsearch when required, minimum-stability for RC targets, symfony/runtime constraint relax) - Runs `composer update --with-all-dependencies --no-scripts` and restores the backup on failure - Runs `bin/console system:update:prepare` and `system:update:finish` - Tracks the outcome Extracts the MD5-based cleanup map from `flexmigrator.Cleanup` into a new `flexmigrator.CleanupByHash` helper so the upgrade flow can reuse it without also deleting flex-migration-specific files.
The interactive flow is now a small bubbletea Program that mirrors the install-wizard / setup-guide visual idiom: - Welcome card (cowsay mascot) with current version + project root - Step 1: select target version (RenderSelectList) - Step 2 (when extensions are installed): compatibility lookup with spinner, then per-extension checkmark/blocker icons - Step 3: review card with from/to/executor and the full task list - Step 4: running phase with per-task spinner / checkmark / failure icons and a live tail of the composer/console output - Done card summarising success or failure, restored composer.json on failure, and listing any plugins that were dropped Non-interactive mode (`-n`) and `--to <version>` continue to use the existing headless flow so CI runs are unchanged.
The upgrade rewrites composer.json, deletes recipe-managed files, and drops incompatible plugins. Mixing those rewrites with unrelated uncommitted changes makes it hard to review the diff or roll back, so the command now refuses to run with a dirty working tree. - Adds `git.IsRepository` and `git.WorkingTreeStatus` helpers so other commands can reuse the same checks. - When the project directory is not inside a git working tree the check is skipped (greenfield projects, tarball-installed copies). - The error message lists up to ten changed paths and points at `--allow-dirty` as the explicit override.
…gins Before doing anything destructive, `project upgrade` now requires every directory under custom/plugins/ to be tracked by composer (i.e. appear in vendor/composer/installed.json). When plain file-drop plugins are detected the upgrade aborts with a pointer at `project autofix composer-plugins`. The `--allow-non-composer` flag opts out for projects that have not migrated yet. When a composer-managed plugin's declared shopware/core constraint is not satisfied by the upgrade target, the resolver now queries a package registry (repo.packagist.org for plain composer packages, packages.shopware.com for store.shopware.com/* packages) for the newest release whose require.shopware/core does satisfy the target and rewrites the composer.json constraint to "^<that-version>". Only when no compatible release is found does the plugin fall back to being dropped, matching the old behaviour. The Shopware Packages token is read from SHOPWARE_PACKAGES_TOKEN or the project's auth.json. When neither is present and the project has store plugins the interactive flow prompts for the token (and skips store lookups gracefully if the prompt is left empty). The wizard's "Done" card now lists bumped constraints (old → new) in addition to the removed plugins, so users can see exactly what shifted. Tests: 9 new tests covering the resolver (bump, remove, registry error, no installed.json), FindNonComposerPlugins, and the ensureAllPluginsAreComposerManaged pre-flight check. All packages pass.
- Drop trailing punctuation from the dirty-git-tree and non-composer-plugin error strings (ST1005). - Make the phase / task-status switches exhaustive (exhaustive). - Rewrite the compat-result if/else chain as a tagless switch (gocritic). - Rename the `max` parameter in `truncate` to `maxRunes` so it stops shadowing the predeclared builtin (predeclared). - Wrap `resp.Body.Close()` in a small `closeBody` helper so we don't ignore its error inline (errcheck). - Rename the test-only `stringErr` type to `testError` to match the `xxxError` naming convention (errname). - Add `t.Parallel()` to the render-smoke subtest (tparallel). - Drop the unused `upgradeDoneMsg` type (unused). - Drop the unused `projectRoot` parameter from `runCompatibilityCheck` (unparam).
The registry duplicated the packagist HTTP client, the composer v2 minified-metadata unminifier, the response-body closer, and the packages.json fetch. Move the generic lookups into the packagist package instead: - Add packagist.GetComposerPackageVersions(ctx, name) for any composer package and rebuild GetShopwarePackageVersions on top of it. - Add a Require field to packagist.PackageVersion so store-package metadata carries its shopware/core constraint. PackagistRegistry and ShopwareStoreRegistry now delegate to the packagist package, dropping ~120 lines of duplicated logic.
Contributor
|
Next step: prep this for team demo |
The upgrade flow parsed vendor/composer/installed.json by hand, resolved install paths, and re-implemented composer version-constraint checks. Move that composer logic into the packagist package where the rest of the composer model (composer.json, composer.lock, auth.json) already lives: - packagist.InstalledJson / InstalledPackage / ReadInstalledJson model and read vendor/composer/installed.json. - InstalledPackage.InstallDirName resolves a package's install location (symlinks included) to its directory name under a given base dir. - packagist.ConstraintsSatisfiedBy reports whether a require map's constraints for a set of packages are satisfied by a target version. - packagist.BumpConstraint turns a concrete version into a caret constraint. projectupgrade now consumes these helpers and keeps only the upgrade policy (which Shopware packages matter, registry resolution). Its duplicate ShopwarePackages list is reused in place of the former pluginShopwarePackages. plugins.go drops ~145 lines.
742a657 to
256390f
Compare
…teps Several fixes to the project upgrade flow surfaced by real upgrades: - Treat store "with new Shopware version" status as resolvable, not a blocker. Classification now keys on the semantic status name (notCompatible) instead of the display color, matching the platform's ExtensionCompatibility constants. - Resolve plugin constraints for vendor-installed plugins, not just those under custom/plugins/. Scope candidates by the root composer.json require so store plugins (swag/*, frosh/*) installed into vendor/ get bumped too. - Look up store-owned, vendor-named plugins via the store registry first (falling back to Packagist) instead of routing only by name prefix. - Run system:update:prepare before composer update so it executes on the still-installed Shopware; restore composer.json if prepare fails. - Center the wizard in the terminal and replay the full failed-step log after the alt-screen tears down. Adds tests for status classification, vendor-installed resolution, registry routing, and upgrade step ordering.
39ef87d to
951109a
Compare
Replace the wizard's hand-rolled version-list cursor and rendering with the reusable tui.SelectList component: it owns the cursor, windowing, paging (PgUp/PgDn, Home/End) and the navigation shortcuts, so the wizard only forwards keys and renders.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements an interactive upgrade wizard for Shopware projects that guides users through the upgrade process with a TUI interface. This mirrors the behavior of the shopware/web-installer but runs from the command line.
Key Changes
New Packages
internal/projectupgrade/- Core upgrade logic package containing:wizard.go- Interactive TUI-based upgrade wizard using Bubble Teacomposer.go- Composer.json rewriting for target versionsplugins.go- Plugin compatibility resolution and constraint bumpingregistry.go- Package registry abstraction for version lookupsreleases.go- Version filtering and selection logiccmd/project/project_upgrade.go- Newproject upgradecommand with:Upgrade Workflow
The wizard guides users through:
composer update --with-all-dependenciesbin/console system:update:preparebin/console system:update:finishPlugin Resolution
Registry System
CombinedRegistryroutes lookups to appropriate backend (Store vs Packagist)PackagistRegistryqueries repo.packagist.org with minified format supportSupporting Changes
internal/git/withIsRepository()andWorkingTreeStatus()functionsinternal/flexmigrator/withCleanupByHash()for recipe file cleanupImplementation Details
https://claude.ai/code/session_01F4pXpGEuJGsxpfTudpnoLo