Skip to content

Commit

Permalink
Fixed #43 (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
v1nc3n4 authored Jun 22, 2019
1 parent 107c06c commit 8046049
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 68 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Code coverage](https://sonarcloud.io/api/project_badges/measure?project=Siouan_frontend-gradle-plugin&metric=coverage)](https://sonarcloud.io/dashboard?id=Siouan_frontend-gradle-plugin)
[![Reliability](https://sonarcloud.io/api/project_badges/measure?project=Siouan_frontend-gradle-plugin&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=Siouan_frontend-gradle-plugin)

This plugin allows to integrate a frontend NPM/Yarn build into Gradle. It is inspired by the
This plugin allows to integrate a frontend Node/NPM/Yarn build into Gradle. It is inspired by the
[frontend-maven-plugin][frontend-maven-plugin]. See the [quick start guide](#quick-start-guide) below to
install/configure the plugin, and build your frontend application.

Expand All @@ -34,6 +34,7 @@ install/configure the plugin, and build your frontend application.
- [Clean frontend](#clean-frontend)
- [Assemble frontend](#assemble-frontend)
- [Check frontend](#check-frontend)
- [Run custom Node script](#run-custom-node-script)
- [Run custom NPM/Yarn script](#run-custom-npmyarn-script)
- [Usage guidelines](#usage-guidelines)
- [How to assemble a frontend and a Java backend into a single artifact?](#how-to-assemble-a-frontend-and-a-java-backend-into-a-single-artifact)
Expand Down Expand Up @@ -118,7 +119,7 @@ frontend {
// [OPTIONAL] Yarn version, used to build the URL to download the corresponding distribution, if the
// 'yarnDistributionUrl' property is not set. This property is mandatory when the 'yarnEnabled' property is
// true.
yarnVersion = '1.15.2'
yarnVersion = '1.16.0'
// [OPTIONAL] Sets this property to force the download from a custom website. By default, this property is
// 'null', and the plugin attempts to download the distribution compatible with the current platform from
Expand Down Expand Up @@ -265,6 +266,22 @@ be defined in the project's `package.json` file, and the `checkscript` property
NPM/Yarn command. A typical check script defined in the project's `package.json` file may lint frontend source files,
execute tests, and perform additional analysis tasks.

### Run custom Node script

The plugin provides the task type `org.siouan.frontendgradleplugin.tasks.RunNodeTask` that allows creating a custom
task to launch a frontend script. The `script` property must be set with the corresponding Node command. For
instance, the code below added in the `build.gradle` file allows to run a JS `my-custom-script.js` with Node:

```groovy
tasks.register('myCustomScript', org.siouan.frontendgradleplugin.tasks.RunNodeTask) {
// Choose whether Node only is required, or if additional dependencies located in the package.json file should be
// installed: make the task either depends on 'installNode' task or on 'installFrontend' task.
// dependsOn tasks.named('installNode')
// dependsOn tasks.named('installFrontend')
script = 'my-custom-script.js'
}
```

### Run custom NPM/Yarn script

The plugin provides the task type `org.siouan.frontendgradleplugin.tasks.RunScriptTask` that allows creating a custom
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ExecSpecAction implements Action<ExecSpec> {
/**
* Whether the script shall be run with Yarn instead of NPM.
*/
private final boolean yarnEnabled;
private final Executor executor;

/**
* Directory where the Node distribution is installed.
Expand Down Expand Up @@ -63,18 +63,18 @@ class ExecSpecAction implements Action<ExecSpec> {
/**
* Builds an action to run a frontend script on the local platform.
*
* @param yarnEnabled Whether the script shall be run with Yarn instead of NPM.
* @param executor Type of execution.
* @param nodeInstallDirectory Directory where the Node distribution is installed.
* @param yarnInstallDirectory Directory where the Yarn distribution is installed.
* @param script Name of the script to execute.
* @param afterConfigured A consumer called once the exec specification has been configured.
* @param osName Name of the O/S.
* @throws ExecutableNotFoundException When an executable cannot be found (Node, NPM, Yarn).
*/
public ExecSpecAction(final boolean yarnEnabled, final File nodeInstallDirectory, final File yarnInstallDirectory,
public ExecSpecAction(final Executor executor, final File nodeInstallDirectory, final File yarnInstallDirectory,
final String osName, final String script, final Consumer<ExecSpec> afterConfigured)
throws ExecutableNotFoundException {
this.yarnEnabled = yarnEnabled;
this.executor = executor;
this.nodeInstallDirectory = nodeInstallDirectory;
this.yarnInstallDirectory = yarnInstallDirectory;
this.osName = osName;
Expand All @@ -83,12 +83,20 @@ public ExecSpecAction(final boolean yarnEnabled, final File nodeInstallDirectory

nodeExecutablePath = Utils.getNodeExecutablePath(nodeInstallDirectory.toPath(), osName)
.orElseThrow(ExecutableNotFoundException::newNodeExecutableNotFoundException);
if (yarnEnabled) {
scriptExecutablePath = Utils.getYarnExecutablePath(yarnInstallDirectory.toPath(), osName)
.orElseThrow(ExecutableNotFoundException::newYarnExecutableNotFoundException);
} else {
switch (executor) {
case NODE:
scriptExecutablePath = nodeExecutablePath;
break;
case NPM:
scriptExecutablePath = Utils.getNpmExecutablePath(nodeInstallDirectory.toPath(), osName)
.orElseThrow(ExecutableNotFoundException::newNpmExecutableNotFoundException);
break;
case YARN:
scriptExecutablePath = Utils.getYarnExecutablePath(yarnInstallDirectory.toPath(), osName)
.orElseThrow(ExecutableNotFoundException::newYarnExecutableNotFoundException);
break;
default:
throw new IllegalArgumentException("Unsupported type of execution: " + executor);
}
}

Expand Down Expand Up @@ -118,7 +126,7 @@ public void execute(final ExecSpec execSpec) {
final String pathVariable = findPathVariable(environment);
final StringBuilder pathValue = new StringBuilder(nodeExecutablePath.getParent().toString());
pathValue.append(File.pathSeparatorChar);
if (yarnEnabled) {
if (executor == Executor.YARN) {
pathValue.append(scriptExecutablePath.getParent().toString());
pathValue.append(File.pathSeparatorChar);
}
Expand All @@ -131,12 +139,12 @@ public void execute(final ExecSpec execSpec) {
}

/**
* Whether Yarn is enabled and will be used at execution.
* Gets the executor used to run the script.
*
* @return {@code true} if Yarn is enabled.
* @return Executor.
*/
public boolean isYarnEnabled() {
return yarnEnabled;
public Executor getExecutor() {
return executor;
}

/**
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/siouan/frontendgradleplugin/core/Executor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.siouan.frontendgradleplugin.core;

/**
* Enumeration of types of execution supported by the plugin.
*
* @since 1.2.0
*/
public enum Executor {
NODE,
NPM,
YARN;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
public class RunScriptJob extends AbstractTaskJob {

/**
* Whether a Yarn distribution shall be downloaded and installed.
* Executor use to run the script.
*/
private final boolean yarnEnabled;
private final Executor executor;

/**
* Directory where the Node distribution is installed.
Expand All @@ -38,25 +38,25 @@ public class RunScriptJob extends AbstractTaskJob {
* Builds a job to run a script.
*
* @param task Parent task.
* @param yarnEnabled Whether Yarn shall be used instead of NPM to run the script.
* @param executor Executor to use to run the script.
* @param nodeInstallDirectory Node install directory.
* @param yarnInstallDirectory Yarn install directory.
* @param script The script run by the job.
* @param osName O/S name.
*/
public RunScriptJob(final Task task, final boolean yarnEnabled, final File nodeInstallDirectory,
public RunScriptJob(final Task task, final Executor executor, final File nodeInstallDirectory,
final File yarnInstallDirectory, final String script, final String osName) {
super(task);
this.yarnEnabled = yarnEnabled;
this.executor = executor;
this.nodeInstallDirectory = nodeInstallDirectory;
this.yarnInstallDirectory = yarnInstallDirectory;
this.script = script;
this.osName = osName;
}

public void run() throws ExecutableNotFoundException {
task.getProject().exec(
new ExecSpecAction(yarnEnabled, nodeInstallDirectory, yarnInstallDirectory, osName, script, execSpec -> {
task.getProject()
.exec(new ExecSpecAction(executor, nodeInstallDirectory, yarnInstallDirectory, osName, script, execSpec -> {
logDebug(execSpec.getEnvironment().toString());
logLifecycle(
"Running '" + execSpec.getExecutable() + ' ' + String.join(" ", execSpec.getArgs()) + '\'');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.TaskAction;
import org.siouan.frontendgradleplugin.core.ExecutableNotFoundException;
import org.siouan.frontendgradleplugin.core.Executor;
import org.siouan.frontendgradleplugin.core.RunScriptJob;
import org.siouan.frontendgradleplugin.core.Utils;

Expand Down Expand Up @@ -42,6 +43,10 @@ public abstract class AbstractRunScriptTask extends DefaultTask {
script = getProject().getObjects().property(String.class);
}

protected Executor getExecutionType() {
return yarnEnabled.get() ? Executor.YARN : Executor.NPM;
}

/**
* Executes the task. If a script has been provided, it is run with NPM/Yarn. Otherwise, the task does nothing.
*
Expand All @@ -50,7 +55,7 @@ public abstract class AbstractRunScriptTask extends DefaultTask {
@TaskAction
public void execute() throws ExecutableNotFoundException {
if (script.isPresent()) {
new RunScriptJob(this, yarnEnabled.get(), nodeInstallDirectory.get(), yarnInstallDirectory.get(),
new RunScriptJob(this, getExecutionType(), nodeInstallDirectory.get(), yarnInstallDirectory.get(),
script.get(), Utils.getSystemOsName()).run();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.siouan.frontendgradleplugin.tasks;

import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.siouan.frontendgradleplugin.FrontendExtension;
import org.siouan.frontendgradleplugin.core.ExecutableNotFoundException;
import org.siouan.frontendgradleplugin.core.Executor;

/**
* Task provided as a type to let developers implement custom task based on it. The task does not expose Node related
* options to avoid duplicating the plugin configuration. Using this task as a type to register a custom task requires
* only to define the {@code script} attribute, and to make the custom task depends on the {@code installNode} or {@code
* installFrontend} tasks. Choosing the related parent task will depend on the user needs.
* <p>
* A typical usage of this task in a 'build.gradle' file would be:
* <pre>
* tasks.register('mytask', org.siouan.frontendgradleplugin.tasks.RunNodeTask) {
* dependsOn tasks.named('installFrontend')
* script = 'myscript'
* }
* </pre>
*/
public class RunNodeTask extends AbstractRunScriptTask {

@Input
public Property<String> getScript() {
return script;
}

@Override
protected Executor getExecutionType() {
return Executor.NODE;
}

@Override
public void execute() throws ExecutableNotFoundException {
final FrontendExtension extension = getProject().getExtensions().findByType(FrontendExtension.class);
yarnEnabled.set(extension.getYarnEnabled());
nodeInstallDirectory.set(extension.getNodeInstallDirectory());
yarnInstallDirectory.set(extension.getYarnInstallDirectory());
super.execute();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/**
* Task provided as a type to let developers implement custom task based on it. The task does not expose Node/Yarn
* related options to avoid duplicating the plugin configuration. Using this task as a type to register a custom task
* requires only to define the 'script' attribute, and to make the custom task depend on the 'installFrontend' task.
* requires only to define the 'script' attribute, and to make the custom task depends on the 'installFrontend' task.
* <p>
* A typical usage of this task in a 'build.gradle' file would be:
* <pre>
Expand Down
Loading

0 comments on commit 8046049

Please sign in to comment.