├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── Sakefile ├── comp └── _sake ├── package-lock.json ├── package.json ├── src ├── cache.coffee ├── cli.coffee ├── index.coffee ├── init.coffee ├── load.coffee ├── run.coffee ├── transform.coffee └── utils.coffee ├── templates └── coffee │ └── Sakefile └── test ├── Sakefile ├── cli.coffee ├── helper.coffee ├── invoke-async.coffee ├── invoke-generator.coffee ├── invoke-parallel.coffee ├── invoke-promise.coffee └── task.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bin/ 3 | lib/ 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | Cakefile 2 | src/ 3 | test/ 4 | lib/*.map 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 7 4 | script: 5 | - npm test 6 | cache: 7 | directories: 8 | - node_modules 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | Copyright (c) 2017-present, Hanzo, Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name Hanzo nor the names of its contributors may be used to 17 | endorse or promote products derived from this software without specific 18 | prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sake-cli 2 | 3 | [![npm][npm-img]][npm-url] 4 | [![build][build-img]][build-url] 5 | [![dependencies][dependencies-img]][dependencies-url] 6 | [![downloads][downloads-img]][downloads-url] 7 | [![license][license-img]][license-url] 8 | [![chat][chat-img]][chat-url] 9 | 10 | > The Sake command line interface. 11 | 12 | Install this globally and you'll have access to the `sake` command anywhere on 13 | your system. 14 | 15 | ```bash 16 | npm install -g sake-cli 17 | ``` 18 | 19 | Note: The job of the `sake` command is to load and run the version of Sake you 20 | have installed locally to your project, irrespective of its version. 21 | 22 | ## Installing sake locally 23 | 24 | If you prefer the idiomatic Node.js method to get started with a project (`npm 25 | install && npm test`) then install `sake` locally with `npm install sake-cli 26 | --save-dev`. Then add a script to your `package.json` to run the associated Sake 27 | task: `"scripts": { "test": "sake test" }`. Now `npm test` will use the locally 28 | installed `./node_modules/.bin/sake` executable to run your Sake tasks. 29 | 30 | To read more about npm scripts, please visit the [npm docs][npm-docs]. 31 | 32 | ## Autocompletion 33 | Sake ships with a simple [completion function for zsh][compdef] which can 34 | autocomplete available task names: 35 | 36 | ```bash 37 | fpath=( path/to/comp/_sake $fpath ) 38 | comdef _sake sake 39 | ``` 40 | 41 | ## License 42 | [BSD][license-url] 43 | 44 | [npm-docs]: https://docs.npmjs.com/misc/scripts 45 | [compdef]: https://github.com/sakejs/sake-cli/blob/master/comp/_sake 46 | 47 | [build-img]: https://img.shields.io/travis/sakejs/sake-cli.svg 48 | [build-url]: https://travis-ci.org/sakejs/sake-cli 49 | [chat-img]: https://badges.gitter.im/join-chat.svg 50 | [chat-url]: https://gitter.im/sakejs/chat 51 | [coverage-img]: https://coveralls.io/repos/sakejs/sake-cli/badge.svg?branch=master&service=github 52 | [coverage-url]: https://coveralls.io/github/sakejs/sake-cli?branch=master 53 | [dependencies-img]: https://david-dm.org/sakejs/sake-cli.svg 54 | [dependencies-url]: https://david-dm.org/sakejs/sake-cli 55 | [downloads-img]: https://img.shields.io/npm/dm/sake-cli.svg 56 | [downloads-url]: http://badge.fury.io/js/sake-cli 57 | [license-img]: https://img.shields.io/npm/l/sake-cli.svg 58 | [license-url]: https://github.com/sakejs/sake-cli/blob/master/LICENSE 59 | [npm-img]: https://img.shields.io/npm/v/sake-cli.svg 60 | [npm-url]: https://www.npmjs.com/package/sake-cli 61 | -------------------------------------------------------------------------------- /Sakefile: -------------------------------------------------------------------------------- 1 | use 'sake-bundle' 2 | use 'sake-outdated' 3 | use 'sake-publish' 4 | use 'sake-test' 5 | use 'sake-version' 6 | 7 | task 'build', 'build project', -> 8 | b = new Bundle entry: 'src/cli.coffee' 9 | 10 | Promise.all [ 11 | b.write format: 'cli', executable: true 12 | b.write formats: ['cjs', 'es'] 13 | ] 14 | -------------------------------------------------------------------------------- /comp/_sake: -------------------------------------------------------------------------------- 1 | #compdef sake 2 | 3 | # sake, version 1.0.0 4 | 5 | local curcontext="$curcontext" state line expl ret=1 6 | typeset -A opt_args 7 | 8 | # -f FILE, --file=FILE read tasks from FILE [pavement.py] 9 | _arguments -C -s -S \ 10 | '*:target:->target' && ret=0 11 | 12 | case "$state" in 13 | target) 14 | local -a targets 15 | if [ -f "Sakefile" ] || [ -f "Cakefile" ] || [ -f "Sakefile.js" ] || [ -f "Sakefile.ts" ]; then 16 | targets=( ${${(f)"$(_call_program targets $words[1] 2>/dev/null | grep sake | grep -v 'defines the following' | sed 's/ *#.*//g; s/sake //g')"}}) 17 | _wanted targets expl 'sake target' compadd -a targets && return 0 18 | else 19 | _message -e target 'sake target' 20 | fi 21 | ;; 22 | esac 23 | 24 | return ret 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sake-cli", 3 | "version": "0.7.3", 4 | "description": "The Sake command line interface", 5 | "homepage": "http://github.com/sakejs/sake-cli", 6 | "bugs": "http://github.com/sakejs/sake-cli/issues", 7 | "keywords": [ 8 | "async", 9 | "build", 10 | "bundle", 11 | "cli", 12 | "coffee", 13 | "coffeescript", 14 | "make", 15 | "minify", 16 | "reload", 17 | "sake", 18 | "sakefile", 19 | "scaffold", 20 | "server", 21 | "task", 22 | "test", 23 | "tool", 24 | "typescript", 25 | "uglify", 26 | "watch" 27 | ], 28 | "bin": { 29 | "sake": "bin/sake" 30 | }, 31 | "main": "lib/sake.js", 32 | "module": "lib/sake.mjs", 33 | "scripts": { 34 | "build": "handroll src/cli.coffee --cli --executable -o bin/sake", 35 | "prepublishOnly": "npm run build", 36 | "pretest": "npm run build", 37 | "test": "bin/sake test" 38 | }, 39 | "author": "Hanzo, Inc. ", 40 | "license": "BSD-3-Clause", 41 | "repository": { 42 | "type": "git", 43 | "url": "http://github.com/sakejs/sake-cli" 44 | }, 45 | "dependencies": { 46 | "babel-core": "^6.26.0", 47 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", 48 | "find-coffee": "^0.2.0", 49 | "sake-core": "^1.6.7", 50 | "yargs": "^11.1.0" 51 | }, 52 | "devDependencies": { 53 | "bluebird": "^3.5.1", 54 | "coffeescript": "^2.2.4", 55 | "es-is": "^3.3.10", 56 | "mz": "^2.7.0", 57 | "sake-bundle": "^0.6.7", 58 | "sake-outdated": "^0.3.0", 59 | "sake-publish": "^0.1.17", 60 | "sake-test": "^0.2.1", 61 | "sake-version": "^0.1.19" 62 | } 63 | } -------------------------------------------------------------------------------- /src/cache.coffee: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | import transform from './transform' 5 | 6 | 7 | # Find local node_modules relative to current project 8 | findNodeModules = (dir) -> 9 | while true 10 | p = (path.join dir, 'node_modules') 11 | if fs.existsSync p 12 | return p 13 | if dir == '/' 14 | throw new Error 'Unable to locate node_modules' 15 | dir = path.resolve path.join dir, '..' 16 | 17 | 18 | # Path to cache directory 19 | cacheDir = (dir) -> 20 | path.join (findNodeModules dir), '.sake' 21 | 22 | 23 | # Path to cache file 24 | cachePath = (dir) -> 25 | path.join (cacheDir dir), 'Sakefile.js' 26 | 27 | 28 | # Safely make directory 29 | mkdirp = (dir) -> 30 | try 31 | fs.mkdirSync dir 32 | catch err 33 | throw err unless err.code == 'EEXIST' 34 | 35 | 36 | # Read cache file 37 | read = (dir) -> 38 | fs.readFileSync (cachePath dir), 'utf8' 39 | 40 | 41 | # Read origin dir for cache file 42 | readOrigin = (dir) -> 43 | try 44 | fs.readFileSync (path.join (cacheDir dir), 'origin'), 'utf8' 45 | catch err # Support older copies of sake 46 | dir 47 | 48 | 49 | # Write cache file 50 | write = (dir, code) -> 51 | mkdirp cacheDir dir 52 | transformed = transform code 53 | fs.writeFileSync (cachePath dir), transformed, 'utf8' 54 | fs.writeFileSync (path.join (cacheDir dir), 'origin'), dir, 'utf8' 55 | 56 | 57 | # Require cached Sakefile such that require and other Node machinery work 58 | requireCached = (dir) -> 59 | # Symlink cached Sakefile back into Sakefile dir 60 | tempFile = path.resolve path.join dir, "__Sakefile.js" 61 | fs.linkSync (cachePath dir), tempFile 62 | 63 | try 64 | require tempFile # Require cached Sakefile 65 | catch err 66 | 67 | fs.unlinkSync tempFile # Ensure link is cleaned up 68 | throw err if err? # Throw if failed to require Sakefile 69 | 70 | 71 | # Load cached Sakefile unless it's older than source or from different Sakefile 72 | load = (dir, file) -> 73 | try 74 | cached = fs.statSync cachePath dir 75 | source = fs.statSync path.join dir, file 76 | catch err 77 | return false if err.code == 'ENOENT' 78 | throw err 79 | 80 | if cached.mtime > source.mtime and dir == (readOrigin dir) 81 | requireCached dir 82 | true 83 | else 84 | false 85 | 86 | 87 | export default cache = 88 | dir: cacheDir 89 | path: cachePath 90 | load: load 91 | write: write 92 | require: requireCached 93 | -------------------------------------------------------------------------------- /src/cli.coffee: -------------------------------------------------------------------------------- 1 | import run from './run'; run() 2 | -------------------------------------------------------------------------------- /src/index.coffee: -------------------------------------------------------------------------------- 1 | export {default as run} from './run' 2 | -------------------------------------------------------------------------------- /src/init.coffee: -------------------------------------------------------------------------------- 1 | import exec from 'executive' 2 | import fs from 'fs' 3 | 4 | command = 'npm install --dev sake-cli sake-bundle sake-outdated sake-publish sake-version' 5 | 6 | export default init = -> 7 | # Copy over default Sakefile 8 | console.log 'cp Sakefile .' 9 | buf = fs.readFileSync __dirname + '/../templates/coffee/Sakefile' 10 | fs.writeFileSync 'Sakefile', buf 11 | 12 | # Install deps 13 | console.log command 14 | exec command 15 | -------------------------------------------------------------------------------- /src/load.coffee: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | import findCoffee from 'find-coffee' 5 | import cache from './cache' 6 | 7 | # Load Cakefile 8 | loadCakefile = (dir, file) -> 9 | # Try to load from cache 10 | return if cache.load dir, file 11 | 12 | # Find local copy of CoffeeScript 13 | coffee = findCoffee() 14 | 15 | # Register .coffee extension 16 | coffee.register() 17 | 18 | # Compile Cakefile 19 | code = fs.readFileSync file, 'utf8' 20 | js = coffee.compile code, 21 | bare: true 22 | filename: file 23 | sourceMap: false 24 | 25 | # Write to cache and try to load 26 | cache.write dir, js 27 | cache.require dir 28 | 29 | # Load Sakefile 30 | loadSakefile = (dir, file) -> 31 | # Try to load from cache 32 | return if cache.load dir, file 33 | 34 | try 35 | code = fs.readFileSync file, 'utf8' 36 | cache.write dir, code 37 | cache.require dir 38 | catch err 39 | throw err unless (path.extname file) == '' 40 | throw err unless err.constructor.name == 'SyntaxError' 41 | loadCakefile dir, file 42 | 43 | 44 | # Load Sakefile.ts 45 | loadSakefileTs = (dir, file) -> 46 | # Try to load from cache 47 | return if cache.load dir, file 48 | 49 | # Write straight to cache 50 | exec.sync "tsc --types sake-core --target ES6 --outFile #{cache.path(dir)} Sakefile.ts" 51 | 52 | # Load from cache 53 | cache.require dir 54 | 55 | export default load = 56 | Cakefile: loadCakefile 57 | Sakefile: loadSakefile 58 | SakefileTs: loadSakefileTs 59 | -------------------------------------------------------------------------------- /src/run.coffee: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import sake from 'sake-core' 3 | import yargs from 'yargs' 4 | 5 | import cache from './cache' 6 | import load from './load' 7 | import init from './init' 8 | import {findSakefile, missingTask, printTasks} from './utils' 9 | import {version} from '../package.json' 10 | 11 | 12 | # Run `sake`. Executes all of the tasks you pass, in order. If no tasks are 13 | # passed, print the help screen. Keep a reference to the original directory 14 | # name, when running Cake tasks from subdirectories. 15 | export default run = -> 16 | # Save record of original directory 17 | global.__originalDirname = fs.realpathSync '.' 18 | 19 | # Process arguments 20 | argv = yargs.argv 21 | tasks = argv._.slice 0 # Create a copy of tasks to execute 22 | argv.arguments = argv._ # For backwards compatibility with cake 23 | 24 | if argv.debug 25 | process.env.VERBOSE = true 26 | 27 | # Print Sake version 28 | if argv.version or argv.v and not argv._.length 29 | console.log "#{version} (core: #{sake.version})" 30 | process.exit 0 31 | 32 | # Search for sakefile 33 | try 34 | {dir, file} = findSakefile __originalDirname 35 | catch err 36 | if tasks[0] == 'init' 37 | return init() 38 | else 39 | console.log(err.toString()) 40 | process.exit 1 41 | 42 | # Change dir to match Sakefile location 43 | process.chdir dir 44 | 45 | # Install Sake globals 46 | sake.install() 47 | 48 | # Load Sakefile 49 | unless cache.load dir, file 50 | switch file 51 | when 'Cakefile' 52 | load.Cakefile dir, file 53 | when 'Sakefile', 'Sakefile.js' 54 | load.Sakefile dir, file 55 | when 'Sakefile.ts' 56 | load.SakefileTs dir, file 57 | 58 | # Bail if no tasks specified 59 | return printTasks dir, file unless argv._.length 60 | 61 | # Bail if missing task 62 | for task in tasks 63 | unless sake.tasks[task]? 64 | missingTask task 65 | 66 | # Let's drink 67 | sake.invoke tasks, argv, (err) -> 68 | if err? 69 | console.error err 70 | process.exit 1 71 | -------------------------------------------------------------------------------- /src/transform.coffee: -------------------------------------------------------------------------------- 1 | export default transform = (code) -> 2 | babel = require 'babel-core' 3 | esModules = require 'babel-plugin-transform-es2015-modules-commonjs' 4 | 5 | out = babel.transform code, 6 | plugins: [ 7 | [esModules, loose: true] 8 | ] 9 | out.code 10 | -------------------------------------------------------------------------------- /src/utils.coffee: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import fs from 'fs' 3 | 4 | import isFunction from 'es-is/function' 5 | import {options} from 'sake-core' 6 | import {tasks} from 'sake-core' 7 | 8 | # Ensure local node_modules bin is on the front of $PATH 9 | export preferLocalModules = -> 10 | binPath = path.join process.cwd(), 'node_modules/', '.bin' 11 | process.env.PATH = ([binPath].concat process.env.PATH.split ':').join ':' 12 | 13 | # When `sake` is invoked, search in the current and all parent directories 14 | # to find the relevant Sakefile (or Cakefile). 15 | export findSakefile = (dir) -> 16 | for file in ['Sakefile', 'Sakefile.js', 'Cakefile', 'Sakefile.ts'] 17 | return file: file, dir: dir if fs.existsSync path.join dir, file 18 | 19 | # Recurse up the directory structure 20 | parent = path.normalize path.join dir, '..' 21 | return findSakefile parent unless parent is dir 22 | 23 | # We're at the top, bail 24 | throw new Error "Sakefile not found in #{process.cwd()}" 25 | 26 | # Display the list of Cake tasks in a format similar to `rake -T` 27 | export printTasks = (dir, file) -> 28 | relative = path.relative or path.resolve 29 | filePath = path.join relative(__originalDirname, process.cwd()), file 30 | 31 | console.log "#{filePath} defines the following tasks:\n" 32 | 33 | delete tasks.has 34 | 35 | names = Object.keys(tasks).sort() 36 | 37 | for name in names 38 | task = tasks[name] 39 | spaces = 20 - name.length 40 | spaces = if spaces > 0 then Array(spaces + 1).join(' ') else '' 41 | desc = if task.description then "# #{task.description}" else '' 42 | console.log "sake #{name}#{spaces} #{desc}" 43 | 44 | if Object.keys(options).length > 1 45 | console.log() 46 | for own k,v of options 47 | continue if isFunction v 48 | 49 | if v.flag? 50 | switches = "#{v.letter}, #{v.flag}" 51 | else 52 | switches = "#{v.letter}" 53 | spaces = 18 - switches.length 54 | spaces = if spaces > 0 then Array(spaces + 1).join(' ') else '' 55 | console.log " #{switches}#{spaces} #{v.description ? ''}" 56 | 57 | # Print an error and exit when attempting to use an invalid task/option. 58 | export fatalError = (message) -> 59 | console.error message + '\n' 60 | console.log 'To see a list of all tasks/options, run "sake"' 61 | process.exit 1 62 | 63 | export missingTask = (task) -> fatalError "No such task: #{task}" 64 | -------------------------------------------------------------------------------- /templates/coffee/Sakefile: -------------------------------------------------------------------------------- 1 | use('sake-bundle') 2 | use('sake-outdated') 3 | use('sake-publish') 4 | use('sake-version') 5 | 6 | task('build', 'Build project', () => { 7 | bundle.write() 8 | }) 9 | -------------------------------------------------------------------------------- /test/Sakefile: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | 3 | option '-v', '--verbose', 'Verbose option' 4 | 5 | task 'options', '', (options) -> 6 | console.log options 7 | 8 | task 'no-description', -> 9 | console.log 'no-description' 10 | 11 | task 'no-description-deps', ['no-description'], -> 12 | console.log 'no-description-deps' 13 | 14 | task 'no-description-deps-only', ['no-description-deps'] 15 | 16 | task 'async', '', (done) -> 17 | console.log done 18 | done() 19 | 20 | task 'async-options', '', (options, done) -> 21 | console.log options 22 | done() 23 | 24 | task 'delay:0', '', -> 25 | console.log 'delay:0' 26 | 27 | task 'delay:10', '', (done) -> 28 | setTimeout -> 29 | console.log 'delay:10' 30 | done() 31 | , 10 32 | 33 | task 'delay:20', '', (options, done) -> 34 | setTimeout -> 35 | console.log 'delay:20' 36 | done() 37 | , 200 38 | 39 | task 'nested', '', -> 40 | invoke 'delay:20', -> 41 | invoke 'delay:10', -> 42 | invoke 'delay:0', -> 43 | console.log 'nested' 44 | 45 | task 'serial', '', -> 46 | invoke ['delay:20', 'delay:10', 'delay:0'], -> 47 | console.log 'serial' 48 | 49 | task 'parallel', '', -> 50 | invoke.parallel ['delay:20', 'delay:10', 'delay:0'], -> 51 | console.log 'parallel' 52 | 53 | task 'promise', '', -> 54 | invoke 'delay:0' 55 | 56 | task 'promise-nested', '', -> 57 | invoke 'promise' 58 | 59 | task 'gen', '', -> 60 | yield console.log 'gen-1' 61 | yield console.log 'gen-2' 62 | yield console.log 'gen-3' 63 | 64 | task 'gen-promise', '', -> 65 | n = 0 66 | promise = -> 67 | new Promise (resolve, reject) -> 68 | n++ 69 | setTimeout (-> resolve 'promise-' + n), 1 70 | 71 | value = yield promise() 72 | console.log value 73 | 74 | value = yield promise() 75 | console.log value 76 | 77 | value = yield promise() 78 | console.log value 79 | 80 | task 'gen-mz', '', -> 81 | mfs = require 'mz/fs' 82 | 83 | exists = yield mfs.exists 'Sakefile' 84 | console.log exists 85 | exists = yield mfs.exists 'does not exist' 86 | console.log exists 87 | exists = yield mfs.exists 'Sakefile' 88 | console.log exists 89 | exists = yield mfs.exists 'does not exist' 90 | console.log exists 91 | 92 | task 'gen-bluebird', '', -> 93 | Promise = require 'bluebird' 94 | pfs = Promise.promisifyAll require 'fs' 95 | 96 | yield (pfs.statAsync 'does not exist').catch (err) -> 97 | console.log 'does not exist' 98 | stat = yield pfs.statAsync 'Sakefile' 99 | console.log 'exists' 100 | 101 | yield (pfs.statAsync 'does not exist').catch (err) -> 102 | console.log 'does not exist' 103 | stat = yield pfs.statAsync 'Sakefile' 104 | console.log 'exists' 105 | -------------------------------------------------------------------------------- /test/cli.coffee: -------------------------------------------------------------------------------- 1 | describe 'bin/sake', -> 2 | it 'should show normal sake usage', -> 3 | {stdout} = yield run '' 4 | stdout.lines[0].should.equal 'Sakefile defines the following tasks:' 5 | 6 | it 'should fail to run non-existent task', -> 7 | {status} = yield run 'non-existent-task' 8 | status.should.eq 1 9 | 10 | -------------------------------------------------------------------------------- /test/helper.coffee: -------------------------------------------------------------------------------- 1 | # convenient for testing 2 | Object.defineProperty String.prototype, 'lines', 3 | get: -> @split '\n' 4 | 5 | path = require 'path' 6 | exec = require('executive').quiet 7 | 8 | # path to sake 9 | cwd = __dirname 10 | bin = require.resolve '../bin/sake' 11 | 12 | # Helper to run sake in tests 13 | run = (cmd) -> 14 | console.log bin, cmd 15 | p = exec "#{bin} #{cmd}", {cwd: cwd} 16 | p.then (res) -> 17 | res.stdout = res.stdout.trim() 18 | res.stderr = res.stdout.trim() 19 | p.catch (err) -> 20 | throw err 21 | 22 | before -> global.run = run 23 | -------------------------------------------------------------------------------- /test/invoke-async.coffee: -------------------------------------------------------------------------------- 1 | describe 'invoke', -> 2 | it 'should invoke tasks in serial', -> 3 | {stdout} = yield run 'serial' 4 | stdout.should.eq ''' 5 | delay:20 6 | delay:10 7 | delay:0 8 | serial 9 | ''' 10 | 11 | it 'should execute nested invoke calls', -> 12 | {stdout} = yield run 'nested' 13 | stdout.should.eq ''' 14 | delay:20 15 | delay:10 16 | delay:0 17 | nested 18 | ''' 19 | -------------------------------------------------------------------------------- /test/invoke-generator.coffee: -------------------------------------------------------------------------------- 1 | describe 'invoke (generator)', -> 2 | it 'should consume generator tasks completely', -> 3 | {stdout} = yield run 'gen' 4 | stdout.should.eq ''' 5 | gen-1 6 | gen-2 7 | gen-3 8 | ''' 9 | 10 | it 'should send back promise results to generator tasks', -> 11 | {stdout} = yield run 'gen-promise' 12 | stdout.should.eq ''' 13 | promise-1 14 | promise-2 15 | promise-3 16 | ''' 17 | 18 | it 'should support various promise libraries', -> 19 | {stdout} = yield run 'gen-mz' 20 | stdout.should.eq ''' 21 | true 22 | false 23 | true 24 | false 25 | ''' 26 | 27 | {stdout} = yield run 'gen-bluebird' 28 | stdout.should.eq ''' 29 | does not exist 30 | exists 31 | does not exist 32 | exists 33 | ''' 34 | -------------------------------------------------------------------------------- /test/invoke-parallel.coffee: -------------------------------------------------------------------------------- 1 | describe 'invoke (parallel)', -> 2 | it 'should invoke tasks in parallel', -> 3 | {stdout} = yield run 'parallel' 4 | stdout.should.eq ''' 5 | delay:0 6 | delay:10 7 | delay:20 8 | parallel 9 | ''' 10 | -------------------------------------------------------------------------------- /test/invoke-promise.coffee: -------------------------------------------------------------------------------- 1 | describe 'invoke (promise)', -> 2 | it 'should invoke returned promises', -> 3 | {stdout} = yield run 'promise' 4 | stdout.should.eq 'delay:0' 5 | 6 | it 'should invoke nested promise tasks', -> 7 | {stdout} = yield run 'promise-nested' 8 | stdout.should.eq 'delay:0' 9 | 10 | -------------------------------------------------------------------------------- /test/task.coffee: -------------------------------------------------------------------------------- 1 | describe 'task', -> 2 | it 'should accept action expecting options', -> 3 | {stdout} = yield run 'options' 4 | stdout.should.equal """ 5 | { _: [ 'options' ], 6 | help: false, 7 | version: false, 8 | '$0': '../bin/sake', 9 | arguments: [ 'options' ] } 10 | """ 11 | 12 | it 'should accept action expecting only a callback', -> 13 | {stdout} = yield run 'async' 14 | stdout.should.equal '[Function: done]' 15 | 16 | it 'should accept action expecting options and callback', -> 17 | {stdout} = yield run 'async-options' 18 | stdout.should.equal """ 19 | { _: [ 'async-options' ], 20 | help: false, 21 | version: false, 22 | '$0': '../bin/sake', 23 | arguments: [ 'async-options' ] } 24 | """ 25 | 26 | it 'should accept task without description', -> 27 | {stdout} = yield run 'no-description' 28 | stdout.should.equal 'no-description' 29 | 30 | it 'should accept task without description and deps', -> 31 | {stdout} = yield run 'no-description-deps' 32 | stdout.should.equal ''' 33 | no-description 34 | no-description-deps 35 | ''' 36 | 37 | it 'should accept task without description and only deps', -> 38 | {stdout} = yield run 'no-description-deps-only' 39 | stdout.should.equal ''' 40 | no-description 41 | no-description-deps 42 | ''' 43 | --------------------------------------------------------------------------------