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

Add a new npx task to execute npm CLI tools thanks to the npx command #32

Merged
merged 14 commits into from
Sep 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions docs/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,45 @@ task installExpress(type: NpmTask) {
}
```

## Executing `npm` Commands via `npx`

[As of 5.2](https://blog.npmjs.org/post/162869356040/introducing-npx-an-npm-package-runner),
`npm` is bundled with a new command called [`npx`](https://www.npmjs.com/package/npx) which is aimed at running CLI
commands from NPM packages.

It enables to execute `npm` commands without needing to declare them as a `script` in the `package.json` file and run
thanks to the `npm run` command.

It does not require the command to be locally or globally installed. If the command is not already installed, the
corresponding package is installed then the command is run. In this case, it is necessary to indicate the package
name instead of the command name.

The `NpxTask` is able to execute some `npx` commands. It depends on the `npmSetup` to ensure `npx` is available.

To generate a new Angular project with the `ng` command coming from `@angular/cli` which is not installed
(note that we can specify the version):

```gradle
task generateAngularApp(type: NpxTask) {
command = '@angular/cli@8.3.2'
args = ['new', 'myApp']
}
```

To build an Angular application with `@angular/cli` locally installed:

```gradle
task buildAngularApp(type: NpxTask) {
dependsOn npmInstall
command = 'ng'
args = ['build', '--prod']
inputs.files('package.json', 'package-lock.json', 'angular.json', 'tsconfig.json', 'tsconfig.app.json')
inputs.dir('src')
inputs.dir(fileTree("node_modules").exclude(".cache"))
outputs.dir('dist')
}
```


## Executing Yarn Tasks

Expand Down
2 changes: 2 additions & 0 deletions src/main/groovy/com/moowork/gradle/node/NodeExtension.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class NodeExtension

String npmCommand = 'npm'

String npxCommand = 'npx'

String npmInstallCommand = 'install'

String yarnCommand = 'yarn'
Expand Down
2 changes: 2 additions & 0 deletions src/main/groovy/com/moowork/gradle/node/NodePlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.moowork.gradle.node
import com.moowork.gradle.node.npm.NpmInstallTask
import com.moowork.gradle.node.npm.NpmSetupTask
import com.moowork.gradle.node.npm.NpmTask
import com.moowork.gradle.node.npm.NpxTask
import com.moowork.gradle.node.task.NodeTask
import com.moowork.gradle.node.task.SetupTask
import com.moowork.gradle.node.variant.VariantBuilder
Expand Down Expand Up @@ -48,6 +49,7 @@ class NodePlugin
{
addGlobalTaskType( NodeTask )
addGlobalTaskType( NpmTask )
addGlobalTaskType( NpxTask )
addGlobalTaskType( YarnTask )
}

Expand Down
33 changes: 26 additions & 7 deletions src/main/groovy/com/moowork/gradle/node/exec/ExecRunner.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package com.moowork.gradle.node.exec
import com.moowork.gradle.node.NodeExtension
import com.moowork.gradle.node.variant.Variant
import org.gradle.api.Project
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Optional
import org.gradle.process.ExecResult

abstract class ExecRunner
Expand All @@ -15,11 +18,12 @@ abstract class ExecRunner

def Map<String, ?> environment = [:]

def Object workingDir
def File workingDir

@Internal
def List<?> arguments = []

def boolean ignoreExitValue
def boolean ignoreExitValue = false

def Closure execOverrides

Expand All @@ -29,6 +33,25 @@ abstract class ExecRunner
this.environment << System.getenv()
}

@Input
@Optional
File getWorkingDir()
{
return workingDir
}

@Input
Map<String, ?> getEnvironment()
{
return this.environment
}

@Input
boolean getIgnoreExitValue()
{
return ignoreExitValue
}

protected final ExecResult run( final String exec, final List<?> args )
{
def realExec = exec
Expand All @@ -38,17 +61,13 @@ abstract class ExecRunner
it.executable = realExec
it.args = realArgs
it.environment = this.environment
it.ignoreExitValue = this.ignoreExitValue

if ( this.workingDir != null )
{
it.workingDir = this.workingDir
}

if ( this.ignoreExitValue != null )
{
it.ignoreExitValue = this.ignoreExitValue
}

if ( this.execOverrides != null )
{
this.execOverrides( it )
Expand Down
24 changes: 19 additions & 5 deletions src/main/groovy/com/moowork/gradle/node/npm/NpmExecRunner.groovy
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.moowork.gradle.node.npm

import com.moowork.gradle.node.exec.ExecRunner
import com.moowork.gradle.node.exec.NodeExecRunner
import org.gradle.api.InvalidUserDataException
import org.gradle.api.Project
import org.gradle.api.tasks.Internal
import org.gradle.process.ExecResult

class NpmExecRunner
Expand All @@ -18,7 +17,7 @@ class NpmExecRunner
protected ExecResult doExecute()
{

def exec = this.variant.npmExec
def exec = getCommand()
def arguments = this.arguments

if ( this.ext.download )
Expand All @@ -40,7 +39,7 @@ class NpmExecRunner
environment['PATH'] = path + File.pathSeparator + environment['PATH']
}

def File localNpm = project.file( new File( this.ext.nodeModulesDir, 'node_modules/npm/bin/npm-cli.js' ) )
def File localNpm = getLocalCommandScript()
if ( localNpm.exists() )
{
exec = this.variant.nodeExec
Expand All @@ -49,9 +48,24 @@ class NpmExecRunner
else if ( !new File(exec).exists() )
{
exec = this.variant.nodeExec
arguments = [this.variant.npmScriptFile] + arguments
arguments = [getCommandScript()] + arguments
}
}
return run( exec, arguments )
}

@Internal
protected String getCommand() {
this.variant.npmExec
}

@Internal
protected File getLocalCommandScript() {
return project.file(new File(this.ext.nodeModulesDir, 'node_modules/npm/bin/npm-cli.js'))
}

@Internal
protected String getCommandScript() {
return this.variant.npmScriptFile
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class NpmInstallTask

@OutputFile
@Optional
@PathSensitive(PathSensitivity.RELATIVE)
deepy marked this conversation as resolved.
Show resolved Hide resolved
protected getPackageLockFileAsOutput()
{
if (npmCommand[0] == "install") {
Expand Down
11 changes: 9 additions & 2 deletions src/main/groovy/com/moowork/gradle/node/npm/NpmSetupTask.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.moowork.gradle.node.task.SetupTask
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.process.ExecResult
Expand Down Expand Up @@ -37,7 +38,7 @@ class NpmSetupTask
}

@Input
Set<String> getInput()
Set<Object> getInput()
{
def set = new HashSet<>()
set.add( getConfig().download )
Expand Down Expand Up @@ -76,12 +77,12 @@ class NpmSetupTask
return getConfig().variant
}

@Input
List<?> getArgs()
{
return this.args
}

@Internal
void setArgs( final Iterable<?> value )
{
this.args = value.toList()
Expand All @@ -97,6 +98,12 @@ class NpmSetupTask
this.runner.execOverrides = closure
}

@Nested
NpmExecRunner getRunner()
{
return runner
}

@TaskAction
void exec()
{
Expand Down
15 changes: 12 additions & 3 deletions src/main/groovy/com/moowork/gradle/node/npm/NpmTask.groovy
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.moowork.gradle.node.npm

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.TaskAction
import org.gradle.process.ExecResult

Expand Down Expand Up @@ -43,6 +45,7 @@ class NpmTask
this.args = value.asList()
}

@Input
String[] getNpmCommand() {
return npmCommand
}
Expand All @@ -52,20 +55,26 @@ class NpmTask
this.npmCommand = cmd
}

@Internal
@Input
List<?> getArgs()
{
return this.args
}

@Nested
NpmExecRunner getExecRunner()
{
return this.runner
}

void setEnvironment( final Map<String, ?> value )
{
this.runner.environment << value
}

void setWorkingDir( final Object value )
void setWorkingDir( final File workingDir )
{
this.runner.workingDir = value
this.runner.workingDir = workingDir
}

void setIgnoreExitValue( final boolean value )
Expand Down
30 changes: 30 additions & 0 deletions src/main/groovy/com/moowork/gradle/node/npm/NpxExecRunner.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.moowork.gradle.node.npm

import org.gradle.api.Project
import org.gradle.api.tasks.Internal

class NpxExecRunner
extends NpmExecRunner
{
public NpxExecRunner(Project project) {
super(project)
}

@Override
@Internal
protected String getCommand() {
return this.variant.npxExec
}

@Override
@Internal
protected File getLocalCommandScript() {
return project.file(new File(this.ext.nodeModulesDir, 'node_modules/npm/bin/npx-cli.js'))
}

@Override
@Internal
protected String getCommandScript() {
return this.variant.npxScriptFile
}
}
Loading