diff --git a/README.md b/README.md index 3497159..89fdf3e 100644 --- a/README.md +++ b/README.md @@ -42,12 +42,6 @@ Set up your GitHub Actions workflow with a specific version of [uv](https://docs For an example workflow, see [here](https://github.com/charliermarsh/autobot/blob/e42c66659bf97b90ca9ff305a19cc99952d0d43f/.github/workflows/ci.yaml). -> [!TIP] -> -> Using `latest` requires to download the uv executable on every run, which incurs a cost -> (especially on self-hosted runners). As a best practice, consider pinning the version to a -> specific release. - ### Install a specific version ```yaml diff --git a/dist/setup/index.js b/dist/setup/index.js index e038284..dd4995b 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -89645,106 +89645,6 @@ exports.KNOWN_CHECKSUMS = { }; -/***/ }), - -/***/ 5608: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.downloadLatest = downloadLatest; -const core = __importStar(__nccwpck_require__(7484)); -const tc = __importStar(__nccwpck_require__(3472)); -const exec = __importStar(__nccwpck_require__(5236)); -const path = __importStar(__nccwpck_require__(6760)); -const node_fs_1 = __nccwpck_require__(3024); -const checksum_1 = __nccwpck_require__(5391); -const constants_1 = __nccwpck_require__(6156); -function downloadLatest(platform, arch, checkSum, githubToken) { - return __awaiter(this, void 0, void 0, function* () { - const artifact = `uv-${arch}-${platform}`; - let extension = ".tar.gz"; - if (platform === "pc-windows-msvc") { - extension = ".zip"; - } - const downloadUrl = `https://github.com/${constants_1.OWNER}/${constants_1.REPO}/releases/latest/download/${artifact}${extension}`; - core.info(`Downloading uv from "${downloadUrl}" ...`); - const downloadPath = yield tc.downloadTool(downloadUrl, undefined, githubToken); - let uvExecutablePath; - let uvDir; - if (platform === "pc-windows-msvc") { - const fullPathWithExtension = `${downloadPath}${extension}`; - yield node_fs_1.promises.copyFile(downloadPath, fullPathWithExtension); - uvDir = yield tc.extractZip(fullPathWithExtension); - // On windows extracting the zip does not create an intermediate directory - uvExecutablePath = path.join(uvDir, "uv.exe"); - } - else { - const extractedDir = yield tc.extractTar(downloadPath); - uvDir = path.join(extractedDir, artifact); - uvExecutablePath = path.join(uvDir, "uv"); - } - const version = yield getVersion(uvExecutablePath); - yield (0, checksum_1.validateChecksum)(checkSum, downloadPath, arch, platform, version); - const cachedToolDir = yield tc.cacheDir(uvDir, constants_1.TOOL_CACHE_NAME, version, arch); - return { cachedToolDir, version }; - }); -} -function getVersion(uvExecutablePath) { - return __awaiter(this, void 0, void 0, function* () { - // Parse the output of `uv --version` to get the version - // The output looks like - // uv 0.3.1 (be17d132a 2024-08-21) - const options = { - silent: !core.isDebug(), - }; - const execArgs = ["--version"]; - let output = ""; - options.listeners = { - stdout: (data) => { - output += data.toString(); - }, - }; - yield exec.exec(uvExecutablePath, execArgs, options); - const parts = output.split(" "); - return parts[1].trim(); - }); -} - - /***/ }), /***/ 8255: @@ -89787,6 +89687,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge Object.defineProperty(exports, "__esModule", ({ value: true })); exports.tryGetFromToolCache = tryGetFromToolCache; exports.downloadVersion = downloadVersion; +exports.resolveVersion = resolveVersion; const core = __importStar(__nccwpck_require__(7484)); const tc = __importStar(__nccwpck_require__(3472)); const path = __importStar(__nccwpck_require__(6760)); @@ -89832,8 +89733,11 @@ function downloadVersion(platform, arch, version, checkSum, githubToken) { return { version: resolvedVersion, cachedToolDir }; }); } -function resolveVersion(version, githubToken) { +function resolveVersion(versionInput, githubToken) { return __awaiter(this, void 0, void 0, function* () { + const version = versionInput === "latest" + ? yield getLatestVersion(githubToken) + : versionInput; if (tc.isExplicitVersion(version)) { core.debug(`Version ${version} is an explicit version.`); return version; @@ -89856,6 +89760,19 @@ function getAvailableVersions(githubToken) { return response.map((release) => release.tag_name); }); } +function getLatestVersion(githubToken) { + return __awaiter(this, void 0, void 0, function* () { + const octokit = github.getOctokit(githubToken); + const { data: latestRelease } = yield octokit.rest.repos.getLatestRelease({ + owner: constants_1.OWNER, + repo: constants_1.REPO, + }); + if (!latestRelease) { + throw new Error("Could not determine latest release."); + } + return latestRelease.tag_name; + }); +} /***/ }), @@ -90010,7 +89927,6 @@ const core = __importStar(__nccwpck_require__(7484)); const path = __importStar(__nccwpck_require__(6760)); const download_version_1 = __nccwpck_require__(8255); const restore_cache_1 = __nccwpck_require__(7772); -const download_latest_1 = __nccwpck_require__(5608); const platforms_1 = __nccwpck_require__(8361); const inputs_1 = __nccwpck_require__(9612); function run() { @@ -90045,27 +89961,20 @@ function run() { } function setupUv(platform, arch, versionInput, checkSum, githubToken) { return __awaiter(this, void 0, void 0, function* () { - let installedPath; - let cachedToolDir; - let version; - if (versionInput === "latest") { - const latestResult = yield (0, download_latest_1.downloadLatest)(platform, arch, checkSum, githubToken); - version = latestResult.version; - cachedToolDir = latestResult.cachedToolDir; + const resolvedVersion = yield (0, download_version_1.resolveVersion)(versionInput, githubToken); + const toolCacheResult = (0, download_version_1.tryGetFromToolCache)(arch, resolvedVersion); + if (toolCacheResult.installedPath) { + core.info(`Found uv in tool-cache for ${toolCacheResult.version}`); + return { + uvDir: toolCacheResult.installedPath, + version: toolCacheResult.version, + }; } - else { - const toolCacheResult = (0, download_version_1.tryGetFromToolCache)(arch, versionInput); - version = toolCacheResult.version; - installedPath = toolCacheResult.installedPath; - if (installedPath) { - core.info(`Found uv in tool-cache for ${versionInput}`); - return { uvDir: installedPath, version }; - } - const versionResult = yield (0, download_version_1.downloadVersion)(platform, arch, versionInput, checkSum, githubToken); - cachedToolDir = versionResult.cachedToolDir; - version = versionResult.version; - } - return { uvDir: cachedToolDir, version }; + const downloadVersionResult = yield (0, download_version_1.downloadVersion)(platform, arch, resolvedVersion, checkSum, githubToken); + return { + uvDir: downloadVersionResult.cachedToolDir, + version: downloadVersionResult.version, + }; }); } function addUvToPath(cachedPath) { diff --git a/src/download/download-latest.ts b/src/download/download-latest.ts deleted file mode 100644 index edb8926..0000000 --- a/src/download/download-latest.ts +++ /dev/null @@ -1,73 +0,0 @@ -import * as core from "@actions/core"; -import * as tc from "@actions/tool-cache"; -import * as exec from "@actions/exec"; -import * as path from "node:path"; -import { promises as fs } from "node:fs"; -import type { Architecture, Platform } from "../utils/platforms"; -import { validateChecksum } from "./checksum/checksum"; -import { OWNER, REPO, TOOL_CACHE_NAME } from "../utils/constants"; - -export async function downloadLatest( - platform: Platform, - arch: Architecture, - checkSum: string | undefined, - githubToken: string | undefined, -): Promise<{ cachedToolDir: string; version: string }> { - const artifact = `uv-${arch}-${platform}`; - let extension = ".tar.gz"; - if (platform === "pc-windows-msvc") { - extension = ".zip"; - } - const downloadUrl = `https://github.com/${OWNER}/${REPO}/releases/latest/download/${artifact}${extension}`; - core.info(`Downloading uv from "${downloadUrl}" ...`); - - const downloadPath = await tc.downloadTool( - downloadUrl, - undefined, - githubToken, - ); - let uvExecutablePath: string; - let uvDir: string; - if (platform === "pc-windows-msvc") { - const fullPathWithExtension = `${downloadPath}${extension}`; - await fs.copyFile(downloadPath, fullPathWithExtension); - uvDir = await tc.extractZip(fullPathWithExtension); - // On windows extracting the zip does not create an intermediate directory - uvExecutablePath = path.join(uvDir, "uv.exe"); - } else { - const extractedDir = await tc.extractTar(downloadPath); - uvDir = path.join(extractedDir, artifact); - uvExecutablePath = path.join(uvDir, "uv"); - } - const version = await getVersion(uvExecutablePath); - await validateChecksum(checkSum, downloadPath, arch, platform, version); - const cachedToolDir = await tc.cacheDir( - uvDir, - TOOL_CACHE_NAME, - version, - arch, - ); - - return { cachedToolDir, version }; -} - -async function getVersion(uvExecutablePath: string): Promise { - // Parse the output of `uv --version` to get the version - // The output looks like - // uv 0.3.1 (be17d132a 2024-08-21) - - const options: exec.ExecOptions = { - silent: !core.isDebug(), - }; - const execArgs = ["--version"]; - - let output = ""; - options.listeners = { - stdout: (data: Buffer) => { - output += data.toString(); - }, - }; - await exec.exec(uvExecutablePath, execArgs, options); - const parts = output.split(" "); - return parts[1].trim(); -} diff --git a/src/download/download-version.ts b/src/download/download-version.ts index 3e9fb59..a22698d 100644 --- a/src/download/download-version.ts +++ b/src/download/download-version.ts @@ -70,10 +70,14 @@ export async function downloadVersion( return { version: resolvedVersion, cachedToolDir }; } -async function resolveVersion( - version: string, +export async function resolveVersion( + versionInput: string, githubToken: string, ): Promise { + const version = + versionInput === "latest" + ? await getLatestVersion(githubToken) + : versionInput; if (tc.isExplicitVersion(version)) { core.debug(`Version ${version} is an explicit version.`); return version; @@ -95,3 +99,17 @@ async function getAvailableVersions(githubToken: string): Promise { }); return response.map((release) => release.tag_name); } + +async function getLatestVersion(githubToken: string) { + const octokit = github.getOctokit(githubToken); + + const { data: latestRelease } = await octokit.rest.repos.getLatestRelease({ + owner: OWNER, + repo: REPO, + }); + + if (!latestRelease) { + throw new Error("Could not determine latest release."); + } + return latestRelease.tag_name; +} diff --git a/src/setup-uv.ts b/src/setup-uv.ts index 43a469a..f95babc 100644 --- a/src/setup-uv.ts +++ b/src/setup-uv.ts @@ -3,10 +3,10 @@ import * as path from "node:path"; import { downloadVersion, tryGetFromToolCache, + resolveVersion, } from "./download/download-version"; import { restoreCache } from "./cache/restore-cache"; -import { downloadLatest } from "./download/download-latest"; import { type Architecture, getArch, @@ -69,38 +69,28 @@ async function setupUv( checkSum: string | undefined, githubToken: string, ): Promise<{ uvDir: string; version: string }> { - let installedPath: string | undefined; - let cachedToolDir: string; - let version: string; - if (versionInput === "latest") { - const latestResult = await downloadLatest( - platform, - arch, - checkSum, - githubToken, - ); - version = latestResult.version; - cachedToolDir = latestResult.cachedToolDir; - } else { - const toolCacheResult = tryGetFromToolCache(arch, versionInput); - version = toolCacheResult.version; - installedPath = toolCacheResult.installedPath; - if (installedPath) { - core.info(`Found uv in tool-cache for ${versionInput}`); - return { uvDir: installedPath, version }; - } - const versionResult = await downloadVersion( - platform, - arch, - versionInput, - checkSum, - githubToken, - ); - cachedToolDir = versionResult.cachedToolDir; - version = versionResult.version; + const resolvedVersion = await resolveVersion(versionInput, githubToken); + const toolCacheResult = tryGetFromToolCache(arch, resolvedVersion); + if (toolCacheResult.installedPath) { + core.info(`Found uv in tool-cache for ${toolCacheResult.version}`); + return { + uvDir: toolCacheResult.installedPath, + version: toolCacheResult.version, + }; } - return { uvDir: cachedToolDir, version }; + const downloadVersionResult = await downloadVersion( + platform, + arch, + resolvedVersion, + checkSum, + githubToken, + ); + + return { + uvDir: downloadVersionResult.cachedToolDir, + version: downloadVersionResult.version, + }; } function addUvToPath(cachedPath: string): void {