Skip to content

Commit

Permalink
Merge pull request #644 from jenius/sprout-upgrade
Browse files Browse the repository at this point in the history
Sprout upgrade
  • Loading branch information
Jeff Escalante committed Jul 12, 2015
2 parents b760780 + efce555 commit 182a49e
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 54 deletions.
43 changes: 37 additions & 6 deletions lib/api/new.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ path = require 'path'
fs = require 'fs'
W = require 'when'
nodefn = require 'when/node'
sprout = require 'sprout'
Sprout = require '../sprout'
global_config = require '../global_config'
_ = require 'lodash'
npm = require 'npm'
inquirer = require 'inquirer'

base_tpl_name = 'roots-base'
base_tpl_url = 'https://github.com/roots-dev/base.git'
Expand All @@ -30,6 +31,26 @@ base_tpl_url = 'https://github.com/roots-dev/base.git'
* @return {Promise} promise for completed new template
###

###*
* Creates a new roots project using a template. If a template is not provided,
* the roots-base template is used. If the roots-base template has not been
* installed, that is installed first. Once the template has been created, if it
* contains a package.json file with dependencies, they are installed. To review
* the promise chain:
*
* - check to see if roots-base is installed
* - if not, install it, emitting 'template:base_added' when finished
* - initialize the template with sprout
* - when finished, emit 'template:created'
* - check to see if deps are present
* - if so install them, emit 'deps:installing' before and 'deps:finished' after
* - at the end, emit 'done' or 'error events', and return a promise
*
* @param {Roots} roots - roots instance
* @param {Object} opts - options object
* @return {Promise} promise for completed new template
###

class New
constructor: (@Roots) ->

Expand All @@ -49,14 +70,24 @@ class New

pkg = path.join(opts.path, 'package.json')

W.resolve(_.contains(sprout.list(), base_tpl_name))
sprout = Sprout()
sprout_opts =
locals: opts.overrides
questionnaire: (questions, skip) ->
W.promise (resolve, reject) ->
qs = []
for question in questions
qs.push(question) unless _.contains(skip, question.name)
inquirer.prompt qs, (answers) -> resolve(answers)

W.resolve(_.contains(_.keys(sprout.templates), base_tpl_name))
.then (res) ->
if not res
sprout.add(name: base_tpl_name, uri: base_tpl_url)
sprout.add(base_tpl_name, base_tpl_url)
.tap(-> d.notify('base template added'))
.then(-> sprout.init(opts))
.tap(-> d.notify('project created'))
.then(-> if fs.existsSync(pkg) then install_deps(d, pkg))
.then -> sprout.init(opts.name, opts.path, sprout_opts)
.tap -> d.notify('project created')
.then -> if fs.existsSync(pkg) then install_deps(d, pkg)
.done((=> d.resolve(new @Roots(opts.path))), d.reject.bind(d))

return d.promise
Expand Down
32 changes: 24 additions & 8 deletions lib/api/template.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ fs = require 'fs'
_ = require 'lodash'
W = require 'when'
nodefn = require 'when/node'
sprout = require 'sprout'
Sprout = require '../sprout'
global_config = require '../global_config'

sprout = Sprout()

###*
* Adds a template to sprout. Delegates directly to sprout's API.
*
Expand All @@ -15,7 +17,8 @@ global_config = require '../global_config'

exports.add = (args) ->
__track('api', { name: 'template-add', template: args.name })
sprout.add(args)
sprout.add(args.name, args.uri, _.omit(args, 'name', 'uri'))
.then -> "template '#{args.name}' added"

###*
* Removes a template from sprout. Delegates directly to sprout's API.
Expand All @@ -24,18 +27,31 @@ exports.add = (args) ->
* @return {Promise} promise for removed template
###

exports.remove = (args) ->
exports.remove = (args = {}) ->
__track('api', { name: 'template-remove', template: args.name })
sprout.remove(args)

if not args.name
return W.reject(new Error('please provide a template name to remove'))

sprout.remove(args.name)
.then -> "template '#{args.name}' removed"
.catch (err) -> W.reject(err)

###*
* List all templates. Delegates directly to sprout's API.
* @param {Object} args - can contain key `pretty`
* @return {String} a string colored and formatted for the terminal
###

exports.list = (args) ->
exports.list = (args = {}) ->
__track('api', { name: 'template-list' })
sprout.list(args)

templates = _.keys(sprout.templates)
if args.pretty
"\n- #{templates.join('\n- ')}\n"
else
return templates


###*
* Set the default template used with roots new when one isn't supplied.
Expand All @@ -50,13 +66,13 @@ exports.default = (args = {}) ->
if not args.name
return W.reject(new Error('please provide a template name'))

if not _.contains(sprout.list(), args.name)
if not _.contains(_.keys(sprout.templates), args.name)
return W.reject(new Error "you do not have this template installed")

config = global_config()
config.set('default_template', args.name)

W.resolve("default template set to #{args.name}")
W.resolve("default template set to '#{args.name}'")

###*
* Resets the global config file and removes all installed sprout templates.
Expand Down
1 change: 0 additions & 1 deletion lib/cli/index.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ class CLI extends EventEmitter
help: 'Add a new template for future use'

s.addArgument ['name'],
nargs: '?'
help: "What you'd like to name the template"

s.addArgument ['uri'],
Expand Down
10 changes: 10 additions & 0 deletions lib/sprout.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Sprout = require 'sprout'
path = require 'path'
osenv = require 'osenv'
mkdirp = require 'mkdirp'
fs = require 'fs'

module.exports = ->
p = path.join(osenv.home(), '.config/roots/templates')
if not fs.existsSync(p) then mkdirp.sync(p)
new Sprout(p)
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@
"colors": "1.x",
"configstore": "0.3.x",
"graceful-fs": "3.x",
"inquirer": "^0.8.5",
"keen.io": "0.1.x",
"lodash": "3.x",
"minimatch": "2.x",
"mkdirp": "0.5.x",
"npm": "2.x",
"open": "0.0.5",
"osenv": "^0.1.0",
"readdirp": "1.x",
"rimraf": "2.x",
"serve-static": "1.x",
"ship": "0.2.x",
"sprout": "0.1.x",
"sprout": "0.4.x",
"update-notifier": "0.3.x",
"vinyl": "0.4.x",
"when": "3.x"
Expand Down
22 changes: 5 additions & 17 deletions test/cli.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -216,42 +216,30 @@ describe 'cli', ->
@stub.restore()
mockery.deregisterAll()

it 'should error without a name', ->
it 'should error without two arguments', ->
(-> cli.run('tpl add')).should.throw()

it 'should succeed with a name', (done) ->
spy = sinon.spy()

cli.on('success', spy)

cli.run('tpl add foo').then ->
spy.should.have.been.calledOnce
cli.removeListener('success', spy)
done()
(-> cli.run('tpl add foo')).should.throw()

it 'should succeed with a name and url', (done) ->
spy = sinon.spy()

cli.on('success', spy)

cli.run('tpl add foo bar').then ->
cli.run('tpl add foo git@github.com:carrot/sprout-express').then ->
spy.should.have.been.calledOnce
cli.removeListener('success', spy)
done()

it 'should handle errors correctly', ->
@stub.restore()
@stub = sinon.stub(Roots.template, 'add').returns(W.reject())
cli.run('tpl add foo').should.be.rejected
cli.run('tpl add foo asdf').should.be.rejected

describe 'list', ->

it 'should list all templates', (done) ->

cli.once 'data', (data) ->
data.should.match /Templates/
done()

cli.once 'data', (data) -> done()
cli.run('tpl list')

describe 'default', ->
Expand Down
30 changes: 21 additions & 9 deletions test/new.coffee
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
rimraf = require 'rimraf'
_ = require 'lodash'
nodefn = require 'when/node'
test_tpl_path = 'https://github.com/jenius/sprout-test-template.git'
new_path = path.join(base_path, 'new/testing')


before ->
@starting_templates = Roots.template.list()
if _.contains(@starting_templates, 'roots-base')
# remove roots-base to verify 'base template added'
# functionality in lib/api/new.coffee
Roots.template.remove(name: 'roots-base')

describe 'new', ->

before (done) -> Roots.template.remove('roots-base').done((-> done()), done)
before (done) ->
Roots.template.add(name: 'test', uri: test_tpl_path)
.then -> Roots.template.default(name: 'test')
.then -> done()

beforeEach (done) ->
rimraf.sync(new_path, done())

it 'should reject if not given a path', ->
Roots.new().should.be.rejected

it 'should create a project', (done) ->
spy = sinon.spy()

Roots.new
path: new_path
overrides: { name: 'testing', description: 'wow' }
overrides: { foo: 'love it' }
.progress(spy)
.catch(done)
.done (proj) ->
proj.root.should.exist
spy.should.have.callCount(4)
spy.should.have.callCount(2)
spy.should.have.been.calledWith('base template added')
spy.should.have.been.calledWith('project created')
spy.should.have.been.calledWith('dependencies installing')
spy.should.have.been.calledWith('dependencies finished installing')
rimraf(new_path, done)

it 'should create a project with another template if provided', (done) ->
Roots.template.add(name: 'foobar', uri: test_tpl_path)
.then ->
Roots.new(path: new_path, overrides: { foo: 'bar' }, template: 'foobar')
.then ->
util.file.exists('new/testing/index.html').should.be.true
overrides = { foo: 'hate it' }
Roots.new(path: new_path, overrides: overrides, template: 'foobar')
.then -> util.file.exists('new/testing/index.html').should.be.true
.then ->
Roots.template.remove(name: 'foobar')
nodefn.call(rimraf, new_path)
Expand Down
29 changes: 17 additions & 12 deletions test/template.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ describe 'template', ->

it 'should add a new template if given a valid name and uri', ->
Roots.template.add(name: test_tpl_name, uri: test_tpl_path)
.then(-> Roots.template.list().should.include(test_tpl_name))
.then(-> Roots.template.remove(name: test_tpl_name))
.then(-> Roots.template.list().should.not.include(test_tpl_name))
.then -> Roots.template.list().should.include(test_tpl_name)
.then -> Roots.template.remove(name: test_tpl_name)
.then -> Roots.template.list().should.not.include(test_tpl_name)
.should.be.fulfilled

describe 'list', ->
Expand All @@ -25,18 +25,17 @@ describe 'template', ->

describe 'remove', ->

# TODO: really this should return a rejected promise
it 'should error if not given a name', ->
(-> Roots.template.remove()).should.throw()
Roots.template.remove().should.be.rejected

it 'should error if trying to remove a non-existant template', ->
Roots.template.remove(name: 'wow').should.be.rejected

it 'should remove a template if it exists', ->
Roots.template.add(name: test_tpl_name, uri: test_tpl_path)
.then(-> Roots.template.list().should.include(test_tpl_name))
.then(-> Roots.template.remove(name: test_tpl_name))
.then(-> Roots.template.list().should.not.include(test_tpl_name))
.then -> Roots.template.list().should.include(test_tpl_name)
.then -> Roots.template.remove(name: test_tpl_name)
.then -> Roots.template.list().should.not.include(test_tpl_name)
.should.be.fulfilled

describe 'default', ->
Expand All @@ -49,12 +48,18 @@ describe 'template', ->

it 'should make a template the default if the name given is installed', ->
Roots.template.add(name: test_tpl_name, uri: test_tpl_path)
.then(-> Roots.template.default(name: test_tpl_name))
.then(-> Roots.template.remove(name: test_tpl_name))
.then(-> Roots.template.default(name: 'roots-base'))
.then -> Roots.template.default(name: test_tpl_name)
.then -> Roots.template.remove(name: test_tpl_name)
.should.be.fulfilled

describe 'reset', ->
after (done) ->
Roots.template.add(
name: 'roots-base',
uri: 'https://github.com/roots-dev/base.git'
).then -> Roots.template.default(name: 'roots-base')
.then(-> done())

describe.skip 'reset', ->
it 'should ask to confirm via command line'
it 'should not ask to confirm via command line if override is passed'
it 'should remove all templates and reset global config'

0 comments on commit 182a49e

Please sign in to comment.