UNPKG

@gabortorma/mwm

Version:

Multi-repo Workspace Manager

272 lines (259 loc) 7.79 kB
import git from 'simple-git'; import path, { join, resolve } from 'node:path'; import { consola } from 'consola'; import { l as loadConfig } from './mwm.Bxg0O5XR.mjs'; import { g as getStringArg, a as getBoolArg, c as checkCancel } from './mwm.CyrEUDRq.mjs'; import { Octokit } from '@octokit/rest'; import { readPackageJSON, writePackageJSON } from 'pkg-types'; import { replaceInFile } from 'replace-in-file'; import { camelCase, pascalCase } from 'change-case'; async function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function getRepoUrl({ owner: { id, token }, name }) { return `https://${id}:${token}@github.com/${id}/${name}.git`; } async function cloneRepo(repo) { const repoUrl = getRepoUrl(repo); return git().clone(repoUrl, repo.path); } async function selectOwner(owner, owners) { if (!owners) { throw new Error("No owners found! Please add owners to the config file"); } const ownersWithToken = {}; for (const key of Object.keys(owners)) { if (owners[key].token) ownersWithToken[key] = owners[key]; } const options = Object.keys(ownersWithToken); if (options.length === 0) { throw new Error("No owners with token found! Please add owners with token to the config file"); } if (!ownersWithToken[owner]) { owner = await consola.prompt("Select Owner", { type: "select", options }); checkCancel(owner); } return { id: owner, ...ownersWithToken[owner] }; } async function getName(name) { return getStringArg(name, "Enter the name of the new repo"); } async function getDescription(description) { return getStringArg(description, "Enter the description of the new repo"); } async function getPath(dir, name, template) { if (dir) { return dir; } const repoPath = path.join(template.path, name); const result = consola.prompt("Set the path of the new repo", { type: "text", placeholder: repoPath, default: repoPath }); checkCancel(result); return result; } async function getPrivate(arg) { return getBoolArg(arg, "Create a private repository?"); } async function getClone(arg) { return getBoolArg(arg, "Clone the repo instead of submodule?"); } async function getAddRemoteTemplate(arg) { return getBoolArg(arg, "Add remote template repository?"); } async function getFixReplacements(arg) { return getBoolArg(arg, "Fix replacements?"); } function getKeywords(arg) { if (typeof arg === "string") return arg.split(",").map((keyword) => keyword.trim()); } async function getRepo(args, template) { const { config } = await loadConfig(); const name = await getName(args.name); return { owner: await selectOwner(args.owner, config.owners), name, description: await getDescription(args.description), path: await getPath(args.dir, name, template), private: await getPrivate(args.private), keywords: getKeywords(args.keywords) }; } async function generateGitHubRepo(template, repo) { const octokit = new Octokit({ auth: repo.owner.token }); await octokit.request(`POST /repos/${template.owner}/${template.repo}/generate`, { owner: repo.owner.id, name: repo.name, description: repo.description, private: repo.private, include_all_branches: false, headers: { "X-GitHub-Api-Version": "2022-11-28" } }); } async function fixReplacements(replacements, repo) { for (const replacement of replacements) { if (replacement.type === "replace") { let files = replacement.files; if (!Array.isArray(files)) { files = [files]; } replacement.files = files.map((file) => join(".", repo.path, file)); await replaceInFile(replacement); } else if (replacement.type === "pkg") { const file = resolve(".", repo.path, "package.json"); const packageJson = await readPackageJSON(file); await writePackageJSON(file, replacement.replace(packageJson, repo)); } } } const packageReplacement = { type: "pkg", replace: (packageJson, repo) => { const fullRepo = `${repo.owner.id}/${repo.name}`; packageJson.name = `@${repo.owner.id.toLowerCase()}/${repo.name}`; packageJson.author = repo.owner.name || repo.owner.id; packageJson.description = repo.description; packageJson.version = "0.0.1"; packageJson.repository = { type: "github", url: `git+ssh://git@github.com/${fullRepo}.git` }; if (repo.keywords) packageJson.keywords = repo.keywords; if (packageJson.homepage) packageJson.homepage = `https://github.com/${fullRepo}`; if (packageJson.bugs) packageJson.bugs = `https://github.com/${fullRepo}/issues`; return packageJson; } }; function getReadmeReplacement(template, repo) { return { type: "replace", files: ["README.md"], from: [ new RegExp(template.owner, "gi"), new RegExp(template.repo, "g"), new RegExp(camelCase(template.repo), "g"), new RegExp(pascalCase(template.repo), "g"), "_description_" ], to: [ repo.owner.id.toLowerCase(), repo.name, camelCase(repo.name), pascalCase(repo.name), repo.description ] }; } const nitroPluginTemplate = { path: "releases", owner: "GaborTorma", repo: "mwm-nitro-plugin-template", branch: "main", getReplacements(repo) { return [ packageReplacement, getReadmeReplacement(this, repo) ]; } }; const nuxtLayerTemplate = { path: "layers", owner: "GaborTorma", repo: "mwm-nuxt-layer-template", branch: "main", getReplacements(repo) { return [ packageReplacement, getReadmeReplacement(this, repo) ]; } }; const nuxtModuleTemplate = { path: "modules", owner: "GaborTorma", repo: "mwm-nuxt-module-template", branch: "main", getReplacements(repo) { return [ packageReplacement, getReadmeReplacement(this, repo), { // configKey type: "replace", files: [ "playground/nuxt.config.ts", "src/module.ts" ], from: new RegExp(camelCase(this.repo), "g"), to: camelCase(repo.name) }, { // module name type: "replace", files: [ "src/module.ts", "src/runtime/plugin.ts" ], from: new RegExp(this.repo, "g"), to: repo.name } ]; } }; const templateTypes = ["nuxt-layer", "nuxt-module", "nitro-plugin"]; const templates = { "nuxt-layer": nuxtLayerTemplate, "nuxt-module": nuxtModuleTemplate, "nitro-plugin": nitroPluginTemplate }; async function selectTemplate(template) { if (!templates[template]) { template = await consola.prompt("Select template", { type: "select", options: templateTypes }); checkCancel(template); } return templates[template]; } async function getGit(repo) { return git({ baseDir: path.resolve(repo.path) }); } async function addRemoteTemplate(template, repo) { const git = await getGit(repo); await git.addRemote("template", `git@github.com:${template.owner}/${template.repo}.git`); await git.fetch("template", "main"); await git.merge([`template/${template.branch}`, "--allow-unrelated-histories", "--message=Merge template"]); } async function commitInitChanges(repo) { const git = await getGit(repo); await git.add("."); await git.commit("Customize template"); } async function pushChanges(repo) { const git = await getGit(repo); await git.push("origin", "main"); } export { getAddRemoteTemplate as a, addRemoteTemplate as b, cloneRepo as c, getFixReplacements as d, commitInitChanges as e, fixReplacements as f, generateGitHubRepo as g, packageReplacement as h, getRepo as i, selectTemplate as j, getRepoUrl as k, getClone as l, pushChanges as p, sleep as s };