Documentation
¶
Overview ¶
Package upgrade implements the backend for the interactive Shopware upgrade wizard (`shopware-cli project upgrade`): project readiness checks, the upgrade version catalog, extension compatibility classification, and the execution engine that applies the upgrade locally. It contains no UI code so every part can be tested without a terminal.
Index ¶
- Constants
- Variables
- func ApplyResolvedVersions(results []ExtensionResult, resolve ResolveResult)
- func ApplyStoreLinks(results []ExtensionResult, changelogs []ExtensionChangelog)
- func IsMultiMajorJump(current, target *version.Version) bool
- func SuggestComposerName(projectRoot string) string
- func ValidateComposerName(name string) error
- type Catalog
- type ChangelogEntry
- type CheckState
- type ExtStatus
- type ExtensionChangelog
- type ExtensionResult
- type HeadlessOptions
- type InstalledExtension
- type PackageChange
- type ProjectUpgrader
- func (u *ProjectUpgrader) AuditBlockDisabled() bool
- func (u *ProjectUpgrader) CheckComposerResolvable(ctx context.Context, target string) (ResolveResult, error)
- func (u *ProjectUpgrader) CheckExtensions(ctx context.Context, current, target *version.Version, ...) []ExtensionResult
- func (u *ProjectUpgrader) DisableAuditBlock()
- func (u *ProjectUpgrader) InstalledPHPVersion(ctx context.Context) string
- func (u *ProjectUpgrader) LoadCatalog(ctx context.Context, current *version.Version) (*Catalog, error)
- func (u *ProjectUpgrader) LoadExtensionChangelogs(ctx context.Context, target string, results []ExtensionResult) []ExtensionChangelog
- func (u *ProjectUpgrader) LogPath() string
- func (u *ProjectUpgrader) PackagistReachable(ctx context.Context) bool
- func (u *ProjectUpgrader) PlannedChanges() []string
- func (u *ProjectUpgrader) ReportPath() string
- func (u *ProjectUpgrader) RewriteComposerJSON(target string, resolved map[string]string) ([]string, error)
- func (u *ProjectUpgrader) Run(ctx context.Context, opts RunOptions) <-chan StepEvent
- func (u *ProjectUpgrader) RunHeadless(ctx context.Context, opts HeadlessOptions) error
- func (u *ProjectUpgrader) RunReadinessChecks(ctx context.Context) Readiness
- func (u *ProjectUpgrader) SetComposerName(name string) error
- func (u *ProjectUpgrader) TargetPHPRequirement(ctx context.Context, target *version.Version) string
- func (u *ProjectUpgrader) UpgradeDir() string
- func (u *ProjectUpgrader) WriteReport(data ReportData) (string, error)
- type Readiness
- type ReadinessCheck
- type ReportData
- type ResolveResult
- type RunOptions
- type StepEvent
- type StepID
- type VersionOption
Constants ¶
const ( TargetRecommended = "recommended" TargetLatestPatch = "latest-patch" )
Target keywords accepted by HeadlessOptions.Target besides an exact version.
Variables ¶
var RunSteps = []StepID{ StepRewriteComposer, StepComposerUpdate, StepRecipesInstall, StepDeploymentHelper, StepWriteReport, }
RunSteps lists the visible steps in execution order.
Functions ¶
func ApplyResolvedVersions ¶
func ApplyResolvedVersions(results []ExtensionResult, resolve ResolveResult)
ApplyResolvedVersions overwrites each extension's Available version with the exact release the resolution picked, where one was found.
A successful resolution also overrides metadata-derived blockers: the solver found an installable set that contains every root-required extension, so an extension it updated — or silently kept at the installed release — is proven compatible no matter what the repository metadata claimed.
func ApplyStoreLinks ¶
func ApplyStoreLinks(results []ExtensionResult, changelogs []ExtensionChangelog)
ApplyStoreLinks overwrites each matching extension's changelog URL with the Store listing when the Store returned one, replacing the Packagist fallback.
func IsMultiMajorJump ¶
IsMultiMajorJump reports whether upgrading from current to target skips more than one major.minor release line (e.g. 6.5 -> 6.7 or 6.5 -> 8.0). Extension vendors typically validate one line at a time, so such paths carry extra risk.
func SuggestComposerName ¶
SuggestComposerName derives a valid Composer package name from the OS username and the project directory name, e.g. "shyim/acme-shop" for "/srv/shops/Acme Shop". It falls back to the "shopware" vendor when no usable username is available. It is the pre-filled value of the wizard's package-name prompt.
func ValidateComposerName ¶
ValidateComposerName returns an error when name does not satisfy Composer's package-name rule (the pattern the schema validates "name" against).
Types ¶
type Catalog ¶
type Catalog struct {
Current *version.Version
Options []VersionOption
Recommended int // index into Options, -1 when empty
LatestPatch int // index of the newest patch of the current minor, -1 when none
}
Catalog lists the versions the project can upgrade to, newest first.
type ChangelogEntry ¶
type ChangelogEntry struct {
Version string
// Date is the release date (yyyy-mm-dd), "" when the Store has none.
Date string
// Text is the release note as plain text (the Store serves HTML).
Text string
}
ChangelogEntry is one release note of an extension update.
type CheckState ¶
type CheckState int
CheckState describes the lifecycle of a single check or execution step.
const ( StatePending CheckState = iota StateRunning StateOK StateWarn StateFail )
type ExtStatus ¶
type ExtStatus int
ExtStatus classifies an extension's compatibility with the target version.
const ( // ExtOK: the installed release already allows the target version. ExtOK ExtStatus = iota // ExtNeedsUpdate: a compatible Composer release exists but is newer than // the installed one. ExtNeedsUpdate // ExtMismatch: the Store labels the extension compatible but no Composer // release satisfies the target — Composer is the source of truth. ExtMismatch // ExtDeprecated: the extension is deprecated/replaced per Store metadata. ExtDeprecated // ExtBlocked: no compatible Composer release exists for the target. ExtBlocked // ExtReview: a local (non Composer-managed) extension the wizard does not // check; needs a manual review. ExtReview )
func (ExtStatus) BlocksUpgrade ¶
Blocksupgrade reports whether this status prevents starting the upgrade.
func (ExtStatus) NeedsAttention ¶
NeedsAttention reports whether this finding requires the user's review — everything except OK and routine update-available results.
type ExtensionChangelog ¶
type ExtensionChangelog struct {
// Extension is the technical name, e.g. SwagPayPal.
Extension string
// From is the installed version, To the update's target version.
From string
To string
// StoreLink is the Shopware Store listing URL when the Store knows the
// extension, "" otherwise.
StoreLink string
// Entries are ordered newest first.
Entries []ChangelogEntry
}
ExtensionChangelog collects the Store changelog entries an extension update applies — everything after the installed release up to and including the release the upgrade moves to.
type ExtensionResult ¶
type ExtensionResult struct {
Extension InstalledExtension
Status ExtStatus
// Available is the lowest extension release compatible with the target
// version ("" when none exists).
Available string
// StoreLabel is the compatibility label reported by the Shopware Store
// ("" when the extension is unknown to the Store).
StoreLabel string
// Replacement names a successor extension when Status is ExtDeprecated.
Replacement string
// ChangelogURL points at the Shopware Store listing when the extension
// is known there, otherwise at the providing Composer repository page.
ChangelogURL string
// Detail is a one-line explanation shown in the detail overlay.
Detail string
}
ExtensionResult is the classified compatibility outcome for one extension.
type HeadlessOptions ¶
type HeadlessOptions struct {
// Target is the version to upgrade to: an exact version from the
// supported catalog, or the keywords "recommended" / "latest-patch".
Target string
// DryRun stops after the read-only preflight (readiness, extension
// compatibility, Composer dry-run) without modifying any file.
DryRun bool
// NoAudit continues when dependencies are blocked by security advisories
// (config.audit.block-insecure = false, like project create's --no-audit).
NoAudit bool
// Out receives the progress output.
Out io.Writer
}
HeadlessOptions configure a non-interactive upgrade run.
type InstalledExtension ¶
type InstalledExtension struct {
Name string // technical name, e.g. SwagPayPal
Package string // composer package name, e.g. swag/paypal
Path string
Version string
ComposerManaged bool
// PathInstalled is true when Composer installed the package from a path
// repository (composer.lock dist.type == "path"). The installed files are
// the local project copy — typically under custom/static-plugins — not a
// published release that can be version-bumped independently.
PathInstalled bool
// Require is the package's composer.json/lock require map when known.
// Used to classify path and other unpublished packages against the
// target Shopware version.
Require map[string]string
}
InstalledExtension is an extension found in the project, either managed through Composer (vendor/ or a path repository) or locally in custom/plugins and friends.
type PackageChange ¶
type PackageChange struct {
Name string
// From is empty for new installs; To is empty for removals.
From string
To string
// Op is "install", "upgrade", "downgrade", or "remove".
Op string
}
PackageChange is one resolved lock-file difference: the version a package moves to when the upgrade runs.
type ProjectUpgrader ¶
type ProjectUpgrader struct {
// contains filtered or unexported fields
}
ProjectUpgrader is the entry point for upgrading a Shopware project: it runs the readiness checks, loads the version catalog, checks extension compatibility, verifies Composer can resolve the upgrade, and executes it.
External dependencies live in unexported fields with production defaults so tests can replace them per instance.
func NewProjectUpgrader ¶
func NewProjectUpgrader(projectRoot string, exec executor.Executor) *ProjectUpgrader
NewProjectUpgrader creates an upgrader for the project at projectRoot. The executor runs composer and the deployment helper in the project's environment during Run; the earlier, read-only phases don't use it.
func (*ProjectUpgrader) AuditBlockDisabled ¶
func (u *ProjectUpgrader) AuditBlockDisabled() bool
AuditBlockDisabled reports whether the user chose to continue without Composer's security-audit blocking.
func (*ProjectUpgrader) CheckComposerResolvable ¶
func (u *ProjectUpgrader) CheckComposerResolvable(ctx context.Context, target string) (ResolveResult, error)
CheckComposerResolvable verifies that Composer can find an installable set of dependencies for the target version without modifying any project file. It runs `composer update --no-install` against a temporary manifest, which resolves and writes a temporary lock file; diffing that against the real composer.lock yields the exact versions the upgrade will install.
func (*ProjectUpgrader) CheckExtensions ¶
func (u *ProjectUpgrader) CheckExtensions(ctx context.Context, current, target *version.Version, extensions []InstalledExtension) []ExtensionResult
CheckExtensions classifies every discovered extension against the target Shopware version, combining Store compatibility metadata with the Composer release constraints (Composer being the source of truth). Results are ordered most severe first.
func (*ProjectUpgrader) DisableAuditBlock ¶
func (u *ProjectUpgrader) DisableAuditBlock()
DisableAuditBlock makes the preflight resolution and the upgrade run with Composer's security-audit blocking disabled. The user opts into this after being warned that dependencies are affected by security advisories.
func (*ProjectUpgrader) InstalledPHPVersion ¶
func (u *ProjectUpgrader) InstalledPHPVersion(ctx context.Context) string
InstalledPHPVersion returns the PHP version of the environment the upgrade runs in, or "" when it cannot be determined.
func (*ProjectUpgrader) LoadCatalog ¶
func (u *ProjectUpgrader) LoadCatalog(ctx context.Context, current *version.Version) (*Catalog, error)
LoadCatalog fetches all Shopware versions newer than current and annotates them with release-cycle support information. Stable versions only — release candidates and other prereleases are excluded, matching `project upgrade-check`.
func (*ProjectUpgrader) LoadExtensionChangelogs ¶
func (u *ProjectUpgrader) LoadExtensionChangelogs(ctx context.Context, target string, results []ExtensionResult) []ExtensionChangelog
LoadExtensionChangelogs fetches the Store changelogs for every extension the upgrade updates (installed -> available release) and keeps the entries inside that version window. Store metadata is advisory, so failures degrade to nil instead of erroring.
func (*ProjectUpgrader) LogPath ¶
func (u *ProjectUpgrader) LogPath() string
LogPath returns the location of the streamed upgrade log.
func (*ProjectUpgrader) PackagistReachable ¶
func (u *ProjectUpgrader) PackagistReachable(ctx context.Context) bool
PackagistReachable reports whether the Packagist repository answers, i.e. whether Composer will be able to download packages.
func (*ProjectUpgrader) PlannedChanges ¶
func (u *ProjectUpgrader) PlannedChanges() []string
PlannedChanges lists what the runner will do — shown on the review panel, in dry runs, and in the report.
func (*ProjectUpgrader) ReportPath ¶
func (u *ProjectUpgrader) ReportPath() string
ReportPath returns the location of the Markdown upgrade report.
func (*ProjectUpgrader) RewriteComposerJSON ¶
func (u *ProjectUpgrader) RewriteComposerJSON(target string, resolved map[string]string) ([]string, error)
RewriteComposerJSON applies the target constraints to the project's real composer.json and saves it, pinning extensions to the versions the preflight resolution picked. Used by the runner after the user confirmed the plan.
func (*ProjectUpgrader) Run ¶
func (u *ProjectUpgrader) Run(ctx context.Context, opts RunOptions) <-chan StepEvent
Run executes the upgrade asynchronously and streams progress events. The channel closes after a final StepFinished event. Cancelling ctx aborts the current step and rolls back composer.json and composer.lock. All file-changing operations happen here — the earlier phases are read-only.
func (*ProjectUpgrader) RunHeadless ¶
func (u *ProjectUpgrader) RunHeadless(ctx context.Context, opts HeadlessOptions) error
RunHeadless executes the upgrade pipeline without the TUI — for --no-interaction runs and environments without a terminal. It walks the same phases as the wizard: readiness checks, target selection, preflight, and (unless DryRun) the guided execution with rollback on failure.
func (*ProjectUpgrader) RunReadinessChecks ¶
func (u *ProjectUpgrader) RunReadinessChecks(ctx context.Context) Readiness
RunReadinessChecks inspects the project and returns the readiness checklist for the wizard's first step. It is read-only and can be re-run ("Recheck") after the user fixes a failing check.
func (*ProjectUpgrader) SetComposerName ¶
func (u *ProjectUpgrader) SetComposerName(name string) error
SetComposerName validates name against Composer's package-name rule and writes it into the project's composer.json. The upgrade refuses to run without one (see the composer-name readiness check), so the wizard offers to set it in place.
func (*ProjectUpgrader) TargetPHPRequirement ¶
TargetPHPRequirement returns the PHP constraint the target shopware/core release declares (e.g. ">=8.2"), or "" when it cannot be determined.
func (*ProjectUpgrader) UpgradeDir ¶
func (u *ProjectUpgrader) UpgradeDir() string
UpgradeDir returns the directory below the project root where the wizard stores its report, log, and backups.
func (*ProjectUpgrader) WriteReport ¶
func (u *ProjectUpgrader) WriteReport(data ReportData) (string, error)
WriteReport renders the Markdown upgrade report into the upgrade directory and returns its path.
type Readiness ¶
type Readiness struct {
Checks []ReadinessCheck
CurrentVersion *version.Version
Extensions []InstalledExtension
}
Readiness is the result of RunReadinessChecks.
func (Readiness) ComposerManagedCount ¶
ComposerManagedCount returns how many discovered extensions are managed via Composer.
type ReadinessCheck ¶
type ReadinessCheck struct {
ID string
Label string
Value string // short right-aligned value, e.g. "yes" or "14"
Detail string // dimmed sub-line, e.g. the repository path
State CheckState
Blocking bool // a failed blocking check prevents continuing
}
ReadinessCheck is one row of the "Check project readiness" panel.
func (ReadinessCheck) Failed ¶
func (c ReadinessCheck) Failed() bool
Failed reports whether the check blocks the wizard from continuing.
type ReportData ¶
type ReportData struct {
ProjectName string
Current string
Target string
GeneratedAt time.Time
Checks []ReadinessCheck
Extensions []ExtensionResult
PlannedChanges []string
// PHPRequirement is the PHP constraint of the target shopware/core
// release; PHPInstalled the locally detected version.
PHPRequirement string
PHPInstalled string
// ComposerReport is the raw Composer output attached when dependency
// resolution failed.
ComposerReport string
// ResolvedChanges are the lock-file operations the dry run predicted.
ResolvedChanges []PackageChange
// Changelogs are the Store release notes of the extension updates the
// upgrade applies.
Changelogs []ExtensionChangelog
// Failed marks a report written for an upgrade that was rolled back;
// Error carries the failing step's message.
Failed bool
Error string
}
ReportData collects everything that goes into the shareable upgrade report.
type ResolveResult ¶
type ResolveResult struct {
OK bool
// Report is Composer's raw output; when the resolution fails it is the
// diagnostic to attach to the upgrade report and support tickets.
Report string
// Changes are the lock-file differences of a successful resolution — the
// exact versions Composer will install.
Changes []PackageChange
}
ResolveResult is the outcome of the "Composer can resolve this upgrade" check.
func (ResolveResult) ResolvedVersion ¶
func (r ResolveResult) ResolvedVersion(pkg string) string
ResolvedVersion returns the version a package resolves to, or "" when the resolution does not change it.
func (ResolveResult) SecurityBlocked ¶
func (r ResolveResult) SecurityBlocked() bool
SecurityBlocked reports whether the resolution failed because Composer (>= 2.9 with audit blocking enabled) refused to load packages affected by known security advisories.
func (ResolveResult) VersionMap ¶
func (r ResolveResult) VersionMap() map[string]string
VersionMap returns the resolved package -> version map (installs and up/downgrades; removals are excluded).
type RunOptions ¶
type RunOptions struct {
// Target is the Shopware version to upgrade to.
Target string
// ResolvedVersions maps packages to the version the preflight resolution
// picked; extensions are pinned to these in composer.json.
ResolvedVersions map[string]string
// Report is the pre-assembled report data; the run fills in the Composer
// changes it makes and writes the report file at the end.
Report ReportData
}
RunOptions configure one upgrade execution.
type StepEvent ¶
type StepEvent struct {
Step StepID
State CheckState
Line string
Err error
}
StepEvent is emitted by the Runner while the upgrade executes. Line events carry streamed subprocess output (State is StateRunning); state events mark step transitions.
type StepID ¶
type StepID int
StepID identifies one step of the upgrade execution (panel 5's checklist).
type VersionOption ¶
type VersionOption struct {
Version *version.Version
Tag string // e.g. "recommended", "latest 6.6 patch"
SupportType string // "active", "security", "eol" or "" when unknown
SupportUntil time.Time
ReleaseNotesURL string
}
VersionOption is one selectable target version in the version picker.
func (VersionOption) SupportLeft ¶
func (o VersionOption) SupportLeft() string
SupportLeft returns a compact human description of the remaining support window, e.g. "1y 7m", or "" when unknown.