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

Commit

Permalink
feat: implemented base commad
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Jan 16, 2018
1 parent 9efef67 commit 7fc7932
Show file tree
Hide file tree
Showing 20 changed files with 480 additions and 304 deletions.
7 changes: 3 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- v0-yarn-{{ .Environment.CIRCLE_JOB }}-{{checksum "scripts/circleci"}}-{{checksum ".circleci/config.yml"}}-{{ .Branch }}-{{checksum "yarn.lock"}}
- v0-yarn-{{ .Environment.CIRCLE_JOB }}-{{checksum "scripts/circleci"}}-{{checksum ".circleci/config.yml"}}-{{ .Branch }}-
- v0-yarn-{{ .Environment.CIRCLE_JOB }}-{{checksum "scripts/circleci"}}-{{checksum ".circleci/config.yml"}}-master-
- run: ./scripts/circleci
- run: ./scripts/circleci test
- store_test_results:
path: ~/cli/reports
- save_cache: &save_cache
Expand All @@ -30,13 +30,12 @@ jobs:
steps:
- checkout
- restore_cache: *restore_cache
- run: yarn
- run: ./node_modules/.bin/dxcli-dev-semantic-release
- run: ./scripts/circleci release
- save_cache: *save_cache

workflows:
version: 2
test:
"@dxcli/command":
jobs:
- node-latest
- node-8
Expand Down
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
* text=auto
*.js text eol=lf
*.ts text eol=lf
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
*-debug.log
*-error.log
/.nyc_output
/coverage
/coverage.lcov
/lib
/node_modules
/tmp
/lib
/.nyc_output
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@dxcli/command
==============

dxcli base command

[![Version](https://img.shields.io/npm/v/@dxcli/command.svg)](https://npmjs.org/package/@dxcli/command)
[![CircleCI](https://circleci.com/gh/dxcli/command/tree/master.svg?style=svg)](https://circleci.com/gh/dxcli/command/tree/master)
[![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)
Expand Down
6 changes: 5 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ environment:
nodejs_version: "9"
cache:
- '%LOCALAPPDATA%\Yarn -> appveyor.yml'
- node_modules -> package.json
- node_modules -> yarn.lock

install:
- ps: Install-Product node $env:nodejs_version x64
- git submodule sync
- git submodule update --init --recursive
- git config --global user.email "[email protected]"
- git config --global user.name "dxcli"
- yarn
test_script:
- yarn test
Expand Down
25 changes: 25 additions & 0 deletions example/ls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env ts-node

import cli from 'cli-ux'
import * as fs from 'fs'

import Command, {flags} from '..' // use @dxcli/command outside this repo

class LS extends Command {
static flags = {
// run with --dir= or -d=
dir: flags.string({
char: 'd',
default: process.cwd(),
}),
}

async run() {
let files = fs.readdirSync(this.flags.dir)
for (let f of files) {
cli.log(f)
}
}
}

LS.run()
11 changes: 11 additions & 0 deletions example/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"rootDir": ".."
},
"include": [
"../examples/**/*",
"../src/**/*",
"../test/**/*"
]
}
43 changes: 29 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@
"description": "dxcli base command",
"version": "0.0.0",
"author": "Jeff Dickey @jdxcode",
"dependencies": {},
"bugs": "https://github.com/dxcli/command/issues",
"dependencies": {
"@dxcli/config": "^0.1.1",
"@dxcli/parser": "^0.0.2",
"@dxcli/screen": "^0.0.0",
"cli-ux": "^3.0.0-alpha.1",
"debug": "^3.1.0",
"http-call": "^5.0.0"
},
"devDependencies": {
"@dxcli/dev": "^1.1.0",
"@dxcli/dev": "^1.1.3",
"@dxcli/dev-semantic-release": "^0.0.3",
"@dxcli/dev-test": "^0.0.1",
"@dxcli/dev-tslint": "^0.0.6",
"@dxcli/dev-test": "^0.2.1",
"@dxcli/dev-tslint": "^0.0.15",
"@types/node": "^9.3.0",
"del-cli": "^1.1.0",
"@types/read-pkg-up": "^3.0.0",
"@types/semver": "^5.4.0",
"eslint": "^4.15.0",
"eslint-config-dxcli": "^1.1.3",
"eslint-config-dxcli": "^1.1.4",
"husky": "^0.14.3",
"mocha": "^4.1.0",
"nyc": "^11.4.1",
Expand All @@ -23,16 +32,16 @@
"workflows": {
"test": [
"eslint .",
"tsc",
"tslint -p .",
"commitlint --from master",
"tsc -p test --noEmit",
"tslint -p test",
"commitlint --from origin/master",
"mocha \"test/**/*.ts\""
],
"lint": [
"eslint .",
"tsc",
"tslint -p .",
"commitlint --from master"
"tsc -p test --noEmit",
"tslint -p test",
"commitlint --from origin/master"
]
}
},
Expand All @@ -42,13 +51,19 @@
"files": [
"/lib"
],
"homepage": "https://github.com/dxcli/command",
"keywords": [
"dxcli"
],
"license": "MIT",
"main": "lib/index.js",
"repository": "dxcli/command",
"scripts": {
"commitmsg": "dxcli-dev-commitmsg",
"lint": "dxcli-dev lint",
"precommit": "dxcli-dev lint",
"prepare": "del-cli ./lib && tsc",
"prepare": "rm -rf lib && tsc",
"test": "dxcli-dev test"
}
},
"types": "lib/index.d.ts"
}
77 changes: 54 additions & 23 deletions scripts/circleci
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,64 @@

set -ex

duration() {
set +x
start=$(date +%s)
"$@"
end=$(date +%s)
python -c "print 'Ran $1 in %u:%02u' % ((${end} - ${start})/60, (${end} - ${start})%60)"
set -x
}

PATH=/usr/local/share/.config/yarn/global/node_modules/.bin:$PATH

CLI_ENGINE_UTIL_YARN_ARGS="--frozen-lockfile"
if [[ ! -z "$GIT_EMAIL" ]] & [[ ! -z "$GIT_USERNAME" ]]; then
git config --global push.default simple
git config --global user.email "$GIT_EMAIL"
git config --global user.user "$GIT_USERNAME"
fi

git submodule sync
git submodule update --init --recursive

if [[ "$CIRCLE_BRANCH" == greenkeeper/* ]]; then
CLI_ENGINE_GREENKEEPER_BRANCH=1
CLI_ENGINE_UTIL_YARN_ARGS=""
if [[ ! -x "$(command -v greenkeeper-lockfile-update)" ]]; then
yarn global add greenkeeper-lockfile@1
_test() {
CLI_ENGINE_UTIL_YARN_ARGS="--frozen-lockfile"

if [[ "$CIRCLE_BRANCH" == greenkeeper/* ]]; then
CLI_ENGINE_GREENKEEPER_BRANCH=1
CLI_ENGINE_UTIL_YARN_ARGS=""
if [[ ! -x "$(command -v greenkeeper-lockfile-update)" ]]; then
duration yarn global add greenkeeper-lockfile@1
fi
duration greenkeeper-lockfile-update
fi
greenkeeper-lockfile-update
fi

yarn install $CLI_ENGINE_UTIL_YARN_ARGS
duration yarn install $CLI_ENGINE_UTIL_YARN_ARGS

if [[ "$CLI_ENGINE_GREENKEEPER_BRANCH" == 1 ]]; then
greenkeeper-lockfile-upload
fi
if [[ "$CLI_ENGINE_GREENKEEPER_BRANCH" == 1 ]]; then
duration greenkeeper-lockfile-upload
fi

CWD=$(pwd)
NYC=(./node_modules/.bin/nyc --nycrc-path node_modules/@dxcli/dev-nyc-config/.nycrc)
mkdir -p reports
MOCHA_FILE="$CWD/reports/mocha.xml" \
DXCLI_MOCHA_OPTS="--reporter mocha-junit-reporter" \
DXCLI_ESLINT_OPTS="--format junit --output-file $CWD/reports/eslint.xml" \
DXCLI_TSLINT_OPTS="--format junit > $CWD/reports/tslint.xml" \
duration "${NYC[@]}" yarn test

duration "${NYC[@]}" report --reporter=text-lcov > coverage.lcov

duration curl -s https://codecov.io/bash | bash
}

_release() {
yarn --frozen-lockfile
./node_modules/.bin/dxcli-dev-semantic-release
}

CWD=$(pwd)
NYC="./node_modules/.bin/nyc --nycrc-path node_modules/@dxcli/dev-nyc-config/.nycrc"
mkdir -p reports
MOCHA_FILE="$CWD/reports/mocha.xml" \
DXCLI_MOCHA_OPTS="--reporter mocha-junit-reporter" \
DXCLI_ESLINT_OPTS="--format junit --output-file $CWD/reports/eslint.xml" \
DXCLI_TSLINT_OPTS="--format junit > $CWD/reports/tslint.xml" \
$NYC yarn test
$NYC report --reporter=text-lcov > coverage.lcov

curl -s https://codecov.io/bash | bash
case "$1" in
release) _release;;
*) _test;;
esac
109 changes: 109 additions & 0 deletions src/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const pjson = require('../package.json')
import {ConfigOptions, IConfig, IPlugin, isIConfig, PluginConfig} from '@dxcli/config'
import {args} from '@dxcli/parser'
import {HTTP} from 'http-call'

import deps from './deps'
import * as flags from './flags'

export type CommandRunFn = <T extends Command>(this: ICommandClass<T>, argv?: string[], config?: IConfig | ConfigOptions) => Promise<T>

export interface ICommandClass<T extends Command> {
run: CommandRunFn
new (config: IConfig): T
}

const parentModule = module.parent && module.parent.parent && module.parent.parent.filename

export default abstract class Command {
static id?: string
static description: string | undefined
static hidden: boolean
static usage: string | undefined
static help: string | undefined
static aliases: string[] = []
static variableArgs = false
static flags: flags.Input
static args: args.IArg[] = []
static _base = `${pjson.name}@${pjson.version}`
static plugin: IPlugin | undefined

/**
* instantiate and run the command
*/
static run: CommandRunFn = async function (argv: string[] = process.argv.slice(2), config: IConfig | ConfigOptions = {}) {
if (!isIConfig(config)) config = await PluginConfig.create({root: parentModule!, ...config})
const cmd = new this(config as any)
try {
await cmd.init(argv)
await cmd.run()
await cmd.done()
} catch (err) {
// throw HelpErr to allow the CLI to do something with it
if (err.code === 'EHELP') throw err
deps.cli.error(err)
}
return cmd
}

flags: { [name: string]: any } = {}
argv: string[]
args: { [name: string]: string } = {}

// prevent setting things that need to be static
topic: null
command: null
description: null
hidden: null
usage: null
help: null
aliases: null

protected debug: (...args: any[]) => void

get ctor(): typeof Command {
return this.constructor as typeof Command
}

get http(): typeof HTTP { return require('http-call').HTTP }

constructor(protected config: IConfig) {
global['http-call'] = global['http-call'] || {}
global['http-call']!.userAgent = config.userAgent
this.debug = require('debug')(`cli:command:${this.ctor.id || config.name}`)
}

/**
* actual command run code goes here
*/
abstract async run(): Promise<void>

protected async init(argv: string[]) {
this.debug('init version: %s argv: %o', this.ctor._base, argv)
deps.cli.config.errlog = this.config.errlog
try {
const parse = await deps.Parser.parse({
argv,
args: this.ctor.args || [],
flags: this.ctor.flags || {},
strict: !this.ctor.variableArgs,
})
this.flags = parse.flags
this.argv = parse.argv
this.args = parse.args
} catch (err) {
if (err.message.match(/^Unexpected argument: (-h|help|--help)/)) {
throw new deps.HelpErr(err.message)
}
throw err
}
}

protected async done() {
try {
await deps.cli.done()
} catch (err) {
deps.cli.warn(err)
}
}
}
Loading

0 comments on commit 7fc7932

Please sign in to comment.