Developer-Dashboard
view release on metacpan or search on metacpan
t/40-install-bootstrap.t view on Meta::CPAN
like(
$install_sh_text,
qr{\Q$default_bootstrap_repository\E},
'install.sh knows the canonical GitHub repository for the default streamed Unix-like checkout target',
);
like(
$install_sh_text,
qr/git clone --depth 1 --branch master/,
'install.sh clones the current GitHub master checkout when no explicit Unix-like install target override is set',
);
like(
$install_sh_text,
qr/run_cpanm --notest \./,
'install.sh installs the resolved local checkout with cpanm dot for default Unix-like bootstrap targets',
);
}
{
my $install_ps_text = _slurp($install_ps);
like( $install_ps_text, qr/Set-StrictMode -Version Latest/, 'install.ps1 enables strict PowerShell mode' );
like( $install_ps_text, qr/\$ErrorActionPreference = 'Stop'/, 'install.ps1 treats PowerShell errors as fatal' );
like( $install_ps_text, qr/^\& \{/m, 'install.ps1 wraps its body in a script block so the streamed irm ... | iex path stays valid' );
like( $install_ps_text, qr/Developer Dashboard install progress/, 'install.ps1 prints the Windows progress board title' );
like( $install_ps_text, qr/winget/, 'install.ps1 uses winget to bootstrap missing Windows packages' );
like( $install_ps_text, qr/--source',\s*'winget'/, 'install.ps1 pins Windows package installs to the winget source so a broken msstore source does not block bootstrap installs' );
like( $install_ps_text, qr/source\s+reset|winget source reset/s, 'install.ps1 includes a winget source repair path for bootstrap failures' );
like( $install_ps_text, qr/Format-ExitCode/, 'install.ps1 formats native Windows exit codes so winget failures show their HRESULT value' );
like( $install_ps_text, qr/System\.BitConverter.*ToUInt32/s, 'install.ps1 formats negative HRESULT exit codes through BitConverter instead of a failing direct uint32 cast' );
like( $install_ps_text, qr/function Set-TlsSecurityProtocol/, 'install.ps1 defines a shared TLS hardening helper for Windows bootstrap downloads' );
like( $install_ps_text, qr/SecurityProtocolType\]::Tls12/, 'install.ps1 explicitly enables TLS 1.2 for bootstrap web requests' );
like( $install_ps_text, qr/function Download-RemoteFile/, 'install.ps1 defines a shared resilient file downloader for Windows bootstrap assets' );
like( $install_ps_text, qr/function Get-RemoteJson/, 'install.ps1 defines a shared resilient JSON downloader for Windows bootstrap metadata' );
like( $install_ps_text, qr/function Get-WindowsBootstrapArchitecture/, 'install.ps1 detects the effective Windows bootstrap architecture before choosing vendor fallback assets' );
like( $install_ps_text, qr/PROCESSOR_ARCHITEW6432.*PROCESSOR_ARCHITECTURE/s, 'install.ps1 checks both WOW64 and native processor environment variables when resolving Windows architecture' );
like( $install_ps_text, qr/ARM64.*return 'arm64'/s, 'install.ps1 maps ARM64 Windows hosts explicitly during bootstrap architecture detection' );
like( $install_ps_text, qr/function Invoke-InstallerCommand/, 'install.ps1 defines a dedicated installer runner for GUI and MSI bootstrap packages' );
like( $install_ps_text, qr/Start-Process\s+-FilePath\s+\$FilePath\s+-ArgumentList\s+\$Arguments\s+-PassThru\s+-Wait/s, 'install.ps1 waits for GUI and MSI installers through Start-Process instead of piping them like console commands' );
like( $install_ps_text, qr/curl\.exe|curl/, 'install.ps1 can fall back to curl when Invoke-WebRequest is unreliable inside the Windows guest' );
like( $install_ps_text, qr/WebClient/, 'install.ps1 can fall back to System\.Net\.WebClient when both Invoke-WebRequest and curl are unavailable or broken' );
like( $install_ps_text, qr/Install-WindowsPackageFallback/, 'install.ps1 defines an explicit fallback installer path when winget source repair still cannot install a required package' );
like( $install_ps_text, qr/function Resolve-GitForWindowsInstallerUrl/, 'install.ps1 resolves the latest Git for Windows installer URL dynamically instead of trusting a brittle static redirect' );
like( $install_ps_text, qr/git-for-windows\/git\/releases\/latest/, 'install.ps1 uses the official Git for Windows latest release page as the source of truth for the fallback installer asset' );
like( $install_ps_text, qr/git-for-windows\/git\/releases\/download/, 'install.ps1 builds the final Git for Windows fallback asset URL from the resolved release tag and installer filename' );
like( $install_ps_text, qr/Git-64-bit\.exe/, 'install.ps1 can fall back to the official Git for Windows installer download when winget remains broken' );
like( $install_ps_text, qr/Git-\[0-9\]\[\^"''<\]\*-arm64\\\.exe/, 'install.ps1 can fall back to the official Git for Windows ARM64 installer download on Windows ARM hosts' );
like( $install_ps_text, qr/strawberryperl\.com\/releases\.json/, 'install.ps1 resolves Strawberry Perl fallback installers from the official release feed' );
like( $install_ps_text, qr/MSWin32-x64-multi-thread/, 'install.ps1 targets the supported Strawberry Perl release architecture from the official release feed' );
like( $install_ps_text, qr/arm64'.*MSWin32-x64-multi-thread/s, 'install.ps1 maps Windows ARM hosts to the official Strawberry Perl x64 build when no ARM-native Strawberry Perl release exists' );
like( $install_ps_text, qr/nodejs\.org\/dist\/index\.json/, 'install.ps1 resolves Node.js LTS fallback installers from the official Node release index' );
like( $install_ps_text, qr/function Resolve-NodeLtsPackage/, 'install.ps1 resolves a Windows-architecture-aware Node.js fallback package instead of assuming one MSI shape' );
like( $install_ps_text, qr/win-arm64-zip/, 'install.ps1 supports the official Node.js ARM64 ZIP fallback for Windows ARM hosts' );
like( $install_ps_text, qr/function Install-PortableNodeZip/, 'install.ps1 defines a portable Node.js ZIP installer for Windows ARM fallback installs' );
like( $install_ps_text, qr/Expand-Archive -LiteralPath \$ZipPath -DestinationPath \$extractRoot -Force/, 'install.ps1 extracts the official Node.js ZIP fallback under the user-space install root on Windows ARM hosts' );
like( $install_ps_text, qr/Add-ProcessPathSegment -PathSegment \$nodeBin/, 'install.ps1 activates the portable Node.js fallback by prepending its runtime directory to PATH' );
unlike( $install_ps_text, qr/Invoke-RestMethod\s+-Uri\s+'https:\/\/strawberryperl\.com\/releases\.json'/, 'install.ps1 no longer hard-codes Invoke-RestMethod for the Strawberry Perl release feed' );
unlike( $install_ps_text, qr/Invoke-RestMethod\s+-Uri\s+'https:\/\/nodejs\.org\/dist\/index\.json'/, 'install.ps1 no longer hard-codes Invoke-RestMethod for the Node.js release index' );
unlike( $install_ps_text, qr/Invoke-WebRequest\s+-Uri\s+'https:\/\/github\.com\/git-for-windows\/git\/releases\/latest\/download\/Git-64-bit\.exe'/, 'install.ps1 no longer hard-codes Invoke-WebRequest for the stale Git fallback installer download...
unlike( $install_ps_text, qr/Invoke-WebRequest\s+-Uri\s+'https:\/\/cpanmin\.us\/'/, 'install.ps1 no longer hard-codes Invoke-WebRequest for the cpanm bootstrap script download' );
like( $install_ps_text, qr/msiexec\.exe/, 'install.ps1 uses msiexec for MSI-based Windows fallback installers' );
like( $install_ps_text, qr/2>&1 \| ForEach-Object \{ Write-Host \$\_ \}/, 'install.ps1 streams native command output to the host instead of leaking it into helper return values' );
like( $install_ps_text, qr/\$previousErrorActionPreference\s*=\s*\$ErrorActionPreference/s, 'install.ps1 snapshots PowerShell error handling before streaming native command stderr' );
like( $install_ps_text, qr/\$ErrorActionPreference\s*=\s*'Continue'/s, 'install.ps1 downgrades native stderr records while streaming command output so git and winget progress do not abort the bootstrap' );
like( $install_ps_text, qr/Refresh-ProcessPathFromEnvironment/, 'install.ps1 refreshes the current PATH after winget installs new tools' );
like( $install_ps_text, qr/cpanmin\.us/, 'install.ps1 bootstraps cpanm for Windows installs from the standalone cpanmin.us script' );
unlike( $install_ps_text, qr/'local::lib'\s*,\s*'App::cpanminus'/, 'install.ps1 no longer tries to self-install App::cpanminus while the downloaded cpanm script is still running on Windows' );
like( $install_ps_text, qr{https://github\.com/manif3station/developer-dashboard\.git}, 'install.ps1 knows the canonical GitHub repository for the streamed Windows bootstrap source' );
like( $install_ps_text, qr/git\s+clone/s, 'install.ps1 clones the current GitHub master source for the default streamed Windows install target' );
like( $install_ps_text, qr/Push-Location\s+\$effectiveCpanTarget/s, 'install.ps1 installs the default cloned Windows checkout from inside the local checkout directory' );
like( $install_ps_text, qr/Sync-LocalLibEnvironmentFromPerl/, 'install.ps1 delegates local::lib environment setup to perl so Windows install paths stay canonical' );
like(
$install_ps_text,
qr/'--notest',\s*'--local-lib-contained',\s*\$InstallRoot,\s*'local::lib',\s*'File::ShareDir::Install'/s,
'install.ps1 bootstraps the checkout configure prerequisite into the private Windows install root before it installs the checkout',
);
like( $install_ps_text, qr/--notest',\s*'--local-lib-contained',\s*\$InstallRoot,\s*'\.'/s, 'install.ps1 runs cpanm against dot with an explicit local-lib target for the default cloned Windows checkout' );
like( $install_ps_text, qr/--notest',\s*'--local-lib-contained',\s*\$InstallRoot,\s*\$effectiveCpanTarget/s, 'install.ps1 runs cpanm against explicit Windows targets with the same local-lib target' );
like( $install_ps_text, qr/Sync-LocalLibEnvironmentFromPerl\s+-PerlPath\s+\$perlPath\s+-TargetInstallRoot\s+\$InstallRoot/s, 'install.ps1 reapplies the perl-reported local::lib environment after bootstrapping local::lib on Windows' );
like( $install_ps_text, qr/function Ensure-GnuMakeCommand/, 'install.ps1 defines a GNU make shim helper for Windows skill Makefiles' );
like( $install_ps_text, qr/Resolve-CommandPath\s+-Names\s+@\(\s*'gmake\.exe'.*?'mingw32-make\.exe'.*?'make\.exe'/s, 'install.ps1 resolves GNU make from the Strawberry Windows toolchain before creating the shim' );
like( $install_ps_text, qr/Join-Path\s+\$shimDir\s+'make\.cmd'/s, 'install.ps1 writes a stable make.cmd shim into the user-space Windows bin directory' );
like( $install_ps_text, qr/%\*/, 'install.ps1 forwards Windows make arguments through the shim without shell mangling' );
like( $install_ps_text, qr/Ensure-GnuMakeCommand\s+-TargetInstallRoot\s+\$InstallRoot/s, 'install.ps1 wires GNU make setup into the Windows Perl bootstrap flow' );
like( $install_ps_text, qr/cpanm, local::lib, GNU make, and configure prereqs ready/, 'install.ps1 reports GNU make readiness in the Windows Perl bootstrap progress detail' );
like( $install_ps_text, qr/Ensure-ProfileContains\s+-TargetProfile\s+\$ProfilePath\s+-Block\s+\$profileBlock\s+-Marker\s+'Developer Dashboard bootstrap'/s, 'install.ps1 replaces the managed Developer Dashboard profile block instead of appending d...
like( $install_ps_text, qr/# >>> Developer Dashboard bootstrap >>>/, 'install.ps1 wraps the managed PowerShell profile block in a stable begin marker' );
like( $install_ps_text, qr/# <<< Developer Dashboard bootstrap <<</, 'install.ps1 wraps the managed PowerShell profile block in a stable end marker' );
like( $install_ps_text, qr/\[Regex\]::Escape\(\$beginMarker\)/, 'install.ps1 escapes the managed begin marker with the .NET regex API before replacing older profile blocks' );
like( $install_ps_text, qr/\[Regex\]::Escape\(\$endMarker\)/, 'install.ps1 escapes the managed end marker with the .NET regex API before replacing older profile blocks' );
unlike( $install_ps_text, qr/\\Q\$beginMarker\\E|\\Q\$endMarker\\E/, 'install.ps1 avoids Perl-style \\Q...\\E regex quoting that PowerShell does not support in [Regex]::Replace' );
like( $install_ps_text, qr/legacyManagedPattern/, 'install.ps1 strips legacy unmarked Developer Dashboard profile blocks from earlier Windows bootstrap failures' );
like( $install_ps_text, qr/Join-Path\s+\`\$HOME\s+'.developer-dashboard\\cli\\dd\\_dashboard-core'/s, 'install.ps1 only asks dashboard shell ps for profile bootstrap when the staged home helper runtime is present' );
like( $install_ps_text, qr/if\s+\(\[string\]::IsNullOrWhiteSpace\(\`\$env:HOME\)\s+-and\s+-not\s+\[string\]::IsNullOrWhiteSpace\(\`\$HOME\)\)\s*\{\s*\`\$env:HOME = \`\$HOME/s, 'install.ps1 seeds env:HOME from PowerShell HOME inside the managed pr...
like( $install_ps_text, qr/\$profilePerlRuntimePaths\s*=\s*\@/s, 'install.ps1 captures the resolved Strawberry Perl runtime directories before writing the managed PowerShell profile block' );
like( $install_ps_text, qr/\$profileExtraRuntimePaths\s*=\s*\@/s, 'install.ps1 captures extra Windows runtime directories such as portable Node.js before writing the managed PowerShell profile block' );
like( $install_ps_text, qr/\`\$ddPerlRuntimePaths\s*=\s*\@/s, 'install.ps1 writes the Strawberry Perl runtime directories into the managed PowerShell profile block for future sessions' );
like( $install_ps_text, qr/\`\$ddExtraRuntimePaths\s*=\s*\@/s, 'install.ps1 writes any extra portable Windows runtime directories into the managed PowerShell profile block for future sessions' );
like( $install_ps_text, qr/foreach\s+\(\`\$ddPerlRuntimePath in \`\$ddPerlRuntimePaths\)/s, 'install.ps1 prepends the persisted Strawberry Perl runtime directories in future PowerShell sessions before resolving dashboard' );
like( $install_ps_text, qr/foreach\s+\(\`\$ddExtraRuntimePath in \`\$ddExtraRuntimePaths\)/s, 'install.ps1 also prepends any persisted portable Windows runtime directories in future PowerShell sessions' );
like( $install_ps_text, qr/\$ddDashboardCandidate in \@\(\s*\(Join-Path\s+\`\$ddPerlBin\s+'dashboard\.bat'\),\s*\(Join-Path\s+\`\$ddPerlBin\s+'dashboard\.cmd'\),\s*\(Join-Path\s+\`\$ddPerlBin\s+'dashboard'\),\s*\(\(Get-Command dashboard -ErrorAct...
like( $install_ps_text, qr/\$ddShellBootstrap\s*=\s*&\s+\`\$ddPerlCommand\.Source\s+\`\$ddDashboardCommand\s+shell\s+ps/s, 'install.ps1 captures dashboard shell ps output through perl plus the resolved managed dashboard command before invoking it...
unlike( $install_ps_text, qr/\$ddShellBootstrapText\s*=\s*Join-ScriptText\s+-Value\s+\`\$ddShellBootstrap/s, 'install.ps1 does not leak installer-only Join-ScriptText helper calls into the generated PowerShell profile block' );
like( $install_ps_text, qr/\$ddShellBootstrapText\s*=\s*\(\(@\(\`\$ddShellBootstrap \| Where-Object \{ .*? \} \| ForEach-Object \{ .*? \}\)\) -join \[Environment\]::NewLine\)/s, 'install.ps1 normalizes dashboard shell ps output arrays inline insi...
like( $install_ps_text, qr/if\s+\(-not\s+\[string\]::IsNullOrWhiteSpace\(\`\$ddShellBootstrapText\)\)\s*\{\s*Invoke-Expression\s+\`\$ddShellBootstrapText/s, 'install.ps1 skips Invoke-Expression when the normalized profile bootstrap is empty' );
like( $install_ps_text, qr/Invoke-NativeCommand\s+-Label\s+'dashboard init'\s+-FilePath\s+\$dashboardCommand\s+-Arguments\s+\@\(\'init\'\).*?&\s+\$perlPath\s+\$dashboardCommand\s+shell\s+ps/s, 'install.ps1 initializes the dashboard runtime before...
like( $install_ps_text, qr/\$dashboardShellBootstrapText\s*=\s*Join-ScriptText\s+-Value\s+\$dashboardShellBootstrap/s, 'install.ps1 normalizes the current-session dashboard shell ps output into one script string' );
unlike( $install_ps_text, qr/Invoke-Expression\s+\(&\s+\$dashboardCommand\s+shell\s+ps\)/, 'install.ps1 no longer invokes dashboard shell ps directly without checking for empty output' );
unlike( $install_ps_text, qr/\$CpanTarget\s*=\s*if\s*\(\[string\]::IsNullOrWhiteSpace\(\$env:DD_INSTALL_CPAN_TARGET\)\)\s*\{\s*'Developer::Dashboard'\s*\}/, 'install.ps1 no longer defaults streamed Windows installs to the stale CPAN module name' ...
like( $install_ps_text, qr/cpanm.*--notest/s, 'install.ps1 installs Developer Dashboard with cpanm --notest on Windows' );
like( $install_ps_text, qr/dashboard init/, 'install.ps1 initializes the dashboard runtime after the Windows install' );
like( $install_ps_text, qr/\bshell\s+ps\b/, 'install.ps1 activates the PowerShell bootstrap after installation' );
like( $install_ps_text, qr/Set-ExecutionPolicy\s+-Scope\s+CurrentUser\s+-ExecutionPolicy\s+RemoteSigned\s+-Force/s, 'install.ps1 enables a CurrentUser PowerShell execution policy that can load the generated profile in future sessions' );
like( $install_ps_text, qr/ExecutionPolicyOverride/, 'install.ps1 treats the benign CurrentUser execution-policy override warning explicitly during streamed bootstrap runs' );
like( $install_ps_text, qr/kept the saved CurrentUser policy and continued/s, 'install.ps1 explains when a more specific PowerShell execution-policy scope keeps the current session in Bypass while the saved CurrentUser policy still succeeds' );
like( $install_ps_text, qr/Get-ExecutionPolicy\s+-Scope\s+CurrentUser/s, 'install.ps1 inspects the current-user execution policy before changing it' );
like( $install_ps_text, qr/-Mlocal::lib=\$normalizedInstallRoot/s, 'install.ps1 asks perl local::lib for canonical Windows environment values instead of composing INSTALL_BASE manually' );
like( $install_ps_text, qr/-Mlocal::lib=\`\$ddInstallRootForward/s, 'install.ps1 writes a profile block that refreshes local::lib from perl in future PowerShell sessions' );
}
my @apt_packages = _manifest_lines($aptfile);
my @apk_packages = _manifest_lines($apkfile);
my @dnf_packages = _manifest_lines($dnfile);
my @brew_packages = _manifest_lines($brewfile);
( run in 1.380 second using v1.01-cache-2.11-cpan-6aa56a78535 )