Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multitask option to set the default behavior when a subtask is not specified #815

Open
dylang opened this issue Jun 12, 2013 · 27 comments
Open
Labels
Milestone

Comments

@dylang
Copy link
Contributor

dylang commented Jun 12, 2013

Sometimes it's dangerous or undesired to run all of a multitask's subtasks by default.

Proposal: an option to set the default behavior when a subtask is not specified instead of iterating through all the subtasks.

Default deploy to use dev when a subtask is not specified:

deploy: {
  options: { 
    default: 'dev'
  },
  dev: { .. },
  qa: { .. },
  prod: { .. }
}
$ grunt deploy  # only runs deploy:dev instead of all of them

Example:
Don't run any bump subtasks if the subtask is not specified.

bump: {
  options: { 
    default: false
  },
  major: { .. },
  minor: { .. },
  patch: { .. },
  build: { .. }
}
$ grunt bump  # returns an error that the bump subtask was not specified
@NickHeiner
Copy link

👍

This would also be helpful when you have a bunch of subtasks for clean and running them all at once is an uncommon scenario.

@kiurchv
Copy link

kiurchv commented Jun 29, 2013

👍

@neagle
Copy link

neagle commented Oct 2, 2013

I have a case where I'd like to have some additional watch targets for specific deployment targets, but I'd like the generic watch task not to run any of them, and an option like the one described by @dylang would be very useful.

@softwaredoug
Copy link

+1

@peol
Copy link

peol commented Oct 18, 2013

I agree, I actually thought this was the default behavior when I first started using grunt, it just made sense. options is a grunt reserved keyword now, maybe defaults could be as well?

grunt.initConfig({
  myMultiTask: {
    options: {
      clean: true,
      dir: ""
    },
    defaults: {
      clean: false.
      dir: "foo"
    },
    bamboo: {
      dir: "bar"
    },
    jenkins: {
      dir: "baz"
    }
  }
});

Invoke:

$ grunt myMultiTask
-- Running myMultiTask...
$ grunt myMultiTask:bamboo
-- Running myMultiTask (subtask bamboo)...
$

@cowboy: Does this make any sense or are there perhaps any plans on a different approach that enables one to run this without having to define a new task that runs a specific subtask?

@rsternagel
Copy link

👍

Having the exact same situation with clean as described by @NickHeiner.

@rinatio
Copy link

rinatio commented Dec 12, 2013

+1 for default subtask

@jethrolarson
Copy link

👍

@cowboy
Copy link
Member

cowboy commented Jan 22, 2014

I don't like the idea of a named option, because it will 1. override any existing task's defaults option and 2. be meaningless once options are merged down to the target level.

This problem could be solved with another reserved key next to the options key, like default.

Another possible solution: Right now, properties starting with _ are ignored in multi-tasks and are invalid targets. Maybe I could change that behavior to make them non-iterable, but still valid.

Here's a sample Gruntfile:

module.exports = function(grunt) {
  grunt.initConfig({
    foo: {
      a: {},
      b: {},
      _c: {},
    }
  });

  grunt.registerMultiTask('foo', function() {
    console.log(this.nameArgs);
  });
};

And some sample CLI output.

$ grunt foo
Running "foo:a" (foo) task
foo:a

Running "foo:b" (foo) task
foo:b

Done, without errors.

$ grunt foo:_c
Running "foo:_c" (foo) task
foo:_c

Done, without errors.

Note that in the current Grunt, running grunt foo:_c will error. This would be a bit of a change.

@neagle
Copy link

neagle commented Jan 22, 2014

I love the underscore option. It maps to the way partials work in Sass, in
a way.

Nate Eagle

On Jan 22, 2014, at 3:12 PM, Ben Alman notifications@github.com wrote:

I don't like the idea of a named option, because it will 1. override any
existing task's defaults option and 2. be meaningless once options are
merged down to the target level.

This problem could be solved with another reserved key next to the
optionskey, like
default.

Another possible solution: Right now, properties starting with _ are
ignored in multi-tasks and are invalid targets. Maybe I could change that
behavior to make them non-iterable, but still valid.

Here's a sample Gruntfile:

module.exports = function(grunt) {
grunt.initConfig({
foo: {
a: {},
b: {},
_c: {},
}
});

grunt.registerMultiTask('foo', function() {
console.log(this.nameArgs);
});};

And some CLI output.

$ grunt foo
Running "foo:a" (foo) task
foo:a

Running "foo:b" (foo) task
foo:b

Done, without errors.

$ grunt foo:_c
Running "foo:_c" (foo) task
foo:_c

Done, without errors.

It's just a thought, for now at least.


Reply to this email directly or view it on
GitHubhttps://github.com//issues/815#issuecomment-33062465
.

@rinatio
Copy link

rinatio commented Jan 23, 2014

@cowboy how would _ options help with default behavior? If you run grunt foo is it still running all subtasks?

@jethrolarson
Copy link

I like using "default" as an extra keyword. Though that could break code in the wild I guess.

The next question is whether the value should be a string that references the default task or just be the task object itself. I suppose it could be both dependant on the type the user uses.

@vladikoff vladikoff modified the milestones: 0.4.5, 0.4.4 Mar 12, 2014
@vladikoff vladikoff modified the milestones: 0.4.6, 0.4.5 Apr 8, 2014
@codepunkt
Copy link

+1 for default target.

I'm using a build task that has several targets, named 'package1' to 'packageN'.
Each package target builds a list of modules, many of which are built into multiple packages.

Running the build task without a target would build a lot of the modules more than once.
Thats why im using an additional 'all' target that builds every module.

Being able to flag this target would be exactly what i need.

The underscore option is fine, but in my situation it would lead to the use of a lot of underscore target names (_packageX) - which seems awkward.

@mustafa0x
Copy link

👍 A default target is needed and makes sense.

@jcwilson
Copy link

+1
Why is this not a thing yet? :)

Here's a dirty hack until something more official comes along. Create a file (tasks/multitask-default.js) and call grunt.loadTasks('tasks') in your Gruntfile.js. Use this for the contents of the file:


/**
 * Enable default multitask support. Define your default task by adding another task
 * with the empty string ('') as its name and the name of the default task as its value.
 *
 * Example: (publish is a multi-task)
 *     // In your Gruntfile.js
 *     grunt.initConfig({
 *         publish: {
 *             options: {
 *                // some options
 *             },
 *             '': 'dev',
 *             dev: {
 *                 // definition
 *             },
 *             release: {
 *                 // definition
 *             }
 *         }
 *     });
 *
 *     // Running "grunt publish" will only invoke publish:dev
 *
 */
module.exports = function (grunt) {
    var originalRunAllTargets = grunt.task.runAllTargets;
    grunt.task.runAllTargets = function(taskname, args) {

        var targets = grunt.config.getRaw(taskname) || {},
            target;

        function isValidMultiTaskTarget(name) {
            return !/^_|^options$/.test(name);
        }

        target = targets[''];
        if (typeof target === 'undefined') {
            originalRunAllTargets(taskname, args);
        } else {
            if (! isValidMultiTaskTarget(target)) {
                throw new Error('Invalid default target "' + target + '" specified.');
            }
            grunt.task.run([taskname, target].concat(args || []).join(':'));
        }
    };
};

@vladikoff vladikoff modified the milestones: 0.5.0, 0.4.6 Jun 19, 2014
@mar10
Copy link

mar10 commented Jun 19, 2014

👍
How about naming it defaultTarget.
I would even prefer to change the current behavior and make running all targets explicit:

grunt.initConfig({
  myMultiTask: {
    defaultTarget: 'jenkins',
    options: {
      clean: true,
      dir: ""
    },
    bamboo: {
      dir: "bar"
    },
    jenkins: {
      dir: "baz"
    }
  }
});
  • myMultiTask:bamboo runs the bamboo target
  • myMultiTask runs the default target (jenkins).
    If no defaultTarget is defined, myMultiTask will raise an error
  • myMultiTask:* runs bamboo and jenkins

@jcwilson
Copy link

I like the * designation to make it explicit that you want to run all of the tasks, too.

@mcandre
Copy link

mcandre commented Jul 30, 2014

+1

I would like to write independent grunt-exec tasks, where only the specified subtask runs by default, similar to how a traditional Makefile behaves.

@vgrinko
Copy link

vgrinko commented Oct 10, 2014

+1 for default subtask.

@jawshooah
Copy link

👍 This would be a great feature.

@JobaDiniz
Copy link

Hi, I have the following scenario:

My app is built for multiple clients, so I'm setting up grunt to handle commands like:
grunt scsslint --client=company1
grunt scsslint --client=company2

Gruntfile.js

module.exports = function (grunt) {

    var client = grunt.option('client') || 'company1';
    var scsslint = {
        options: {
            config: 'scss-lint-config.yml',
            reporterOutput: 'scss-lint-report.xml'
        },
        core: ['core/**/*.scss']
    };
    scsslint[client] = [client + '/**/*.scss'];

   grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        config: grunt.file.readJSON(client + '-config.json'),
        scsslint: scsslint,

grunt scsslint --client=company1 should be the same as running grunt scsslint:company1.
However, grunt scsslint --client=company1 run all sub-tasks. grunt scsslint:company1 works just fine.

Any ideas to accomplish what I want?

@sasikanth
Copy link

+1 for the defaultTarget
+1 for myMultiTask:* to all the targets explicitly

grunt.initConfig({
  myMultiTask: {
    defaultTarget: 'jenkins',
    options: {
      clean: true,
      dir: ""
    },
    bamboo: {
      dir: "bar"
    },
    jenkins: {
      dir: "baz"
    }
  }
});

myMultiTask:bamboo runs the bamboo target
myMultiTask runs the default target (jenkins).
If defaultTarget is not provided / defined, myMultiTask will raise an error
myMultiTask:* runs bamboo and jenkins

@MichaelSitter
Copy link

👍 Would solve some problems we are having really nicely

@Henni
Copy link

Henni commented Jun 3, 2015

+1 for defaultTarget

Especially in the case of multiple watch targets this would be really helpful.

@honzajavorek
Copy link

It's easy to overcome this limitation by monkeypatching:

module.exports = (grunt) ->
  grunt.registerMultiTask 'test', 'Docs...', ->
    ...

  decoratedFn = grunt.task._tasks['test'].fn
  decorator = (target) ->
    args = grunt.util.toArray(arguments)

    if not target
      args = ['all'].concat(args.slice(1)) # running just 'grunt test'
    else if not grunt.config(['test', target])
      args = ['arbitrary', target].concat(args.slice(1)) # running arbitrary test, e.g. 'grunt:test/my-specific-test-file.coffee'

    @nameArgs = "test:#{args[0]}"
    decoratedFn.apply(@, args)
  grunt.task._tasks['test'].fn = decorator

Config:

  test:
      options:
        reporter: 'spec'
        timeout: 120000

      all:
        options: ...

      arbitrary:
        options: ...

      unit:
        src: 'test/*-test.coffee'
        options:
          timeout: 30000

Now I'm able to do:

grunt test:path/to/my/test.coffee # unknown target, assuming path to file, target 'arbitrary'
grunt test:unit # specific target 'unit'
grunt test # target 'all', thus the same as 'grunt test:all'

@titocr
Copy link

titocr commented Jul 12, 2016

+1 This would be a useful feature.

@JoseFaeti
Copy link

How come this is still not a thing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests