Compare commits

...

2 Commits

Author SHA1 Message Date
Zsolt Dollenstein
37802adc94 Fetch uv from Astral's mirror by default (#809)
Some checks failed
Release Drafter / ✏️ Draft release (push) Waiting to run
test / test-default-version (macos-14) (push) Waiting to run
test / test-default-version (macos-latest) (push) Waiting to run
test / test-default-version (windows-latest) (push) Waiting to run
test / test-tool-install (macos-14) (push) Waiting to run
test / test-checksum (map[checksum:a70cbfbf3bb5c08b2f84963b4f12c94e08fbb2468ba418a3bfe1066fbe9e7218 os:macos-latest]) (push) Waiting to run
test / test-tool-install (macos-latest) (push) Waiting to run
test / test-tool-install (windows-latest) (push) Waiting to run
test / test-python-version (macos-latest) (push) Waiting to run
CodeQL / Analyze (TypeScript) (push) Failing after 3s
test / test-python-version (windows-latest) (push) Waiting to run
test / test-activate-environment (macos-latest) (push) Waiting to run
test / test-activate-environment (windows-latest) (push) Waiting to run
test / test-activate-environment-custom-path (macos-latest) (push) Waiting to run
test / test-activate-environment-custom-path (windows-latest) (push) Waiting to run
test / test-cache-key-os-version (macos-14, macos-14) (push) Waiting to run
test / test-cache-key-os-version (macos-15, macos-15) (push) Waiting to run
test / test-cache-key-os-version (ubuntu-24.04, ubuntu-24.04) (push) Waiting to run
test / test-cache-key-os-version (windows-2022, windows-2022) (push) Waiting to run
test / test-cache-key-os-version (windows-2025, windows-2025) (push) Waiting to run
test / test-setup-cache (auto, windows-latest) (push) Waiting to run
test / lint (push) Failing after 3s
test / test-setup-cache (false, windows-latest) (push) Waiting to run
test / test-setup-cache (true, windows-latest) (push) Waiting to run
test / test-restore-cache (auto, windows-latest) (push) Blocked by required conditions
test / test-restore-cache (true, ubuntu-latest) (push) Blocked by required conditions
test / test-restore-cache (true, windows-latest) (push) Blocked by required conditions
test / test-restore-cache (auto, ubuntu-latest) (push) Blocked by required conditions
test / test-restore-cache (false, ubuntu-latest) (push) Blocked by required conditions
test / test-restore-cache (false, windows-latest) (push) Blocked by required conditions
test / test-cache-local (map[expected-cache-dir:D:\a\_temp\setup-uv-cache os:windows-latest]) (push) Waiting to run
test / test-python-install-dir (map[expected-python-dir:D:\a\_temp\uv-python-dir os:windows-latest]) (push) Waiting to run
test / all-tests-passed (push) Blocked by required conditions
test / test-default-version (ubuntu-latest) (push) Failing after 3s
test / test-uv-no-modify-path (push) Failing after 4s
test / test-specific-version (map[expected-version:0.1.0 resolution-strategy:lowest version-input:>=0.1.0,<0.2]) (push) Failing after 4s
test / test-specific-version (map[expected-version:0.1.45 resolution-strategy:highest version-input:>=0.1,<0.2]) (push) Failing after 3s
test / test-specific-version (map[expected-version:0.3.0 version-input:0.3.0]) (push) Failing after 3s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3]) (push) Failing after 5s
test / test-specific-version (map[expected-version:0.3.2 version-input:0.3.2]) (push) Failing after 6s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3.x]) (push) Failing after 5s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25,<0.5]) (push) Failing after 5s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25]) (push) Failing after 5s
test / test-specific-version (map[expected-version:0.4.30 version-input:>=0.4.25,<0.5]) (push) Failing after 11s
test / test-latest-version (>=0.8) (push) Failing after 12s
test / test-activate-environment (ubuntu-latest) (push) Failing after 32s
test / test-latest-version (latest) (push) Failing after 16s
test / test-from-working-directory-version (map[expected-version:0.5.14 working-directory:__tests__/fixtures/pyproject-toml-project]) (push) Failing after 16s
test / test-from-working-directory-version (map[expected-version:0.5.15 working-directory:__tests__/fixtures/uv-toml-project]) (push) Failing after 17s
test / test-version-file-version (map[expected-version:0.5.15 version-file:__tests__/fixtures/.tool-versions]) (push) Failing after 22s
test / test-version-file-version (map[expected-version:0.8.3 version-file:__tests__/fixtures/uv-in-requirements-hash-txt-project/requirements.txt]) (push) Failing after 24s
test / test-malformed-pyproject-file-fallback (push) Failing after 25s
test / test-version-file-version (map[expected-version:0.6.17 version-file:__tests__/fixtures/uv-in-requirements-txt-project/requirements.txt]) (push) Failing after 21s
test / test-checksum (map[checksum:4d9279ad5ca596b1e2d703901d508430eb07564dc4d8837de9e2fca9c90f8ecd os:ubuntu-latest]) (push) Failing after 25s
test / test-with-explicit-token (push) Failing after 31s
test / test-uvx (push) Failing after 31s
test / test-tool-install (ubuntu-latest) (push) Failing after 32s
test / test-python-version (ubuntu-latest) (push) Failing after 32s
test / test-activate-environment-custom-path (ubuntu-latest) (push) Failing after 34s
test / test-cache-key-os-version (ubuntu-22.04, ubuntu-22.04) (push) Failing after 32s
test / test-setup-cache (auto, ubuntu-latest) (push) Failing after 32s
test / test-setup-cache (false, ubuntu-latest) (push) Failing after 33s
test / test-setup-cache (true, ubuntu-latest) (push) Failing after 32s
test / test-setup-cache-requirements-txt (push) Failing after 33s
test / test-restore-cache-requirements-txt (push) Has been skipped
test / test-setup-cache-dependency-glob (push) Failing after 37s
test / test-restore-cache-dependency-glob (push) Has been skipped
test / test-musl (push) Failing after 45s
test / test-setup-cache-save-cache-false (push) Failing after 38s
test / test-restore-cache-save-cache-false (push) Has been skipped
test / test-debian-unstable (push) Failing after 48s
test / test-setup-cache-restore-cache-false (push) Failing after 43s
test / test-cache-local (map[expected-cache-dir:/home/runner/work/_temp/setup-uv-cache os:ubuntu-latest]) (push) Failing after 43s
test / test-restore-cache-restore-cache-false (push) Has been skipped
test / test-cache-local-cache-disabled (push) Failing after 43s
test / test-cache-local-cache-disabled-but-explicit-path (push) Failing after 43s
test / test-no-python-version (push) Failing after 43s
test / test-custom-manifest-file (push) Failing after 42s
test / test-absolute-path (push) Failing after 43s
test / test-relative-path (push) Failing after 43s
test / test-cache-prune-force (push) Failing after 43s
test / test-cache-dir-from-file (push) Failing after 43s
test / test-cache-python-missing-managed-install-dir (push) Failing after 43s
test / test-cache-python-installs (push) Failing after 43s
test / test-python-install-dir (map[expected-python-dir:/home/runner/work/_temp/uv-python-dir os:ubuntu-latest]) (push) Failing after 43s
test / test-restore-python-installs (push) Has been skipped
test / test-act (push) Failing after 43s
test / validate-typings (push) Failing after 43s
This PR tries fetching the uv artifact from `releases.astral.sh` by
default, only in cases where the artifact would otherwise have come from
`https://github.com/astral-sh/uv/releases/download/`. The checksums are
supposed to be the same for the mirror, and can still come from
`raw.githubusercontent.com/astral-sh/versions`. If the download fails,
we fall back to the original URL.

This avoids hitting GitHub's Releases API which is prone to rate
limiting. As far as I can tell, together with
https://github.com/astral-sh/setup-uv/pull/802 this PR makes a github
token entirely unnecessary for this action.


Towards https://github.com/astral-sh/uv/issues/18503.
2026-03-16 13:38:17 +01:00
dependabot[bot]
9f00d186ce chore(deps): bump zizmorcore/zizmor-action from 0.5.0 to 0.5.2 (#808)
Bumps
[zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action)
from 0.5.0 to 0.5.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/zizmorcore/zizmor-action/releases">zizmorcore/zizmor-action's
releases</a>.</em></p>
<blockquote>
<h2>v0.5.2</h2>
<h2>What's Changed</h2>
<ul>
<li>zizmor 1.23.1 is now the default used by this action.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/zizmorcore/zizmor-action/compare/v0.5.1...v0.5.2">https://github.com/zizmorcore/zizmor-action/compare/v0.5.1...v0.5.2</a></p>
<h2>v0.5.1</h2>
<h2>What's Changed</h2>
<ul>
<li>zizmor 1.23.0 is now the default used by this action.</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/zizmorcore/zizmor-action/compare/v0.5.0...v0.5.1">https://github.com/zizmorcore/zizmor-action/compare/v0.5.0...v0.5.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="71321a20a9"><code>71321a2</code></a>
Sync zizmor versions (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/96">#96</a>)</li>
<li><a
href="5ed31db096"><code>5ed31db</code></a>
Bump pins (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/95">#95</a>)</li>
<li><a
href="195d10ad90"><code>195d10a</code></a>
Sync zizmor versions (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/94">#94</a>)</li>
<li><a
href="c65bc88761"><code>c65bc88</code></a>
chore(deps): bump github/codeql-action in the github-actions group (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/93">#93</a>)</li>
<li><a
href="c2c887f846"><code>c2c887f</code></a>
chore(deps): bump zizmorcore/zizmor-action in the github-actions group
(<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/91">#91</a>)</li>
<li><a
href="5507ab0c02"><code>5507ab0</code></a>
Bump pins in README (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/90">#90</a>)</li>
<li>See full diff in <a
href="0dce2577a4...71321a20a9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=zizmorcore/zizmor-action&package-manager=github_actions&previous-version=0.5.0&new-version=0.5.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 12:37:11 +01:00
5 changed files with 229 additions and 21 deletions

View File

@@ -27,7 +27,7 @@ jobs:
- name: Actionlint
uses: eifinger/actionlint-action@7802e0cc3ab3f81cbffb36fb0bf1a3621d994b89 # v1.10.1
- name: Run zizmor
uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version-file: .nvmrc

View File

@@ -68,6 +68,7 @@ const {
downloadVersionFromManifest,
downloadVersionFromNdjson,
resolveVersion,
rewriteToMirror,
} = await import("../../src/download/download-version");
describe("download-version", () => {
@@ -198,6 +199,135 @@ describe("download-version", () => {
"0.9.26",
);
});
it("rewrites GitHub Releases URLs to the Astral mirror", async () => {
mockGetArtifactFromNdjson.mockResolvedValue({
archiveFormat: "tar.gz",
sha256: "abc123",
url: "https://github.com/astral-sh/uv/releases/download/0.9.26/uv-x86_64-unknown-linux-gnu.tar.gz",
});
await downloadVersionFromNdjson(
"unknown-linux-gnu",
"x86_64",
"0.9.26",
undefined,
"token",
);
expect(mockDownloadTool).toHaveBeenCalledWith(
"https://releases.astral.sh/github/uv/releases/download/0.9.26/uv-x86_64-unknown-linux-gnu.tar.gz",
undefined,
undefined,
);
});
it("does not rewrite non-GitHub URLs", async () => {
mockGetArtifactFromNdjson.mockResolvedValue({
archiveFormat: "tar.gz",
sha256: "abc123",
url: "https://example.com/uv.tar.gz",
});
await downloadVersionFromNdjson(
"unknown-linux-gnu",
"x86_64",
"0.9.26",
undefined,
"token",
);
expect(mockDownloadTool).toHaveBeenCalledWith(
"https://example.com/uv.tar.gz",
undefined,
"token",
);
});
it("falls back to GitHub Releases when the mirror fails", async () => {
mockGetArtifactFromNdjson.mockResolvedValue({
archiveFormat: "tar.gz",
sha256: "abc123",
url: "https://github.com/astral-sh/uv/releases/download/0.9.26/uv-x86_64-unknown-linux-gnu.tar.gz",
});
mockDownloadTool
.mockRejectedValueOnce(new Error("mirror unavailable"))
.mockResolvedValueOnce("/tmp/downloaded");
await downloadVersionFromNdjson(
"unknown-linux-gnu",
"x86_64",
"0.9.26",
undefined,
"token",
);
expect(mockDownloadTool).toHaveBeenCalledTimes(2);
// Mirror request: no token
expect(mockDownloadTool).toHaveBeenNthCalledWith(
1,
"https://releases.astral.sh/github/uv/releases/download/0.9.26/uv-x86_64-unknown-linux-gnu.tar.gz",
undefined,
undefined,
);
// GitHub fallback: token restored
expect(mockDownloadTool).toHaveBeenNthCalledWith(
2,
"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-x86_64-unknown-linux-gnu.tar.gz",
undefined,
"token",
);
expect(mockWarning).toHaveBeenCalledWith(
"Failed to download from mirror, falling back to GitHub Releases: mirror unavailable",
);
});
it("does not fall back for non-GitHub URLs", async () => {
mockGetArtifactFromNdjson.mockResolvedValue({
archiveFormat: "tar.gz",
sha256: "abc123",
url: "https://example.com/uv.tar.gz",
});
mockDownloadTool.mockRejectedValue(new Error("download failed"));
await expect(
downloadVersionFromNdjson(
"unknown-linux-gnu",
"x86_64",
"0.9.26",
undefined,
"token",
),
).rejects.toThrow("download failed");
expect(mockDownloadTool).toHaveBeenCalledTimes(1);
});
});
describe("rewriteToMirror", () => {
it("rewrites a GitHub Releases URL to the Astral mirror", () => {
expect(
rewriteToMirror(
"https://github.com/astral-sh/uv/releases/download/0.9.26/uv-x86_64-unknown-linux-gnu.tar.gz",
),
).toBe(
"https://releases.astral.sh/github/uv/releases/download/0.9.26/uv-x86_64-unknown-linux-gnu.tar.gz",
);
});
it("returns undefined for non-GitHub URLs", () => {
expect(rewriteToMirror("https://example.com/uv.tar.gz")).toBeUndefined();
});
it("returns undefined for a different GitHub repo", () => {
expect(
rewriteToMirror(
"https://github.com/other/repo/releases/download/v1.0/file.tar.gz",
),
).toBeUndefined();
});
});
describe("downloadVersionFromManifest", () => {

29
dist/setup/index.cjs generated vendored
View File

@@ -91887,6 +91887,8 @@ var TOOL_CACHE_NAME = "uv";
var STATE_UV_PATH = "uv-path";
var STATE_UV_VERSION = "uv-version";
var VERSIONS_NDJSON_URL = "https://raw.githubusercontent.com/astral-sh/versions/main/v1/uv.ndjson";
var GITHUB_RELEASES_PREFIX = "https://github.com/astral-sh/uv/releases/download/";
var ASTRAL_MIRROR_PREFIX = "https://releases.astral.sh/github/uv/releases/download/";
// src/download/checksum/checksum.ts
var crypto6 = __toESM(require("node:crypto"), 1);
@@ -96658,6 +96660,26 @@ async function downloadVersionFromNdjson(platform2, arch3, version4, checkSum2,
`Could not find artifact for version ${version4}, arch ${arch3}, platform ${platform2} in ${VERSIONS_NDJSON_URL} .`
);
}
const mirrorUrl = rewriteToMirror(artifact.url);
const downloadUrl = mirrorUrl ?? artifact.url;
const downloadToken = mirrorUrl !== void 0 ? void 0 : githubToken2;
try {
return await downloadVersion(
downloadUrl,
`uv-${arch3}-${platform2}`,
platform2,
arch3,
version4,
checkSum2,
downloadToken
);
} catch (err) {
if (mirrorUrl === void 0) {
throw err;
}
warning(
`Failed to download from mirror, falling back to GitHub Releases: ${err.message}`
);
return await downloadVersion(
artifact.url,
`uv-${arch3}-${platform2}`,
@@ -96667,6 +96689,13 @@ async function downloadVersionFromNdjson(platform2, arch3, version4, checkSum2,
checkSum2,
githubToken2
);
}
}
function rewriteToMirror(url2) {
if (!url2.startsWith(GITHUB_RELEASES_PREFIX)) {
return void 0;
}
return ASTRAL_MIRROR_PREFIX + url2.slice(GITHUB_RELEASES_PREFIX.length);
}
async function downloadVersionFromManifest(manifestUrl, platform2, arch3, version4, checkSum2, githubToken2) {
const artifact = await getManifestArtifact(

View File

@@ -4,7 +4,12 @@ import * as core from "@actions/core";
import * as tc from "@actions/tool-cache";
import * as pep440 from "@renovatebot/pep440";
import * as semver from "semver";
import { TOOL_CACHE_NAME, VERSIONS_NDJSON_URL } from "../utils/constants";
import {
ASTRAL_MIRROR_PREFIX,
GITHUB_RELEASES_PREFIX,
TOOL_CACHE_NAME,
VERSIONS_NDJSON_URL,
} from "../utils/constants";
import type { Architecture, Platform } from "../utils/platforms";
import { validateChecksum } from "./checksum/checksum";
import {
@@ -48,8 +53,32 @@ export async function downloadVersionFromNdjson(
);
}
const mirrorUrl = rewriteToMirror(artifact.url);
const downloadUrl = mirrorUrl ?? artifact.url;
// Don't send the GitHub token to the Astral mirror.
const downloadToken = mirrorUrl !== undefined ? undefined : githubToken;
// For the default astral-sh/versions source, checksum validation relies on
// user input or the built-in KNOWN_CHECKSUMS table, not NDJSON sha256 values.
try {
return await downloadVersion(
downloadUrl,
`uv-${arch}-${platform}`,
platform,
arch,
version,
checkSum,
downloadToken,
);
} catch (err) {
if (mirrorUrl === undefined) {
throw err;
}
core.warning(
`Failed to download from mirror, falling back to GitHub Releases: ${(err as Error).message}`,
);
return await downloadVersion(
artifact.url,
`uv-${arch}-${platform}`,
@@ -59,6 +88,18 @@ export async function downloadVersionFromNdjson(
checkSum,
githubToken,
);
}
}
/**
* Rewrite a GitHub Releases URL to the Astral mirror.
* Returns `undefined` if the URL does not match the expected GitHub prefix.
*/
export function rewriteToMirror(url: string): string | undefined {
if (!url.startsWith(GITHUB_RELEASES_PREFIX)) {
return undefined;
}
return ASTRAL_MIRROR_PREFIX + url.slice(GITHUB_RELEASES_PREFIX.length);
}
export async function downloadVersionFromManifest(
@@ -99,7 +140,7 @@ async function downloadVersion(
arch: Architecture,
version: string,
checksum: string | undefined,
githubToken: string,
githubToken: string | undefined,
): Promise<{ version: string; cachedToolDir: string }> {
core.info(`Downloading uv from "${downloadUrl}" ...`);
const downloadPath = await tc.downloadTool(

View File

@@ -3,3 +3,11 @@ export const STATE_UV_PATH = "uv-path";
export const STATE_UV_VERSION = "uv-version";
export const VERSIONS_NDJSON_URL =
"https://raw.githubusercontent.com/astral-sh/versions/main/v1/uv.ndjson";
/** GitHub Releases URL prefix for uv artifacts. */
export const GITHUB_RELEASES_PREFIX =
"https://github.com/astral-sh/uv/releases/download/";
/** Astral mirror URL prefix that fronts GitHub Releases for uv artifacts. */
export const ASTRAL_MIRROR_PREFIX =
"https://releases.astral.sh/github/uv/releases/download/";