Skip to content

Commit cf3986f

Browse files
committed
feat: support Go standard for target platform
TICKET: VL-4112
1 parent c038e23 commit cf3986f

File tree

5 files changed

+132
-38
lines changed

5 files changed

+132
-38
lines changed

dist/index.js

Lines changed: 50 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/fetch.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Octokit } from "./octokit";
22
import { isEqual, isSome, none, Option, some } from "./option";
33
import { stripTargetTriple } from "./platform";
4+
import type { TargetDuple } from "./types";
45

56
import {
67
isExactSemanticVersion,
@@ -133,6 +134,7 @@ export async function fetchReleaseAssetMetadataFromTag(
133134
binaryName: Option<BinaryName>,
134135
tag: ExactSemanticVersion,
135136
targetTriple: TargetTriple,
137+
targetDuple: TargetDuple,
136138
): Promise<ReleaseAssetMetadata> {
137139
// Maintainer's note: this impure function call makes this function difficult to test.
138140
const releaseMetadata = await octokit.rest.repos.getReleaseByTag({
@@ -141,45 +143,52 @@ export async function fetchReleaseAssetMetadataFromTag(
141143
tag,
142144
});
143145

144-
// When the binary name is provided, look for matching binary and target triple.
146+
// When the binary name is provided, look for matching binary with target triple or target duple
145147
if (isSome(binaryName)) {
146-
const targetLabel = `${binaryName.value}-${targetTriple}`;
148+
const targetLabelTraditional = `${binaryName.value}-${targetTriple}`;
149+
const targetLabelDuple = `${binaryName.value}${targetDuple}`;
150+
147151
const asset = releaseMetadata.data.assets.find(
148-
(asset) => asset.label === targetLabel,
152+
(asset) =>
153+
typeof asset.label === "string" &&
154+
(asset.label === targetLabelTraditional || asset.label === targetLabelDuple),
149155
);
156+
150157
if (asset === undefined) {
151158
throw new Error(
152-
`Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label ${targetLabel}`,
159+
`Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label ${targetLabelTraditional} or ${targetLabelDuple}`,
153160
);
154161
}
162+
155163
return {
156164
binaryName: binaryName,
157165
url: asset.url,
158166
};
159167
}
160168

161-
// When the binary name is not provided, support two use cases:
169+
// When the binary name is not provided, support these use cases:
162170
// 1. There is only one binary uploaded to this release, a named binary.
163-
// 2. There is an asset label matching the target triple (with no binary name).
171+
// 2. There is an asset label matching the target triple or target duple.
164172
// In both cases, we assume that's the binary the user meant.
165173
// If there is ambiguity, exit with an error.
166-
const matchingTargetTriples = releaseMetadata.data.assets.filter(
174+
const matchingAssets = releaseMetadata.data.assets.filter(
167175
(asset) =>
168-
typeof asset.label === "string" && asset.label.endsWith(targetTriple),
176+
typeof asset.label === "string" &&
177+
(asset.label.endsWith(targetTriple) || asset.label.endsWith(targetDuple)),
169178
);
170-
if (matchingTargetTriples.length === 0) {
179+
if (matchingAssets.length === 0) {
171180
throw new Error(
172-
`Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label ending in ${targetTriple}`,
181+
`Expected to find asset in release ${slug.owner}/${slug.repository}@${tag} with label ending in ${targetTriple} or ${targetDuple}`,
173182
);
174183
}
175-
if (matchingTargetTriples.length > 1) {
184+
if (matchingAssets.length > 1) {
176185
throw new Error(
177-
`Ambiguous targets: expected to find a single asset in release ${slug.owner}/${slug.repository}@${tag} matching target triple ${targetTriple}, but found ${matchingTargetTriples.length}.
186+
`Ambiguous targets: expected to find a single asset in release ${slug.owner}/${slug.repository}@${tag} matching target triple ${targetTriple} or target duple ${targetDuple}, but found ${matchingAssets.length}.
178187
179188
To resolve, specify the desired binary with the target format ${slug.owner}/${slug.repository}/<binary-name>@${tag}`,
180189
);
181190
}
182-
const asset = matchingTargetTriples.shift()!;
191+
const asset = matchingAssets.shift()!;
183192
const targetName = stripTargetTriple(asset.label!);
184193
return {
185194
binaryName: targetName,

src/index.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
parseTargetReleases,
1414
parseToken,
1515
} from "./parse";
16-
import { getTargetTriple } from "./platform";
16+
import { getTargetTriple, getTargetDuple } from "./platform";
1717
import {
1818
fetchReleaseAssetMetadataFromTag,
1919
findExactSemanticVersionTag,
@@ -48,7 +48,10 @@ async function installGitHubReleaseBinary(
4848
token: string,
4949
ignoreExisting: boolean,
5050
): Promise<void> {
51-
const targetTriple = getTargetTriple(arch(), platform());
51+
const currentArch = arch();
52+
const currentPlatform = platform();
53+
const targetTriple = getTargetTriple(currentArch, currentPlatform);
54+
const targetDuple = getTargetDuple(currentArch, currentPlatform);
5255

5356
const releaseTag = await findExactSemanticVersionTag(
5457
octokit,
@@ -60,8 +63,8 @@ async function installGitHubReleaseBinary(
6063
storageDirectory,
6164
targetRelease.slug,
6265
releaseTag,
63-
platform(),
64-
arch(),
66+
currentPlatform,
67+
currentArch,
6568
);
6669

6770
const releaseAsset = await fetchReleaseAssetMetadataFromTag(
@@ -70,6 +73,7 @@ async function installGitHubReleaseBinary(
7073
targetRelease.binaryName,
7174
releaseTag,
7275
targetTriple,
76+
targetDuple,
7377
);
7478

7579
const destinationBasename = unwrapOrDefault(

src/platform.ts

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { TargetTriple } from "./types";
1+
import type { TargetTriple, TargetDuple } from "./types";
22
import { none, some, type Option } from "./option";
33

44
const ALL_TARGET_TRIPLES: readonly TargetTriple[] = [
@@ -8,6 +8,14 @@ const ALL_TARGET_TRIPLES: readonly TargetTriple[] = [
88
"x86_64-unknown-linux-musl",
99
] as unknown as readonly TargetTriple[];
1010

11+
// Target duples (Go format OS-architecture combinations)
12+
export const TARGET_DUPLES: readonly TargetDuple[] = [
13+
"-linux-amd64",
14+
"-linux-arm64",
15+
"-darwin-amd64",
16+
"-darwin-arm64",
17+
] as unknown as readonly TargetDuple[];
18+
1119
function architectureLabel(arch: string): string {
1220
switch (arch) {
1321
case "arm64":
@@ -54,16 +62,55 @@ export function getTargetTriple(
5462
}
5563

5664
/**
57-
* String the string of its target triple suffix
65+
* Get the target duple (e.g. "-linux-amd64") for the given architecture and platform
66+
*/
67+
export function getTargetDuple(
68+
arch: string,
69+
platform: NodeJS.Platform,
70+
): TargetDuple {
71+
switch (platform) {
72+
case "darwin":
73+
return arch === "arm64" ? "-darwin-arm64" as TargetDuple : "-darwin-amd64" as TargetDuple;
74+
case "linux":
75+
return arch === "arm64" ? "-linux-arm64" as TargetDuple : "-linux-amd64" as TargetDuple;
76+
default:
77+
throw new Error(
78+
`Unsupported platform ${platform} for target duple conversion`,
79+
);
80+
}
81+
}
82+
83+
/**
84+
* Strip the target triple or target duple suffix from a string
5885
*/
5986
export function stripTargetTriple(value: string): Option<string> {
6087
// Can't strip away the target tuple if nothing else remains
6188
if (ALL_TARGET_TRIPLES.find((targetTriple) => targetTriple === value)) {
6289
return none();
6390
}
64-
const stripped = ALL_TARGET_TRIPLES.reduce(
91+
92+
// Try to strip traditional target triple format first
93+
const strippedTriple = ALL_TARGET_TRIPLES.reduce(
6594
(value, targetTriple) => value.replace(new RegExp(`-${targetTriple}$`), ""),
6695
value,
6796
);
68-
return some(stripped);
97+
98+
// If the value changed, a target triple was found and stripped
99+
if (strippedTriple !== value) {
100+
return some(strippedTriple);
101+
}
102+
103+
// Try to strip target duple suffix
104+
const strippedDuple = TARGET_DUPLES.reduce(
105+
(value, duple) => value.replace(new RegExp(`${duple}$`), ""),
106+
value,
107+
);
108+
109+
// If the value changed, a target duple was found and stripped
110+
if (strippedDuple !== value) {
111+
return some(strippedDuple);
112+
}
113+
114+
// Nothing was stripped, return the original value
115+
return some(value);
69116
}

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export type RepositorySlug = {
3232
};
3333

3434
export type TargetTriple = string & { readonly __tag: unique symbol };
35+
export type TargetDuple = string & { readonly __tag: unique symbol };
3536
export type BinaryName = string & { readonly __tag: unique symbol };
3637

3738
export type TargetRelease = {

0 commit comments

Comments
 (0)