From e378e4f18981931e01be022ba05c7046a98ff6d2 Mon Sep 17 00:00:00 2001 From: Ryan Garant Date: Tue, 24 Sep 2019 21:10:24 -0700 Subject: [PATCH] refactor(options): make options immutable with immer --- .vscode/launch.json | 4 +- package-lock.json | 7 +++- package.json | 1 + src/base.ts | 12 ------ src/cmd.ts | 95 ++++++++++++++++++++++++++------------------- src/cmds/help.ts | 3 +- src/cmds/repo.ts | 6 ++- src/cmds/user.ts | 5 ++- src/git.ts | 4 ++ 9 files changed, 77 insertions(+), 60 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 3c762649..96b06197 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "node", "request": "launch", "runtimeArgs": ["-r", "ts-node/register"], - "args": ["${workspaceFolder}/src/debug.ts", "user", "--user=zeno"], + "args": ["${workspaceFolder}/src/debug.ts", "us", "--whoami"], // "args": ["${workspaceFolder}/src/debug.ts", "ji", "LWM-117", "--status"], "console": "integratedTerminal" }, @@ -19,7 +19,7 @@ "request": "launch", "env": { "NODE_ENV": "testing", "GH_USER": "protoEvangelion", "GH_TOKEN": "0001" }, "runtimeArgs": ["-r", "ts-node/register"], - "args": ["${workspaceFolder}/src/debug.ts", "pr", "659", "--browser"], + "args": ["${workspaceFolder}/src/debug.ts", "re", "--new", "foo", "--init"], "console": "integratedTerminal" } ] diff --git a/package-lock.json b/package-lock.json index 3b25dec7..1d54e97a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gh", - "version": "2.0.3", + "version": "2.0.6", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4606,6 +4606,11 @@ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true }, + "immer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-4.0.0.tgz", + "integrity": "sha512-374/m+biF/6Z24jiqR/u49SH095oIgYr/qLiQnR88svojs5RNJh/h9i0Qq0pqhgUon3Txx8PgUWH+obRy6jbKw==" + }, "import-fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", diff --git a/package.json b/package.json index c77f6469..8b77b8bd 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "cli-table3": "0.5.1", "colors": "1.3.3", "handlebars": "^4.2.0", + "immer": "^4.0.0", "inquirer": "6.2.1", "lodash": "^4.17.15", "marked": "^0.7.0", diff --git a/src/base.ts b/src/base.ts index 9adaf30d..1e6f6286 100644 --- a/src/base.ts +++ b/src/base.ts @@ -19,18 +19,6 @@ export function clone(o) { export function load() {} -/** - * Checks if there are aliases in your .gh.json file. - * If there are aliases in your .gh.json file, we will attempt to resolve the user, PR forwarder or PR submitter to your alias. - */ -export function expandAliases(options) { - if (config.alias) { - options.fwd = config.alias[options.fwd] || options.fwd - options.submit = config.alias[options.submit] || options.submit - options.user = config.alias[options.user] || options.user - } -} - export function find(filepath, opt_pattern) { return fs.readdirSync(filepath).filter(file => { return (opt_pattern || /.*/).test(file) diff --git a/src/cmd.ts b/src/cmd.ts index 81d943b2..cb06eb87 100755 --- a/src/cmd.ts +++ b/src/cmd.ts @@ -10,10 +10,10 @@ import * as fs from 'fs' import * as nopt from 'nopt' import * as path from 'path' import * as updateNotifier from 'update-notifier' -import { find, getUser, expandAliases } from './base' +import { find, getUser } from './base' import * as configs from './configs' import * as git from './git' -import * as logger from './logger' +import { produce, setAutoFreeze } from 'immer' const config = configs.getConfig() @@ -93,17 +93,19 @@ function notifyVersion() { } } -export async function setUp() { - let Command - let options - const parsed = nopt(process.argv) - let remain = parsed.argv.remain - let cooked = parsed.argv.cooked - +async function getCommand(args) { + /** + * nopt function returns: + * + * remain: The remaining args after all the parsing has occurred. + * original: The args as they originally appeared. + * cooked: The args after flags and shorthands are expanded. + */ + const parsed = nopt(args) + const remain = parsed.argv.remain + const cooked = parsed.argv.cooked let module = remain[0] - notifyVersion() - if (cooked[0] === '--version' || cooked[0] === '-v') { module = 'version' } else if (!remain.length || cooked.indexOf('-h') >= 0 || cooked.indexOf('--help') >= 0) { @@ -111,7 +113,7 @@ export async function setUp() { } try { - Command = await loadCommand(module) + var Command = await loadCommand(module) } catch (err) { throw new Error(`Cannot find module ${module}\n${err}`) } @@ -120,41 +122,56 @@ export async function setUp() { throw new Error(`No cmd or plugin found.`) } - options = nopt(Command.DETAILS.options, Command.DETAILS.shorthands, process.argv, 2) - - cooked = options.argv.cooked - remain = options.argv.remain - - options.number = options.number || [remain[1]] - options.remote = options.remote || config.default_remote - - const remoteUrl = git.getRemoteUrl(options.remote) + return Command +} - options.isTTY = {} - options.isTTY.in = Boolean(process.stdin.isTTY) - options.isTTY.out = Boolean(process.stdout.isTTY) - options.loggedUser = getUser() - options.remoteUser = git.getUserFromRemoteUrl(remoteUrl) +export async function setUp() { + notifyVersion() - if (!options.user) { - if (options.repo || options.all) { - options.user = options.loggedUser - } else { - options.user = process.env.GH_USER || options.remoteUser || options.loggedUser + const Command = await getCommand(process.argv) + + const args = nopt(Command.DETAILS.options, Command.DETAILS.shorthands, process.argv, 2) + + setAutoFreeze(false) + + const options = produce(args, draft => { + // Gets 2nd positional arg (`gh pr 1` will return 1) + const secondArg = [draft.argv.remain[1]] + const remote = draft.remote || config.default_remote + const remoteUrl = git.getRemoteUrl(remote) + + draft.remote = remote + draft.number = draft.number || secondArg + draft.loggedUser = getUser() + draft.remoteUser = git.getUserFromRemoteUrl(remoteUrl) + draft.repo = draft.repo || git.getRepoFromRemoteURL(remoteUrl) + draft.currentBranch = git.getCurrentBranch() + draft.github_host = config.github_host + draft.github_gist_host = config.github_gist_host + + if (!draft.user) { + if (draft.repo || draft.all) { + draft.user = draft.loggedUser + } else { + draft.user = process.env.GH_USER || draft.remoteUser || draft.loggedUser + } } - } - - expandAliases(options) - options.repo = options.repo || git.getRepoFromRemoteURL(remoteUrl) - options.currentBranch = testing ? 'master' : git.getCurrentBranch() - options.github_host = config.github_host - options.github_gist_host = config.github_gist_host + /** + * Checks if there are aliases in your .gh.json file. + * If there are aliases in your .gh.json file, we will attempt to resolve the user, PR forwarder or PR submitter to your alias. + */ + if (config.alias) { + draft.fwd = config.alias[draft.fwd] || draft.fwd + draft.submit = config.alias[draft.submit] || draft.submit + draft.user = config.alias[draft.user] || draft.user + } + }) if (testing) { const { prepareTestFixtures } = await import('./utils') - await new Command(options).run(prepareTestFixtures(Command.name, cooked)) + await new Command(options).run(prepareTestFixtures(Command.name, args.argv.cooked)) } else { await new Command(options).run() } diff --git a/src/cmds/help.ts b/src/cmds/help.ts index 6167e584..b186171d 100644 --- a/src/cmds/help.ts +++ b/src/cmds/help.ts @@ -151,8 +151,7 @@ Help.prototype.listFlags_ = function(command) { } Help.prototype.listCommands_ = function(commands) { - let content = - 'usage: gh [payload] [--flags] [--verbose] [--no-color] [--no-hooks]\n\n' + let content = 'usage: gh [--flags] [--verbose] [--no-color] [--no-hooks]\n\n' content += 'List of available commands:\n' diff --git a/src/cmds/repo.ts b/src/cmds/repo.ts index 76598539..c2027e8b 100644 --- a/src/cmds/repo.ts +++ b/src/cmds/repo.ts @@ -304,7 +304,9 @@ Repo.prototype.run = async function(done) { options.type = options.type || Repo.TYPE_OWNER } - if (options.isTTY.out) { + // Add a isTTY value on the options to determine whether or not the command is executed in a TTY context or not. + // Will be false if cmd is piped like: gh re --list | cat + if (Boolean(process.stdout.isTTY)) { logger.log( `Listing ${logger.colors.green(options.type)} repos for ${logger.colors.green( user @@ -474,7 +476,7 @@ Repo.prototype.listCallback_ = function(repos): void { logger.log(`last update ${logger.getDuration(repo.updated_at, options.date)}`) } - if (options.isTTY.out) { + if (Boolean(process.stdout.isTTY)) { logger.log( `${logger.colors.green( `forks: ${repo.forks}, stars: ${repo.watchers}, issues: ${ diff --git a/src/cmds/user.ts b/src/cmds/user.ts index a65ba15b..ab98f19e 100644 --- a/src/cmds/user.ts +++ b/src/cmds/user.ts @@ -42,12 +42,13 @@ User.DETAILS = { User.prototype.run = async function(done) { const instance = this const options = instance.options + let login if (!hasCmdInOptions(User.DETAILS.commands, options)) { - options.login = true + login = true } - if (options.login) { + if (login) { if (tokenExists()) { logger.log(`You're logged in as ${logger.colors.green(options.user)}`) } else { diff --git a/src/git.ts b/src/git.ts index cb9be682..63de32b0 100644 --- a/src/git.ts +++ b/src/git.ts @@ -148,6 +148,10 @@ export function getConfig(key) { } export function getCurrentBranch() { + if (testing) { + return 'master' + } + var git = exec.spawnSync(git_command, ['symbolic-ref', '--short', 'HEAD']) if (git.status !== 0) {