blob: 9a337369538ed39c5650312477f61eb5c2548b83 [file] [log] [blame] [edit]
/* This file is a part of @mdn/browser-compat-data
* See LICENSE file for more information. */
import {
execSync,
ExecSyncOptionsWithStringEncoding,
spawnSync,
SpawnSyncOptionsWithStringEncoding,
} from 'node:child_process';
/**
* Execute a command
* @param command The command to execute
* @param opts The options to pass to execSync
* @returns The output from the command
*/
export const exec = (
command: string,
opts?: ExecSyncOptionsWithStringEncoding,
): string => execSync(command, { encoding: 'utf8', ...opts }).trim();
/**
* Execute a command
* @param command The command to execute
* @param args The arguments to pass
* @param opts The options to pass to spawnSync
* @returns The output from the command
*/
export const spawn = (
command: string,
args: readonly string[],
opts?: SpawnSyncOptionsWithStringEncoding,
): string => {
const result = spawnSync(command, args, { encoding: 'utf8', ...opts });
if (result.error) {
throw result.error;
}
if (result.status !== 0) {
throw new Error(
`The command '${command}' returned non-zero exit status ${result.status}: ${result.stderr}`,
);
}
return result.stdout.trim();
};
/**
* Check for GitHub CLI and exit the program if it's not existent
*/
export const requireGitHubCLI = (): void => {
const command = 'gh auth status';
try {
execSync(command, { encoding: 'utf8', stdio: 'ignore' });
} catch (err) {
console.trace(err);
console.error(`Error: ${command} failed.`);
console.error('The GitHub CLI is required.');
console.error('See https://cli.github.com/ for installation instructions.');
process.exit(1);
}
};
/**
* Check for repository write permissions
*/
export const requireWriteAccess = () => {
const username = exec('gh api user -q .login');
const authStats = githubAPI(`/collaborators/${username}/permission`);
if (authStats.permission === 'read') {
console.error(
'Error: you must have write access to mdn/browser-compat-data to use this script.',
);
process.exit(1);
}
};
/**
* Run a query on the GitHub API using the GitHub CLI
* @param endpoint The API endpoint to query
* @returns The response from the API
*/
export const githubAPI = (endpoint: string): any =>
JSON.parse(exec(`gh api /repos/mdn/browser-compat-data${endpoint}`));
/**
* Query pull requests
* @param queryArgs The CLI arguments for the query
* @returns The response from the API
*/
export const queryPRs = (queryArgs: any): any => {
const searchDetails = {
limit: 1000, // As many PRs as GitHub will allow
json: 'number',
...queryArgs,
};
const args = Object.entries(searchDetails)
.map(([key, value]) => `--${key}='${value}'`)
.join(' ');
const command = `gh pr list ${args}`;
return JSON.parse(exec(command));
};
/**
* Ensures main is fetched.
*/
export const fetchMain = (): void => {
exec('git fetch origin main');
};
/**
* Get the latest Git tag
* @returns The latest Git tag
*/
export const getLatestTag = (): string =>
exec('git describe --abbrev=0 --tags');
/**
* Get the date of a specified ref
* @param ref The ref to check
* @param querySafe Format the string for HTML
* @returns The ref date
*/
export const getRefDate = (ref: string, querySafe = false): string => {
const rawDateString = exec(`git log -1 --format=%aI ${ref}`);
if (querySafe) {
return rawDateString.replaceAll('+', '%2B');
}
return rawDateString;
};
/**
* Wait for a key press
* @returns Once the key is pressed, return
*/
export const keypress = async () => {
process.stdin.setRawMode(true);
return new Promise((resolve) =>
process.stdin.once('data', () => {
process.stdin.setRawMode(false);
resolve(true);
}),
);
};