diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2024-08-16 22:59:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-16 23:59:10 +0200 |
commit | 2eeea0a1d2011567d3a41065d66802097366dc8c (patch) | |
tree | a231ffa562cbd2eabbd7703a25938b3f9e47fb25 /tools/release | |
parent | db75462bd6f01d4a470c2ed7b5aad2f9a877f150 (diff) |
ci: add script to promote to RC release (#25072)
This commits add a CI script that allows to promote a certain
canary build to a "Release Candidate" release.
This is done using `libsui` and `patchver` utilities.
Diffstat (limited to 'tools/release')
-rw-r--r-- | tools/release/promote_to_rc.ts | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/tools/release/promote_to_rc.ts b/tools/release/promote_to_rc.ts new file mode 100644 index 000000000..6d7375385 --- /dev/null +++ b/tools/release/promote_to_rc.ts @@ -0,0 +1,212 @@ +#!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { $ } from "jsr:@david/dax@0.41.0"; +import { gray } from "jsr:@std/fmt@1/colors"; +import { patchver } from "jsr:@deno/patchver@0.1.0"; + +const SUPPORTED_TARGETS = [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", +]; + +const DENO_BINARIES = [ + "deno", + "denort", +]; + +const CHANNEL = "rc"; + +const CANARY_URL = "https://dl.deno.land"; + +function getCanaryBinaryUrl( + version: string, + binary: string, + target: string, +): string { + return `${CANARY_URL}/canary/${version}/${binary}-${target}.zip`; +} + +function getUnzippedFilename(binary: string, target: string) { + if (target.includes("windows")) { + return `${binary}.exe`; + } else { + return binary; + } +} + +function getRcBinaryName(binary: string, target: string): string { + let ext = ""; + if (target.includes("windows")) { + ext = ".exe"; + } + return `${binary}-${target}-rc${ext}`; +} + +function getArchiveName(binary: string, target: string): string { + return `${binary}-${target}.zip`; +} + +interface CanaryVersion { + target: string; + version: string; +} + +async function remove(filePath: string) { + try { + await Deno.remove(filePath); + } catch { + // pass + } +} + +async function fetchLatestCanaryBinary( + version: string, + binary: string, + target: string, +) { + const url = getCanaryBinaryUrl(version, binary, target); + await $.request(url).showProgress().pipeToPath(); +} + +async function fetchLatestCanaryBinaries(canaryVersion: string) { + for (const binary of DENO_BINARIES) { + for (const target of SUPPORTED_TARGETS) { + $.logStep("Download", binary, gray("target:"), target); + await fetchLatestCanaryBinary(canaryVersion, binary, target); + } + } +} + +async function unzipArchive(archiveName: string, unzippedName: string) { + await remove(unzippedName); + const output = await $`unzip ./${archiveName}`; + if (output.code !== 0) { + $.logError(`Failed to unzip ${archiveName} (error code ${output.code})`); + Deno.exit(1); + } +} + +async function createArchive(rcBinaryName: string, archiveName: string) { + const output = await $`zip -r ./${archiveName} ./${rcBinaryName}`; + + if (output.code !== 0) { + $.logError( + `Failed to create archive ${archiveName} (error code ${output.code})`, + ); + Deno.exit(1); + } +} + +async function runPatchver( + binary: string, + target: string, + rcBinaryName: string, +) { + const input = await Deno.readFile(binary); + const output = patchver(input, CHANNEL); + + try { + await Deno.writeFile(rcBinaryName, output); + } catch (e) { + $.logError( + `Failed to promote to RC ${binary} (${target}), error:`, + e, + ); + Deno.exit(1); + } +} + +async function promoteBinaryToRc(binary: string, target: string) { + const unzippedName = getUnzippedFilename(binary, target); + const rcBinaryName = getRcBinaryName(binary, target); + const archiveName = getArchiveName(binary, target); + await remove(unzippedName); + await remove(rcBinaryName); + $.logStep( + "Unzip", + archiveName, + gray("binary"), + binary, + gray("rcBinaryName"), + rcBinaryName, + ); + + await unzipArchive(archiveName, unzippedName); + await remove(archiveName); + + $.logStep( + "Patchver", + unzippedName, + `(${target})`, + gray("output to"), + rcBinaryName, + ); + await runPatchver(unzippedName, target, rcBinaryName); + // Remove the unpatched binary and rename patched one. + await remove(unzippedName); + await Deno.rename(rcBinaryName, unzippedName); + // Set executable permission + if (!target.includes("windows")) { + Deno.chmod(unzippedName, 0o777); + } + + await createArchive(unzippedName, archiveName); + await remove(unzippedName); +} + +async function promoteBinariesToRc() { + const totalCanaries = SUPPORTED_TARGETS.length * DENO_BINARIES.length; + + for (let targetIdx = 0; targetIdx < SUPPORTED_TARGETS.length; targetIdx++) { + const target = SUPPORTED_TARGETS[targetIdx]; + for (let binaryIdx = 0; binaryIdx < DENO_BINARIES.length; binaryIdx++) { + const binaryName = DENO_BINARIES[binaryIdx]; + const currentIdx = (targetIdx * 2) + binaryIdx + 1; + $.logLight( + `[${currentIdx}/${totalCanaries}]`, + "Promote", + binaryName, + target, + "to RC...", + ); + await promoteBinaryToRc(binaryName, target); + $.logLight( + `[${currentIdx}/${totalCanaries}]`, + "Promoted", + binaryName, + target, + "to RC!", + ); + } + } +} + +async function dumpRcVersion() { + $.logStep("Compute version"); + await unzipArchive(getArchiveName("deno", Deno.build.target), "deno"); + const output = await $`./deno -V`.stdout("piped"); + const denoVersion = output.stdout.slice(5).split("+")[0]; + $.logStep("Computed version", denoVersion); + await Deno.writeTextFile("./release-rc-latest.txt", denoVersion); +} + +async function main() { + const commitHash = Deno.args[0]; + if (!commitHash) { + throw new Error("Commit hash needs to be provided as an argument"); + } + $.logStep("Download canary binaries..."); + await fetchLatestCanaryBinaries(commitHash); + console.log("All canary binaries ready"); + $.logStep("Promote canary binaries to RC..."); + await promoteBinariesToRc(); + + // Finally dump the version name to a `release.txt` file for uploading to GCP + await dumpRcVersion(); +} + +await main(); |