eng/scripts/helpers.js (101 lines of code) (raw):
import { findWorkspacePackagesNoCheck } from "@pnpm/workspace.find-packages";
import { spawn, spawnSync } from "child_process";
import { lstatSync, readdirSync } from "fs";
import { dirname, resolve } from "path";
import { fileURLToPath } from "url";
export const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
export const coreRepoRoot = resolve(repoRoot, "core");
export const prettier = resolve(repoRoot, "core/packages/compiler/node_modules/.bin/prettier");
export const tsc = resolve(repoRoot, "core/packages/compiler/node_modules/.bin/tsc");
export const autorest = resolve(repoRoot, "eng/scripts/node_modules/.bin/autorest");
/** @returns {Promise<import("@pnpm/workspace.find-packages").Project[]>*/
export function listPackages() {
return findWorkspacePackagesNoCheck(repoRoot);
}
export async function getProjectVersion(projectName) {
const packages = await listPackages();
return packages.find((each) => each.manifest.name === projectName).version;
}
// We could use { shell: true } to let Windows find .cmd, but that causes other issues.
// It breaks ENOENT checking for command-not-found and also handles command/args with spaces
// poorly.
const isCmdOnWindows = [
"pnpm",
"npm",
"code",
"code-insiders",
"docusaurus",
tsc,
prettier,
autorest,
];
export class CommandFailedError extends Error {
constructor(msg, proc) {
super(msg);
this.proc = proc;
}
}
export function run(command, args, options) {
if (!options?.silent) {
console.log();
console.log(`> ${command} ${args.join(" ")}`);
}
options = {
stdio: "inherit",
sync: true,
throwOnNonZeroExit: true,
...options,
};
if (process.platform === "win32" && isCmdOnWindows.includes(command)) {
command += ".cmd";
}
const proc = (options.sync ? spawnSync : spawn)(command, args, options);
if (proc.error) {
if (options.ignoreCommandNotFound && proc.error.code === "ENOENT") {
console.log(`Skipped: Command \`${command}\` not found.`);
} else {
throw proc.error;
}
} else if (options.throwOnNonZeroExit && proc.status !== undefined && proc.status !== 0) {
throw new CommandFailedError(
`Command \`${command} ${args.join(" ")}\` failed with exit code ${proc.status}`,
proc,
);
}
return proc;
}
export function clearScreen() {
process.stdout.write("\x1bc");
}
export function logWithTime(msg) {
const time = new Date().toLocaleTimeString();
console.log(`[${time}] ${msg}`);
}
export function scanSwaggers(root) {
const files = [];
for (const file of readdirSync(root)) {
const fullPath = root + "/" + file;
if (lstatSync(fullPath).isDirectory()) {
scanSwaggers(fullPath).forEach((x) => files.push(x));
}
if (file === "openapi.json") {
files.push(fullPath);
}
}
return files;
}
export async function checkForChangedFiles(cwd, comment = undefined, options = {}) {
if (comment && !options.silent) {
console.log();
console.log(comment);
}
const proc = run("git", ["status", "--porcelain"], {
encoding: "utf-8",
stdio: [null, "pipe", "pipe"],
cwd,
...options,
});
if (proc.stdout && !options.silent) {
console.log(proc.stdout);
}
if (proc.stderr && !options.silent) {
console.error(proc.stderr);
}
return proc.stdout || proc.stderr;
}