upgrade

package
v0.18.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 23, 2026 License: MIT Imports: 28 Imported by: 0

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

View Source
const (
	TargetRecommended = "recommended"
	TargetLatestPatch = "latest-patch"
)

Target keywords accepted by HeadlessOptions.Target besides an exact version.

Variables

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(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

func IsMultiMajorJump(current, target *version.Version) bool

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

func SuggestComposerName(projectRoot string) string

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

func ValidateComposerName(name string) error

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

func (s ExtStatus) BlocksUpgrade() bool

Blocksupgrade reports whether this status prevents starting the upgrade.

func (ExtStatus) Label

func (s ExtStatus) Label() string

Label returns the short result column text used in the extension queue.

func (ExtStatus) NeedsAttention

func (s ExtStatus) NeedsAttention() bool

NeedsAttention reports whether this finding requires the user's review — everything except OK and routine update-available results.

func (ExtStatus) Rank

func (s ExtStatus) Rank() int

Rank orders statuses by severity for the extension queue (most severe first).

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

func (u *ProjectUpgrader) TargetPHPRequirement(ctx context.Context, target *version.Version) string

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) Blocked

func (r Readiness) Blocked() bool

Blocked reports whether any blocking readiness check failed.

func (Readiness) ComposerManagedCount

func (r Readiness) ComposerManagedCount() int

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).

const (
	StepRewriteComposer StepID = iota
	StepComposerUpdate
	StepRecipesInstall
	StepDeploymentHelper
	StepWriteReport
	// StepFinished is the synthetic final event: StateOK when the upgrade
	// succeeded, StateFail (with Err) when it was aborted and rolled back.
	StepFinished
)

func (StepID) Label

func (s StepID) Label() string

Label returns the checklist text for a step.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL