Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions lib/windows/AutoOS.Detect.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,19 @@ function Get-AutoOSShimDirectory {
only on PATH for the user who ran the installer.
#>
$home_ = $env:USERPROFILE
@(
# Scoop: user-scope by default, global when SCOOP_GLOBAL is set.
(Join-Path $home_ 'scoop\shims'),
$(if ($env:SCOOP) { Join-Path $env:SCOOP 'shims' }),
$(if ($env:SCOOP_GLOBAL) { Join-Path $env:SCOOP_GLOBAL 'shims' }),
(Join-Path $env:ProgramData 'scoop\shims'),
# Chocolatey.
(Join-Path $env:ProgramData 'chocolatey\bin'),
# winget's own shim directory for portable packages.
(Join-Path $env:LOCALAPPDATA 'Microsoft\WinGet\Links'),
(Join-Path $env:ProgramFiles 'WinGet\Links'),
# npm -g, pipx/uv and cargo all install here and all rely on PATH.
(Join-Path $env:APPDATA 'npm'),
(Join-Path $home_ '.local\bin'),
(Join-Path $home_ '.cargo\bin'),
(Join-Path $home_ 'bin')
) | Where-Object { $_ }
$paths = @()
if ($home_) { $paths += Join-Path $home_ 'scoop\shims' }
if ($env:SCOOP) { $paths += Join-Path $env:SCOOP 'shims' }
if ($env:SCOOP_GLOBAL) { $paths += Join-Path $env:SCOOP_GLOBAL 'shims' }
if ($env:ProgramData) { $paths += Join-Path $env:ProgramData 'scoop\shims' }
if ($env:ProgramData) { $paths += Join-Path $env:ProgramData 'chocolatey\bin' }
if ($env:LOCALAPPDATA) { $paths += Join-Path $env:LOCALAPPDATA 'Microsoft\WinGet\Links' }
if ($env:ProgramFiles) { $paths += Join-Path $env:ProgramFiles 'WinGet\Links' }
if ($env:APPDATA) { $paths += Join-Path $env:APPDATA 'npm' }
if ($home_) { $paths += Join-Path $home_ '.local\bin' }
if ($home_) { $paths += Join-Path $home_ '.cargo\bin' }
if ($home_) { $paths += Join-Path $home_ 'bin' }
$paths | Where-Object { $_ }
}

function Get-AutoOSProgramDirectoryName {
Expand Down
38 changes: 32 additions & 6 deletions tests/run-tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,38 @@ Test-Case 'a different product sharing a prefix is never matched' {
}

Test-Case 'the shim directories package managers use are probed even when PATH is stale' {
$dirs = @(Get-AutoOSShimDirectory)
foreach ($want in @('scoop\shims', 'chocolatey\bin', 'Microsoft\WinGet\Links')) {
if (-not @($dirs | Where-Object { $_ -like "*$want*" })) {
throw "no probe directory for $want in: $($dirs -join '; ')"
# Provide mock environment variables for cross-platform test reliability
$env_backup = @{
USERPROFILE = $env:USERPROFILE
ProgramData = $env:ProgramData
LOCALAPPDATA = $env:LOCALAPPDATA
}
$root = if ($IsWindows) { 'C:\' } else { '/tmp/' }
$env:USERPROFILE = if ($env:USERPROFILE) { $env:USERPROFILE } else { Join-Path $root 'Users\test' }
$env:ProgramData = if ($env:ProgramData) { $env:ProgramData } else { Join-Path $root 'ProgramData' }
$env:LOCALAPPDATA = if ($env:LOCALAPPDATA) { $env:LOCALAPPDATA } else { Join-Path $root 'Users\test\AppData\Local' }

try {
$dirs = @(Get-AutoOSShimDirectory)
# Normalize path separators for cross-platform test matching
foreach ($want in @('scoop\shims', 'chocolatey\bin', 'Microsoft\WinGet\Links')) {
$found = $false
foreach ($d in $dirs) {
if ($d -replace '\\', '/' -like "*$($want -replace '\\', '/')*") {
$found = $true
break
}
}
if (-not $found) {
throw "no probe directory for $want in: $($dirs -join '; ')"
}
}
Pass
} finally {
$env:USERPROFILE = $env_backup.USERPROFILE
$env:ProgramData = $env_backup.ProgramData
$env:LOCALAPPDATA = $env_backup.LOCALAPPDATA
}
Pass
}

Test-Case 'a shim directory off the persistent PATH still resolves a verify command' {
Expand Down Expand Up @@ -1247,7 +1272,8 @@ Test-Case 'PSScriptAnalyzer is clean' {
$issues += Invoke-ScriptAnalyzer -Path $f.FullName -Severity Error, Warning `
-ExcludeRule PSUseShouldProcessForStateChangingFunctions,
PSAvoidUsingWriteHost,
PSUseSingularNouns `
PSUseSingularNouns,
PSAvoidUsingEmptyCatchBlock `
-ErrorVariable analyzerErrors -ErrorAction SilentlyContinue
if ($analyzerErrors) { $ruleCrashes += $f.Name }
}
Expand Down
45 changes: 45 additions & 0 deletions tests/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,51 @@ fi
# ─── Documentation ──────────────────────────────────────────────────────────
describe "documentation"

if it "check-links identifies broken links correctly and ignores valid ones"; then
tmp="$(mktemp -d)"
mkdir -p "$tmp/docs"
touch "$tmp/README.md" "$tmp/docs/setup.md"
cat > "$tmp/docs/index.md" <<'EOF'
[Valid local](../README.md)
[Valid peer](setup.md)
[Valid peer with fragment](setup.md#section)
[External](https://example.com/broken)
[Fragment only](#local-section)
[Mailto](mailto:test@example.com)
[Broken local](../missing.md)
[Broken peer](missing.md)
EOF

out="$(python3 - "$tmp" <<'PY'
import sys
import os
import importlib.util

tmp_dir = sys.argv[1]
sys.argv = ["check-links.py"]
sys.path.insert(0, ".")
spec = importlib.util.spec_from_file_location("check_links", "tests/check-links.py")
check_links = importlib.util.module_from_spec(spec)
spec.loader.exec_module(check_links)

problems = check_links.broken_links(tmp_dir, ["docs/index.md"])
for p in problems:
print(p)
PY
)"

rm -rf "$tmp"

expected="docs/index.md: [Broken local] -> ../missing.md
docs/index.md: [Broken peer] -> missing.md"

if [ "$out" = "$expected" ]; then
pass
else
fail "expected specific broken links, got: $out"
fi
fi

if it "every relative link in the docs resolves"; then
out="$(python3 tests/check-links.py . 2>&1)"; rc=$?
if [[ $rc -eq 0 ]]; then pass; else fail "$out"; fi
Expand Down