Skip to content
Merged
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
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,29 @@ jobs:
"$dir/sshmgr" version
test -x "$dir/sshmgr"

# The Windows installer is an `irm | iex` entry point and was only ever
# parsed, never run. Run it, then run it again with the API URL broken so
# the releases/latest fallback is what resolves the version.
- name: The Windows installer actually installs
if: runner.os == 'Windows'
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
foreach ($case in 'api', 'redirect-fallback') {
$script = Get-Content -Raw src/scripts/install.ps1
if ($case -eq 'redirect-fallback') {
$broken = $script -replace 'api\.github\.com/repos/\$owner/\$repo/releases/latest', 'api.github.com/repos/$owner/$repo-forced-404/releases/latest'
if ($broken -eq $script) { throw 'could not break the API URL; the fallback would go untested' }
$script = $broken
}
$path = Join-Path $env:RUNNER_TEMP "install-$case.ps1"
Set-Content -Path $path -Value $script
$dir = Join-Path $env:RUNNER_TEMP "bin-$case"
& $path -InstallDir $dir
& (Join-Path $dir 'sshmgr.exe') version
if ($LASTEXITCODE -ne 0) { throw "sshmgr version failed ($case)" }
}

- name: E2E smoke
if: runner.os != 'Windows'
shell: bash
Expand Down
27 changes: 24 additions & 3 deletions src/scripts/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,30 @@ switch ($env:PROCESSOR_ARCHITECTURE) {
if (-not $InstallDir) { $InstallDir = Join-Path $env:LOCALAPPDATA "Programs\$repo" }

if (-not $Version) {
$rel = Invoke-RestMethod -Headers @{ 'Accept' = 'application/vnd.github+json' } `
"https://api.github.com/repos/$owner/$repo/releases/latest"
$Version = $rel.tag_name
try {
$rel = Invoke-RestMethod -Headers @{ 'Accept' = 'application/vnd.github+json' } `
"https://api.github.com/repos/$owner/$repo/releases/latest"
$Version = $rel.tag_name
} catch { $Version = $null }

# The API allows 60 unauthenticated requests an hour per IP, and anyone behind a
# shared NAT - or on a CI runner - can find that spent and get a 403. The
# releases/latest web redirect is not counted against it and names the same tag,
# so fall back to it rather than failing the install (install.sh does the same).
# HttpWebRequest with redirects off reads the Location header identically on
# Windows PowerShell 5.1 and PowerShell 7; a 3xx can surface as an exception on
# the latter, so its response is read from there too.
if (-not $Version) {
$req = [System.Net.HttpWebRequest]::Create("https://github.com/$owner/$repo/releases/latest")
$req.AllowAutoRedirect = $false
$req.Method = 'HEAD'
try { $resp = $req.GetResponse() } catch [System.Net.WebException] { $resp = $_.Exception.Response }
if ($resp) {
try { $location = [string]$resp.Headers['Location'] } finally { $resp.Close() }
if ($location -match '/releases/tag/([^/?#]+)$') { $Version = $Matches[1] }
}
}
if (-not $Version) { throw 'could not determine the version to install.' }
}
if ($Version -notlike 'v*') { $Version = "v$Version" }

Expand Down
Loading