├── .gitignore
├── .travis.yml
├── Gulpfile.js
├── LICENSE
├── README.md
├── index.js
├── package.json
└── test
├── fixtures
└── Gruntfile.js
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # node
2 |
3 | lib-cov
4 | *.seed
5 | *.log
6 | *.csv
7 | *.dat
8 | *.out
9 | *.pid
10 | *.gz
11 | *.node
12 |
13 | pids
14 | logs
15 | results
16 |
17 | npm-debug.log
18 |
19 | .DS_Store
20 | node_modules
21 | build
22 |
23 | # idea
24 | .idea/
25 | *.iml
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.10
4 | threadsafe: yes
5 | before_install: npm install -g grunt-cli
--------------------------------------------------------------------------------
/Gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var mocha = require('gulp-mocha');
3 |
4 | gulp.task('test', function (cb) {
5 | gulp.src('test/*.js')
6 | .pipe(mocha({
7 | reporter: 'spec'
8 | }));
9 | });
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 gratimax
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [gulp](https://github.com/gulpjs/gulp)-grunt
2 |
3 |
4 | #### Run grunt tasks from gulp
5 | [](https://npmjs.org/package/gulp-grunt)
6 | [](https://travis-ci.org/gratimax/gulp-grunt)
7 | [](https://david-dm.org/gratimax/gulp-grunt)
8 |
9 | What if your favorite grunt plugin isn't available for gulp yet?
10 | Don't fret, there is nothing to worry about!
11 | Why don't you just hook in your grunt configuration?
12 |
13 | This plugin is a bit different from most other gulp plugins.
14 | You cannot use it inline, because it does not create a stream.
15 | Rather, use it at the top of your gulpfile, calling it with your gulp as an argument.
16 | This classifies gulp-grunt as _gulpfriendly_, not a gulpplugin.
17 |
18 | ## Example usage
19 | ```js
20 | var gulp = require('gulp');
21 | require('gulp-grunt')(gulp); // add all the gruntfile tasks to gulp
22 |
23 | // continue defining tasks...
24 | gulp.task('do-this', function() {
25 | ...
26 | });
27 |
28 | // run them like any other task
29 | gulp.task('default', [
30 | // run complete grunt tasks
31 | 'grunt-minify',
32 | 'grunt-test',
33 | // or run specific targets
34 | 'grunt-sass:dist',
35 | 'grunt-browserify:dev'
36 | ]);
37 | ```
38 | Note that all the grunt tasks that were added begin with the prefix 'grunt-'.
39 | This is for usability, so that your grunt tasks do not clash with your gulp tasks.
40 | Also note that `require('gulp-grunt')(gulp)` does not have to be at the top of your file.
41 | It could very well be at the bottom, except that then it could possibly overwrite some of your
42 | gulp tasks.
43 |
44 | To run specific targets, use the regular grunt syntax `[task]:[target]`, as in the example above. (To learn more about Grunt targets, check out [the Grunt documentation](http://gruntjs.com/configuring-tasks#task-configuration-and-targets).)
45 |
46 | ## Functions
47 |
48 | ### gulp-grunt()
49 | __Takes__ `(gulp, options)`
50 |
51 | Configuration is done with the function call:
52 | ```js
53 | require('gulp-grunt')(gulp, {
54 | base: ...,
55 | prefix: ...
56 | });
57 | ```
58 | This function appends all the grunt tasks it has found to your gulp object as normal gulp tasks.
59 |
60 | #### gulp
61 | Your gulp object that you imported with the code:
62 | ```js
63 | var gulp = require('gulp');
64 | ```
65 | Pass it in and gulp-grunt will add all the tasks.
66 |
67 | #### options
68 | `options` is the configuration object you pass in.
69 |
70 | #### options.base
71 | This tells grunt where to look for your gruntfile.
72 | Set it to some absolute path.
73 | This may require you to use `path.join` for relative paths:
74 | ```js
75 | require('gulp-grunt')(gulp, {
76 | base: require('path').join(__dirname, 'yourrelativepathhere')
77 | });
78 | ```
79 |
80 | #### options.prefix
81 | This tells gulp-grunt how to prefix your tasks.
82 | For instance, if in the gruntfile you define the tasks 'minify' and 'compile',
83 | and if you pass gulp-grunt this configuration:
84 | ```js
85 | require('gulp-grunt')(gulp, {
86 | prefix: 'theknightswhosay-'
87 | })
88 | ```
89 | The grunt tasks can be called from gulp, except they would have the prefix, so
90 | 'theknightswhosay-minify' and 'theknightswhosay-compile'.
91 |
92 | You can simply pass in an empty string(`''`) if you wish to have no prefix.
93 |
94 | #### options.verbose
95 | If this option is enabled(true), then gulp-grunt will tell you when it starts running a Grunt task or stops it.
96 | This option is mainly for debugging.
97 |
98 | #### options.force
99 | If this option set to `true`, grunt task will never fail, but just give you a warning instead.
100 |
101 | #### default options
102 |
103 | ```js
104 | {
105 | base: null, // this is just the directory that your Gulpfile is in
106 | prefix: 'grunt-',
107 | verbose: false,
108 | force: true
109 | }
110 | ```
111 |
112 | ### gulp-grunt.tasks()
113 | __Takes__ `(options)`
114 |
115 | This just returns all the grunt tasks found, along with their associated functions.
116 | Calling is essentially the same as with the main function:
117 | ```js
118 | var gulp_grunt = require('gulp-grunt')
119 | var tasks = gulp_grunt.tasks({
120 | base: ...,
121 | prefix: ...
122 | });
123 | ```
124 | Output is something like:
125 | ```js
126 | {
127 | 'grunt-test': [Function],
128 | 'grunt-minify': [Function]
129 | // etc...
130 | }
131 | ```
132 |
133 | #### options
134 | This object is the exact same as for [gulp-grunt()](#gulp-grunt-1) above.
135 | This tells gulp-grunt what prefix to use and what base to search for, among other things.
136 |
137 | ***
138 |
139 | Have fun grunting and gulping! :D
140 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var grunt = require('grunt');
2 | var spawn = require('child_process').spawn;
3 |
4 | var gruntCmd = (process.platform === 'win32') ? 'grunt.cmd' : 'grunt';
5 |
6 | var makeOptions = function (options) {
7 |
8 | var baseOptions = {
9 | base: null,
10 | prefix: 'grunt-',
11 | verbose: false,
12 | force: true
13 | };
14 |
15 | if (options) {
16 | for (var key in options) {
17 | baseOptions[key] = options[key];
18 | if(key != 'base' && key != 'prefix'){
19 | grunt.option(key, options[key]);
20 | }
21 | }
22 | }
23 |
24 | return baseOptions;
25 | };
26 |
27 | module.exports = function (gulp, options) {
28 | var tasks = getTasks(options);
29 |
30 | for (var name in tasks) {
31 | if (tasks.hasOwnProperty(name)) {
32 | var fn = tasks[name];
33 | gulp.task(name, fn);
34 | }
35 | }
36 |
37 | };
38 |
39 | var getTasks = module.exports.tasks = function (options) {
40 | var opt = makeOptions(options);
41 |
42 | var oldCwd = process.cwd();
43 | var cwd = opt.base != null ? opt.base : oldCwd;
44 |
45 | grunt.file.setBase(cwd);
46 |
47 | var gruntCliDir = opt.base ? (opt.base + "/") : "";
48 |
49 | grunt.task.init([]);
50 |
51 | process.chdir(oldCwd);
52 |
53 | var gruntTasks = grunt.task._tasks,
54 | finalTasks = {};
55 |
56 | var registerGruntTask = function (name) {
57 | finalTasks[opt.prefix + name] = function (cb) {
58 | if (opt.verbose) {
59 | console.log('[grunt-gulp] Running Grunt "' + name + '" task...');
60 | }
61 | var args = opt.force ? [name, '--force', '--verbose=' + opt.verbose] : [name, '--verbose=' + opt.verbose];
62 | for (var key in opt) {
63 | if (key != 'base' && key != 'prefix') {
64 | args = args.concat('--' + key + '=' + opt[key]);
65 | }
66 | }
67 | var child = spawn(
68 | gruntCliDir + gruntCmd,
69 | args,
70 | {cwd: cwd}
71 | );
72 | child.stdout.on('data', function (d) {
73 | grunt.log.write(d);
74 | });
75 | child.stderr.on('data', function (d) {
76 | grunt.log.error(d);
77 | });
78 | child.on('close', function (code) {
79 | if (opt.verbose) {
80 | grunt.log.ok('[grunt-gulp] Done running Grunt "' + name + '" task.');
81 | }
82 | if (code != 0) {
83 | grunt.fail.warn('[grunt-gulp] Failed running Grunt "' + name + '" task.')
84 | }
85 | cb();
86 | });
87 | };
88 | }
89 |
90 | for (var name in gruntTasks) {
91 | if (gruntTasks.hasOwnProperty(name)) {
92 | // add tasks
93 | registerGruntTask(name);
94 | // also add target-specific tasks
95 | for (var target in grunt.config.get(name)) {
96 | registerGruntTask(name + ':' + target);
97 | }
98 | }
99 | }
100 |
101 | return finalTasks;
102 | };
103 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-grunt",
3 | "description": "Run grunt tasks from gulp",
4 | "version": "0.5.5",
5 | "homepage": "http://github.com/gratimax/gulp-grunt",
6 | "repository": "git://github.com/gratimax/gulp-grunt.git",
7 | "author": "gratimax ",
8 | "main": "./index.js",
9 | "keywords": [
10 | "gulpfriendly",
11 | "grunt"
12 | ],
13 | "dependencies": {
14 | "grunt": "^1.0.1"
15 | },
16 | "devDependencies": {
17 | "gulp-mocha": "^2.1.3",
18 | "mocha": "^2.3.3",
19 | "chai": "^3.3.0",
20 | "gulp": "^3.9.0"
21 | },
22 | "scripts": {
23 | "test": "mocha -R spec"
24 | },
25 | "engines": {
26 | "node": ">= 0.9.0"
27 | },
28 | "license": "MIT"
29 | }
30 |
--------------------------------------------------------------------------------
/test/fixtures/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 |
3 | grunt.registerTask('test', 'does blah', function () {
4 | console.log('[test] you should probably see that it has tested');
5 | });
6 |
7 | grunt.registerTask('error', 'makes an error', function () {
8 | grunt.log.error('[test] you should see this error');
9 | return false;
10 | });
11 |
12 | grunt.registerTask('epic-error', 'should interupt build', function() {
13 | grunt.fail.warn('[test] I am totally failed');
14 | return false;
15 | });
16 |
17 | };
18 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | var expect = require('chai').expect;
2 | var path = require('path');
3 | var Gulp = require('gulp').Gulp;
4 | var addGrunt = require('../');
5 | require('mocha');
6 |
7 | describe('gulp-grunt', function () {
8 |
9 | var gulp;
10 |
11 | /*
12 | This function essentially takes a function and 'silences' it.
13 | This means that all the output will be logged to an array('out') instead of stdout.
14 | If the function only takes one parameter,
15 | that array will be passed in and the function will be synchronous.
16 | If the function takes two parameters(the array and a callback),
17 | everything is done asynchronously.
18 | This also has the advantage of making the output look very clean.
19 | */
20 | var silence = function (silenced) {
21 | return function (cb) {
22 | var out = [],
23 | // everything back to normal
24 | revert = (function (write) {
25 | return function () {
26 | process.stdout.write = write;
27 | }
28 | })(process.stdout.write);
29 |
30 | // modify process.stdout
31 | process.stdout.write = function (string) {
32 | out.push(string);
33 | };
34 |
35 | if (silenced.length == 1) {
36 | // If the function is synchronous
37 | silenced(out);
38 | revert();
39 | cb();
40 | } else if (silenced.length == 2) {
41 | // If the function is asynchronous
42 | silenced(out, function (err) {
43 | revert();
44 | if (err) {
45 | cb(err);
46 | } else {
47 | cb();
48 | }
49 | });
50 | }
51 |
52 | }
53 | };
54 |
55 | // Encapsulate the expect clauses on asynchronous silenced functions.
56 | var clause = function (fn, done) {
57 | try {
58 | fn();
59 | done();
60 | } catch (e) {
61 | done(e);
62 | }
63 | };
64 |
65 | beforeEach(function () {
66 | gulp = new Gulp;
67 | });
68 |
69 | it('should load grunt tasks', function () {
70 | addGrunt(gulp, { base: path.join(__dirname, 'fixtures')});
71 | expect(gulp.tasks).to.have.keys(['grunt-test', 'grunt-error', 'grunt-epic-error']);
72 | });
73 |
74 | it('should still run gulp tasks', function () {
75 | var ran = false;
76 |
77 | gulp.task('x', function () {
78 | ran = true;
79 | });
80 | gulp.run('x');
81 | expect(ran).to.be.true;
82 | });
83 |
84 | it('should work with another prefix', function () {
85 | addGrunt(gulp, { base: path.join(__dirname, 'fixtures'), prefix: 'gr-' });
86 | expect(gulp.tasks).to.have.keys(['gr-test', 'gr-error', 'gr-epic-error']);
87 | });
88 |
89 | it('should work with no prefix', function () {
90 | addGrunt(gulp, { base: path.join(__dirname, 'fixtures'), prefix: '' });
91 | expect(gulp.tasks).to.have.keys(['test', 'error', 'epic-error']);
92 | });
93 |
94 | it('should run grunt tasks, which fails', silence(function (out, done) {
95 | addGrunt(gulp, { base: path.join(__dirname, 'fixtures'), force: false});
96 | gulp.run('grunt-epic-error', function () {
97 | clause(function () {
98 | expect(out).to.include('[test] I am totally failed\n');
99 | }, done);
100 | });
101 |
102 | }));
103 |
104 | it('should run grunt tasks', silence(function (out, done) {
105 | addGrunt(gulp, { base: path.join(__dirname, 'fixtures')});
106 | gulp.run('grunt-test', function () {
107 | clause(function () {
108 | expect(out).to.include('[test] you should probably see that it has tested\n');
109 | }, done);
110 | });
111 |
112 | }));
113 |
114 | it('should handle errors gracefully', silence(function (out, done) {
115 | addGrunt(gulp, { base: path.join(__dirname, 'fixtures') });
116 |
117 | gulp.run('grunt-error', function () {
118 | clause(function () {
119 | var errored = false;
120 | for (var i = 0; i < out.length; i++) {
121 | if (out[i].indexOf("[test] you should see this error") != -1) {
122 | errored = true;
123 | }
124 | }
125 | expect(errored).to.be.true;
126 | }, done);
127 | });
128 |
129 | }));
130 |
131 | });
132 |
--------------------------------------------------------------------------------