From 8bd9170ab9a4cff3798f06ae9f79cc68c69af286 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Thu, 22 Jan 2026 07:57:07 -0600 Subject: [PATCH] Review --- .github/workflows/update-known-versions.yml | 1 - __tests__/download/versions-client.test.ts | 11 +- dist/setup/index.js | 114 +++++++------------- dist/update-known-versions/index.js | 99 ++--------------- src/download/checksum/checksum.ts | 43 ++++---- src/download/download-version.ts | 40 ++----- src/download/versions-client.ts | 41 ++----- src/setup-uv.ts | 26 +++-- src/update-known-versions.ts | 3 +- 9 files changed, 106 insertions(+), 272 deletions(-) diff --git a/.github/workflows/update-known-versions.yml b/.github/workflows/update-known-versions.yml index 6b4cc38..4f2f30a 100644 --- a/.github/workflows/update-known-versions.yml +++ b/.github/workflows/update-known-versions.yml @@ -27,7 +27,6 @@ jobs: node dist/update-known-versions/index.js src/download/checksum/known-checksums.ts version-manifest.json - ${{ secrets.GITHUB_TOKEN }} - name: Check for changes id: changes-exist run: | diff --git a/__tests__/download/versions-client.test.ts b/__tests__/download/versions-client.test.ts index 2237581..f0a6e04 100644 --- a/__tests__/download/versions-client.test.ts +++ b/__tests__/download/versions-client.test.ts @@ -23,13 +23,12 @@ function createMockResponse( statusText: string, data: string, ) { - const encoder = new TextEncoder(); - const body = { - async *[Symbol.asyncIterator]() { - yield encoder.encode(data); - }, + return { + ok, + status, + statusText, + text: async () => data, }; - return { body, ok, status, statusText }; } describe("versions-client", () => { diff --git a/dist/setup/index.js b/dist/setup/index.js index b516760..177af36 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -91627,36 +91627,32 @@ const fs = __importStar(__nccwpck_require__(3024)); const core = __importStar(__nccwpck_require__(7484)); const known_checksums_1 = __nccwpck_require__(2764); async function validateChecksum(checkSum, downloadPath, arch, platform, version, ndjsonChecksum) { - let isValid; - let checksumUsed; // Priority: user-provided checksum > KNOWN_CHECKSUMS > NDJSON fallback + const key = `${arch}-${platform}-${version}`; + let checksumToUse; + let source; if (checkSum !== undefined && checkSum !== "") { - checksumUsed = checkSum; - core.debug("Using user-provided checksum."); - isValid = await validateFileCheckSum(downloadPath, checkSum); + checksumToUse = checkSum; + source = "user-provided"; + } + else if (key in known_checksums_1.KNOWN_CHECKSUMS) { + checksumToUse = known_checksums_1.KNOWN_CHECKSUMS[key]; + source = `known checksum for ${key}`; + } + else if (ndjsonChecksum !== undefined && ndjsonChecksum !== "") { + checksumToUse = ndjsonChecksum; + source = "NDJSON version data"; } else { - const key = `${arch}-${platform}-${version}`; - if (key in known_checksums_1.KNOWN_CHECKSUMS) { - checksumUsed = known_checksums_1.KNOWN_CHECKSUMS[key]; - core.debug(`Using known checksum for ${key}.`); - isValid = await validateFileCheckSum(downloadPath, checksumUsed); - } - else if (ndjsonChecksum !== undefined && ndjsonChecksum !== "") { - checksumUsed = ndjsonChecksum; - core.debug("Using checksum from NDJSON version data."); - isValid = await validateFileCheckSum(downloadPath, ndjsonChecksum); - } - else { - core.debug(`No checksum found for ${key}.`); - } + core.debug(`No checksum found for ${key}.`); + return; } - if (isValid === false) { - throw new Error(`Checksum for ${downloadPath} did not match ${checksumUsed}.`); - } - if (isValid === true) { - core.debug(`Checksum for ${downloadPath} is valid.`); + core.debug(`Using ${source}.`); + const isValid = await validateFileCheckSum(downloadPath, checksumToUse); + if (!isValid) { + throw new Error(`Checksum for ${downloadPath} did not match ${checksumToUse}.`); } + core.debug(`Checksum for ${downloadPath} is valid.`); } async function validateFileCheckSum(filePath, expected) { return new Promise((resolve, reject) => { @@ -95882,7 +95878,7 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.tryGetFromToolCache = tryGetFromToolCache; -exports.downloadVersionFromGithub = downloadVersionFromGithub; +exports.downloadVersionFromNdjson = downloadVersionFromNdjson; exports.downloadVersionFromManifest = downloadVersionFromManifest; exports.resolveVersion = resolveVersion; const node_fs_1 = __nccwpck_require__(3024); @@ -95906,17 +95902,11 @@ function tryGetFromToolCache(arch, version) { const installedPath = tc.find(constants_1.TOOL_CACHE_NAME, resolvedVersion, arch); return { installedPath, version: resolvedVersion }; } -async function downloadVersionFromGithub(platform, arch, version, checkSum, githubToken) { +async function downloadVersionFromNdjson(platform, arch, version, checkSum, githubToken) { const artifact = `uv-${arch}-${platform}`; const extension = getExtension(platform); - // Try to get artifact info from NDJSON (includes checksum) - let artifactInfo; - try { - artifactInfo = await (0, versions_client_1.getArtifact)(version, arch, platform); - } - catch (err) { - core.debug(`Failed to get artifact from NDJSON: ${err.message}`); - } + // Get artifact info from NDJSON (includes URL and checksum) + const artifactInfo = await (0, versions_client_1.getArtifact)(version, arch, platform); const downloadUrl = artifactInfo?.url ?? `https://github.com/${constants_1.OWNER}/${constants_1.REPO}/releases/download/${version}/${artifact}${extension}`; return await downloadVersion(downloadUrl, artifact, platform, arch, version, checkSum, githubToken, artifactInfo?.sha256); @@ -95924,19 +95914,9 @@ async function downloadVersionFromGithub(platform, arch, version, checkSum, gith async function downloadVersionFromManifest(manifestUrl, platform, arch, version, checkSum, githubToken) { const downloadUrl = await (0, version_manifest_1.getDownloadUrl)(manifestUrl, version, arch, platform); if (!downloadUrl) { - core.info(`manifest-file does not contain version ${version}, arch ${arch}, platform ${platform}. Falling back to GitHub releases.`); - return await downloadVersionFromGithub(platform, arch, version, checkSum, githubToken); + throw new Error(`manifest-file does not contain version ${version}, arch ${arch}, platform ${platform}.`); } - // Try to get checksum from NDJSON for manifest downloads too - let ndjsonChecksum; - try { - const artifactInfo = await (0, versions_client_1.getArtifact)(version, arch, platform); - ndjsonChecksum = artifactInfo?.sha256; - } - catch (err) { - core.debug(`Failed to get artifact from NDJSON: ${err.message}`); - } - return await downloadVersion(downloadUrl, `uv-${arch}-${platform}`, platform, arch, version, checkSum, githubToken, ndjsonChecksum); + return await downloadVersion(downloadUrl, `uv-${arch}-${platform}`, platform, arch, version, checkSum, githubToken, undefined); } async function downloadVersion(downloadUrl, artifactName, platform, arch, version, checkSum, githubToken, ndjsonChecksum) { core.info(`Downloading uv from "${downloadUrl}" ...`); @@ -96205,42 +96185,19 @@ async function fetchVersionData() { if (!response.ok) { throw new Error(`Failed to fetch version data: ${response.status} ${response.statusText}`); } + const body = await response.text(); const versions = []; - if (!response.body) { - throw new Error("Response body is null"); - } - // Stream and parse NDJSON line by line - const decoder = new TextDecoder(); - let buffer = ""; - for await (const chunk of response.body) { - buffer += decoder.decode(chunk, { stream: true }); - // Process complete lines - const lines = buffer.split("\n"); - // Keep the last potentially incomplete line in buffer - buffer = lines.pop() ?? ""; - for (const line of lines) { - const trimmed = line.trim(); - if (trimmed === "") { - continue; - } - try { - const version = JSON.parse(trimmed); - versions.push(version); - } - catch { - core.debug(`Failed to parse NDJSON line: ${trimmed}`); - } + for (const line of body.split("\n")) { + const trimmed = line.trim(); + if (trimmed === "") { + continue; } - } - // Process any remaining content in buffer - const remaining = buffer.trim(); - if (remaining !== "") { try { - const version = JSON.parse(remaining); + const version = JSON.parse(trimmed); versions.push(version); } catch { - core.debug(`Failed to parse NDJSON line: ${remaining}`); + core.debug(`Failed to parse NDJSON line: ${trimmed}`); } } if (versions.length === 0) { @@ -96513,7 +96470,10 @@ async function setupUv(platform, arch, checkSum, githubToken) { version: toolCacheResult.version, }; } - const downloadVersionResult = await (0, download_version_1.downloadVersionFromManifest)(inputs_1.manifestFile, platform, arch, resolvedVersion, checkSum, githubToken); + // Use the same source for download as we used for version resolution + const downloadVersionResult = inputs_1.manifestFile + ? await (0, download_version_1.downloadVersionFromManifest)(inputs_1.manifestFile, platform, arch, resolvedVersion, checkSum, githubToken) + : await (0, download_version_1.downloadVersionFromNdjson)(platform, arch, resolvedVersion, checkSum, githubToken); return { uvDir: downloadVersionResult.cachedToolDir, version: downloadVersionResult.version, diff --git a/dist/update-known-versions/index.js b/dist/update-known-versions/index.js index f078ece..18fc7ba 100644 --- a/dist/update-known-versions/index.js +++ b/dist/update-known-versions/index.js @@ -27471,42 +27471,19 @@ async function fetchVersionData() { if (!response.ok) { throw new Error(`Failed to fetch version data: ${response.status} ${response.statusText}`); } + const body = await response.text(); const versions = []; - if (!response.body) { - throw new Error("Response body is null"); - } - // Stream and parse NDJSON line by line - const decoder = new TextDecoder(); - let buffer = ""; - for await (const chunk of response.body) { - buffer += decoder.decode(chunk, { stream: true }); - // Process complete lines - const lines = buffer.split("\n"); - // Keep the last potentially incomplete line in buffer - buffer = lines.pop() ?? ""; - for (const line of lines) { - const trimmed = line.trim(); - if (trimmed === "") { - continue; - } - try { - const version = JSON.parse(trimmed); - versions.push(version); - } - catch { - core.debug(`Failed to parse NDJSON line: ${trimmed}`); - } + for (const line of body.split("\n")) { + const trimmed = line.trim(); + if (trimmed === "") { + continue; } - } - // Process any remaining content in buffer - const remaining = buffer.trim(); - if (remaining !== "") { try { - const version = JSON.parse(remaining); + const version = JSON.parse(trimmed); versions.push(version); } catch { - core.debug(`Failed to parse NDJSON line: ${remaining}`); + core.debug(`Failed to parse NDJSON line: ${trimmed}`); } } if (versions.length === 0) { @@ -27595,6 +27572,7 @@ var __importStar = (this && this.__importStar) || (function () { }; })(); Object.defineProperty(exports, "__esModule", ({ value: true })); +const node_fs_1 = __nccwpck_require__(3024); const core = __importStar(__nccwpck_require__(7484)); const semver = __importStar(__nccwpck_require__(9318)); const update_known_checksums_1 = __nccwpck_require__(6182); @@ -27655,7 +27633,6 @@ async function run() { core.setOutput("latest-version", latestVersion); } async function updateVersionManifestFromEntries(filePath, entries) { - const { promises: fs } = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 3024, 23)); const manifest = entries.map((entry) => ({ arch: entry.arch, artifactName: entry.artifactName, @@ -27664,7 +27641,7 @@ async function updateVersionManifestFromEntries(filePath, entries) { version: entry.version, })); core.debug(`Updating manifest-file: ${JSON.stringify(manifest)}`); - await fs.writeFile(filePath, JSON.stringify(manifest)); + await node_fs_1.promises.writeFile(filePath, JSON.stringify(manifest)); } run(); @@ -29639,64 +29616,6 @@ module.exports = parseParams /******/ } /******/ /************************************************************************/ -/******/ /* webpack/runtime/create fake namespace object */ -/******/ (() => { -/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); -/******/ var leafPrototypes; -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 16: return value when it's Promise-like -/******/ // mode & 8|1: behave like require -/******/ __nccwpck_require__.t = function(value, mode) { -/******/ if(mode & 1) value = this(value); -/******/ if(mode & 8) return value; -/******/ if(typeof value === 'object' && value) { -/******/ if((mode & 4) && value.__esModule) return value; -/******/ if((mode & 16) && typeof value.then === 'function') return value; -/******/ } -/******/ var ns = Object.create(null); -/******/ __nccwpck_require__.r(ns); -/******/ var def = {}; -/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; -/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { -/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); -/******/ } -/******/ def['default'] = () => (value); -/******/ __nccwpck_require__.d(ns, def); -/******/ return ns; -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/define property getters */ -/******/ (() => { -/******/ // define getter functions for harmony exports -/******/ __nccwpck_require__.d = (exports, definition) => { -/******/ for(var key in definition) { -/******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) { -/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); -/******/ } -/******/ } -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/hasOwnProperty shorthand */ -/******/ (() => { -/******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) -/******/ })(); -/******/ -/******/ /* webpack/runtime/make namespace object */ -/******/ (() => { -/******/ // define __esModule on exports -/******/ __nccwpck_require__.r = (exports) => { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ })(); -/******/ /******/ /* webpack/runtime/compat */ /******/ /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; diff --git a/src/download/checksum/checksum.ts b/src/download/checksum/checksum.ts index 56a5508..7cc3ddb 100644 --- a/src/download/checksum/checksum.ts +++ b/src/download/checksum/checksum.ts @@ -13,37 +13,34 @@ export async function validateChecksum( version: string, ndjsonChecksum?: string, ): Promise { - let isValid: boolean | undefined; - let checksumUsed: string | undefined; - // Priority: user-provided checksum > KNOWN_CHECKSUMS > NDJSON fallback + const key = `${arch}-${platform}-${version}`; + let checksumToUse: string | undefined; + let source: string; + if (checkSum !== undefined && checkSum !== "") { - checksumUsed = checkSum; - core.debug("Using user-provided checksum."); - isValid = await validateFileCheckSum(downloadPath, checkSum); + checksumToUse = checkSum; + source = "user-provided"; + } else if (key in KNOWN_CHECKSUMS) { + checksumToUse = KNOWN_CHECKSUMS[key]; + source = `known checksum for ${key}`; + } else if (ndjsonChecksum !== undefined && ndjsonChecksum !== "") { + checksumToUse = ndjsonChecksum; + source = "NDJSON version data"; } else { - const key = `${arch}-${platform}-${version}`; - if (key in KNOWN_CHECKSUMS) { - checksumUsed = KNOWN_CHECKSUMS[key]; - core.debug(`Using known checksum for ${key}.`); - isValid = await validateFileCheckSum(downloadPath, checksumUsed); - } else if (ndjsonChecksum !== undefined && ndjsonChecksum !== "") { - checksumUsed = ndjsonChecksum; - core.debug("Using checksum from NDJSON version data."); - isValid = await validateFileCheckSum(downloadPath, ndjsonChecksum); - } else { - core.debug(`No checksum found for ${key}.`); - } + core.debug(`No checksum found for ${key}.`); + return; } - if (isValid === false) { + core.debug(`Using ${source}.`); + const isValid = await validateFileCheckSum(downloadPath, checksumToUse); + + if (!isValid) { throw new Error( - `Checksum for ${downloadPath} did not match ${checksumUsed}.`, + `Checksum for ${downloadPath} did not match ${checksumToUse}.`, ); } - if (isValid === true) { - core.debug(`Checksum for ${downloadPath} is valid.`); - } + core.debug(`Checksum for ${downloadPath} is valid.`); } async function validateFileCheckSum( diff --git a/src/download/download-version.ts b/src/download/download-version.ts index 996eaf0..37acc5d 100644 --- a/src/download/download-version.ts +++ b/src/download/download-version.ts @@ -8,11 +8,10 @@ import { OWNER, REPO, TOOL_CACHE_NAME } from "../utils/constants"; import type { Architecture, Platform } from "../utils/platforms"; import { validateChecksum } from "./checksum/checksum"; import { - getDownloadUrl, getLatestKnownVersion as getLatestVersionInManifest, + getDownloadUrl as getManifestDownloadUrl, } from "./version-manifest"; import { - type ArtifactResult, getAllVersions, getArtifact, getLatestVersion as getLatestVersionFromNdjson, @@ -33,7 +32,7 @@ export function tryGetFromToolCache( return { installedPath, version: resolvedVersion }; } -export async function downloadVersionFromGithub( +export async function downloadVersionFromNdjson( platform: Platform, arch: Architecture, version: string, @@ -43,13 +42,8 @@ export async function downloadVersionFromGithub( const artifact = `uv-${arch}-${platform}`; const extension = getExtension(platform); - // Try to get artifact info from NDJSON (includes checksum) - let artifactInfo: ArtifactResult | undefined; - try { - artifactInfo = await getArtifact(version, arch, platform); - } catch (err) { - core.debug(`Failed to get artifact from NDJSON: ${(err as Error).message}`); - } + // Get artifact info from NDJSON (includes URL and checksum) + const artifactInfo = await getArtifact(version, arch, platform); const downloadUrl = artifactInfo?.url ?? @@ -68,39 +62,23 @@ export async function downloadVersionFromGithub( } export async function downloadVersionFromManifest( - manifestUrl: string | undefined, + manifestUrl: string, platform: Platform, arch: Architecture, version: string, checkSum: string | undefined, githubToken: string, ): Promise<{ version: string; cachedToolDir: string }> { - const downloadUrl = await getDownloadUrl( + const downloadUrl = await getManifestDownloadUrl( manifestUrl, version, arch, platform, ); if (!downloadUrl) { - core.info( - `manifest-file does not contain version ${version}, arch ${arch}, platform ${platform}. Falling back to GitHub releases.`, + throw new Error( + `manifest-file does not contain version ${version}, arch ${arch}, platform ${platform}.`, ); - return await downloadVersionFromGithub( - platform, - arch, - version, - checkSum, - githubToken, - ); - } - - // Try to get checksum from NDJSON for manifest downloads too - let ndjsonChecksum: string | undefined; - try { - const artifactInfo = await getArtifact(version, arch, platform); - ndjsonChecksum = artifactInfo?.sha256; - } catch (err) { - core.debug(`Failed to get artifact from NDJSON: ${(err as Error).message}`); } return await downloadVersion( @@ -111,7 +89,7 @@ export async function downloadVersionFromManifest( version, checkSum, githubToken, - ndjsonChecksum, + undefined, // No NDJSON checksum for manifest downloads ); } diff --git a/src/download/versions-client.ts b/src/download/versions-client.ts index 1e0ff41..9eac37d 100644 --- a/src/download/versions-client.ts +++ b/src/download/versions-client.ts @@ -31,46 +31,19 @@ export async function fetchVersionData(): Promise { ); } + const body = await response.text(); const versions: NdjsonVersion[] = []; - if (!response.body) { - throw new Error("Response body is null"); - } - - // Stream and parse NDJSON line by line - const decoder = new TextDecoder(); - let buffer = ""; - - for await (const chunk of response.body) { - buffer += decoder.decode(chunk, { stream: true }); - - // Process complete lines - const lines = buffer.split("\n"); - // Keep the last potentially incomplete line in buffer - buffer = lines.pop() ?? ""; - - for (const line of lines) { - const trimmed = line.trim(); - if (trimmed === "") { - continue; - } - try { - const version = JSON.parse(trimmed) as NdjsonVersion; - versions.push(version); - } catch { - core.debug(`Failed to parse NDJSON line: ${trimmed}`); - } + for (const line of body.split("\n")) { + const trimmed = line.trim(); + if (trimmed === "") { + continue; } - } - - // Process any remaining content in buffer - const remaining = buffer.trim(); - if (remaining !== "") { try { - const version = JSON.parse(remaining) as NdjsonVersion; + const version = JSON.parse(trimmed) as NdjsonVersion; versions.push(version); } catch { - core.debug(`Failed to parse NDJSON line: ${remaining}`); + core.debug(`Failed to parse NDJSON line: ${trimmed}`); } } diff --git a/src/setup-uv.ts b/src/setup-uv.ts index b239dfc..2c477b7 100644 --- a/src/setup-uv.ts +++ b/src/setup-uv.ts @@ -5,6 +5,7 @@ import * as exec from "@actions/exec"; import { restoreCache } from "./cache/restore-cache"; import { downloadVersionFromManifest, + downloadVersionFromNdjson, resolveVersion, tryGetFromToolCache, } from "./download/download-version"; @@ -138,14 +139,23 @@ async function setupUv( }; } - const downloadVersionResult = await downloadVersionFromManifest( - manifestFile, - platform, - arch, - resolvedVersion, - checkSum, - githubToken, - ); + // Use the same source for download as we used for version resolution + const downloadVersionResult = manifestFile + ? await downloadVersionFromManifest( + manifestFile, + platform, + arch, + resolvedVersion, + checkSum, + githubToken, + ) + : await downloadVersionFromNdjson( + platform, + arch, + resolvedVersion, + checkSum, + githubToken, + ); return { uvDir: downloadVersionResult.cachedToolDir, diff --git a/src/update-known-versions.ts b/src/update-known-versions.ts index 6dafc0f..66de996 100644 --- a/src/update-known-versions.ts +++ b/src/update-known-versions.ts @@ -1,3 +1,4 @@ +import { promises as fs } from "node:fs"; import * as core from "@actions/core"; import * as semver from "semver"; import { updateChecksums } from "./download/checksum/update-known-checksums"; @@ -100,8 +101,6 @@ async function updateVersionManifestFromEntries( filePath: string, entries: ArtifactEntry[], ): Promise { - const { promises: fs } = await import("node:fs"); - const manifest = entries.map((entry) => ({ arch: entry.arch, artifactName: entry.artifactName,