radashi-helper
Version:
Help with managing your own Radashi
364 lines (325 loc) • 13.1 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
var _chunkQJPNUX4Pcjs = require('./chunk-QJPNUX4P.cjs');
var _chunkZTBV44GEcjs = require('./chunk-ZTBV44GE.cjs');
require('./chunk-BCKUBJLJ.cjs');
var _chunk7UCE7HEGcjs = require('./chunk-7UCE7HEG.cjs');
var _chunk3OOKBKZBcjs = require('./chunk-3OOKBKZB.cjs');
var _chunkWVUG42ZOcjs = require('./chunk-WVUG42ZO.cjs');
require('./chunk-27XA2ZBL.cjs');
var _chunkDNQVKCXJcjs = require('./chunk-DNQVKCXJ.cjs');
require('./chunk-IWXG7YVC.cjs');
var _chunk4WZBZWYDcjs = require('./chunk-4WZBZWYD.cjs');
var _chunkZP624W2Acjs = require('./chunk-ZP624W2A.cjs');
var _chunkST3J6QTNcjs = require('./chunk-ST3J6QTN.cjs');
var _chunk5R2KEZLQcjs = require('./chunk-5R2KEZLQ.cjs');
// ../../node_modules/.pnpm/glob-regex@0.3.2/node_modules/glob-regex/index.js
var require_glob_regex = _chunk5R2KEZLQcjs.__commonJS.call(void 0, {
"../../node_modules/.pnpm/glob-regex@0.3.2/node_modules/glob-regex/index.js"(exports, module) {
"use strict";
var dotRE = /\./g;
var dotPattern = "\\.";
var restRE = /\*\*$/g;
var restPattern = "(.+)";
var globRE = /(?:\*\*\/|\*\*|\*)/g;
var globPatterns = {
"*": "([^/]+)",
// no backslashes
"**": "(.+/)?([^/]+)",
// short for "**/*"
"**/": "(.+/)?"
// one or more directories
};
function mapToPattern(str) {
return globPatterns[str];
}
function replace(glob) {
return glob.replace(dotRE, dotPattern).replace(restRE, restPattern).replace(globRE, mapToPattern);
}
function join3(globs) {
return "((" + globs.map(replace).join(")|(") + "))";
}
function globRegex2(glob) {
return new RegExp("^" + (Array.isArray(glob) ? join3 : replace)(glob) + "$");
}
globRegex2.replace = replace;
Object.defineProperty(globRegex2, "default", { value: globRegex2 });
module.exports = globRegex2;
}
});
// src/pr-import.ts
var import_glob_regex = _chunk5R2KEZLQcjs.__toESM.call(void 0, require_glob_regex(), 1);
var _colors = require('kleur/colors');
var _fs = require('fs');
var _promises = require('fs/promises'); var _promises2 = _interopRequireDefault(_promises);
var _path = require('path');
// src/rewired/undoRewire.ts
async function undoRewire(funcPath, env) {
_chunkZP624W2Acjs.debug.call(void 0, `Removing rewired file for "${funcPath}"`);
const rewiredFile = _path.join.call(void 0, env.overrideDir, "rewired", funcPath + ".ts");
await _promises2.default.rm(rewiredFile);
const rewired = await _chunk7UCE7HEGcjs.loadRewired.call(void 0, env);
const newRewired = rewired.filter((path) => path !== funcPath);
await _promises.writeFile.call(void 0, rewiredFile, JSON.stringify(newRewired, null, 2));
}
// src/util/checkCommand.ts
var _child_process = require('child_process');
async function checkCommand(cmd) {
return new Promise((resolve) => {
_child_process.exec.call(void 0, `command -v ${cmd}`, (error) => {
resolve(!error);
});
});
}
// src/pr-import.ts
async function importPullRequest(prNumber, options = {}) {
if (Number.isNaN(+prNumber)) {
throw new (0, _chunkST3J6QTNcjs.RadashiError)(`Invalid PR number "${prNumber}"`);
}
if (!await checkCommand("gh")) {
throw new (0, _chunkST3J6QTNcjs.RadashiError)(
_chunkQJPNUX4Pcjs.dedent`
gh command is not installed.
You can install it using Homebrew:
brew install gh
Or using the official website:
https://cli.github.com/
`
);
}
const env = _nullishCoalesce(options.env, () => ( _chunkZP624W2Acjs.getEnv.call(void 0, options.dir)));
if (!env.radashiDir) {
throw new (0, _chunkST3J6QTNcjs.RadashiError)("No upstream repository exists");
}
await _chunkZTBV44GEcjs.assertRepoClean.call(void 0, env.root);
await _chunk3OOKBKZBcjs.pullRadashi.call(void 0, env);
await _chunkST3J6QTNcjs.exec.call(void 0, "git", ["branch", "-D", "pr-" + prNumber], {
cwd: env.radashiDir,
reject: false
});
_chunkST3J6QTNcjs.log.call(void 0, "Checking out PR...");
await _chunkST3J6QTNcjs.exec.call(void 0, "gh", ["pr", "checkout", prNumber, "-b", "pr-" + prNumber], {
cwd: env.radashiDir
}).catch((error) => {
_chunkST3J6QTNcjs.log.error(error.stderr);
let reason = "";
if (error.message.includes("Could not resolve")) {
reason = `Could not find any PR with number ${prNumber}.`;
} else if (error.message.includes("couldn't find remote ref")) {
reason = "The author appears to have deleted the PR branch.";
}
throw new (0, _chunkST3J6QTNcjs.RadashiError)(
"Failed to checkout PR" + (reason ? `: ${reason}` : "")
);
});
const targetBranch = await getTargetBranch(env);
_chunkZP624W2Acjs.debug.call(void 0, "Target branch of the PR:", targetBranch);
await _chunkST3J6QTNcjs.exec.call(void 0,
"git",
["fetch"].concat(
targetBranch.includes("/") ? targetBranch.split("/") : ["origin", targetBranch]
),
{
cwd: env.radashiDir
}
).catch(_chunkST3J6QTNcjs.forwardStderrAndRethrow);
const baseCommit = await _chunkST3J6QTNcjs.exec.call(void 0, "git", ["merge-base", "HEAD", targetBranch], {
cwd: env.radashiDir
}).then((r) => r.stdout);
_chunkZP624W2Acjs.debug.call(void 0, "Base commit of the PR:", baseCommit);
const changes = await parseGitDiff(baseCommit, {
cwd: env.radashiDir
});
_chunkZP624W2Acjs.debug.call(void 0, "Parsed changes from git diff:", changes);
const pathsIn = await _chunkDNQVKCXJcjs.findSources.call(void 0, env);
const srcGlob = (0, import_glob_regex.default)("src/*/*.ts");
changes.sort((a, b) => {
return srcGlob.test(a.file) && !srcGlob.test(b.file) ? -1 : srcGlob.test(b.file) && !srcGlob.test(a.file) ? 1 : a.file.localeCompare(b.file);
});
const addedFiles = [];
const modifiedFiles = [];
for (const change of changes) {
const file = _path.basename.call(void 0, change.file, _path.extname.call(void 0, change.file));
if (options.files && !options.files.includes(file)) {
continue;
}
if (change.status === "A") {
addedFiles.push(change.file);
if (change.file.startsWith("src/")) {
const srcPath = _path.join.call(void 0, env.root, change.file);
if (pathsIn.src.includes(srcPath)) {
throw new (0, _chunkST3J6QTNcjs.RadashiError)(
`Cannot import PR. File named "${change.file}" is already a source file created by you.`
);
}
}
} else if (change.status === "M" && change.file !== "src/mod.ts") {
modifiedFiles.push(change.file);
if (change.file.startsWith("src/")) {
const overridePath = _path.join.call(void 0,
env.root,
change.file.replace("src/", "overrides/src/")
);
if (pathsIn.overrides.includes(overridePath)) {
throw new (0, _chunkST3J6QTNcjs.RadashiError)(
`Cannot import PR. File named "${change.file}" already exists in the overrides folder.`
);
}
const funcPath = _path.relative.call(void 0, env.overrideDir, overridePath).slice(0, -3);
const rewiredPath = overridePath.replace("/src/", "/rewired/");
if (pathsIn.rewired.includes(rewiredPath)) {
await undoRewire(funcPath, env);
}
await _chunkZTBV44GEcjs.addOverride.call(void 0, funcPath, {
env,
exactMatch: true,
fromBranch: baseCommit
});
}
}
}
for (const file of addedFiles) {
_chunkZP624W2Acjs.debug.call(void 0, `Adding "${file}" to project`);
await tryCopyFile(_path.join.call(void 0, env.radashiDir, file), _path.join.call(void 0, env.root, file));
}
for (const file of modifiedFiles) {
_chunkZP624W2Acjs.debug.call(void 0, `Modifying "${file}" override in project`);
await tryCopyFile(
_path.join.call(void 0, env.radashiDir, file),
_path.join.call(void 0, env.root, "overrides", file)
);
}
let prTitle = await _chunkST3J6QTNcjs.exec.call(void 0,
"gh",
["pr", "view", "--json", "title", "--jq", ".title"],
{ cwd: env.radashiDir }
).then((result) => result.stdout.trim());
const validTitleRE = /^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([^):]+\))?: /;
if (!validTitleRE.test(prTitle)) {
_chunkST3J6QTNcjs.log.error("");
_chunkST3J6QTNcjs.log.error(
_colors.yellow.call(void 0, "ATTN"),
"The PR title does not follow the Conventional Commits format."
);
_chunkST3J6QTNcjs.log.error("Please select the type of change this PR introduces:\n");
const type = await _chunk4WZBZWYDcjs.prompt.call(void 0, {
type: "autocomplete",
name: "type",
message: "Select the type of change:",
choices: getConventionalCommitTypes()
});
if (!type) {
throw new (0, _chunkST3J6QTNcjs.EarlyExitError)("No change type selected. Exiting...");
}
const description = await _chunk4WZBZWYDcjs.prompt.call(void 0, {
type: "text",
name: "description",
message: "Enter a short description of the change:"
});
if (!description) {
throw new (0, _chunkST3J6QTNcjs.EarlyExitError)("No description provided. Exiting...");
}
prTitle = `${type}: ${description}`;
}
const { default: build } = await Promise.resolve().then(() => _interopRequireWildcard(require("./build-D32K7VSY.cjs")));
await build({ env });
_chunkST3J6QTNcjs.log.call(void 0, "");
await _chunkWVUG42ZOcjs.botCommit.call(void 0, prTitle, {
cwd: env.root,
add: ["-A"]
});
}
async function tryCopyFile(src, dst) {
if (_fs.existsSync.call(void 0, src)) {
try {
await _promises.mkdir.call(void 0, _path.dirname.call(void 0, dst), { recursive: true });
await _promises.copyFile.call(void 0, src, dst);
return true;
} catch (e) {
}
}
return false;
}
async function parseGitDiff(ref, opts) {
const { stdout: nameStatus } = await _chunkST3J6QTNcjs.exec.call(void 0,
"git",
["diff", ref, "--name-status"],
opts
);
return nameStatus.trim().split("\n").map((line) => {
const [status, file] = line.split(" ");
return { status, file };
});
}
async function getTargetBranch(env) {
const { stdout } = await _chunkST3J6QTNcjs.exec.call(void 0,
"gh",
["pr", "view", "--json", "baseRefName", "--jq", ".baseRefName"],
{ cwd: env.radashiDir }
);
const targetBranch = _nullishCoalesce(_optionalChain([stdout, 'optionalAccess', _ => _.trim, 'call', _2 => _2()]), () => ( "main"));
const radashiRef = await env.radashiRef;
if (_chunkZP624W2Acjs.isPreReleaseRadashiTag.call(void 0, radashiRef)) {
return "radashi/" + targetBranch;
}
return targetBranch;
}
function getConventionalCommitTypes() {
return [
{
title: "feat",
description: "A new feature",
value: "feat"
},
{
title: "fix",
description: "A bug fix",
value: "fix"
},
{
title: "docs",
description: "Documentation only changes",
value: "docs"
},
{
title: "style",
description: "Changes that do not affect the meaning of the code",
value: "style"
},
{
title: "refactor",
description: "A code change that neither fixes a bug nor adds a feature",
value: "refactor"
},
{
title: "perf",
description: "A code change that improves performance",
value: "perf"
},
{
title: "test",
description: "Adding missing tests or correcting existing tests",
value: "test"
},
{
title: "build",
description: "Changes that affect the build system or external dependencies",
value: "build"
},
{
title: "ci",
description: "Changes to our CI configuration files and scripts",
value: "ci"
},
{
title: "chore",
description: "Other changes that don't modify src or test files",
value: "chore"
},
{
title: "revert",
description: "Reverts a previous commit",
value: "revert"
}
];
}
exports.importPullRequest = importPullRequest;