Skip to content
This repository was archived by the owner on Aug 22, 2023. It is now read-only.

Commit 7fc7932

Browse files
committed
feat: implemented base commad
1 parent 9efef67 commit 7fc7932

20 files changed

+480
-304
lines changed

.circleci/config.yml

+3-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- v0-yarn-{{ .Environment.CIRCLE_JOB }}-{{checksum "scripts/circleci"}}-{{checksum ".circleci/config.yml"}}-{{ .Branch }}-{{checksum "yarn.lock"}}
1313
- v0-yarn-{{ .Environment.CIRCLE_JOB }}-{{checksum "scripts/circleci"}}-{{checksum ".circleci/config.yml"}}-{{ .Branch }}-
1414
- v0-yarn-{{ .Environment.CIRCLE_JOB }}-{{checksum "scripts/circleci"}}-{{checksum ".circleci/config.yml"}}-master-
15-
- run: ./scripts/circleci
15+
- run: ./scripts/circleci test
1616
- store_test_results:
1717
path: ~/cli/reports
1818
- save_cache: &save_cache
@@ -30,13 +30,12 @@ jobs:
3030
steps:
3131
- checkout
3232
- restore_cache: *restore_cache
33-
- run: yarn
34-
- run: ./node_modules/.bin/dxcli-dev-semantic-release
33+
- run: ./scripts/circleci release
3534
- save_cache: *save_cache
3635

3736
workflows:
3837
version: 2
39-
test:
38+
"@dxcli/command":
4039
jobs:
4140
- node-latest
4241
- node-8

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
* text=auto
2+
*.js text eol=lf
3+
*.ts text eol=lf

.gitignore

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
*-debug.log
22
*-error.log
3+
/.nyc_output
34
/coverage
5+
/coverage.lcov
6+
/lib
47
/node_modules
58
/tmp
6-
/lib
7-
/.nyc_output

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
@dxcli/command
22
==============
33

4+
dxcli base command
5+
46
[![Version](https://img.shields.io/npm/v/@dxcli/command.svg)](https://npmjs.org/package/@dxcli/command)
57
[![CircleCI](https://circleci.com/gh/dxcli/command/tree/master.svg?style=svg)](https://circleci.com/gh/dxcli/command/tree/master)
68
[![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/dxcli/command?branch=master&svg=true)](https://ci.appveyor.com/project/heroku/command/branch/master)

appveyor.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ environment:
22
nodejs_version: "9"
33
cache:
44
- '%LOCALAPPDATA%\Yarn -> appveyor.yml'
5-
- node_modules -> package.json
5+
- node_modules -> yarn.lock
66

77
install:
88
- ps: Install-Product node $env:nodejs_version x64
9+
- git submodule sync
10+
- git submodule update --init --recursive
11+
- git config --global user.email "[email protected]"
12+
- git config --global user.name "dxcli"
913
- yarn
1014
test_script:
1115
- yarn test

example/ls.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env ts-node
2+
3+
import cli from 'cli-ux'
4+
import * as fs from 'fs'
5+
6+
import Command, {flags} from '..' // use @dxcli/command outside this repo
7+
8+
class LS extends Command {
9+
static flags = {
10+
// run with --dir= or -d=
11+
dir: flags.string({
12+
char: 'd',
13+
default: process.cwd(),
14+
}),
15+
}
16+
17+
async run() {
18+
let files = fs.readdirSync(this.flags.dir)
19+
for (let f of files) {
20+
cli.log(f)
21+
}
22+
}
23+
}
24+
25+
LS.run()

example/tsconfig.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "../tsconfig",
3+
"compilerOptions": {
4+
"rootDir": ".."
5+
},
6+
"include": [
7+
"../examples/**/*",
8+
"../src/**/*",
9+
"../test/**/*"
10+
]
11+
}

package.json

+29-14
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,25 @@
33
"description": "dxcli base command",
44
"version": "0.0.0",
55
"author": "Jeff Dickey @jdxcode",
6-
"dependencies": {},
6+
"bugs": "https://github.com/dxcli/command/issues",
7+
"dependencies": {
8+
"@dxcli/config": "^0.1.1",
9+
"@dxcli/parser": "^0.0.2",
10+
"@dxcli/screen": "^0.0.0",
11+
"cli-ux": "^3.0.0-alpha.1",
12+
"debug": "^3.1.0",
13+
"http-call": "^5.0.0"
14+
},
715
"devDependencies": {
8-
"@dxcli/dev": "^1.1.0",
16+
"@dxcli/dev": "^1.1.3",
917
"@dxcli/dev-semantic-release": "^0.0.3",
10-
"@dxcli/dev-test": "^0.0.1",
11-
"@dxcli/dev-tslint": "^0.0.6",
18+
"@dxcli/dev-test": "^0.2.1",
19+
"@dxcli/dev-tslint": "^0.0.15",
1220
"@types/node": "^9.3.0",
13-
"del-cli": "^1.1.0",
21+
"@types/read-pkg-up": "^3.0.0",
22+
"@types/semver": "^5.4.0",
1423
"eslint": "^4.15.0",
15-
"eslint-config-dxcli": "^1.1.3",
24+
"eslint-config-dxcli": "^1.1.4",
1625
"husky": "^0.14.3",
1726
"mocha": "^4.1.0",
1827
"nyc": "^11.4.1",
@@ -23,16 +32,16 @@
2332
"workflows": {
2433
"test": [
2534
"eslint .",
26-
"tsc",
27-
"tslint -p .",
28-
"commitlint --from master",
35+
"tsc -p test --noEmit",
36+
"tslint -p test",
37+
"commitlint --from origin/master",
2938
"mocha \"test/**/*.ts\""
3039
],
3140
"lint": [
3241
"eslint .",
33-
"tsc",
34-
"tslint -p .",
35-
"commitlint --from master"
42+
"tsc -p test --noEmit",
43+
"tslint -p test",
44+
"commitlint --from origin/master"
3645
]
3746
}
3847
},
@@ -42,13 +51,19 @@
4251
"files": [
4352
"/lib"
4453
],
54+
"homepage": "https://github.com/dxcli/command",
55+
"keywords": [
56+
"dxcli"
57+
],
4558
"license": "MIT",
59+
"main": "lib/index.js",
4660
"repository": "dxcli/command",
4761
"scripts": {
4862
"commitmsg": "dxcli-dev-commitmsg",
4963
"lint": "dxcli-dev lint",
5064
"precommit": "dxcli-dev lint",
51-
"prepare": "del-cli ./lib && tsc",
65+
"prepare": "rm -rf lib && tsc",
5266
"test": "dxcli-dev test"
53-
}
67+
},
68+
"types": "lib/index.d.ts"
5469
}

scripts/circleci

+54-23
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,64 @@
22

33
set -ex
44

5+
duration() {
6+
set +x
7+
start=$(date +%s)
8+
"$@"
9+
end=$(date +%s)
10+
python -c "print 'Ran $1 in %u:%02u' % ((${end} - ${start})/60, (${end} - ${start})%60)"
11+
set -x
12+
}
13+
514
PATH=/usr/local/share/.config/yarn/global/node_modules/.bin:$PATH
615

7-
CLI_ENGINE_UTIL_YARN_ARGS="--frozen-lockfile"
16+
if [[ ! -z "$GIT_EMAIL" ]] & [[ ! -z "$GIT_USERNAME" ]]; then
17+
git config --global push.default simple
18+
git config --global user.email "$GIT_EMAIL"
19+
git config --global user.user "$GIT_USERNAME"
20+
fi
21+
22+
git submodule sync
23+
git submodule update --init --recursive
824

9-
if [[ "$CIRCLE_BRANCH" == greenkeeper/* ]]; then
10-
CLI_ENGINE_GREENKEEPER_BRANCH=1
11-
CLI_ENGINE_UTIL_YARN_ARGS=""
12-
if [[ ! -x "$(command -v greenkeeper-lockfile-update)" ]]; then
13-
yarn global add greenkeeper-lockfile@1
25+
_test() {
26+
CLI_ENGINE_UTIL_YARN_ARGS="--frozen-lockfile"
27+
28+
if [[ "$CIRCLE_BRANCH" == greenkeeper/* ]]; then
29+
CLI_ENGINE_GREENKEEPER_BRANCH=1
30+
CLI_ENGINE_UTIL_YARN_ARGS=""
31+
if [[ ! -x "$(command -v greenkeeper-lockfile-update)" ]]; then
32+
duration yarn global add greenkeeper-lockfile@1
33+
fi
34+
duration greenkeeper-lockfile-update
1435
fi
15-
greenkeeper-lockfile-update
16-
fi
1736

18-
yarn install $CLI_ENGINE_UTIL_YARN_ARGS
37+
duration yarn install $CLI_ENGINE_UTIL_YARN_ARGS
1938

20-
if [[ "$CLI_ENGINE_GREENKEEPER_BRANCH" == 1 ]]; then
21-
greenkeeper-lockfile-upload
22-
fi
39+
if [[ "$CLI_ENGINE_GREENKEEPER_BRANCH" == 1 ]]; then
40+
duration greenkeeper-lockfile-upload
41+
fi
42+
43+
CWD=$(pwd)
44+
NYC=(./node_modules/.bin/nyc --nycrc-path node_modules/@dxcli/dev-nyc-config/.nycrc)
45+
mkdir -p reports
46+
MOCHA_FILE="$CWD/reports/mocha.xml" \
47+
DXCLI_MOCHA_OPTS="--reporter mocha-junit-reporter" \
48+
DXCLI_ESLINT_OPTS="--format junit --output-file $CWD/reports/eslint.xml" \
49+
DXCLI_TSLINT_OPTS="--format junit > $CWD/reports/tslint.xml" \
50+
duration "${NYC[@]}" yarn test
51+
52+
duration "${NYC[@]}" report --reporter=text-lcov > coverage.lcov
53+
54+
duration curl -s https://codecov.io/bash | bash
55+
}
56+
57+
_release() {
58+
yarn --frozen-lockfile
59+
./node_modules/.bin/dxcli-dev-semantic-release
60+
}
2361

24-
CWD=$(pwd)
25-
NYC="./node_modules/.bin/nyc --nycrc-path node_modules/@dxcli/dev-nyc-config/.nycrc"
26-
mkdir -p reports
27-
MOCHA_FILE="$CWD/reports/mocha.xml" \
28-
DXCLI_MOCHA_OPTS="--reporter mocha-junit-reporter" \
29-
DXCLI_ESLINT_OPTS="--format junit --output-file $CWD/reports/eslint.xml" \
30-
DXCLI_TSLINT_OPTS="--format junit > $CWD/reports/tslint.xml" \
31-
$NYC yarn test
32-
$NYC report --reporter=text-lcov > coverage.lcov
33-
34-
curl -s https://codecov.io/bash | bash
62+
case "$1" in
63+
release) _release;;
64+
*) _test;;
65+
esac

src/command.ts

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
const pjson = require('../package.json')
2+
import {ConfigOptions, IConfig, IPlugin, isIConfig, PluginConfig} from '@dxcli/config'
3+
import {args} from '@dxcli/parser'
4+
import {HTTP} from 'http-call'
5+
6+
import deps from './deps'
7+
import * as flags from './flags'
8+
9+
export type CommandRunFn = <T extends Command>(this: ICommandClass<T>, argv?: string[], config?: IConfig | ConfigOptions) => Promise<T>
10+
11+
export interface ICommandClass<T extends Command> {
12+
run: CommandRunFn
13+
new (config: IConfig): T
14+
}
15+
16+
const parentModule = module.parent && module.parent.parent && module.parent.parent.filename
17+
18+
export default abstract class Command {
19+
static id?: string
20+
static description: string | undefined
21+
static hidden: boolean
22+
static usage: string | undefined
23+
static help: string | undefined
24+
static aliases: string[] = []
25+
static variableArgs = false
26+
static flags: flags.Input
27+
static args: args.IArg[] = []
28+
static _base = `${pjson.name}@${pjson.version}`
29+
static plugin: IPlugin | undefined
30+
31+
/**
32+
* instantiate and run the command
33+
*/
34+
static run: CommandRunFn = async function (argv: string[] = process.argv.slice(2), config: IConfig | ConfigOptions = {}) {
35+
if (!isIConfig(config)) config = await PluginConfig.create({root: parentModule!, ...config})
36+
const cmd = new this(config as any)
37+
try {
38+
await cmd.init(argv)
39+
await cmd.run()
40+
await cmd.done()
41+
} catch (err) {
42+
// throw HelpErr to allow the CLI to do something with it
43+
if (err.code === 'EHELP') throw err
44+
deps.cli.error(err)
45+
}
46+
return cmd
47+
}
48+
49+
flags: { [name: string]: any } = {}
50+
argv: string[]
51+
args: { [name: string]: string } = {}
52+
53+
// prevent setting things that need to be static
54+
topic: null
55+
command: null
56+
description: null
57+
hidden: null
58+
usage: null
59+
help: null
60+
aliases: null
61+
62+
protected debug: (...args: any[]) => void
63+
64+
get ctor(): typeof Command {
65+
return this.constructor as typeof Command
66+
}
67+
68+
get http(): typeof HTTP { return require('http-call').HTTP }
69+
70+
constructor(protected config: IConfig) {
71+
global['http-call'] = global['http-call'] || {}
72+
global['http-call']!.userAgent = config.userAgent
73+
this.debug = require('debug')(`cli:command:${this.ctor.id || config.name}`)
74+
}
75+
76+
/**
77+
* actual command run code goes here
78+
*/
79+
abstract async run(): Promise<void>
80+
81+
protected async init(argv: string[]) {
82+
this.debug('init version: %s argv: %o', this.ctor._base, argv)
83+
deps.cli.config.errlog = this.config.errlog
84+
try {
85+
const parse = await deps.Parser.parse({
86+
argv,
87+
args: this.ctor.args || [],
88+
flags: this.ctor.flags || {},
89+
strict: !this.ctor.variableArgs,
90+
})
91+
this.flags = parse.flags
92+
this.argv = parse.argv
93+
this.args = parse.args
94+
} catch (err) {
95+
if (err.message.match(/^Unexpected argument: (-h|help|--help)/)) {
96+
throw new deps.HelpErr(err.message)
97+
}
98+
throw err
99+
}
100+
}
101+
102+
protected async done() {
103+
try {
104+
await deps.cli.done()
105+
} catch (err) {
106+
deps.cli.warn(err)
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)