Skip to content

Commit

Permalink
feat: add hook generator (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Mar 23, 2018
1 parent 6e4cdc2 commit 4106708
Show file tree
Hide file tree
Showing 16 changed files with 141 additions and 19 deletions.
16 changes: 16 additions & 0 deletions .circleci/config.yml
Expand Up @@ -67,6 +67,17 @@ jobs:
- run: .circleci/setup_git
- run: yarn exec nps test.command
- store_test_results: *store_test_results
node-latest-hook:
<<: *lint
docker:
- image: node:8
steps: &hook_steps
- checkout
- restore_cache: *restore_cache
- attach_workspace: {at: node_modules}
- run: .circleci/setup_git
- run: yarn exec nps test.hook
- store_test_results: *store_test_results
node-8-base: &node_8
<<: *lint
docker:
Expand All @@ -87,6 +98,9 @@ jobs:
node-8-command:
<<: *node_8
steps: *command_steps
node-8-hook:
<<: *node_8
steps: *hook_steps

cache:
<<: *lint
Expand Down Expand Up @@ -149,8 +163,10 @@ workflows:
- node-latest-plugin: {requires: [lint] }
- node-latest-multi: {requires: [lint] }
- node-latest-command: {requires: [lint] }
- node-latest-hook: {requires: [lint] }
- node-8-base: {requires: [lint] }
- node-8-single: {requires: [lint] }
- node-8-plugin: {requires: [lint] }
- node-8-multi: {requires: [lint] }
- node-8-command: {requires: [lint] }
- node-8-hook: {requires: [lint] }
1 change: 1 addition & 0 deletions appveyor.yml
Expand Up @@ -7,6 +7,7 @@ environment:
- TEST_TYPE: plugin
- TEST_TYPE: multi
- TEST_TYPE: command
- TEST_TYPE: hook
cache:
- '%LOCALAPPDATA%\Yarn -> appveyor.yml'
- node_modules -> yarn.lock
Expand Down
2 changes: 1 addition & 1 deletion package-scripts.js
Expand Up @@ -15,7 +15,7 @@ sh.set('-e')

setColors(['dim'])

const testTypes = ['base', 'plugin', 'single', 'multi', 'command']
const testTypes = ['base', 'plugin', 'single', 'multi', 'command', 'hook']
const tests = testTypes.map(cmd => {
const {silent} = sh.config
sh.config.silent = true
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -24,7 +24,7 @@
"devDependencies": {
"@oclif/dev-cli": "^1.3.1",
"@oclif/tslint": "^1.0.2",
"@types/lodash": "^4.14.105",
"@types/lodash": "^4.14.106",
"@types/read-pkg": "^3.0.0",
"@types/shelljs": "^0.7.8",
"@types/yeoman-generator": "^2.0.1",
Expand All @@ -36,7 +36,7 @@
"fancy-test": "^1.0.1",
"fs-extra": "^5.0.0",
"globby": "^8.0.1",
"mocha": "^5.0.4",
"mocha": "^5.0.5",
"npm-run-path": "^2.0.2",
"nps": "^5.8.2",
"shelljs": "^0.8.1",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/command.ts
Expand Up @@ -25,6 +25,6 @@ export default abstract class AppCommand extends Base {
name: args.name,
defaults: flags.defaults,
force: flags.force
})
} as Options)
}
}
33 changes: 33 additions & 0 deletions src/commands/hook.ts
@@ -0,0 +1,33 @@
import {flags} from '@oclif/command'

import Base from '../command_base'

export interface Options {
name: string
defaults?: boolean
force?: boolean
event: string
}

export default abstract class HookCommand extends Base {
static description = 'add a hook to an existing CLI or plugin'

static flags = {
defaults: flags.boolean({description: 'use defaults for every setting'}),
force: flags.boolean({description: 'overwrite existing files'}),
event: flags.string({description: 'event to run hook on', default: 'init'}),
}
static args = [
{name: 'name', description: 'name of hook (snake_case)', required: true}
]

async run() {
const {flags, args} = this.parse(HookCommand)
await super.generate('hook', {
name: args.name,
event: flags.event,
defaults: flags.defaults,
force: flags.force,
} as Options)
}
}
51 changes: 51 additions & 0 deletions src/generators/hook.ts
@@ -0,0 +1,51 @@
// tslint:disable no-floating-promises
// tslint:disable no-console

import * as _ from 'lodash'
import * as path from 'path'
import * as Generator from 'yeoman-generator'
import yosay = require('yosay')

import {Options} from '../commands/hook'

const {version} = require('../../package.json')

class HookGenerator extends Generator {
pjson!: any

get _path() { return this.options.name.split(':').join('/') }
get _ts() { return this.pjson.devDependencies.typescript }
get _ext() { return this._ts ? 'ts' : 'js' }
get _mocha() { return this.pjson.devDependencies.mocha }

constructor(args: any, public options: Options) {
super(args, options)
}

async prompting() {
this.pjson = this.fs.readJSON('package.json')
this.pjson.oclif = this.pjson.oclif || {}
if (!this.pjson) throw new Error('not in a project directory')
this.log(yosay(`Adding a ${this.options.event} hook to ${this.pjson.name} Version: ${version}`))
}

writing() {
this.sourceRoot(path.join(__dirname, '../../templates'))
this.fs.copyTpl(this.templatePath(`src/hook.${this._ext}.ejs`), this.destinationPath(`src/hooks/${this.options.event}/${this.options.name}.${this._ext}`), this)
if (this._mocha) {
this.fs.copyTpl(this.templatePath(`test/hook.test.${this._ext}.ejs`), this.destinationPath(`test/commands/${this._path}.test.${this._ext}`), this)
}
this.pjson.oclif = this.pjson.oclif || {}
let hooks = this.pjson.oclif.hooks = this.pjson.oclif.hooks || {}
let p = `./${this._ts ? 'lib' : 'src'}/hooks/${this.options.event}/${this.options.name}.js`
if (hooks[this.options.event]) {
hooks[this.options.event] = _.castArray(hooks[this.options.event])
hooks[this.options.event].push(p)
} else {
this.pjson.oclif.hooks[this.options.event] = p
}
this.fs.writeJSON(this.destinationPath('./package.json'), this.pjson)
}
}

export = HookGenerator
9 changes: 0 additions & 9 deletions templates/plugin/test/hooks/init.test.js

This file was deleted.

3 changes: 3 additions & 0 deletions templates/src/hook.js.ejs
@@ -0,0 +1,3 @@
module.exports = async function (opts) {
process.stdout.write(`example hook running ${opts.id}\n`)
}
7 changes: 7 additions & 0 deletions templates/src/hook.ts.ejs
@@ -0,0 +1,7 @@
import {Hook} from '@oclif/config'

const hook: Hook<'<%- options.event %>'> = async function (opts) {
process.stdout.write(`example hook running ${opts.id}\n`)
}

export default hook
9 changes: 9 additions & 0 deletions templates/test/hook.test.js.ejs
@@ -0,0 +1,9 @@
const {expect, test} = require('@oclif/test')

describe('hooks', () => {
test
.stdout()
.hook('init', {id: 'mycommand'})
.do(output => expect(output.stdout).to.contain('example hook running mycommand'))
.it('shows a message')
})
File renamed without changes.
1 change: 1 addition & 0 deletions test/commands/hook/everything.test.js
@@ -0,0 +1 @@
require('../../run')(module.filename)
1 change: 1 addition & 0 deletions test/commands/hook/mocha.test.js
@@ -0,0 +1 @@
require('../../run')(module.filename)
9 changes: 9 additions & 0 deletions test/run.js
Expand Up @@ -84,6 +84,15 @@ module.exports = file => {
sh.exec('node ./bin/run foo:bar:baz --help')
sh.exec('yarn run prepublishOnly')
break
case 'hook':
build('plugin', name)
generate('hook myhook --defaults --force')
// TODO: remove this compilation step
sh.exec('tsc')
sh.exec('yarn test')
sh.exec('node ./bin/run hello')
sh.exec('yarn run prepublishOnly')
break
}
})
.it([cmd, name].join(':'))
Expand Down
12 changes: 6 additions & 6 deletions yarn.lock
Expand Up @@ -114,9 +114,9 @@
"@types/rx" "*"
"@types/through" "*"

"@types/lodash@^4.14.105":
version "4.14.105"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.105.tgz#9fcc4627a1f98f8f8fce79ddb2bff4afd97e959b"
"@types/lodash@^4.14.106":
version "4.14.106"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.106.tgz#6093e9a02aa567ddecfe9afadca89e53e5dce4dd"

"@types/minimatch@*":
version "3.0.3"
Expand Down Expand Up @@ -2073,9 +2073,9 @@ mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1:
dependencies:
minimist "0.0.8"

mocha@^5.0.4:
version "5.0.4"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.4.tgz#6b7aa328472da1088e69d47e75925fd3a3bb63c6"
mocha@^5.0.5:
version "5.0.5"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.5.tgz#e228e3386b9387a4710007a641f127b00be44b52"
dependencies:
browser-stdout "1.3.1"
commander "2.11.0"
Expand Down

0 comments on commit 4106708

Please sign in to comment.