mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-09-21 00:33:38 +00:00
test / test-default-version (ubuntu-latest) (push) Failing after 4s
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 3s
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 4s
test / test-specific-version (map[expected-version:0.3.2 version-input:0.3.2]) (push) Failing after 4s
test / test-uvx (push) Failing after 1s
test / test-latest-version (>=0.8) (push) Failing after 2s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3]) (push) Failing after 22s
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 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-tool-versions-python-version (push) Failing after 16s
test / test-setup-cache-dependency-glob (push) Failing after 17s
test / test-restore-cache-requirements-txt (push) Skipped
test / test-restore-cache-dependency-glob (push) Skipped
test / test-restore-cache-save-cache-false (push) Skipped
test / test-no-python-version (push) Failing after 24s
test / test-custom-manifest-file (push) Failing after 25s
test / test-activate-environment-custom-path (ubuntu-latest) (push) Failing after 1s
test / test-checksum (map[checksum:4d9279ad5ca596b1e2d703901d508430eb07564dc4d8837de9e2fca9c90f8ecd os:ubuntu-latest]) (push) Failing after 18s
test / test-musl (push) Failing after 13s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25,<0.5]) (push) Failing after 6s
test / test-with-explicit-token (push) Failing after 17s
test / test-malformed-pyproject-file-fallback (push) Failing after 17s
test / test-relative-path (push) Failing after 3s
test / test-setup-cache (true, ubuntu-latest) (push) Failing after 12s
test / test-cache-key-os-version (ubuntu-22.04, ubuntu-22.04) (push) Failing after 20s
test / test-tool-install (ubuntu-latest) (push) Failing after 2s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3.x]) (push) Failing after 9s
test / test-latest-version (latest) (push) Failing after 2s
test / test-activate-environment (ubuntu-latest) (push) Failing after 1s
test / test-activate-environment-no-project (push) Failing after 1s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25]) (push) Failing after 12s
test / test-version-file-version (map[expected-version:0.5.15 version-file:__tests__/fixtures/.tool-versions]) (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 17s
test / test-specific-version (map[expected-version:0.4.30 version-input:>=0.4.25,<0.5]) (push) Failing after 20s
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 16s
test / test-python-version (ubuntu-latest) (push) Failing after 17s
test / test-debian-unstable (push) Failing after 15s
test / test-setup-cache (auto, ubuntu-latest) (push) Failing after 6s
test / test-setup-cache (false, ubuntu-latest) (push) Failing after 6s
test / test-cache-local (map[expected-cache-dir:/home/runner/work/_temp/setup-uv-cache os:ubuntu-latest]) (push) Failing after 5s
test / test-cache-local-cache-disabled (push) Failing after 4s
test / test-cache-local-cache-disabled-but-explicit-path (push) Failing after 4s
test / test-download-from-astral-mirror-false (push) Failing after 4s
test / test-absolute-path (push) Failing after 3s
test / test-setup-cache-requirements-txt (push) Failing after 17s
test / test-setup-cache-restore-cache-false (push) Failing after 18s
test / test-restore-cache-restore-cache-false (push) Skipped
test / test-cache-dir-from-file (push) Failing after 22s
test / test-cache-python-missing-managed-install-dir (push) Failing after 22s
test / test-restore-python-installs (push) Skipped
test / test-cache-prune-force (push) Failing after 22s
test / validate-typings (push) Successful in 44s
test / test-python-install-dir (map[expected-python-dir:/home/runner/work/_temp/uv-python-dir os:ubuntu-latest]) (push) Failing after 5s
test / test-setup-cache-save-cache-false (push) Failing after 17s
test / test-cache-python-installs (push) Failing after 21s
CodeQL / Analyze (TypeScript) (push) Failing after 1m40s
test / test-workflow-run (push) Failing after 35s
test / lint (push) Failing after 1m21s
test / test-default-version (macos-14) (push) Canceled after 0s
test / test-default-version (macos-latest) (push) Canceled after 0s
test / test-default-version (windows-latest) (push) Canceled after 0s
test / test-checksum (map[checksum:a70cbfbf3bb5c08b2f84963b4f12c94e08fbb2468ba418a3bfe1066fbe9e7218 os:macos-latest]) (push) Canceled after 0s
test / test-tool-install (macos-14) (push) Canceled after 0s
test / test-tool-install (macos-latest) (push) Canceled after 0s
test / test-tool-install (windows-latest) (push) Canceled after 0s
test / test-python-version (macos-latest) (push) Canceled after 0s
test / test-python-version (windows-latest) (push) Canceled after 0s
test / test-activate-environment (macos-latest) (push) Canceled after 0s
test / test-activate-environment (windows-latest) (push) Canceled after 0s
test / test-activate-environment-custom-path (macos-latest) (push) Canceled after 0s
test / test-activate-environment-custom-path (windows-latest) (push) Canceled after 0s
test / test-cache-key-os-version (macos-14, macos-14) (push) Canceled after 0s
test / test-cache-key-os-version (macos-15, macos-15) (push) Canceled after 0s
test / test-cache-key-os-version (windows-2025, windows-2025) (push) Canceled after 0s
test / test-setup-cache (true, windows-latest) (push) Canceled after 0s
test / test-cache-key-os-version (ubuntu-24.04, ubuntu-24.04) (push) Canceled after 0s
test / test-cache-key-os-version (windows-2022, windows-2022) (push) Canceled after 0s
test / test-setup-cache (auto, windows-latest) (push) Canceled after 0s
test / test-setup-cache (false, windows-latest) (push) Canceled after 0s
test / test-restore-cache (auto, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (auto, windows-latest) (push) Canceled after 0s
test / test-restore-cache (false, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (false, windows-latest) (push) Canceled after 0s
test / test-restore-cache (true, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (true, windows-latest) (push) Canceled after 0s
test / test-cache-local (map[expected-cache-dir:D:\a\_temp\setup-uv-cache os:windows-latest]) (push) Canceled after 0s
test / test-python-install-dir (map[expected-python-dir:D:\a\_temp\uv-python-dir os:windows-latest]) (push) Canceled after 0s
test / all-tests-passed (push) Canceled after 0s
Release Drafter / ✏️ Draft release (push) Canceled after 0s
`setup-uv` currently ignores the `sha256` supplied by the default `astral-sh/versions` manifest when a selected artifact is newer than its bundled checksum table, allowing that download to proceed without validation. Use the manifest checksum as a fallback after explicit and bundled checksums, and reject manifest entries that do not provide one. This preserves the stronger pinned hashes for known releases while verifying newer releases without requiring an action update. Part of #1032. --------- Co-authored-by: Zanie Blue <contact@zanie.dev> Co-authored-by: William Woodruff <william@yossarian.net> Co-authored-by: Kevin Stillhammer <kevin.stillhammer@gmail.com>
202 lines
5.7 KiB
TypeScript
202 lines
5.7 KiB
TypeScript
import { promises as fs } from "node:fs";
|
|
import * as path from "node:path";
|
|
import * as core from "@actions/core";
|
|
import * as tc from "@actions/tool-cache";
|
|
import {
|
|
ASTRAL_MIRROR_PREFIX,
|
|
GITHUB_RELEASES_PREFIX,
|
|
TOOL_CACHE_NAME,
|
|
VERSIONS_MANIFEST_URL,
|
|
} from "../utils/constants";
|
|
import * as log from "../utils/logging";
|
|
import type { Architecture, Platform } from "../utils/platforms";
|
|
import { validateChecksum } from "./checksum/checksum";
|
|
import { getArtifact } from "./manifest";
|
|
|
|
export { resolveVersion } from "../version/resolve";
|
|
|
|
export function tryGetFromToolCache(
|
|
arch: Architecture,
|
|
version: string,
|
|
): { version: string; installedPath: string | undefined } {
|
|
core.debug(`Trying to get uv from tool cache for ${version}...`);
|
|
const cachedVersions = tc.findAllVersions(TOOL_CACHE_NAME, arch);
|
|
core.debug(`Cached versions: ${cachedVersions}`);
|
|
let resolvedVersion = tc.evaluateVersions(cachedVersions, version);
|
|
if (resolvedVersion === "") {
|
|
resolvedVersion = version;
|
|
}
|
|
const installedPath = tc.find(TOOL_CACHE_NAME, resolvedVersion, arch);
|
|
return { installedPath, version: resolvedVersion };
|
|
}
|
|
|
|
export async function downloadVersion(
|
|
platform: Platform,
|
|
arch: Architecture,
|
|
version: string,
|
|
checksum: string | undefined,
|
|
githubToken: string,
|
|
manifestUrl?: string,
|
|
downloadFromAstralMirror = true,
|
|
): Promise<{ version: string; cachedToolDir: string }> {
|
|
const artifact = await getArtifact(version, arch, platform, manifestUrl);
|
|
|
|
if (!artifact) {
|
|
throw new Error(
|
|
getMissingArtifactMessage(version, arch, platform, manifestUrl),
|
|
);
|
|
}
|
|
|
|
// Custom manifests are explicitly selected by the user, so their checksum
|
|
// takes precedence over the built-in table. For the default manifest, pass
|
|
// its checksum as a fallback after user input and KNOWN_CHECKSUMS.
|
|
const resolvedChecksum =
|
|
manifestUrl === undefined
|
|
? checksum
|
|
: resolveChecksum(checksum, artifact.checksum);
|
|
const manifestChecksum = artifact.checksum;
|
|
|
|
const mirrorUrl = downloadFromAstralMirror
|
|
? rewriteToMirror(artifact.downloadUrl)
|
|
: undefined;
|
|
const downloadUrl = mirrorUrl ?? artifact.downloadUrl;
|
|
|
|
try {
|
|
return await downloadArtifact(
|
|
downloadUrl,
|
|
`uv-${arch}-${platform}`,
|
|
platform,
|
|
arch,
|
|
version,
|
|
resolvedChecksum,
|
|
manifestChecksum,
|
|
githubTokenForUrl(downloadUrl, githubToken),
|
|
);
|
|
} catch (err) {
|
|
if (mirrorUrl === undefined) {
|
|
throw err;
|
|
}
|
|
|
|
log.warning(
|
|
`Failed to download from mirror, falling back to GitHub Releases: ${(err as Error).message}`,
|
|
);
|
|
|
|
return await downloadArtifact(
|
|
artifact.downloadUrl,
|
|
`uv-${arch}-${platform}`,
|
|
platform,
|
|
arch,
|
|
version,
|
|
resolvedChecksum,
|
|
manifestChecksum,
|
|
githubTokenForUrl(artifact.downloadUrl, 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);
|
|
}
|
|
|
|
function githubTokenForUrl(
|
|
downloadUrl: string,
|
|
githubToken: string,
|
|
): string | undefined {
|
|
try {
|
|
return new URL(downloadUrl).origin === "https://github.com"
|
|
? githubToken
|
|
: undefined;
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
async function downloadArtifact(
|
|
downloadUrl: string,
|
|
artifactName: string,
|
|
platform: Platform,
|
|
arch: Architecture,
|
|
version: string,
|
|
checksum: string | undefined,
|
|
manifestChecksum: string | undefined,
|
|
githubToken: string | undefined,
|
|
): Promise<{ version: string; cachedToolDir: string }> {
|
|
log.info(`Downloading uv from "${downloadUrl}" ...`);
|
|
const downloadPath = await tc.downloadTool(
|
|
downloadUrl,
|
|
undefined,
|
|
githubToken,
|
|
);
|
|
await validateChecksum(
|
|
checksum,
|
|
downloadPath,
|
|
arch,
|
|
platform,
|
|
version,
|
|
manifestChecksum,
|
|
);
|
|
|
|
let uvDir: string;
|
|
if (platform === "pc-windows-msvc") {
|
|
// On windows extracting the zip does not create an intermediate directory.
|
|
try {
|
|
// Try tar first as it's much faster, but only bsdtar supports zip files,
|
|
// so this may fail if another tar, like gnu tar, ends up being used.
|
|
uvDir = await tc.extractTar(downloadPath, undefined, "x");
|
|
} catch (err) {
|
|
log.info(
|
|
`Extracting with tar failed, falling back to zip extraction: ${(err as Error).message}`,
|
|
);
|
|
const extension = getExtension(platform);
|
|
const fullPathWithExtension = `${downloadPath}${extension}`;
|
|
await fs.copyFile(downloadPath, fullPathWithExtension);
|
|
uvDir = await tc.extractZip(fullPathWithExtension);
|
|
}
|
|
} else {
|
|
const extractedDir = await tc.extractTar(downloadPath);
|
|
uvDir = path.join(extractedDir, artifactName);
|
|
}
|
|
|
|
const cachedToolDir = await tc.cacheDir(
|
|
uvDir,
|
|
TOOL_CACHE_NAME,
|
|
version,
|
|
arch,
|
|
);
|
|
return { cachedToolDir, version };
|
|
}
|
|
|
|
function getMissingArtifactMessage(
|
|
version: string,
|
|
arch: Architecture,
|
|
platform: Platform,
|
|
manifestUrl?: string,
|
|
): string {
|
|
if (manifestUrl === undefined) {
|
|
return `Could not find artifact for version ${version}, arch ${arch}, platform ${platform} in ${VERSIONS_MANIFEST_URL} .`;
|
|
}
|
|
|
|
return `manifest-file does not contain version ${version}, arch ${arch}, platform ${platform}.`;
|
|
}
|
|
|
|
function resolveChecksum(
|
|
checksum: string | undefined,
|
|
manifestChecksum: string,
|
|
): string {
|
|
return checksum !== undefined && checksum !== ""
|
|
? checksum
|
|
: manifestChecksum;
|
|
}
|
|
|
|
function getExtension(platform: Platform): string {
|
|
return platform === "pc-windows-msvc" ? ".zip" : ".tar.gz";
|
|
}
|