From fe2a61414cdcdc2f5c69c973e7dd384994e781e1 Mon Sep 17 00:00:00 2001 From: Renovate <> Date: Sat, 7 Nov 2026 05:37:29 +0000 Subject: [PATCH 1/2] Update uv version pins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit added uv 0.13.7 removed uv 0.13.1 alias uv 0.13: 0.13.1 → 0.13.7 alias uv latest: 0.13.1 → 0.13.7 added python 3.11.18-20261026 added python 3.12.16-20261026 added python 3.13.18-20261026 added python 3.14.10-20261026 added python 3.15.2-20261026 removed python 3.11.17-20261013 removed python 3.12.15-20261013 removed python 3.13.16-20261013 removed python 3.14.8-20261013 removed python 3.15.0-20261013 alias python 3.11: 3.11.17-20261013 → 3.11.18-20261026 alias python 3.12: 3.12.15-20261013 → 3.12.16-20261026 alias python 3.13: 3.13.16-20261013 → 3.13.18-20261026 alias python 3.14: 3.14.8-20261013 → 3.14.10-20261026 alias python 3.15: 3.15.0-20261013 → 3.15.2-20261026 alias python latest: 3.15.0-20261013 → 3.15.2-20261026 --- features/uv/config.json | 94 ++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/features/uv/config.json b/features/uv/config.json index a2f90cb..7ff7979 100644 --- a/features/uv/config.json +++ b/features/uv/config.json @@ -3,90 +3,88 @@ "components": { "uv": { "versions": { - "0.13.1": { + "0.13.7": { "linux-x64": { - "url": "https://github.com/astral-sh/uv/releases/download/0.13.1/uv-x86_64-unknown-linux-musl.tar.gz", - "sha256": "6c86040a8f045ab9adc9e3ec4cdafa03fd00e9a988ed2bf28971c7fc2d0debd0" + "url": "https://github.com/astral-sh/uv/releases/download/0.13.7/uv-x86_64-unknown-linux-musl.tar.gz", + "sha256": "287491da03f2a785c70fa75b13e1f849918c2f2b5415fe84876b8214eeb792f9" }, "linux-arm64": { - "url": "https://github.com/astral-sh/uv/releases/download/0.13.1/uv-aarch64-unknown-linux-musl.tar.gz", - "sha256": "345a8308e4d1835cdfaadf692836fd3137a6d45864773f05ad7bf59442b1ba16" + "url": "https://github.com/astral-sh/uv/releases/download/0.13.7/uv-aarch64-unknown-linux-musl.tar.gz", + "sha256": "2d3ec076a0c4c0e8250bb6418c44080828b544f1a3be0b6e46adf9fb6923de45" } } }, - "aliases": { - "0.13.1": ["0.13", "latest"] - } + "aliases": { "0.13.7": ["0.13", "latest"] } }, "python": { "versions": { - "3.11.17-20261013": { - "pythonVersion": "3.11.17", - "build": "20261013", + "3.11.18-20261026": { + "pythonVersion": "3.11.18", + "build": "20261026", "linux-x64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.11.17%2B20261013-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "3b8e5a248bcc351265ffe68f5e457668a2e09c99a47f81f658988c7d3d107522" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.11.18%2B20261026-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "17c4978a36c496dc53c08899ef8dad1ad2734f6325f08d6033a1e66419e0af26" }, "linux-arm64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.11.17%2B20261013-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "3d09fa150bebc6c4f888f8d601328b46fd17f1be5c62cd390a353b7ccff6ed51" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.11.18%2B20261026-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "ecf28575cd67fa7a53c7bf2355bae5cff2c496efeb51780d50a8b54441cdce74" } }, - "3.12.15-20261013": { - "pythonVersion": "3.12.15", - "build": "20261013", + "3.12.16-20261026": { + "pythonVersion": "3.12.16", + "build": "20261026", "linux-x64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.12.15%2B20261013-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "178d3d83b6e8e99285a65d3fce9c16b87952cc5efdb4d1a0e3ff3be18ff0fc9c" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.12.16%2B20261026-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "ce4f6d0a6cfdb3bed6e44c2f9affd85943c76a42e25ad3a259002f31d6fb8a20" }, "linux-arm64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.12.15%2B20261013-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "9467a99bacc7d90b64b02de7fa9ecfc99b72905e64e74f7ff6b460ad95cfed5a" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.12.16%2B20261026-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "bb4b6392670c5d3f93876996fcaa19858a4a413a0c7720144c18b0d6f1f0db2d" } }, - "3.13.16-20261013": { - "pythonVersion": "3.13.16", - "build": "20261013", + "3.13.18-20261026": { + "pythonVersion": "3.13.18", + "build": "20261026", "linux-x64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.13.16%2B20261013-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "d0080766b6b74aeb81e1949ef0d9a20e6c17f7b160fb295a69b936ccb17660be" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.13.18%2B20261026-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "df15fe60d3ff55bf9dcf25824b5572756bb8816ff93865a273d3301d7066a8b7" }, "linux-arm64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.13.16%2B20261013-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "69a30ed26198178732c37b8de0b6b5191479fbacfe526954da776befe38f18e7" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.13.18%2B20261026-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "578d9da1983463ffb0c8c98ab0da2f18177f44069328eb0af847860c1eb05c3e" } }, - "3.14.8-20261013": { - "pythonVersion": "3.14.8", - "build": "20261013", + "3.14.10-20261026": { + "pythonVersion": "3.14.10", + "build": "20261026", "linux-x64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.14.8%2B20261013-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "d8faa1b588506b9e3e5a3f57807bb056d534a1641a6b10d15b6ea3f0b413b960" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.14.10%2B20261026-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "4d3c16c59ed0802a3d1d34d8bce504b15ceeaff39d62dadecc6a9fa803412aed" }, "linux-arm64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.14.8%2B20261013-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "d8ae14f303d3971431184cf423ae5467202de2bc19bf6491a490250b87647d4b" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.14.10%2B20261026-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "90f48337bc3dd4ae6eda81e001e4c981236d403b6b5a07778bbdf94ee423dc00" } }, - "3.15.0-20261013": { - "pythonVersion": "3.15.0", - "build": "20261013", + "3.15.2-20261026": { + "pythonVersion": "3.15.2", + "build": "20261026", "linux-x64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.15.0%2B20261013-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "69740dcd9b3480b3d53760f2d3b75582adb14fa54434628dea32480ddede542a" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.15.2%2B20261026-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "7b03163a980c607ba8194709d4a4086735a7a9c488cc475b098157306927b36b" }, "linux-arm64": { - "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261013/cpython-3.15.0%2B20261013-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", - "sha256": "064778ca701efc4c8366d0b235a2a0f5dbe14d921aeb2ef4f5c7b93e5a75cbd0" + "url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.15.2%2B20261026-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz", + "sha256": "0f23351c03b39beb880de668976074fcc3c082d9c3b03d0b43185632b2b270a0" } } }, "aliases": { - "3.11.17-20261013": ["3.11", "3.11.17"], - "3.12.15-20261013": ["3.12", "3.12.15"], - "3.13.16-20261013": ["3.13", "3.13.16"], - "3.14.8-20261013": ["3.14", "3.14.8"], - "3.15.0-20261013": ["3.15", "3.15.0", "latest"] + "3.11.18-20261026": ["3.11", "3.11.18"], + "3.12.16-20261026": ["3.12", "3.12.16"], + "3.13.18-20261026": ["3.13", "3.13.18"], + "3.14.10-20261026": ["3.14", "3.14.10"], + "3.15.2-20261026": ["3.15", "3.15.2", "latest"] } } } From 79a382c13108c7e13df792e131c238367a432b15 Mon Sep 17 00:00:00 2001 From: gdlol <.> Date: Sat, 7 Nov 2026 10:19:56 +0000 Subject: [PATCH 2/2] Add feature config formatting check --- features/uv/config.json | 4 ++- scripts/lint.ts | 2 ++ scripts/tasks/build.ts | 2 ++ scripts/tasks/featureConfigs.ts | 28 +++++++++++++++++++ scripts/tasks/features/config.ts | 7 +++++ .../tasks/features/dotnet/generateConfig.ts | 9 ++---- .../tasks/features/ripgrep/generateConfig.ts | 9 ++---- scripts/tasks/features/uv/generateConfig.ts | 9 ++---- scripts/verify/assertions.ts | 21 ++++++++++---- scripts/verify/uv/scenarios.ts | 12 ++++---- 10 files changed, 70 insertions(+), 33 deletions(-) create mode 100644 scripts/tasks/featureConfigs.ts diff --git a/features/uv/config.json b/features/uv/config.json index 7ff7979..29193f4 100644 --- a/features/uv/config.json +++ b/features/uv/config.json @@ -14,7 +14,9 @@ } } }, - "aliases": { "0.13.7": ["0.13", "latest"] } + "aliases": { + "0.13.7": ["0.13", "latest"] + } }, "python": { "versions": { diff --git a/scripts/lint.ts b/scripts/lint.ts index acf3509..f34cba7 100644 --- a/scripts/lint.ts +++ b/scripts/lint.ts @@ -2,6 +2,7 @@ import { csharpierCheck } from "@/scripts/tasks/csharpier.js"; import { spellCheck } from "@/scripts/tasks/cspell.js"; import { dotnetFormatCheck } from "@/scripts/tasks/dotnetFormat.js"; import { eslint } from "@/scripts/tasks/eslint.js"; +import { featureConfigs } from "@/scripts/tasks/featureConfigs.js"; import { imageFeatures } from "@/scripts/tasks/imageFeatures.js"; import { prettierCheck } from "@/scripts/tasks/prettier.js"; import { syncpackLint } from "@/scripts/tasks/syncpack.js"; @@ -13,5 +14,6 @@ await eslint(); await prettierCheck(); await dotnetFormatCheck(); await csharpierCheck(); +await featureConfigs.check(); await imageFeatures.check(); await spellCheck(); diff --git a/scripts/tasks/build.ts b/scripts/tasks/build.ts index b3951f8..d2f57e7 100644 --- a/scripts/tasks/build.ts +++ b/scripts/tasks/build.ts @@ -13,6 +13,7 @@ import prettierOptions from "@/.config/prettier/.prettierrc.json" with { type: " import { getRemoteInfo } from "@/scripts/git.js"; import { projectRoot } from "@/scripts/project.js"; import { shellOptions } from "@/scripts/shell.js"; +import { featureConfigs } from "@/scripts/tasks/featureConfigs.js"; import { imageFeatures } from "@/scripts/tasks/imageFeatures.js"; const formatFile = async (path: string) => { @@ -56,5 +57,6 @@ export const build = async () => { await rm(tempPath, { recursive: true, force: true }); } + await featureConfigs.write(); await imageFeatures.write(); }; diff --git a/scripts/tasks/featureConfigs.ts b/scripts/tasks/featureConfigs.ts new file mode 100644 index 0000000..05ce885 --- /dev/null +++ b/scripts/tasks/featureConfigs.ts @@ -0,0 +1,28 @@ +import { readFile, writeFile } from "node:fs/promises"; + +import { formatConfig } from "@/scripts/tasks/features/config.js"; +import { features } from "@/scripts/tasks/features/features.js"; + +const formatted = async (configPath: string): Promise<{ actual: string; expected: string }> => { + const actual = await readFile(configPath, "utf-8"); + return { actual, expected: await formatConfig(JSON.parse(actual), configPath) }; +}; + +const write = async (): Promise => { + for (const feature of Object.values(features)) { + const { expected } = await formatted(feature.configPath); + await writeFile(feature.configPath, expected); + console.log(`feature-configs: wrote ${feature.configPath}`); + } +}; + +const check = async (): Promise => { + for (const feature of Object.values(features)) { + const { actual, expected } = await formatted(feature.configPath); + if (actual !== expected) { + throw new Error(`${feature.configPath} is not canonically formatted; run pnpm build.`); + } + } +}; + +export const featureConfigs = { write, check } as const; diff --git a/scripts/tasks/features/config.ts b/scripts/tasks/features/config.ts index b169d35..61be1a2 100644 --- a/scripts/tasks/features/config.ts +++ b/scripts/tasks/features/config.ts @@ -1,3 +1,7 @@ +import * as prettier from "prettier"; + +import prettierOptions from "@/.config/prettier/.prettierrc.json" with { type: "json" }; + export const tagPattern = /^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$/u; // The names a key derives before any channel suffix; tagNames takes the first as canonical. @@ -96,3 +100,6 @@ export const checkTagNamespace = (namespace: TagNamespace): void => { } } }; + +export const formatConfig = async (document: unknown, configPath: string): Promise => + prettier.format(JSON.stringify(document, null, 2), { ...prettierOptions, filepath: configPath }); diff --git a/scripts/tasks/features/dotnet/generateConfig.ts b/scripts/tasks/features/dotnet/generateConfig.ts index c9f99cd..9df887b 100644 --- a/scripts/tasks/features/dotnet/generateConfig.ts +++ b/scripts/tasks/features/dotnet/generateConfig.ts @@ -1,12 +1,10 @@ import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; -import * as prettier from "prettier"; import { z } from "zod"; -import prettierOptions from "@/.config/prettier/.prettierrc.json" with { type: "json" }; import { projectRoot } from "@/scripts/project.js"; -import { checkTagNamespace } from "@/scripts/tasks/features/config.js"; +import { checkTagNamespace, formatConfig } from "@/scripts/tasks/features/config.js"; const releasesIndexUrl = "https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json"; export const configPath = path.resolve(projectRoot, "features/dotnet/config.json"); @@ -245,8 +243,5 @@ export const generateConfig = async (): Promise => { }, }; validateConfig(config, configPath); - await writeFile( - configPath, - await prettier.format(JSON.stringify(config), { ...prettierOptions, filepath: configPath }), - ); + await writeFile(configPath, await formatConfig(config, configPath)); }; diff --git a/scripts/tasks/features/ripgrep/generateConfig.ts b/scripts/tasks/features/ripgrep/generateConfig.ts index 7354e80..6c72c23 100644 --- a/scripts/tasks/features/ripgrep/generateConfig.ts +++ b/scripts/tasks/features/ripgrep/generateConfig.ts @@ -1,12 +1,10 @@ import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; -import * as prettier from "prettier"; import { z } from "zod"; -import prettierOptions from "@/.config/prettier/.prettierrc.json" with { type: "json" }; import { projectRoot } from "@/scripts/project.js"; -import { checkTagNamespace } from "@/scripts/tasks/features/config.js"; +import { checkTagNamespace, formatConfig } from "@/scripts/tasks/features/config.js"; const releasesUrl = "https://api.github.com/repos/BurntSushi/ripgrep/releases"; export const configPath = path.resolve(projectRoot, "features/ripgrep/config.json"); @@ -178,8 +176,5 @@ export const generateConfig = async (): Promise => { aliases: { [candidate.tag]: versionAliases(candidate) }, }; validateConfig(config, configPath); - await writeFile( - configPath, - await prettier.format(JSON.stringify(config), { ...prettierOptions, filepath: configPath }), - ); + await writeFile(configPath, await formatConfig(config, configPath)); }; diff --git a/scripts/tasks/features/uv/generateConfig.ts b/scripts/tasks/features/uv/generateConfig.ts index d66e6ac..e5cc74e 100644 --- a/scripts/tasks/features/uv/generateConfig.ts +++ b/scripts/tasks/features/uv/generateConfig.ts @@ -1,12 +1,10 @@ import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; -import * as prettier from "prettier"; import { z } from "zod"; -import prettierOptions from "@/.config/prettier/.prettierrc.json" with { type: "json" }; import { projectRoot } from "@/scripts/project.js"; -import { checkTagNamespace } from "@/scripts/tasks/features/config.js"; +import { checkTagNamespace, formatConfig } from "@/scripts/tasks/features/config.js"; import type { DockerArch, Rid } from "../architecture.js"; import { dockerArchOptions, ridFor, rids } from "../architecture.js"; @@ -274,8 +272,5 @@ export const generateConfig = async (): Promise => { }, }; validateConfig(config, configPath); - await writeFile( - configPath, - await prettier.format(JSON.stringify(config), { ...prettierOptions, filepath: configPath }), - ); + await writeFile(configPath, await formatConfig(config, configPath)); }; diff --git a/scripts/verify/assertions.ts b/scripts/verify/assertions.ts index 22a8a82..20a39bc 100644 --- a/scripts/verify/assertions.ts +++ b/scripts/verify/assertions.ts @@ -3,26 +3,37 @@ import type { CommandResult } from "./lifecycle.js"; export interface Expectation { stdout?: readonly string[]; sorted?: boolean; + fields?: boolean; exitCode?: number; } const linesOf = (text: string): string[] => (text.trim() === "" ? [] : text.trimEnd().split("\n")); -const sameLines = (actual: readonly string[], expected: readonly string[]): boolean => - actual.length === expected.length && actual.every((line, index) => line === expected[index]); +const fieldsOf = (line: string): string[] => (line.trim() === "" ? [] : line.trim().split(/\s+/u)); + +const lineOf = (line: string, fields: boolean): string => (fields ? fieldsOf(line).join(" ") : line); + +const sameLines = (actual: readonly string[], expected: readonly string[], fields: boolean): boolean => + actual.length === expected.length && + actual.every((line, index) => lineOf(line, fields) === lineOf(expected[index], fields)); + +const describe = (lines: readonly string[], fields: boolean): string => + JSON.stringify(lines.map((line) => lineOf(line, fields))); export const assertExec = (result: CommandResult, expectation: Expectation): void => { const stdout = linesOf(result.stdout); const sorted = expectation.sorted === true; - const order = (lines: readonly string[]): string[] => (sorted ? [...lines].sort() : [...lines]); + const fields = expectation.fields === true; + const order = (lines: readonly string[]): string[] => + sorted ? lines.map((line) => lineOf(line, fields)).sort() : [...lines]; const exitCode = expectation.exitCode ?? 0; const problems: string[] = []; if (result.exitCode !== exitCode) { problems.push(`exit code ${result.exitCode ?? "none"}, expected ${exitCode}`); } - if (expectation.stdout !== undefined && !sameLines(order(stdout), order(expectation.stdout))) { - problems.push(`stdout ${JSON.stringify(stdout)}, expected ${JSON.stringify(expectation.stdout)}`); + if (expectation.stdout !== undefined && !sameLines(order(stdout), order(expectation.stdout), fields)) { + problems.push(`stdout ${describe(stdout, fields)}, expected ${describe(expectation.stdout, fields)}`); } if (result.stderr.trim() !== "") { problems.push(`stderr ${JSON.stringify(result.stderr)}`); diff --git a/scripts/verify/uv/scenarios.ts b/scripts/verify/uv/scenarios.ts index 6132a62..d2ab2e0 100644 --- a/scripts/verify/uv/scenarios.ts +++ b/scripts/verify/uv/scenarios.ts @@ -85,7 +85,7 @@ const pythonExecutable = (selection: Selection, pythonVersion: string): string = `${pythonPatchDir(selection, pythonVersion)}/bin/python${minorOf(pythonVersion)}`; const pythonListLine = (selection: Selection, pythonVersion: string): string => - `${pythonKey(selection, pythonVersion)} ${pythonMinorDir(selection, pythonVersion)}/bin/python${minorOf(pythonVersion)}`; + `${pythonKey(selection, pythonVersion)} ${pythonMinorDir(selection, pythonVersion)}/bin/python${minorOf(pythonVersion)}`; const linkTarget = (name: string, target: string): Exec => ({ command: ["sh", "-c", `readlink -f "$XDG_BIN_HOME/${name}"`], @@ -126,7 +126,7 @@ const pythonExecs = (selection: Selection): Exec[] => { { command: ["cat", `${featureDir}/default-python`], expect: { stdout: [pythonVersion] } }, { command: ["uv", "python", "list", "--only-installed"], - expect: { stdout: [pythonListLine(selection, pythonVersion)] }, + expect: { stdout: [pythonListLine(selection, pythonVersion)], fields: true }, }, linkTarget("python", pythonExecutable(selection, pythonVersion)), linkTarget("python3", pythonExecutable(selection, pythonVersion)), @@ -147,7 +147,7 @@ const pythonRestartExecs = (selection: Selection): Exec[] => { { command: ["cat", `${featureDir}/default-python`], expect: { stdout: [pythonVersion] } }, { command: ["uv", "python", "list", "--only-installed"], - expect: { stdout: [pythonListLine(selection, pythonVersion)] }, + expect: { stdout: [pythonListLine(selection, pythonVersion)], fields: true }, }, linkTarget("python", pythonExecutable(selection, pythonVersion)), linkTarget("python3", pythonExecutable(selection, pythonVersion)), @@ -162,7 +162,7 @@ const multiExecs = (selection: Selection): Exec[] => { return [ { command: ["uv", "python", "list", "--only-installed"], - expect: { stdout: [pythonListLine(selection, latest), pythonListLine(selection, previous)] }, + expect: { stdout: [pythonListLine(selection, latest), pythonListLine(selection, previous)], fields: true }, }, linkTarget(`python${minorOf(latest)}`, pythonExecutable(selection, latest)), linkTarget(`python${minorOf(previous)}`, pythonExecutable(selection, previous)), @@ -178,7 +178,7 @@ const downloadExecs = (selection: Selection): Exec[] => { return [ { command: ["uv", "python", "list", "--only-installed"], - expect: { stdout: [pythonListLine(selection, pythonVersion)] }, + expect: { stdout: [pythonListLine(selection, pythonVersion)], fields: true }, }, linkTarget("python", pythonExecutable(selection, pythonVersion)), linkTarget("python3", pythonExecutable(selection, pythonVersion)), @@ -201,7 +201,7 @@ const smokeExecs = (selection: Selection, component: Component): Exec[] => { { command: ["sh", "-c", '"$XDG_BIN_HOME/python" -V'], expect: { stdout: [`Python ${pythonVersion}`] } }, { command: ["uv", "python", "list", "--only-installed"], - expect: { stdout: [pythonListLine(selection, pythonVersion)] }, + expect: { stdout: [pythonListLine(selection, pythonVersion)], fields: true }, }, ); }