diff options
author | 2023-02-01 10:27:04 -0800 | |
---|---|---|
committer | 2023-02-01 10:28:01 -0800 | |
commit | 73d6c888b9d4a9ac94452253d924f7ccea069429 (patch) | |
tree | da5c67a32b9547a057b50dabd0e155e35dcfa03d /packages/bun-release/src/github.ts | |
parent | 661fca9cde8bd82fa848944e0c1e0d6f6f12d403 (diff) | |
download | bun-73d6c888b9d4a9ac94452253d924f7ccea069429.tar.gz bun-73d6c888b9d4a9ac94452253d924f7ccea069429.tar.zst bun-73d6c888b9d4a9ac94452253d924f7ccea069429.zip |
Add bun-release package
Diffstat (limited to 'packages/bun-release/src/github.ts')
-rw-r--r-- | packages/bun-release/src/github.ts | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/packages/bun-release/src/github.ts b/packages/bun-release/src/github.ts new file mode 100644 index 000000000..fbbbbf267 --- /dev/null +++ b/packages/bun-release/src/github.ts @@ -0,0 +1,113 @@ +import type { Endpoints, RequestParameters, Route } from "@octokit/types"; +import { Octokit } from "octokit"; +import { fetch } from "./fetch"; +import { debug, log, warn, error } from "./console"; + +const [owner, repo] = process.env["GITHUB_REPOSITORY"]?.split("/") ?? [ + "oven-sh", + "bun", +]; + +const octokit = new Octokit({ + auth: process.env["GITHUB_TOKEN"], + request: { + fetch, + }, + log: { + debug, + info: log, + warn, + error, + }, +}); + +export async function github<R extends Route>( + url: R | keyof Endpoints, + options?: Omit< + R extends keyof Endpoints + ? Endpoints[R]["parameters"] & RequestParameters + : RequestParameters, + "owner" | "repo" + >, +): Promise< + R extends keyof Endpoints ? Endpoints[R]["response"]["data"] : unknown +> { + // @ts-ignore + const { data } = await octokit.request(url, { + owner, + repo, + ...options, + }); + return data; +} + +export async function getRelease(tag?: string) { + if (!tag) { + return github("GET /repos/{owner}/{repo}/releases/latest"); + } + return github("GET /repos/{owner}/{repo}/releases/tags/{tag}", { + tag: formatTag(tag), + }); +} + +export async function uploadAsset(tag: string, name: string, blob: Blob) { + const release = await getRelease(tag); + const asset = release.assets.find((asset) => asset.name === name); + // Github requires that existing assets are deleted before uploading + // a new asset, but does not provide a rename or re-upload API?!? + if (asset) { + await github("DELETE /repos/{owner}/{repo}/releases/assets/{asset_id}", { + asset_id: asset.id, + }); + } + return github( + "POST {origin}/repos/{owner}/{repo}/releases/{release_id}/assets{?name,label}", + { + baseUrl: "https://uploads.github.com", + release_id: release.id, + name, + headers: { + "content-type": blob.type, + "content-length": blob.size, + }, + data: Buffer.from(await blob.arrayBuffer()), + }, + ); +} + +export async function downloadAsset(tag: string, name: string): Promise<Blob> { + const release = await getRelease(tag); + const asset = release.assets.find((asset) => asset.name === name); + if (!asset) { + throw new Error(`Asset not found: ${name}`); + } + const response = await fetch(asset.browser_download_url); + return response.blob(); +} + +export async function getSha(tag: string, format?: "short" | "long") { + const { sha } = await github("GET /repos/{owner}/{repo}/git/tags/{tag_sha}", { + tag_sha: formatTag(tag), + }); + return format === "short" ? sha.substring(0, 7) : sha; +} + +export async function getSemver(tag?: string, build?: number): Promise<string> { + const { tag_name } = await getRelease(tag); + if (tag_name !== "canary") { + return tag_name.replace("bun-v", ""); + } + const sha = await getSha(tag_name, "short"); + const date = new Date().toISOString().split("T")[0].replace(/-/g, ""); + return `${Bun.version}-canary.${date}.${build ?? 1}+${sha}`; +} + +export function formatTag(tag: string): string { + if (tag === "canary" || tag.startsWith("bun-v")) { + return tag; + } + if (tag.startsWith("v")) { + return tag.slice(1); + } + return `bun-v${tag}`; +} |