fix(install): resolve latest version via GitHub API on Windows

The PowerShell installer scraped the tag from the /releases/latest
redirect via $resp.BaseResponse.ResponseUri, which only exists on
Windows PowerShell 5.1. On PowerShell 7 (the default iwr|iex runtime)
BaseResponse is an HttpResponseMessage with no ResponseUri, so the value
was null, the regex never matched, and the script died with 'could not
resolve latest version' even though zot is public.

Resolve via api.github.com/.../releases/latest instead (tag_name is
returned directly, identical across PS 5.1 and 7+), add status-aware
error messages (404 / 401-403 / other), and drop the stale private-repo
note. Verified on PowerShell 7.7.
This commit is contained in:
patriceckhart 2026-05-29 11:26:18 +02:00
parent edbbcc1086
commit 872a312a06

View file

@ -13,9 +13,10 @@
# and moves it into $ZOT_PREFIX (defaults to $HOME\bin, added to PATH
# via the User environment if missing).
#
# While the repo is private, set $env:GITHUB_TOKEN to a PAT with
# `contents:read` scope; the script uses it for every download. Once
# the repo goes public, the token becomes optional.
# $env:GITHUB_TOKEN is optional for the public repo. Set it to a PAT
# with `contents:read` scope if you hit GitHub API rate limits (or if
# you are installing from a private fork); the script then uses it for
# the version lookup and every download.
[CmdletBinding()]
@ -58,20 +59,41 @@ if ($arch -eq "arm64") {
}
# ---- resolve version ----
#
# Resolve "latest" through the GitHub releases API. This works the same
# on Windows PowerShell 5.1 and PowerShell 7+, unlike scraping the
# /releases/latest redirect target: on PS7 the final URL lives at
# $resp.BaseResponse.RequestMessage.RequestUri while on PS5.1 it is
# $resp.BaseResponse.ResponseUri, and relying on either breaks on the
# other runtime. The API returns the tag directly, so there is nothing
# to scrape.
if ($Version -eq "latest") {
if ($headers.ContainsKey("Authorization")) {
$api = Invoke-RestMethod -Headers $headers "https://api.github.com/repos/$owner/$repo/releases/latest"
$Version = $api.tag_name
} else {
$resp = Invoke-WebRequest -UseBasicParsing -MaximumRedirection 5 `
"https://github.com/$owner/$repo/releases/latest"
if ($resp.BaseResponse.ResponseUri -match '/tag/([^/]+)') {
$Version = $Matches[1]
$apiUrl = "https://api.github.com/repos/$owner/$repo/releases/latest"
# GitHub's API wants a User-Agent; Invoke-RestMethod sets one, but be
# explicit so corporate proxies that strip it don't trip a 403.
$apiHeaders = @{} + $headers
if (-not $apiHeaders.ContainsKey("User-Agent")) { $apiHeaders["User-Agent"] = "zot-installer" }
$apiHeaders["Accept"] = "application/vnd.github+json"
try {
$api = Invoke-RestMethod -UseBasicParsing -Headers $apiHeaders -Uri $apiUrl
} catch {
$status = $null
try { $status = [int]$_.Exception.Response.StatusCode } catch {}
if ($status -eq 404) {
Die "no published release found for $owner/$repo (the repo may have no releases yet)"
} elseif ($status -eq 401 -or $status -eq 403) {
Die "GitHub API request was rejected ($status). If the repo is private, set `$env:GITHUB_TOKEN to a PAT with contents:read; otherwise you may be rate-limited (try again later or set `$env:GITHUB_TOKEN)."
} else {
Die "could not resolve latest version (set `$env:GITHUB_TOKEN if the repo is private)"
Die "could not resolve latest version: $($_.Exception.Message)"
}
}
$Version = $api.tag_name
if (-not $Version) {
Die "could not resolve latest version: GitHub API returned no tag_name for $owner/$repo"
}
}
if (-not $Version.StartsWith("v")) { $Version = "v$Version" }