fix(installer): stop blocking the wizard on things the installer itself installs

The preflight page began refusing to continue while any check was failing, which
is right for something the operator must go and fix. HttpPlatformHandler was
marked FAIL when absent - so on a server without it the wizard stopped dead,
telling the operator the server was not ready, over a module the bundle carries
and stage 4 installs a few pages later. The only way forward was to go and
install by hand the exact thing the installer was about to install.

It is now INFO: reported, not blocking, matching how URL Rewrite is already
handled. Nothing the installer SUPPLIES may block the wizard, and
tests/test_installer_defaults.py now fails if that rule is broken again.

The site-port conflict check is downgraded from FAIL to WARN for the same class
of reason: it runs before the operator reaches the Address page, so it tests the
DEFAULT port rather than the one they intend to use, and blocking refuses an
install over a conflict the very next page lets them resolve.

Genuine blockers are unchanged - no IIS, no WebAdministration, wrong Windows
edition or architecture, no disk, and the MySQL 5.6 index flags. Those the
operator really does have to fix first.
This commit is contained in:
cproudlock
2026-08-04 10:00:44 -04:00
parent 4a8bd138a9
commit 5321649e02
2 changed files with 42 additions and 4 deletions

View File

@@ -221,8 +221,12 @@ Invoke-Check 'Network' 'Site port' {
Add-Result 'Network' 'Site port' 'INFO' `
"TCP $SitePort is used by the existing $SiteName site - this will be upgraded in place"
} else {
Add-Result 'Network' 'Site port' 'FAIL' "TCP $SitePort is in use$owner" `
"Choose a different port with -SitePort, or stop the listener."
# WARN, not FAIL. This check runs before the operator has reached the
# Address page, so it is testing the DEFAULT port, not necessarily
# the one they intend to use. Blocking here would refuse an install
# over a conflict the very next page lets them resolve.
Add-Result 'Network' 'Site port' 'WARN' "TCP $SitePort is in use$owner" `
"Pick a different port on the Address page later in this wizard, or stop whatever is holding it."
}
}
}
@@ -266,8 +270,13 @@ Invoke-Check 'IIS' 'HttpPlatformHandler' {
if ($modules -match 'httpPlatformHandler') {
Add-Result 'IIS' 'HttpPlatformHandler' 'PASS' 'installed'
} else {
Add-Result 'IIS' 'HttpPlatformHandler' 'FAIL' 'not installed' `
'Install httpPlatformHandler_amd64.msi from the bundle. IIS cannot launch waitress without it.'
# NOT a blocker: the MSI is in the bundle and stage 4 installs it. This
# was a FAIL, which - once the preflight page started blocking on any
# failure - stopped the wizard dead over something the installer was
# about to do by itself, with no way forward but to go and install it by
# hand. Nothing the installer SUPPLIES may be a blocker.
Add-Result 'IIS' 'HttpPlatformHandler' 'INFO' 'not installed yet' `
'The installer installs it from the bundle. No action needed.'
}
}

View File

@@ -53,3 +53,32 @@ def test_every_wizard_exclusion_is_a_real_plugin():
for name in wizard_excludes():
assert (PLUGINS / name / 'manifest.json').exists(), (
'%s is excluded by the wizard but has no manifest' % name)
# The preflight blocks the wizard on any FAIL. That is correct for something the
# operator must go and fix, and wrong for anything the installer carries in its
# own bundle - there, blocking stops the wizard over something it was about to do
# itself, with no way forward.
BUNDLE_SUPPLIED = [
'HttpPlatformHandler', # httpplatformhandler\*.msi, installed by stage 4
'URL Rewrite', # urlrewrite\*.msi, installed by stage 4
]
PREFLIGHT = REPO / 'deploy' / 'windows' / 'installer' / 'shopdb-preflight.ps1'
def test_nothing_the_bundle_supplies_is_a_blocker():
"""Regression: HttpPlatformHandler was a FAIL, so a server without it could
not get past the preflight page - to install the very thing that was
missing."""
text = PREFLIGHT.read_text(encoding='utf-8', errors='replace')
offenders = []
for line in text.splitlines():
if "'FAIL'" not in line:
continue
for component in BUNDLE_SUPPLIED:
if component.lower() in line.lower():
offenders.append(line.strip())
assert not offenders, (
'the installer supplies these, so they must not block the wizard:\n %s'
% '\n '.join(offenders))