Does it possible create task factory or something like this?

for example I have a few tasks in gradle/app.gradle:

task 'npm install'(type: Exec) {
    workingDir './app'
    executable 'bash'
    args '-c', 'npm install'
}
task 'npm run build'(type: Exec, dependsOn: ['npm install']) {
    workingDir './app'
    executable 'bash'
    args '-c', 'npm run build'
}
task 'npm start'(type: Exec, dependsOn: ['npm install']) {
    workingDir './app'
    executable 'bash'
    args '-c', 'npm start'
}

and I want refactor it according to the DRY principles in something like factory method:

def npmAction(npmCommand) {
    task "$npmCommand"(type: Exec, dependsOn: ['npm install']) {
        workingDir './app'
        executable 'bash'
        args '-c', "$npmCommand"
    }
}

and in build.gradle I do

apply from: "$rootDir/gradle/app.gradle"

Task npmRunBuild = npmAction('npm run build')
build.dependsOn npmRunBuild
build.shouldRunAfter npmRunBuild

Task npmStart = npmAction('npm start')
// let's assume that npm start process in the separate thread
bootRun.dependsOn npmStart 
bootRun.shouldRunAfter npmStart

ps: I know about npm/node plugins and other solutions to work with npm

best regarts, Max

This is a method declaration which is only visible inside that one script.

If you want to make something available in the project’s scope, you’ll need to put a Closure into the extension container:

ext.npmAction = { npmCommand -> 
  // your code here
}

Firstly I don’t think you can have spaces in task names. Gradle won’t be able to execute these from command line since gradle npm install tells gradle to execute two tasks named “npm” and “install”

I think you want something like

def npmTaskMap = [
   'npmInstall' : 'npm install', 
   'npmStart' : 'npm start' 
] 

npmTaskMap.each { k, v ->
   task.create(name: k, type: Exec) {
      ... 
      args '-c', "$v" 
   } 
} 

I definitely can:

$ gradle 'npm install'
Starting a Gradle Daemon (subsequent builds will be faster)
:npm install

> spring-boot-backbone@0.0.1 postinstall /home/mak/code/test/spring/spring-boot-backbone/app
> bower install jquery bootstrap lodash curl backbone

bower jquery#*                  cached https://github.com/jquery/jquery-dist.git#3.1.1
bower jquery#*                validate 3.1.1 against https://github.com/jquery/jquery-dist.git#*
bower bootstrap#*               cached https://github.com/twbs/bootstrap.git#3.3.7
bower bootstrap#*             validate 3.3.7 against https://github.com/twbs/bootstrap.git#*
bower lodash#*                  cached https://github.com/lodash/lodash.git#4.16.3
bower lodash#*                validate 4.16.3 against https://github.com/lodash/lodash.git#*
bower backbone#*                cached https://github.com/jashkenas/backbone.git#1.3.3
bower backbone#*              validate 1.3.3 against https://github.com/jashkenas/backbone.git#*
bower curl#*                    cached https://github.com/cujojs/curl.git#0.8.13
bower curl#*                  validate 0.8.13 against https://github.com/cujojs/curl.git#*
npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: fsevents@1.0.14

BUILD SUCCESSFUL

Total time: 8.994 secs

nevertheless, it’s OK if I will have any restrictions for task-naming

lovely gradle!
thank you!
this works exactly as I wanted:

gradle/app.gradle

task 'npm install'(type: Exec) {
  workingDir './app'
  executable 'bash'
  args '-c', 'npm install'
}

['npm run build', 'npm start'].each { npmCommand ->
  tasks.create(name: npmCommand, type: Exec, dependsOn: ['npm install']) {
    workingDir './app'
    executable 'bash'
    args '-c', npmCommand
  }
}

build.gradle:

...
apply from: "$rootDir/gradle/app.gradle"
build.dependsOn 'npm run build'
build.shouldRunAfter 'npm run build'
gradle build

worked example

<3 :gradlephant: