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

Run specific task(s) with force option #810

Open
explunit opened this issue Jun 6, 2013 · 43 comments
Open

Run specific task(s) with force option #810

explunit opened this issue Jun 6, 2013 · 43 comments
Milestone

Comments

@explunit
Copy link

explunit commented Jun 6, 2013

I see that several plug-ins have added a force option, for example:
https://github.com/gruntjs/grunt-contrib-jshint#force
https://github.com/gruntjs/grunt-contrib-clean#force

But it would be useful to have a general-purpose way of doing this at the grunt level. Here's what I'm currently doing for a workaround:

grunt.registerTask('usetheforce_on',
 'force the force option on if needed', 
 function() {
  if ( !grunt.option( 'force' ) ) {
    grunt.config.set('usetheforce_set', true);
    grunt.option( 'force', true );
  }
});
grunt.registerTask('usetheforce_restore', 
  'turn force option off if we have previously set it', 
  function() {
  if ( grunt.config.get('usetheforce_set') ) {
    grunt.option( 'force', false );
  }
});
grunt.registerTask( 'myspecialsequence',  [
  'usetheforce_on', 
  'task_that_might_fail_and_we_do_not_care', 
  'another_task', 
  'usetheforce_restore', 
  'qunit', 
  'task_that_should_not_run_after_failed_unit_tests'
] );

Is there a better workaround? If not, would you consider adding a feature for this?

@ampgcat
Copy link

ampgcat commented Jul 4, 2013

I second this request.
Also, when a task iterates over files, it would be nice to have an option to execute it on the next file when one fails.

@mokkabonna
Copy link

Sounds great. I might have an alias for other tasks, some of which are allowed to fail without failing the mother task.

Something like this would be good for me. There probably is a better syntax though.

grunt.registerTask('test', ['jshint --force', 'karma:test']); 

The karma task would have force off unless I run the mother task with --force

grunt test --force

@getify
Copy link

getify commented Oct 30, 2013

+1

btw, @explunit a bit of an improvement to the hack while we wait for this to land:

var previous_force_state = grunt.option("force");

grunt.registerTask("force",function(set){
    if (set === "on") {
        grunt.option("force",true);
    }
    else if (set === "off") {
        grunt.option("force",false);
    }
    else if (set === "restore") {
        grunt.option("force",previous_force_state);
    }
});

// .....

grunt.registerTask("foobar",[
    "task1",
    "task2",
    "force:on",     // temporarily turn on --force
    "task3",        // will run with --force in effect
    "force:restore",// restore previous --force state
    "task4"
]);

@behrang
Copy link

behrang commented Dec 12, 2013

+1

@behrang
Copy link

behrang commented Dec 12, 2013

Proposed solutions don't work in grunt-contrib--watch. Although this may be handled in that task.
EDIT:
It is not inherited by watch task, but it is possible to add it to the watch target's tasks list.

@Bartvds
Copy link

Bartvds commented Dec 12, 2013

There is also https://npmjs.org/package/grunt-continue.

@yuanyan
Copy link

yuanyan commented Dec 12, 2013

May be force also should be a task-level option like files, then we can configure it with some task, not only a global setting:

grunt.initConfig({
  concat: {
    foo: {
      files: {
        'dest/a.js': ['src/aa.js', 'src/aaa.js'],
        'dest/a1.js': ['src/aa1.js', 'src/aaa1.js'],
      },
      force: true,
    },
    bar: {
      files: {
        'dest/b.js': ['src/bb.js', 'src/bbb.js'],
        'dest/b1.js': ['src/bb1.js', 'src/bbb1.js'],
      },
      force: false,
    },
  },
});

@shellscape
Copy link

Issue was opened 7 months ago, and the pull request (yaymukund/grunt-simple-mocha#36) addresses it. Has this been considered by the core contributors?

@vladikoff
Copy link
Member

Currently set milestone target is 0.4.3. Which is the next release, so we shall look at this.

@shellscape
Copy link

Outstanding. Thanks for getting eyes on this @vladikoff

@vladikoff
Copy link
Member

We have looked at this and discussed some syntax options.
Something like ['jshint --force',... is not applicable. There are a lot of task running cases to look into, we shall revisit this again in 0.4.4.
If anyone has more suggestions on how this force option may be defined. For example, should it part of the alias task definition? or anywhere else? Let us know.

@getify
Copy link

getify commented Jan 23, 2014

@vladikoff

Something like ['jshint --force',... is not applicable

Can you elaborate on why that's not an option?

Something like ['jshint:force', ...] could create unfortunate overlap with task parameters, I understand. But --force seems unique enough (non-param syntax) to easily be able to be parsed out ahead of time. Can you help us understand why it's not applicable or feasible?

What about the inverse, like ['force:jshint', 'bar', 'force:bar'], where force was treated like a pre-defined virtual task that does something similar to what I showed in my snippet above, perhaps like:

grunt.registerTask("force",function(task){
   var previous_force_state = grunt.option("force");

   grunt.option("force",true);
   grunt.runTask(task); // ??? is that how you run tasks?
   grunt.option("force",previous_force_state)
});

That way, wherever you have the ability to specify a task, if you want to force it, you just say "force: ..." to force it, or "..." to not force it. Would that work?

@cowboy
Copy link
Member

cowboy commented Jan 23, 2014

@getify unfortunately, task names can be any arbitrary string. By giving the substring --force a special meaning it could cause compatibility issues. Technically. Unlikely, though.

Either way, it feels more like a band-aid than a real solution, because I can think of scenarios where the --force solution would be inadequate or where a more expressive solution might be desired.

For example, what if you have tasks a, b and c and you want b to not run if a fails, but you want c to run, regardless of the success of a or b.

I dunno.

@vladikoff
Copy link
Member

For example, what if you have tasks a, b and c and you want b to not run if a fails, but you want c to run, regardless of the success of a or b.

To expand on that, we were talking about syntax solutions for this:
grunt.registerTask("build",['a','b','c']); - if 'a' fails then 'b', 'c' will not run
grunt.registerTask("build",['a->b,c']); - if 'a' fails then 'b' doesn't run, 'c' will still run (see how the arg is a single string)

@shellscape
Copy link

oh please don't add a custom set of syntax where none is needed. there's already a convention in Javascript which could be used for that kind of notation:

grunt.registerTask("build",['a','b','c']); - if 'a' fails then 'b', 'c' will not run
grunt.registerTask("build",[['a','b'],'c']); - if 'a' fails then 'b' doesn't run, 'c' will still run

['a', 'b'] is clearly a grouping, doesn't require any understanding of special characters or syntax, and follows the same ordering convention that's been in grunt, and unless it's used internally (that notation isn't in any documentation I could find) it should be open for use.

That would only require the introduction of a config option to force, or not to force. Or what to force, specifically. If you wanted to get nuts:

- force all (default)
- force none
- force only grouped tasks
- force only ungrouped tasks

@getify
Copy link

getify commented Jan 23, 2014

+1 I agree with @shellscape on the nesting thing. And I still think ["force:a","b"],"c",["d","force:e","f"] serves the important use-cases. That example would say:

  1. for the first group, "a" can succeed or fail, but "b" will go. if "b" fails, the whole sequence fails.
  2. "c" must succeed
  3. for the second group, "d" must succeed, "e" can succeed or fail, and "f" must succeed.

what use cases would that be missing?

@kmdavis
Copy link

kmdavis commented Jan 23, 2014

@getify that misses 1 use case: if 'a' fails, do we even want to try running 'b', same with e/f

I think I prefer @shellscape's idea (disclaimer: @shellscape is a coworker). Anything in a sub-group is essentially, a sub-grunt that succeeds or fails atomically, and doesn't affect the parent group.

@nschonni
Copy link

I like the prepending format, but what about using something like ! instead? ["a","!b", "c"], although that may cause some confusions with the different meaning in globbing patterns.

@cowboy
Copy link
Member

cowboy commented Jan 23, 2014

@shellscape could you explain all four "force" options? By "default" do you mean the current behavior?

@shellscape
Copy link

Yeah "(default)" got put in the wrong place. Thanks for catching that. By no means set in stone, but off the cuff was thinking:

- force all - all tasks are forced, all continue regardless of result.
- force none (default) - current behavior.
- force only grouped tasks - only grouped tasks would be forced. ungrouped tasks would run with the current behavior
- force only ungrouped tasks - only tasks which were not grouped would be forced. would allow for an inverse setup eg. grunt.registerTask("build",[''c', ['a','b']]); where task c would only be forced.

This was just off the cuff, to add to the discussion. The primary concern was logical grouping over syntax annotations.

@getify
Copy link

getify commented Jan 23, 2014

@kmdavis

that misses 1 use case: if 'a' fails, do we even want to try running 'b', same with e/f

If you want b to only run if a succeeds, then:

[["a","b"],"c"... or even just ["a","b","c"...

If you want the group ["a","b"] to be itself optional (aka forced), then no, my suggestion doesn't handle that. But what's actually a real (not just theoretical) example of such a use case? If the group failed, it would seem logical that the whole chain fails. I can only see in theory the need for "optional (aka forced) groups". Seems like it'd be over-architecting to solve that "optional-group" use-case unless there was a concrete example of such.

@kmdavis
Copy link

kmdavis commented Jan 27, 2014

@getify ok... real use case (please sign NDA here, here, and here, and submit in triplicate...)

In our legacy system (that we're converting over to grunt) we have some tasks that have Soft dependencies. A specific example would be linting. Linting is very nice, and we scream loudly if you fail linting... but we don't actually Stop anything that has a soft dependency on linting. We have a couple other things that are soft dependencies, like code coverage, complexity analysis, generating docs, etc. All things that are non-Essential.

Other things ARE essential. Like syntax checking, compilation, specs, etc. Sometimes, the soft deps are interspersed with the hard deps.

Example: When we run our spec task, it also runs npm install, compilation, docs, linting, syntax checking.
Using @shellscape's proposed syntax, that'd look something like this:

grunt.registerTask('spec', [
  'check-syntax',
  [
    'jshint',
    'gilt-special-linting',
    'complexity',
    'groc'
  ],
  'compile',
  'npm-install',
  'karma'
]);

@getify
Copy link

getify commented Jan 27, 2014

@kmdavis

wouldn't this be the same thing (unless I'm missing something)?

grunt.registerTask('spec', [
  'check-syntax',
  'force:jshint',
  'force:gilt-special-linting',
  'force:complexity',
  'force:groc'
  'compile',
  'npm-install',
  'karma'
]);

To put it more succinctly, I am having trouble imagining a scenario (in the real world) like:

  1. some required tasks
  2. a group of tasks:
    • some which are required
    • some which are optional
    • if any of the required items in the group fails, the group as a whole is optional
  3. more required tasks (that happen even if 2 as a group fails)

@shellscape
Copy link

@getify yes, essentially they're two ways to say the same thing. I was going with the array-grouping notation because of the proposal for additional custom syntax and concerns earlier in the thread about using 'force' as a keyword in any sense. (eg. imagine someone silly writing a starwars grunt task named 'force' -> 'force:use')

We're all in agreement about the gist of the need and seemingly how it should be roughly notated. What we need now is weigh in from the people who make the decisions (@cowboy, @vladikoff) on what sits best with them. I'm good with either array grouping or making 'force:' a reserved word. I believe we are monkey-patching my proposal soonish here, and will likely submit a pull request to add to the conversation.

@getify
Copy link

getify commented Jan 27, 2014

@shellscape agreed, for the most part.

We're inventing new "syntax" to patch a gap in functionality, not inventing a new syntax to cover every possible niche use-case. IMO the former dictates a minimal syntax for covering demonstrable/common use-cases, not a sugared syntax that is broadly capable.

That's the only reason why I was urging a simpler option than the one your proposed, to see if the simpler option (usually better) covered enough of the real-world stuff and restrained itself on the theoretically "nice" stuff which won't really get much bang for the buck.

@cowboy
Copy link
Member

cowboy commented Jan 28, 2014

I'm definitely not going to build-in a force: prefix, but you should be able to create a custom task that does just that. I encourage you to create it and give it a try.

I am, however, very interested in a more general solution, like what @shellscape suggests, as long as we can't poke any big holes in it.

@JGarrido
Copy link

JGarrido commented Feb 1, 2014

👍 to a grunt --force option, in addition to something like the inverse grouping example grunt.registerTask("build",[''c', ['a','b']]) @shellscape mentioned; where grouped tasks would be considered dependent on each other, and so should not be 'forced'. Unless you really, really wanted to force those tasks anyway, in which case I suppose a grunt --force=all would do the trick.

@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
@vladikoff vladikoff modified the milestones: 0.5.0, 0.4.6 May 6, 2014
@jzaefferer
Copy link
Member

Whatever the solution here, I'd like you to consider a related, pretty important aspect: The exit code. Currently, setting the force option on tasks that support it will cause grunt to exit with a zero status code, even when one or more forced tasks had errors.

My usecase is pretty simple: Run all tasks, but exit with non-zero status code if anything failed. That way I'd get the most out of Travis builds, where a trailing comma can be printed as an error in the jshint task and causes the build to fail, but it would still run the unit tests.

@shellscape
Copy link

fwiw we've been using the solution that @kmdavis outlined for four months now and it's been easy as all hell to use and grok, and haven't run into any negative side effects given heavy use of the construct.

@mgol
Copy link

mgol commented May 15, 2014

I agree with @jzaefferer, forcing the task should still make the whole process exit with code different than 0.

@vladikoff
Copy link
Member

#1163

@gausie
Copy link

gausie commented Sep 30, 2014

@shellscape what solution are you referring to there?

@shellscape
Copy link

@gausie this one #810 (comment)

however, we've since moved onto gulp as it made more sense for our needs.

@gausie
Copy link

gausie commented Sep 30, 2014

but isn't that comment just a recommendation for a syntax?

@floriangosse
Copy link

I have published a grunt task which enable the force mode for a specific task: grunt-force-task. It's easy to use and doesn't need any configuration. For example force:jshint.

At the moment I have one untested use case: Some tasks are executed parallel.
But first it's works for me.

@AndersDJohnson
Copy link
Member

@jzaefferer @mzgol Agreed, there needs to be an option continue build (with grouping or --force or whatever) but still carry through the non-zero exit code from intermediary steps so that the final exit code is also non-zero. This should be optional. Having it could solve the use case in #1114. Are there any other approaches to try/catch/finally error handling per-task in Grunt?

@Taytay
Copy link

Taytay commented Jan 12, 2015

Thanks @floriangosse. Your force-task works like a champ.

@atav32
Copy link

atav32 commented Apr 22, 2015

@floriangosse +1 grunt-force-task

@stefcameron
Copy link

@floriangosse +1 grunt-force-task works great!!

@ghost
Copy link

ghost commented Nov 22, 2015

@getify @floriangosse Another +1 for grunt-force-task ... worked as expected. Found it easier to understand than the grouped arrays. Seems more explicit in its use than having force implicitly called based on array structure.

@jsr6720
Copy link

jsr6720 commented Feb 22, 2016

@getify thanks for the workaround. plus one with the others.

@pombadev
Copy link

+1

1 similar comment
@ghost
Copy link

ghost commented Jan 10, 2018

+1

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

No branches or pull requests