account management cli command

This commit is contained in:
Laura Liberda 2021-02-14 20:44:51 +01:00
parent 3f20cfde24
commit d19a3653a9
3 changed files with 195 additions and 0 deletions

View file

@ -46,6 +46,7 @@
"fs-extra": "^9.1.0",
"got": "^11.8.1",
"graphql": "^15.5.0",
"inquirer": "^7.3.3",
"simple-git": "^2.31.0"
},
"devDependencies": {
@ -55,6 +56,8 @@
"@oclif/dev-cli": "^1.26.0",
"@types/fs-extra": "^9.0.6",
"@types/iarna__toml": "^2.0.1",
"@types/inquirer": "^7.3.1",
"@types/node": "^14.14.25",
"eslint": "^7.19.0",
"eslint-config-airbnb-typescript": "^12.0.0",
"eslint-config-prettier": "^7.2.0",

165
src/cli/account.ts Normal file
View file

@ -0,0 +1,165 @@
import { Command, flags } from '@oclif/command';
import assert from 'assert';
import child from 'child_process';
import inquirer from 'inquirer';
import {
CopycatProfile,
CopycatProfileBase,
Vendor,
VENDOR_TYPE,
CopycatVendorConfig,
} from '../types';
import { getConfig, getConfigPath, setConfig } from '../utils';
export default class Account extends Command {
static description = 'manage accounts used by copycat';
static flags = {
help: flags.help({ char: 'h' }),
};
static args = [
{
name: 'subcommand',
required: true,
options: ['get', 'list', 'edit', 'create'],
description: 'the action to run with the accounts',
},
{
name: 'name',
description: 'account name (for "get" subcommand)',
},
];
static strict = true;
protected getPrintableAccountInfo(account: CopycatProfile) {
return `
Name:\t${account.name}
Vendor:\t${account.vendor.type}
Domain:\t${account.config.domain}
`
.trim()
.split('\n')
.map((l) => l.trim())
.join('\n');
}
async run() {
const { args } = this.parse(Account);
const config = getConfig();
const { vendorConfigs } = config;
switch (args.subcommand) {
case 'list':
console.log(vendorConfigs.map(this.getPrintableAccountInfo).join('\n---\n'));
break;
case 'get':
const account = vendorConfigs.find((con) => con.name === args.name);
if (account) {
console.log(this.getPrintableAccountInfo(account));
} else {
console.log('Account not found');
}
break;
case 'edit':
child.spawn(process.env.EDITOR || 'micro', [getConfigPath()]);
break;
case 'create':
const answers = (await inquirer.prompt([
{
type: 'list',
name: 'type',
message: 'Vendor type',
choices: Object.values(VENDOR_TYPE),
},
{
type: 'input',
name: 'domain',
message: 'Vendor domain',
default: ({ type }: { type: VENDOR_TYPE }) => {
if (type === VENDOR_TYPE.GITHUB) {
return 'github.com';
}
return null;
},
validate: (val: string) => {
try {
const url = new URL('https://' + val);
assert(url.pathname === '/');
return true;
} catch (e) {
return 'Enter valid domain name';
}
},
},
{
type: 'password',
name: 'token',
message: ({ type, domain }: { type: VENDOR_TYPE; domain: string }) => {
let tokenGettingURL: string | null = null;
let scopes: string = '[unknown]';
if (type === VENDOR_TYPE.GITHUB) {
tokenGettingURL = `https://${domain}/settings/tokens/new`;
scopes = 'repo or public_repo';
} else if (type === VENDOR_TYPE.GITLAB) {
tokenGettingURL = `https://${domain}/-/profile/personal_access_tokens`;
scopes = 'api';
}
return (
'Authentication token' +
(tokenGettingURL
? ` (you can get a one here: ${tokenGettingURL} , required scopes are: ${scopes})`
: '')
);
},
validate: (val: string) => {
if (!val) {
return 'Enter a token';
}
return true;
},
mask: '*',
},
{
type: 'input',
name: 'name',
message: 'Choose a name for your account to reference to it',
validate: (val: string) => {
if (!val) {
return 'Enter a name';
}
if (config.vendorConfigs.find((v) => v.name === val)) {
return 'Account name must be unique';
}
return true;
},
},
])) as {
type: VENDOR_TYPE;
domain: string;
token: string;
name: string;
};
config.vendorConfigs.push({
vendor: {
type: answers.type,
domain: answers.domain,
},
config: {
domain: answers.domain,
token: answers.token,
},
name: answers.name,
} as CopycatProfile);
setConfig(config);
break;
}
}
}

View file

@ -1218,6 +1218,14 @@
dependencies:
"@types/node" "*"
"@types/inquirer@^7.3.1":
version "7.3.1"
resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.1.tgz#1f231224e7df11ccfaf4cf9acbcc3b935fea292d"
integrity sha512-osD38QVIfcdgsPCT0V3lD7eH0OFurX71Jft18bZrsVQWVRt6TuxRzlr0GJLrxoHZR2V5ph7/qP8se/dcnI7o0g==
dependencies:
"@types/through" "*"
rxjs "^6.4.0"
"@types/js-yaml@^3.12.5":
version "3.12.5"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.5.tgz#136d5e6a57a931e1cce6f9d8126aa98a9c92a6bb"
@ -1257,6 +1265,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1"
integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==
"@types/node@^14.14.25":
version "14.14.25"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.25.tgz#15967a7b577ff81383f9b888aa6705d43fbbae93"
integrity sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@ -1269,6 +1282,13 @@
dependencies:
"@types/node" "*"
"@types/through@*":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==
dependencies:
"@types/node" "*"
"@types/websocket@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.1.tgz#039272c196c2c0e4868a0d8a1a27bbb86e9e9138"
@ -4971,6 +4991,13 @@ rxjs@^6.3.3, rxjs@^6.6.0:
dependencies:
tslib "^1.9.0"
rxjs@^6.4.0:
version "6.6.3"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552"
integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==
dependencies:
tslib "^1.9.0"
safe-buffer@^5.0.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"