From cf44a58d2500f4f9ddbb112e2a471c555ce7a7c9 Mon Sep 17 00:00:00 2001 From: Louis Varin Date: Wed, 14 Jan 2026 18:02:07 -0500 Subject: [PATCH] feat: support finding binary using file path TICKET: VL-4112 --- dist/index.js | 44 ++++++++--- src/fetch.ts | 61 ++++++++++++---- test/test-find-matching-release-asset.ts | 93 +++++++++++++++++++++++- 3 files changed, 173 insertions(+), 25 deletions(-) diff --git a/dist/index.js b/dist/index.js index 17ceb94..7a7fa98 100644 --- a/dist/index.js +++ b/dist/index.js @@ -10146,12 +10146,22 @@ function findMatchingReleaseAssetMetadata(releaseMetadata, slug, binaryName, tag if (isSome(binaryName)) { const targetLabelTraditional = `${binaryName.value}-${targetTriple}`; const targetLabelDuple = `${binaryName.value}-${targetDuple}`; - const asset2 = releaseMetadata.data.assets.find( - (asset3) => typeof asset3.label === "string" && (asset3.label === targetLabelTraditional || asset3.label === targetLabelDuple) - ); + const asset2 = releaseMetadata.data.assets.find((asset3) => { + if (typeof asset3.label === "string") { + if (asset3.label === targetLabelTraditional || asset3.label === targetLabelDuple) { + return true; + } + } + if (typeof asset3.name === "string") { + if (asset3.name === targetLabelTraditional || asset3.name === targetLabelDuple) { + return true; + } + } + return false; + }); if (asset2 === void 0) { throw new Error( - `Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label ${targetLabelTraditional} or ${targetLabelDuple}` + `Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label or name ${targetLabelTraditional} or ${targetLabelDuple}` ); } return { @@ -10159,12 +10169,22 @@ function findMatchingReleaseAssetMetadata(releaseMetadata, slug, binaryName, tag url: asset2.url }; } - const matchingAssets = releaseMetadata.data.assets.filter( - (asset2) => typeof asset2.label === "string" && (asset2.label.endsWith(targetTriple) || asset2.label.endsWith(targetDuple)) - ); + const matchingAssets = releaseMetadata.data.assets.filter((asset2) => { + if (typeof asset2.label === "string") { + if (asset2.label.endsWith(targetTriple) || asset2.label.endsWith(targetDuple)) { + return true; + } + } + if (typeof asset2.name === "string") { + if (asset2.name.endsWith(targetTriple) || asset2.name.endsWith(targetDuple)) { + return true; + } + } + return false; + }); if (matchingAssets.length === 0) { throw new Error( - `Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label ending in ${targetTriple} or ${targetDuple}` + `Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label or name ending in ${targetTriple} or ${targetDuple}` ); } if (matchingAssets.length > 1) { @@ -10175,7 +10195,13 @@ To resolve, specify the desired binary with the target format ${slug.owner}/${sl ); } const asset = matchingAssets.shift(); - const targetName = stripTargetTriple(asset.label); + let matchField; + if (typeof asset.label === "string" && (asset.label.endsWith(targetTriple) || asset.label.endsWith(targetDuple))) { + matchField = asset.label; + } else { + matchField = asset.name; + } + const targetName = stripTargetTriple(matchField); return { binaryName: targetName, url: asset.url diff --git a/src/fetch.ts b/src/fetch.ts index 7b0e6dd..74d66e6 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -135,6 +135,7 @@ export type ReleaseMetadataResponse = { data: { assets: Array<{ label?: string | null; + name?: string; url: string; // Other fields may exist but we don't use them }>; @@ -157,15 +158,27 @@ export function findMatchingReleaseAssetMetadata( const targetLabelTraditional = `${binaryName.value}-${targetTriple}`; const targetLabelDuple = `${binaryName.value}-${targetDuple}`; - const asset = releaseMetadata.data.assets.find( - (asset) => - typeof asset.label === "string" && - (asset.label === targetLabelTraditional || asset.label === targetLabelDuple), - ); + const asset = releaseMetadata.data.assets.find((asset) => { + // Check for label match + if (typeof asset.label === "string") { + if (asset.label === targetLabelTraditional || asset.label === targetLabelDuple) { + return true; + } + } + + // Check for name match + if (typeof asset.name === "string") { + if (asset.name === targetLabelTraditional || asset.name === targetLabelDuple) { + return true; + } + } + + return false; + }); if (asset === undefined) { throw new Error( - `Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label ${targetLabelTraditional} or ${targetLabelDuple}`, + `Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label or name ${targetLabelTraditional} or ${targetLabelDuple}`, ); } @@ -180,14 +193,26 @@ export function findMatchingReleaseAssetMetadata( // 2. There is an asset label matching the target triple or target duple. // In both cases, we assume that's the binary the user meant. // If there is ambiguity, exit with an error. - const matchingAssets = releaseMetadata.data.assets.filter( - (asset) => - typeof asset.label === "string" && - (asset.label.endsWith(targetTriple) || asset.label.endsWith(targetDuple)), - ); + const matchingAssets = releaseMetadata.data.assets.filter((asset) => { + // Check label match + if (typeof asset.label === "string") { + if (asset.label.endsWith(targetTriple) || asset.label.endsWith(targetDuple)) { + return true; + } + } + + // Check name match + if (typeof asset.name === "string") { + if (asset.name.endsWith(targetTriple) || asset.name.endsWith(targetDuple)) { + return true; + } + } + + return false; + }); if (matchingAssets.length === 0) { throw new Error( - `Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label ending in ${targetTriple} or ${targetDuple}`, + `Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label or name ending in ${targetTriple} or ${targetDuple}`, ); } if (matchingAssets.length > 1) { @@ -198,7 +223,17 @@ To resolve, specify the desired binary with the target format ${slug.owner}/${sl ); } const asset = matchingAssets.shift()!; - const targetName = stripTargetTriple(asset.label!); + + // Determine which field matched to use for stripping the target triple + let matchField: string; + if (typeof asset.label === "string" && + (asset.label.endsWith(targetTriple) || asset.label.endsWith(targetDuple))) { + matchField = asset.label; + } else { + matchField = asset.name!; + } + + const targetName = stripTargetTriple(matchField); return { binaryName: targetName, url: asset.url, diff --git a/test/test-find-matching-release-asset.ts b/test/test-find-matching-release-asset.ts index a2747c4..e669ab2 100644 --- a/test/test-find-matching-release-asset.ts +++ b/test/test-find-matching-release-asset.ts @@ -6,7 +6,7 @@ import { findMatchingReleaseAssetMetadata } from "../src/fetch"; import type { ExactSemanticVersion, RepositorySlug, BinaryName, TargetTriple, TargetDuple } from "../src/types"; // Mocked releaseMetadata for tests -function mockReleaseMetadata(assets: Array<{ label?: string; url: string }>) { +function mockReleaseMetadata(assets: Array<{ label?: string; name?: string; url: string }>) { return { data: { assets } }; @@ -89,7 +89,7 @@ test("should throw error when binary name provided but no matching asset found", targetTriple, targetDuple ); - }, new Error(`Expected to find asset in release testowner/testrepo@v1.0.0 with label testbin-aarch64-apple-darwin or testbin-darwin-arm64`)); + }, new Error(`Expected to find asset in release testowner/testrepo@v1.0.0 with label or name testbin-aarch64-apple-darwin or testbin-darwin-arm64`)); }); // Test without binary name @@ -147,7 +147,7 @@ test("should throw error when no binary name provided and no matching asset foun targetTriple, targetDuple ); - }, new Error(`Expected to find asset in release testowner/testrepo@v1.0.0 with label ending in aarch64-apple-darwin or darwin-arm64`)); + }, new Error(`Expected to find asset in release testowner/testrepo@v1.0.0 with label or name ending in aarch64-apple-darwin or darwin-arm64`)); }); test("should throw error when multiple assets match without binary name", () => { @@ -227,4 +227,91 @@ test("should find x86_64 asset with binary name using target duple", () => { binaryName, url: "https://example.com/testbin-x86-duple" }); +}); + +// Tests for the new feature: finding assets by name property +test("should find asset with binary name using name property with target triple", () => { + const binaryName = some("testbin" as unknown as BinaryName); + const mockAssets = [ + // No label property, only name property + { name: "testbin-aarch64-apple-darwin", url: "https://example.com/testbin-triple" }, + ]; + + const result = findMatchingReleaseAssetMetadata( + mockReleaseMetadata(mockAssets), + mockSlug, + binaryName, + mockTag, + targetTriple, + targetDuple + ); + + assert.deepEqual(result, { + binaryName, + url: "https://example.com/testbin-triple" + }); +}); + +test("should find asset with binary name using name property with target duple", () => { + const binaryName = some("testbin" as unknown as BinaryName); + const mockAssets = [ + // No label property, only name property + { name: "testbin-darwin-arm64", url: "https://example.com/testbin-duple" }, + ]; + + const result = findMatchingReleaseAssetMetadata( + mockReleaseMetadata(mockAssets), + mockSlug, + binaryName, + mockTag, + targetTriple, + targetDuple + ); + + assert.deepEqual(result, { + binaryName, + url: "https://example.com/testbin-duple" + }); +}); + +test("should find asset without binary name using name property with target triple", () => { + const mockAssets = [ + // No label property, only name property + { name: "somebin-aarch64-apple-darwin", url: "https://example.com/somebin-triple" }, + ]; + + const result = findMatchingReleaseAssetMetadata( + mockReleaseMetadata(mockAssets), + mockSlug, + none(), + mockTag, + targetTriple, + targetDuple + ); + + assert.deepEqual(result, { + binaryName: some("somebin"), + url: "https://example.com/somebin-triple" + }); +}); + +test("should find asset without binary name using name property with target duple", () => { + const mockAssets = [ + // No label property, only name property + { name: "somebin-darwin-arm64", url: "https://example.com/somebin-duple" }, + ]; + + const result = findMatchingReleaseAssetMetadata( + mockReleaseMetadata(mockAssets), + mockSlug, + none(), + mockTag, + targetTriple, + targetDuple + ); + + assert.deepEqual(result, { + binaryName: some("somebin"), + url: "https://example.com/somebin-duple" + }); }); \ No newline at end of file