1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-19 05:45:09 -05:00
denoland-deno/tools/release/npm/build.ts

238 lines
7.6 KiB
TypeScript
Raw Normal View History

#!/usr/bin/env -S deno run -A --lock=tools/deno.lock.json
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// NOTICE: This deployment/npm folder was lifted from https://github.com/dprint/dprint/blob/0ba79811cc96d2dee8e0cf766a8c8c0fc44879c2/deployment/npm/
// with permission (Copyright 2019-2023 David Sherret)
import $ from "jsr:@david/dax@^0.42.0";
// @ts-types="npm:@types/decompress@4.2.7"
import decompress from "npm:decompress@4.2.1";
import { parseArgs } from "@std/cli/parse-args";
interface Package {
zipFileName: string;
os: "win32" | "darwin" | "linux";
cpu: "x64" | "arm64";
libc?: "glibc" | "musl";
}
const args = parseArgs(Deno.args, {
boolean: ["publish"],
});
const packages: Package[] = [{
zipFileName: "deno-x86_64-pc-windows-msvc.zip",
os: "win32",
cpu: "x64",
}, {
// use x64_64 until there's an arm64 build
zipFileName: "deno-x86_64-pc-windows-msvc.zip",
os: "win32",
cpu: "arm64",
}, {
zipFileName: "deno-x86_64-apple-darwin.zip",
os: "darwin",
cpu: "x64",
}, {
zipFileName: "deno-aarch64-apple-darwin.zip",
os: "darwin",
cpu: "arm64",
}, {
zipFileName: "deno-x86_64-unknown-linux-gnu.zip",
os: "linux",
cpu: "x64",
libc: "glibc",
}, {
zipFileName: "deno-aarch64-unknown-linux-gnu.zip",
os: "linux",
cpu: "arm64",
libc: "glibc",
}];
const markdownText = `# Deno
[Deno](https://www.deno.com)
([/ˈdiːnoʊ/](http://ipa-reader.xyz/?text=%CB%88di%CB%90no%CA%8A), pronounced
\`dee-no\`) is a JavaScript, TypeScript, and WebAssembly runtime with secure
defaults and a great developer experience. It's built on [V8](https://v8.dev/),
[Rust](https://www.rust-lang.org/), and [Tokio](https://tokio.rs/).
Learn more about the Deno runtime
[in the documentation](https://docs.deno.com/runtime/manual).
`;
const currentDir = $.path(import.meta.url).parentOrThrow();
const rootDir = currentDir.parentOrThrow().parentOrThrow().parentOrThrow();
const outputDir = currentDir.join("./dist");
const scopeDir = outputDir.join("@deno");
const denoDir = outputDir.join("deno");
const version = resolveVersion();
$.logStep(`Publishing ${version}...`);
await $`rm -rf ${outputDir}`;
await $`mkdir -p ${denoDir} ${scopeDir}`;
// setup Deno packages
{
$.logStep(`Setting up deno ${version}...`);
const pkgJson = {
"name": "deno",
"version": version,
"description": "A modern runtime for JavaScript and TypeScript.",
"bin": "bin.cjs",
"repository": {
"type": "git",
"url": "git+https://github.com/denoland/deno.git",
},
"keywords": [
"runtime",
"typescript",
],
"author": "the Deno authors",
"license": "MIT",
"bugs": {
"url": "https://github.com/denoland/deno/issues",
},
"homepage": "https://deno.com",
// for yarn berry (https://github.com/dprint/dprint/issues/686)
"preferUnplugged": true,
"scripts": {
"postinstall": "node ./install.cjs",
},
optionalDependencies: packages
.map((pkg) => `@deno/${getPackageNameNoScope(pkg)}`)
.reduce((obj, pkgName) => ({ ...obj, [pkgName]: version }), {}),
};
currentDir.join("bin.cjs").copyFileToDirSync(denoDir);
currentDir.join("install_api.cjs").copyFileToDirSync(denoDir);
currentDir.join("install.cjs").copyFileToDirSync(denoDir);
denoDir.join("package.json").writeJsonPrettySync(pkgJson);
rootDir.join("LICENSE.md").copyFileSync(denoDir.join("LICENSE"));
denoDir.join("README.md").writeTextSync(markdownText);
// ensure the test files don't get published
denoDir.join(".npmignore").writeTextSync("deno\ndeno.exe\n");
// setup each binary package
for (const pkg of packages) {
const pkgName = getPackageNameNoScope(pkg);
$.logStep(`Setting up @deno/${pkgName}...`);
const pkgDir = scopeDir.join(pkgName);
const zipPath = pkgDir.join("output.zip");
await $`mkdir -p ${pkgDir}`;
// download and extract the zip file
const zipUrl =
`https://github.com/denoland/deno/releases/download/v${version}/${pkg.zipFileName}`;
await $.request(zipUrl).showProgress().pipeToPath(zipPath);
await decompress(zipPath.toString(), pkgDir.toString());
zipPath.removeSync();
// create the package.json and readme
pkgDir.join("README.md").writeTextSync(
`# @denoland/${pkgName}\n\n${pkgName} distribution of [Deno](https://deno.land).\n`,
);
pkgDir.join("package.json").writeJsonPrettySync({
"name": `@deno/${pkgName}`,
"version": version,
"description": `${pkgName} distribution of Deno`,
"repository": {
"type": "git",
"url": "git+https://github.com/denoland/deno.git",
},
// force yarn to unpack
"preferUnplugged": true,
"author": "David Sherret",
"license": "MIT",
"bugs": {
"url": "https://github.com/denoland/deno/issues",
},
"homepage": "https://deno.land",
"os": [pkg.os],
"cpu": [pkg.cpu],
libc: pkg.libc == null ? undefined : [pkg.libc],
});
}
}
// verify that the package is created correctly
{
$.logStep("Verifying packages...");
const testPlatform = Deno.build.os == "windows"
? (Deno.build.arch === "x86_64" ? "@deno/win32-x64" : "@deno/win32-arm64")
: Deno.build.os === "darwin"
? (Deno.build.arch === "x86_64" ? "@deno/darwin-x64" : "@deno/darwin-arm64")
: "@deno/linux-x64-glibc";
outputDir.join("package.json").writeJsonPrettySync({
workspaces: [
"deno",
// There seems to be a bug with npm workspaces where this doesn't
// work, so for now make some assumptions and only include the package
// that works on the CI for the current operating system
// ...packages.map(p => `@deno/${getPackageNameNoScope(p)}`),
testPlatform,
],
});
const denoExe = Deno.build.os === "windows" ? "deno.exe" : "deno";
await $`npm install`.cwd(denoDir);
// ensure the post-install script adds the executable to the deno package,
// which is necessary for faster caching and to ensure the vscode extension
// picks it up
if (!denoDir.join(denoExe).existsSync()) {
throw new Error("Deno executable did not exist after post install");
}
// run once after post install created deno, once with a simulated readonly file system, once creating the cache and once with
await $`node bin.cjs -v && rm ${denoExe} && DENO_SIMULATED_READONLY_FILE_SYSTEM=1 node bin.cjs -v && node bin.cjs -v && node bin.cjs -v`
.cwd(denoDir);
if (!denoDir.join(denoExe).existsSync()) {
throw new Error("Deno executable did not exist when lazily initialized");
}
}
// publish if necessary
if (args.publish) {
for (const pkg of packages) {
const pkgName = getPackageNameNoScope(pkg);
$.logStep(`Publishing @deno/${pkgName}...`);
if (await checkPackagePublished(`@deno/${pkgName}`)) {
$.logLight(" Already published.");
continue;
}
const pkgDir = scopeDir.join(pkgName);
await $`cd ${pkgDir} && npm publish --provenance --access public`;
}
$.logStep(`Publishing deno...`);
await $`cd ${denoDir} && npm publish --provenance --access public`;
}
function getPackageNameNoScope(name: Package) {
const libc = name.libc == null ? "" : `-${name.libc}`;
return `${name.os}-${name.cpu}${libc}`;
}
function resolveVersion() {
const firstArg = args._[0];
if (
firstArg != null &&
typeof firstArg === "string" &&
firstArg.trim().length > 0
) {
return firstArg;
}
const version = (rootDir.join("cli/Cargo.toml").readTextSync().match(
/version = "(.*?)"/,
))?.[1];
if (version == null) {
throw new Error("Could not resolve version.");
}
return version;
}
async function checkPackagePublished(pkgName: string) {
const result = await $`npm info ${pkgName}@${version}`.quiet().noThrow();
return result.code === 0;
}