UNPKG

@haxtheweb/create

Version:

CLI for all things HAX the web

374 lines (370 loc) 16.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.partyActions = partyActions; exports.partyCommandDetected = partyCommandDetected; var fs = _interopRequireWildcard(require("node:fs")); var _utils = require("../utils.js"); var _open = _interopRequireDefault(require("open")); var p = _interopRequireWildcard(require("@clack/prompts")); var _picocolors = _interopRequireDefault(require("picocolors")); var _statements = require("../statements.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } const osPathCmd = process.platform === "win32" ? "where.exe" : "which"; let sysGit = true; (0, _utils.exec)(`${osPathCmd} git`, error => { if (error) { sysGit = false; } }); let sysGh = true; (0, _utils.exec)(`${osPathCmd} gh`, error => { if (error) { sysGh = false; } }); let sysSSH = true; function partyActions() { return [{ value: 'docs', label: "View the HAX documentation" }, { value: 'playground', label: "Explore HAX.cloud playground" }, { value: 'psu', label: "Visit official hax.psu.edu site" }, { value: 'issues', label: "Engage with HAX issues on GitHub" }, { value: 'discord', label: "Join the HAX Discord community" }, { value: 'club', label: "Check out HAX The Club at PSU" }, { value: 'github', label: "Contribute to core development for HAX" }]; } async function partyCommandDetected(commandRun) { if (!commandRun.options.quiet) { p.intro(`${_picocolors.default.bgBlack(_picocolors.default.white(` HAXTheWeb : Party detected `))}`); } let actions = partyActions(); let actionAssigned = false; // default to status unless already set so we don't issue a create in a create if (!commandRun.arguments.action) { actionAssigned = true; commandRun.arguments.action = 'party:status'; } commandRun.command = "party"; let operation = { ...commandRun.arguments, ...commandRun.options }; actions.push({ value: 'quit', label: "🚪 Quit" }); while (operation.action !== 'quit') { if (!operation.action) { commandRun = { command: null, arguments: {}, options: { npmClient: `${operation.npmClient}`, author: `${operation.author}` } }; operation = await p.group({ action: ({ results }) => p.select({ message: `Actions you can take:`, defaultValue: actions[0], initialValue: actions[0], options: actions }) }, { onCancel: () => { if (!commandRun.options.quiet) { p.cancel('🧙 Merlin: Canceling CLI.. HAX ya later 🪄'); } process.exit(0); } }); } if (operation.action) { p.intro(`hax party ${_picocolors.default.bold(operation.action)}`); } switch (operation.action) { case "party:status": case "party:stats": if (!commandRun.options.quiet) { p.intro(`${_picocolors.default.green(_picocolors.default.bold(` 888 888 88888b. 8888b. 888d888888888888 888 888 "88b "88b888P" 888 888 888 888 888.d888888888 888 888 888 888 d88P888 888888 Y88b. Y88b 888 88888P" "Y888888888 "Y888 "Y88888 888 888 888 Y8bd88P`))}`); } ; break; case "docs": // open the docs p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` HAX Documentation `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Opening in browser `))}`); await (0, _open.default)("https://haxtheweb.org/"); p.outro(`${_picocolors.default.bgBlue(_picocolors.default.white(` https://haxtheweb.org/ `))}`); break; case "playground": // open the playground p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` HAX Playground `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Opening in browser `))}`); await (0, _open.default)("https://hax.cloud/"); p.outro(`${_picocolors.default.bgBlue(_picocolors.default.white(` https://hax.cloud/ `))}`); break; case "psu": // open the psu site p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` HAX PSU `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Opening in browser `))}`); await (0, _open.default)("https://hax.psu.edu/"); p.outro(`${_picocolors.default.bgBlue(_picocolors.default.white(` https://hax.psu.edu/ `))}`); break; case "issues": // open the issues p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` HAX Issues on Github `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Opening in browser `))}`); await (0, _open.default)("https://github.com/haxtheweb/issues/issues"); p.outro(`${_picocolors.default.bgBlue(_picocolors.default.white(` https://github.com/haxtheweb/issues/issues `))}`); break; case "discord": // open the discord p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` HAX Discord `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Opening in browser `))}`); await (0, _open.default)("https://discord.gg/EKYJAjqGhf"); p.outro(`${_picocolors.default.bgBlue(_picocolors.default.white(` https://discord.gg/EKYJAjqGhf `))}`); break; case "club": // open the club p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` HAX The Club is a student organization at PSU `))}`); p.intro(`${_picocolors.default.bgBlue(_picocolors.default.white(` Opening in browser `))}`); await (0, _open.default)("https://orgcentral.psu.edu/organization/hax-the-club"); p.outro(`${_picocolors.default.bgBlue(_picocolors.default.white(` https://orgcentral.psu.edu/organization/hax-the-club `))}`); // we can change this to the club website when it's up break; case "gh": case "github": try { // auto and y are aliases if (!commandRun.options.root && !commandRun.options.auto) { commandRun.options.root = await p.text({ message: 'What folder will your HAX projects live in?', placeholder: process.cwd(), initialValue: process.cwd(), required: true, validate: value => { if (!value) { return "Path is required (Enter accepts default)"; } if (!fs.existsSync(value)) { return `${value} does not exist. Select a valid folder`; } } }); // subprocesses are based on the root process folder process.chdir(commandRun.options.root); } // list HAX repos const initialValues = ["webcomponents"]; const options = [{ value: "webcomponents", label: "Webcomponents Monorepo - haxtheweb/webcomponents" }, { value: "create", label: "Create CLI - haxtheweb/create" }, { value: "hax-the-club", label: "HAX The Club - haxtheweb/hax-the-club" }, { value: "haxcms-nodejs", label: "HAXcms Node.js - haxtheweb/haxcms-nodejs" }, { value: "haxcms-php", label: "HAXcms PHP - haxtheweb/haxcms-php" }, { value: "desktop", label: "HAX The Desktop - haxtheweb/desktop" }, { value: "HAXiam", label: "HAXiam - haxtheweb/HAXiam" }]; p.note(`${(0, _statements.merlinSays)(`${_picocolors.default.magenta(_picocolors.default.bold('HAX is a party,'))} so you can select ${_picocolors.default.bold('multiple')} repositories at once!`)} Remember to ${_picocolors.default.bold('fork each project')} on ${_picocolors.default.bold('GitHub')} (or you'll be asked to later!)`); if (!commandRun.options.repos && commandRun.options.auto) { commandRun.options.repos = initialValues; } else if (!commandRun.options.repos) { commandRun.options.repos = await p.multiselect({ message: 'Choose GitHub repositories to clone', initialValues: initialValues, options: options, required: false }); } else if (commandRun.options.repos.includes("all")) { commandRun.options.repos = options.map(item => item.value); } await cloneHAXRepositories(commandRun); } catch (e) {} break; case "quit": // quit process.exit(0); break; } // y or noi need to act like it ran and finish instead of looping options if (commandRun.options.y || !commandRun.options.i || !actionAssigned) { process.exit(0); } operation.action = null; } } async function cloneHAXRepositories(commandRun) { let s = p.spinner(); // check for system dependencies: ssh, yarn, etc. if (!sysGit) { console.error(`${_picocolors.default.red(`Git is not installed. The Git CLI is required to access GitHub with ${_picocolors.default.bold('hax party')}.`)} Please follow the instructions at: ${_picocolors.default.underline(_picocolors.default.cyan(`https://git-scm.com/book/en/v2/Getting-Started-Installing-Git`))}`); process.exit(1); } if (!sysGh) { try { const { stdout, stderr } = await (0, _utils.exec)('ssh -T git@github.com'); } catch (error) { // The GitHub SSH test always returns as stderr if (!error.stderr.includes('successfully authenticated')) { sysSSH = false; } } if (!sysSSH) { console.error(`${_picocolors.default.red(`SSH keys are not set up correctly. SSH is required to access GitHub with ${_picocolors.default.bold('hax party')}.`)} Please follow the instructions at: ${_picocolors.default.underline(_picocolors.default.cyan(`https://docs.github.com/en/authentication/connecting-to-github-with-ssh`))}`); process.exit(1); } } else { // gh cli can make new ssh keys and push them to GitHub try { await (0, _utils.exec)('gh auth status'); } catch { console.log(`${_picocolors.default.red(`You have GitHub CLI installed, but it is not properly authenticated.`)} To access GitHub with ${_picocolors.default.bold('hax party')}, please follow this guided login: Select the ${_picocolors.default.cyan(`Generate a new SSH key`)} and ${_picocolors.default.cyan(`Login with a web browser`)} options`); await (0, _utils.interactiveExec)('gh', ['auth', 'login', '-p', 'ssh', '--clipboard']); } } try { await (0, _utils.exec)(`yarn --version`); } catch (e) { await (0, _utils.exec)(`npm install -g yarn`); } for (const item of commandRun.options.repos) { // If GitHub CLI is installed if (sysGh) { try { // ssh link is used since https prompts for password s.start(`Cloning ${_picocolors.default.bold(item)} to ${_picocolors.default.bold(process.cwd())}`); await (0, _utils.exec)(`git clone git@github.com:${commandRun.options.author}/${item}.git`); s.stop(`${_picocolors.default.green("Successfully")} cloned ${_picocolors.default.bold(item)} to ${_picocolors.default.bold(process.cwd())}`); } catch (e) { // skip the loop if the repo already exists if (e.stderr.includes("already exists and is not an empty directory")) { s.stop(`${_picocolors.default.yellow(`${_picocolors.default.bold(`${item}`)} already exists in ${_picocolors.default.bold(process.cwd())}`)}`); break; } s.stop(`${_picocolors.default.red("Failed")} to clone ${_picocolors.default.bold(item)} to ${_picocolors.default.bold(process.cwd())}`); p.note(`${_picocolors.default.red(`Error: HAX could not find your personal ${_picocolors.default.bold("fork")} of the ${_picocolors.default.bold(item)} repository on GitHub`)}`); s.start(`Using ${_picocolors.default.bold(`gh repo`)} utility to fork and clone ${_picocolors.default.bold(item)}`); await (0, _utils.exec)(`gh repo fork haxtheweb/${item} --clone`); s.stop(`${_picocolors.default.green("Successfully")} cloned ${_picocolors.default.bold(item)} to ${_picocolors.default.bold(process.cwd())}`); } } // Standard git, not GitHub CLI else { // while loop keeps HAX active until the user is ready let isForked = false; let firstRun = true; while (!isForked) { try { // ssh link is used since https prompts for password if (firstRun) { s.start(`Cloning ${_picocolors.default.bold(item)} to ${_picocolors.default.bold(process.cwd())}`); } else { s.start(`Trying again... Cloning ${item} to ${_picocolors.default.bold(process.cwd())}`); } await (0, _utils.exec)(`git clone git@github.com:${commandRun.options.author}/${item}.git`); s.stop(`${_picocolors.default.green("Successfully")} cloned ${_picocolors.default.bold(item)} to ${_picocolors.default.bold(process.cwd())}`); isForked = true; } catch (e) { // skip the loop if the repo already exists if (e.stderr.includes("already exists and is not an empty directory")) { s.stop(`${_picocolors.default.yellow(`${_picocolors.default.bold(`${item}`)} already exists in ${_picocolors.default.bold(process.cwd())}`)}`); break; } s.stop(`${_picocolors.default.red("Failed")} to clone ${_picocolors.default.bold(item)} to ${_picocolors.default.bold(process.cwd())}`); p.note(`${_picocolors.default.red(`Error: HAX cannot find a personal ${_picocolors.default.bold("fork")} of the ${_picocolors.default.bold(item)} repository on your GitHub account`)} Use the following link to fork ${_picocolors.default.bold(item)}: ${_picocolors.default.underline(_picocolors.default.cyan(`https://github.com/haxtheweb/${item}/fork`))}`); // We don't want to spam the link every time if (firstRun) { p.intro(`${(0, _statements.merlinSays)("The link will open in your browser in a few seconds")}`); setTimeout(async () => { await (0, _open.default)(`https://github.com/haxtheweb/${item}/fork`); }, 3000); firstRun = false; } let response = await p.confirm({ message: `Have you forked the repository? Would you like to try again?`, initialValue: true }); // Multiple ways to quit (select no, ctrl+c, etc) if (p.isCancel(response) || !response) { p.cancel('🧙 Merlin: Canceling CLI.. HAX ya later 🪄'); process.exit(0); } } } } s.start(`Installing dependencies for ${item}`); switch (item) { case "webcomponents": await (0, _utils.exec)(`yarn global add lerna web-component-analyzer`); await (0, _utils.exec)(`cd ${process.cwd()}/${item} && yarn install`); break; case "create": case "hax-the-club": case "haxcms-nodejs": case "desktop": await (0, _utils.exec)(`cd ${process.cwd()}/${item} && ${commandRun.options.npmClient} install`); break; case "haxcms-php": // ddev setup break; case "HAXiam": // curl setup? break; } s.stop(`Dependencies installed for ${item}`); } ; }