From 381171f7a10d96f1e24765a77c865059b8176295 Mon Sep 17 00:00:00 2001 From: v1nc3n4 <5869062+v1nc3n4@users.noreply.github.com> Date: Tue, 11 Jun 2024 16:53:16 +0200 Subject: [PATCH] feat: added option for custom environment variables in Node.js-based tasks Fixes #220 --- README.md | 3 +- plugin/build.gradle.kts | 2 +- ...esWithDownloadedDistributionsFuncTest.java | 21 +- .../frontendgradleplugin/test/TaskTypes.java | 24 ++- .../domain/ExecutionSettings.java | 12 +- .../domain/ResolveExecutionSettings.java | 6 +- .../ResolveExecutionSettingsCommand.java | 9 + .../gradle/AbstractRunCommandTask.java | 19 ++ .../infrastructure/gradle/ExecSpecAction.java | 81 ++++--- .../gradle/GradleScriptRunnerAdapter.java | 15 +- .../gradle/ScriptProperties.java | 62 +++++- .../domain/ResolveExecutionSettingsTest.java | 33 ++- .../gradle/ExecSpecActionTest.java | 202 ++++++++++++++---- .../gradle/GradleScriptRunnerAdapterTest.java | 17 +- site/src/components/gradle-scripts.vue | 4 +- .../max-download-attempts-property.vue | 1 - .../property/retry-http-statuses-property.vue | 1 - .../retry-initial-interval-ms-property.vue | 1 - .../retry-interval-multiplier-property.vue | 1 - .../retry-max-interval-ms-property.vue | 1 - .../task/assemble-frontend-task.vue | 7 +- .../components/task/check-frontend-task.vue | 7 +- .../components/task/clean-frontend-task.vue | 7 +- .../components/task/install-corepack-task.vue | 3 + .../components/task/install-frontend-task.vue | 7 +- .../task/install-package-manager-task.vue | 1 + .../components/task/publish-frontend-task.vue | 7 +- .../task/run-corepack-task-type.vue | 2 +- .../components/task/run-node-task-type.vue | 2 +- .../src/components/task/run-npm-task-type.vue | 2 +- .../components/task/run-pnpm-task-type.vue | 2 +- .../components/task/run-yarn-task-type.vue | 2 +- site/src/components/task/task.vue | 15 +- .../node-corepack-npm-pnpm-yarn-tasks.vue | 59 ++++- 34 files changed, 493 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index 58c652e9..1d32f274 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Latest release 8.1.0 License Apache 2.0
- Build status + Build status Quality gate status Code coverage Reliability @@ -60,6 +60,7 @@ With their feedback, plugin improvement is possible. Special thanks to: @[jorgheymans](https://github.com/jorgheymans), @[ludik0](https://github.com/ludik0), @[marcospereira](https://github.com/marcospereira), +@[mgiorgino-iobeya](https://github.com/mgiorgino-iobeya), @[mhalbritter](https://github.com/mhalbritter), @[mike-howell](https://github.com/mike-howell), @[napstr](https://github.com/napstr), diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 39e7248e..ff4aabcc 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -134,7 +134,7 @@ tasks.named("wrapper") { distributionType = Wrapper.DistributionType.ALL } -tasks.withType() { +tasks.withType { useJUnitPlatform() } diff --git a/plugin/src/integrationTest/java/org/siouan/frontendgradleplugin/infrastructure/gradle/TaskTypesWithDownloadedDistributionsFuncTest.java b/plugin/src/integrationTest/java/org/siouan/frontendgradleplugin/infrastructure/gradle/TaskTypesWithDownloadedDistributionsFuncTest.java index 06d5c9dd..b600bbbb 100644 --- a/plugin/src/integrationTest/java/org/siouan/frontendgradleplugin/infrastructure/gradle/TaskTypesWithDownloadedDistributionsFuncTest.java +++ b/plugin/src/integrationTest/java/org/siouan/frontendgradleplugin/infrastructure/gradle/TaskTypesWithDownloadedDistributionsFuncTest.java @@ -1,5 +1,6 @@ package org.siouan.frontendgradleplugin.infrastructure.gradle; +import static org.assertj.core.api.Assertions.assertThat; import static org.siouan.frontendgradleplugin.FrontendGradlePlugin.INSTALL_FRONTEND_TASK_NAME; import static org.siouan.frontendgradleplugin.FrontendGradlePlugin.INSTALL_NODE_TASK_NAME; import static org.siouan.frontendgradleplugin.infrastructure.gradle.InstallCorepackTask.LATEST_VERSION_ARGUMENT; @@ -14,12 +15,13 @@ import static org.siouan.frontendgradleplugin.test.TaskTypes.buildNpmTaskDefinition; import static org.siouan.frontendgradleplugin.test.TaskTypes.buildPnpmTaskDefinition; import static org.siouan.frontendgradleplugin.test.TaskTypes.buildYarnTaskDefinition; -import static org.siouan.frontendgradleplugin.test.TaskTypes.createJavascriptFile; +import static org.siouan.frontendgradleplugin.test.TaskTypes.createJavascriptFileLoggingProcessTitle; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.Map; import java.util.Set; import org.gradle.testkit.runner.BuildResult; @@ -55,19 +57,20 @@ void setUp() { } @Test - void should_run_custom_tasks() throws IOException { + void should_run_custom_tasks_and_forward_environment_variables() throws IOException { final Path packageJsonDirectoryPath = Files.createDirectory(projectDirectoryPath.resolve("frontend")); Files.copy(getResourcePath("package-npm.json"), packageJsonDirectoryPath.resolve("package.json")); - final Path temporaryScriptPath = createJavascriptFile(temporaryDirectoryPath.resolve("script.js")); + final Path temporaryScriptPath = createJavascriptFileLoggingProcessTitle( + temporaryDirectoryPath.resolve("script.js")); final FrontendMapBuilder frontendMapBuilder = new FrontendMapBuilder() .nodeVersion("20.14.0") .nodeInstallDirectory(projectDirectoryPath.resolve("node-dist")) .corepackVersion(LATEST_VERSION_ARGUMENT) - .packageJsonDirectory(packageJsonDirectoryPath) - .verboseModeEnabled(false); - final String runCorepackTaskDefinition = buildCorepackTaskDefinition(RUN_COREPACK_TASK_NAME, "-v"); + .packageJsonDirectory(packageJsonDirectoryPath); final String runNodeTaskDefinition = buildNodeTaskDefinition(RUN_NODE_TASK_NAME, - temporaryScriptPath.toString().replace("\\", "\\\\")); + temporaryScriptPath.toString().replace("\\", "\\\\"), + Map.of("NODE_OPTIONS", "--title=\\\"Run custom node task\\\"")); + final String runCorepackTaskDefinition = buildCorepackTaskDefinition(RUN_COREPACK_TASK_NAME, "-v"); final String runNpmTaskDefinition = buildNpmTaskDefinition(RUN_NPM_TASK_NAME, INSTALL_FRONTEND_TASK_NAME, "run another-script"); final String runPnpmTaskDefinition = buildPnpmTaskDefinition(RUN_PNPM_TASK_NAME, INSTALL_FRONTEND_TASK_NAME, @@ -81,6 +84,10 @@ void should_run_custom_tasks() throws IOException { final BuildResult runNodeTaskResult1 = runGradle(projectDirectoryPath, RUN_NODE_TASK_NAME); assertTaskOutcomes(runNodeTaskResult1, SUCCESS, RUN_NODE_TASK_NAME, SUCCESS); + assertThat(runNodeTaskResult1.getOutput()).containsIgnoringNewLines(""" + > Task :customNodeTask + Run custom node task + """); final BuildResult runNodeTaskResult2 = runGradle(projectDirectoryPath, RUN_NODE_TASK_NAME); diff --git a/plugin/src/integrationTest/java/org/siouan/frontendgradleplugin/test/TaskTypes.java b/plugin/src/integrationTest/java/org/siouan/frontendgradleplugin/test/TaskTypes.java index e97af167..913d5344 100644 --- a/plugin/src/integrationTest/java/org/siouan/frontendgradleplugin/test/TaskTypes.java +++ b/plugin/src/integrationTest/java/org/siouan/frontendgradleplugin/test/TaskTypes.java @@ -7,6 +7,7 @@ import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; import java.util.Set; import org.siouan.frontendgradleplugin.infrastructure.gradle.RunCorepack; @@ -31,6 +32,12 @@ public static String buildNodeTaskDefinition(final String taskName, final String return buildTaskDefinition(taskName, RunNode.class, Set.of(INSTALL_NODE_TASK_NAME), script); } + public static String buildNodeTaskDefinition(final String taskName, final String script, + final Map environmentVariables) { + return buildTaskDefinition(taskName, RunNode.class, Set.of(INSTALL_NODE_TASK_NAME), script, + environmentVariables); + } + public static String buildNpmTaskDefinition(final String taskName, final String script) { return buildTaskDefinition(taskName, RunNpm.class, Set.of(), script); } @@ -73,15 +80,20 @@ public static String buildYarnTaskDefinition(final String taskName, final Set taskTypeClass, final Set dependsOnTaskNames, final String script) { + return buildTaskDefinition(taskName, taskTypeClass, dependsOnTaskNames, script, Map.of()); + } + + private static String buildTaskDefinition(final String taskName, final Class taskTypeClass, + final Set dependsOnTaskNames, final String script, final Map environmentVariables) { final StringBuilder definition = new StringBuilder(); definition.append("tasks.register('"); definition.append(taskName); @@ -98,6 +110,14 @@ private static String buildTaskDefinition(final String taskName, final Class definition.append(script); definition.append("'\n"); } + if (!environmentVariables.isEmpty()) { + environmentVariables.forEach((variableName, variableValue) -> definition + .append("environmentVariables.put(\"") + .append(variableName) + .append("\", \"") + .append(variableValue) + .append("\")\n")); + } definition.append("}\n"); return definition.toString(); } diff --git a/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ExecutionSettings.java b/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ExecutionSettings.java index e9395e5b..b406f7ef 100644 --- a/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ExecutionSettings.java +++ b/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ExecutionSettings.java @@ -2,6 +2,7 @@ import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.Set; import lombok.Builder; @@ -42,6 +43,14 @@ public class ExecutionSettings { @ToString.Include private final List arguments; + /** + * Additional environment variables to pass to the process. + * + * @since 8.1.0 + */ + @ToString.Include + private final Map environmentVariables; + /** * Builds execution settings. * @@ -51,10 +60,11 @@ public class ExecutionSettings { * @param arguments List of arguments. */ public ExecutionSettings(final Path workingDirectoryPath, final Set additionalExecutablePaths, - final Path executablePath, final List arguments) { + final Path executablePath, final List arguments, final Map environmentVariables) { this.workingDirectoryPath = workingDirectoryPath; this.additionalExecutablePaths = Set.copyOf(additionalExecutablePaths); this.executablePath = executablePath; this.arguments = List.copyOf(arguments); + this.environmentVariables = Map.copyOf(environmentVariables); } } diff --git a/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettings.java b/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettings.java index 15e9118d..f922fccc 100644 --- a/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettings.java +++ b/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettings.java @@ -78,7 +78,8 @@ public ExecutionSettings execute(final ResolveExecutionSettingsCommand command) args.add(WINDOWS_EXECUTABLE_AUTOEXIT_FLAG); // The command that must be executed in the terminal must be a single argument on itself (like if it was // quoted). - args.add(escapeWhitespacesFromCommandLineToken(executablePath) + " " + command.getScript().trim()); + args.add( + escapeWhitespacesFromCommandLineToken(executablePath) + " " + command.getScript().trim()); } else { executable = UNIX_EXECUTABLE_PATH; args.add(UNIX_EXECUTABLE_AUTOEXIT_FLAG); @@ -97,7 +98,8 @@ public ExecutionSettings execute(final ResolveExecutionSettingsCommand command) } } - return new ExecutionSettings(command.getPackageJsonDirectoryPath(), executablePaths, executable, args); + return new ExecutionSettings(command.getPackageJsonDirectoryPath(), executablePaths, executable, args, + command.getEnvironmentVariables()); } private String escapeWhitespacesFromCommandLineToken(Path path) { diff --git a/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettingsCommand.java b/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettingsCommand.java index eb0ec3f6..fdd1c2aa 100644 --- a/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettingsCommand.java +++ b/plugin/src/main/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettingsCommand.java @@ -1,6 +1,7 @@ package org.siouan.frontendgradleplugin.domain; import java.nio.file.Path; +import java.util.Map; import lombok.Builder; import lombok.EqualsAndHashCode; @@ -45,4 +46,12 @@ public class ResolveExecutionSettingsCommand { */ @EqualsAndHashCode.Include private final String script; + + /** + * Additional environment variables to pass to the process. + * + * @since 8.1.0 + */ + @EqualsAndHashCode.Include + private final Map environmentVariables; } diff --git a/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/AbstractRunCommandTask.java b/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/AbstractRunCommandTask.java index 0eb4a2e6..c4991974 100644 --- a/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/AbstractRunCommandTask.java +++ b/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/AbstractRunCommandTask.java @@ -1,12 +1,15 @@ package org.siouan.frontendgradleplugin.infrastructure.gradle; import java.io.File; +import java.util.Map; import org.gradle.api.DefaultTask; import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.TaskAction; import org.gradle.process.ExecOperations; import org.siouan.frontendgradleplugin.domain.ExecutableType; @@ -71,6 +74,13 @@ public abstract class AbstractRunCommandTask extends DefaultTask { */ protected final Property systemOsName; + /** + * Additional environment variables to pass when executing the script. + * + * @since 8.1.0 + */ + protected final MapProperty environmentVariables; + AbstractRunCommandTask(final ObjectFactory objectFactory, final ExecOperations execOperations) { this.execOperations = execOperations; this.beanRegistryBuildService = objectFactory.property(BeanRegistryBuildService.class); @@ -81,6 +91,7 @@ public abstract class AbstractRunCommandTask extends DefaultTask { this.verboseModeEnabled = objectFactory.property(Boolean.class); this.systemJvmArch = objectFactory.property(String.class); this.systemOsName = objectFactory.property(String.class); + this.environmentVariables = objectFactory.mapProperty(String.class, String.class); } @Internal @@ -108,6 +119,13 @@ public Property getSystemOsName() { return systemOsName; } + @Internal + @Optional + @SuppressWarnings("unused") + public MapProperty getEnvironmentVariables() { + return environmentVariables; + } + @Input public Property getPackageJsonDirectory() { return packageJsonDirectory; @@ -156,6 +174,7 @@ public void execute() throws NonRunnableTaskException, BeanRegistryException { .nodeInstallDirectoryPath(nodeInstallDirectory.map(File::toPath).get()) .script(script.get()) .platform(platform) + .environmentVariables(environmentVariables.getOrElse(Map.of())) .build()); } } diff --git a/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ExecSpecAction.java b/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ExecSpecAction.java index 32fa4167..95f9ac4a 100644 --- a/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ExecSpecAction.java +++ b/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ExecSpecAction.java @@ -1,11 +1,15 @@ package org.siouan.frontendgradleplugin.infrastructure.gradle; -import static java.util.stream.Collectors.joining; - import java.io.File; import java.nio.file.Path; +import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.Builder; import lombok.Getter; @@ -20,6 +24,8 @@ @Getter public class ExecSpecAction implements Action { + public static final String PATH_VARIABLE_NAME = "PATH"; + /** * Execution settings. */ @@ -38,43 +44,48 @@ public class ExecSpecAction implements Action { @Override public void execute(final ExecSpec execSpec) { execSpec.setWorkingDir(executionSettings.getWorkingDirectoryPath().toString()); + execSpec.setExecutable(executionSettings.getExecutablePath().toString()); + execSpec.setArgs(executionSettings.getArguments()); + + final Map userEnvironmentVariables = new HashMap<>(executionSettings.getEnvironmentVariables()); + final Map currentEnvironmentVariables = execSpec.getEnvironment(); - // Prepend directories containing the Node and Yarn executables to the 'PATH' environment variable. - // npm is in the same directory than Node, do nothing for it. - final Map environment = execSpec.getEnvironment(); - final String pathVariable = findPathVariable(environment); - final String executablePaths = executionSettings - .getAdditionalExecutablePaths() + // Put all user-defined environment variables except an eventual PATH environment variable which is processed + // separately. + final Optional> userPathVariable = userEnvironmentVariables + .entrySet() .stream() - .map(Path::toString) - .collect(joining(File.pathSeparator)); - final StringBuilder pathValue = new StringBuilder(); - if (!executablePaths.isEmpty()) { - pathValue.append(executablePaths); - pathValue.append(File.pathSeparatorChar); - } - pathValue.append((String) environment.getOrDefault(pathVariable, "")); + .filter(entry -> entry.getKey().equalsIgnoreCase(PATH_VARIABLE_NAME)) + .findAny(); + userPathVariable.map(Map.Entry::getKey).ifPresent(userEnvironmentVariables::remove); - execSpec.environment(pathVariable, pathValue.toString()); - execSpec.setExecutable(executionSettings.getExecutablePath()); - execSpec.setArgs(executionSettings.getArguments()); - afterConfiguredConsumer.accept(execSpec); - } + if (!userEnvironmentVariables.isEmpty()) { + execSpec.environment(userEnvironmentVariables); + } - /** - * Finds the name of the 'PATH' variable. Depending on the O/S, it may be have a different case than the exact - * 'PATH' name. - * - * @param environment Map of environment variables. - * @return The name of the 'PATH' variable. - */ - private String findPathVariable(final Map environment) { - final String pathVariable; - if (environment.containsKey("Path")) { - pathVariable = "Path"; - } else { - pathVariable = "PATH"; + // If the user overrides the 'PATH' environment variable, it takes precedence over the current value in the + // environment. Otherwise, the original 'PATH' is appended, if any. + final Optional> systemPathVariable = currentEnvironmentVariables + .entrySet() + .stream() + .filter(entry -> entry.getKey().equalsIgnoreCase(PATH_VARIABLE_NAME)) + .findAny(); + // Let's prepare the value of the PATH variable by using the eventual override from the user, or the system + // value. + final Optional basePathVariableValue = userPathVariable + .map(Map.Entry::getValue) + .or(() -> systemPathVariable.map(Map.Entry::getValue).map(Objects::toString)); + // Prepare directories containing executables to be prepended to the 'PATH' environment variable. + final Stream.Builder pathVariableBuilder = Stream.builder(); + final Set additionalExecutablePaths = executionSettings.getAdditionalExecutablePaths(); + if (!additionalExecutablePaths.isEmpty() || basePathVariableValue.isPresent()) { + additionalExecutablePaths.forEach( + additionalExecutablePath -> pathVariableBuilder.accept(additionalExecutablePath.toString())); + basePathVariableValue.ifPresent(pathVariableBuilder); + execSpec.environment(PATH_VARIABLE_NAME, + pathVariableBuilder.build().collect(Collectors.joining(File.pathSeparator))); } - return pathVariable; + + afterConfiguredConsumer.accept(execSpec); } } diff --git a/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/GradleScriptRunnerAdapter.java b/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/GradleScriptRunnerAdapter.java index 9b3dc4b8..4e3e04fa 100644 --- a/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/GradleScriptRunnerAdapter.java +++ b/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/GradleScriptRunnerAdapter.java @@ -28,16 +28,17 @@ public class GradleScriptRunnerAdapter { public void execute(final ScriptProperties scriptProperties) { final ExecutionSettings executionSettings = resolveExecutionSettings.execute(ResolveExecutionSettingsCommand .builder() - .packageJsonDirectoryPath(scriptProperties.packageJsonDirectoryPath()) - .executableType(scriptProperties.executableType()) - .nodeInstallDirectoryPath(scriptProperties.nodeInstallDirectoryPath()) - .platform(scriptProperties.platform()) - .script(scriptProperties.script()) + .packageJsonDirectoryPath(scriptProperties.getPackageJsonDirectoryPath()) + .executableType(scriptProperties.getExecutableType()) + .nodeInstallDirectoryPath(scriptProperties.getNodeInstallDirectoryPath()) + .platform(scriptProperties.getPlatform()) + .script(scriptProperties.getScript()) + .environmentVariables(scriptProperties.getEnvironmentVariables()) .build()); - logger.debug("Execution settings: {}", executionSettings); + logger.info("Execution settings: {}", executionSettings); scriptProperties - .execOperations() + .getExecOperations() .exec(ExecSpecAction .builder() .executionSettings(executionSettings) diff --git a/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ScriptProperties.java b/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ScriptProperties.java index 935c7f64..719910ca 100644 --- a/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ScriptProperties.java +++ b/plugin/src/main/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ScriptProperties.java @@ -1,8 +1,10 @@ package org.siouan.frontendgradleplugin.infrastructure.gradle; import java.nio.file.Path; +import java.util.Map; import lombok.Builder; +import lombok.Getter; import org.gradle.process.ExecOperations; import org.siouan.frontendgradleplugin.domain.ExecutableType; import org.siouan.frontendgradleplugin.domain.Platform; @@ -10,14 +12,58 @@ /** * Properties to run a script. * - * @param execOperations Gradle exec operations. - * @param packageJsonDirectoryPath Path to the directory containing the {@code package.json} file. - * @param executableType Executable use to run the script. - * @param nodeInstallDirectoryPath Directory where the Node distribution is installed. - * @param script The script run by the job with npm or Yarn. - * @param platform Underlying platform. * @since 2.0.0 */ @Builder -public record ScriptProperties(ExecOperations execOperations, Path packageJsonDirectoryPath, - ExecutableType executableType, Path nodeInstallDirectoryPath, String script, Platform platform) {} +@Getter +public class ScriptProperties { + + /** + * Gradle exec operations. + */ + private final ExecOperations execOperations; + + /** + * Path to the directory containing the {@code package.json} file. + */ + private final Path packageJsonDirectoryPath; + + /** + * Executable use to run the script. + */ + private final ExecutableType executableType; + + /** + * Directory where the Node distribution is installed. + */ + private final Path nodeInstallDirectoryPath; + + /** + * The script run by the job with npm or Yarn. + */ + private final String script; + + /** + * Underlying platform. + */ + private final Platform platform; + + /** + * Additional environment variables to pass to the process. + * + * @since 8.1.0 + */ + private final Map environmentVariables; + + ScriptProperties(final ExecOperations execOperations, final Path packageJsonDirectoryPath, + final ExecutableType executableType, final Path nodeInstallDirectoryPath, final String script, + final Platform platform, final Map environmentVariables) { + this.execOperations = execOperations; + this.packageJsonDirectoryPath = packageJsonDirectoryPath; + this.executableType = executableType; + this.nodeInstallDirectoryPath = nodeInstallDirectoryPath; + this.script = script; + this.platform = platform; + this.environmentVariables = Map.copyOf(environmentVariables); + } +} diff --git a/plugin/src/test/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettingsTest.java b/plugin/src/test/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettingsTest.java index ef7bc483..3aa13166 100644 --- a/plugin/src/test/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettingsTest.java +++ b/plugin/src/test/java/org/siouan/frontendgradleplugin/domain/ResolveExecutionSettingsTest.java @@ -3,11 +3,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static org.siouan.frontendgradleplugin.test.PathFixture.ANY_PATH; import static org.siouan.frontendgradleplugin.domain.PlatformFixture.aPlatform; import static org.siouan.frontendgradleplugin.domain.SystemPropertiesFixture.getSystemJvmArch; +import static org.siouan.frontendgradleplugin.test.PathFixture.ANY_PATH; import java.nio.file.Path; +import java.util.Map; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -42,11 +43,13 @@ void should_resolve_exec_settings_with_windows_cmd_when_executable_is_node_in_di .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .build())).thenReturn(nodeExecutablePath); - when(getExecutablePath.execute(GetExecutablePathCommand.builder() - .executableType(ExecutableType.NODE) - .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) - .platform(platform) + when(getExecutablePath.execute(GetExecutablePathCommand + .builder() + .executableType(ExecutableType.NODE) + .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) + .platform(platform) .build())).thenReturn(nodeExecutablePath); + final Map environmentVariables = Map.of("VARIABLE", "value"); final ExecutionSettings executionSettings = usecase.execute(ResolveExecutionSettingsCommand .builder() @@ -55,6 +58,7 @@ void should_resolve_exec_settings_with_windows_cmd_when_executable_is_node_in_di .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .script(SCRIPT) + .environmentVariables(environmentVariables) .build()); assertThat(executionSettings.getWorkingDirectoryPath()).isEqualTo(PACKAGE_JSON_DIRECTORY_PATH); @@ -62,6 +66,7 @@ void should_resolve_exec_settings_with_windows_cmd_when_executable_is_node_in_di assertThat(executionSettings.getExecutablePath()).isEqualTo(ResolveExecutionSettings.WINDOWS_EXECUTABLE_PATH); assertThat(executionSettings.getArguments()).containsExactly( ResolveExecutionSettings.WINDOWS_EXECUTABLE_AUTOEXIT_FLAG, "\"" + nodeExecutablePath + "\" run script"); + assertThat(executionSettings.getEnvironmentVariables()).isEqualTo(environmentVariables); verifyNoMoreInteractions(getNodeExecutablePath, getExecutablePath); } @@ -75,11 +80,13 @@ void should_resolve_exec_settings_with_windows_cmd_when_executable_is_not_node_i .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .build())).thenReturn(nodeExecutablePath); - when(getExecutablePath.execute(GetExecutablePathCommand.builder() + when(getExecutablePath.execute(GetExecutablePathCommand + .builder() .executableType(ExecutableType.NPM) .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .build())).thenReturn(npmExecutablePath); + final Map environmentVariables = Map.of("VARIABLE", "value"); final ExecutionSettings executionSettings = usecase.execute(ResolveExecutionSettingsCommand .builder() @@ -88,6 +95,7 @@ void should_resolve_exec_settings_with_windows_cmd_when_executable_is_not_node_i .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .script(SCRIPT) + .environmentVariables(environmentVariables) .build()); assertThat(executionSettings.getWorkingDirectoryPath()).isEqualTo(PACKAGE_JSON_DIRECTORY_PATH); @@ -95,6 +103,7 @@ void should_resolve_exec_settings_with_windows_cmd_when_executable_is_not_node_i assertThat(executionSettings.getExecutablePath()).isEqualTo(ResolveExecutionSettings.WINDOWS_EXECUTABLE_PATH); assertThat(executionSettings.getArguments()).containsExactly( ResolveExecutionSettings.WINDOWS_EXECUTABLE_AUTOEXIT_FLAG, "\"" + npmExecutablePath + "\" run script"); + assertThat(executionSettings.getEnvironmentVariables()).isEqualTo(environmentVariables); verifyNoMoreInteractions(getNodeExecutablePath, getExecutablePath); } @@ -107,11 +116,13 @@ void should_resolve_exec_settings_with_unix_shell_when_executable_is_node_in_pat .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .build())).thenReturn(nodeExecutablePath); - when(getExecutablePath.execute(GetExecutablePathCommand.builder() + when(getExecutablePath.execute(GetExecutablePathCommand + .builder() .executableType(ExecutableType.NODE) .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .build())).thenReturn(nodeExecutablePath); + final Map environmentVariables = Map.of("VARIABLE", "value"); final ExecutionSettings executionSettings = usecase.execute(ResolveExecutionSettingsCommand .builder() @@ -120,6 +131,7 @@ void should_resolve_exec_settings_with_unix_shell_when_executable_is_node_in_pat .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .script(SCRIPT) + .environmentVariables(environmentVariables) .build()); assertThat(executionSettings.getWorkingDirectoryPath()).isEqualTo(PACKAGE_JSON_DIRECTORY_PATH); @@ -127,6 +139,7 @@ void should_resolve_exec_settings_with_unix_shell_when_executable_is_node_in_pat assertThat(executionSettings.getExecutablePath()).isEqualTo(ResolveExecutionSettings.UNIX_EXECUTABLE_PATH); assertThat(executionSettings.getArguments()).containsExactly( ResolveExecutionSettings.UNIX_EXECUTABLE_AUTOEXIT_FLAG, "\"" + nodeExecutablePath + "\" run script"); + assertThat(executionSettings.getEnvironmentVariables()).isEqualTo(environmentVariables); verifyNoMoreInteractions(getNodeExecutablePath, getExecutablePath); } @@ -140,11 +153,13 @@ void should_resolve_exec_settings_with_unix_shell_when_executable_is_npm_in_path .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .build())).thenReturn(nodeExecutablePath); - when(getExecutablePath.execute(GetExecutablePathCommand.builder() + when(getExecutablePath.execute(GetExecutablePathCommand + .builder() .executableType(ExecutableType.NPM) .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .build())).thenReturn(npmExecutablePath); + final Map environmentVariables = Map.of("VARIABLE", "value"); final ExecutionSettings executionSettings = usecase.execute(ResolveExecutionSettingsCommand .builder() @@ -153,6 +168,7 @@ void should_resolve_exec_settings_with_unix_shell_when_executable_is_npm_in_path .nodeInstallDirectoryPath(NODE_INSTALL_DIRECTORY_PATH) .platform(platform) .script(SCRIPT) + .environmentVariables(environmentVariables) .build()); assertThat(executionSettings.getWorkingDirectoryPath()).isEqualTo(PACKAGE_JSON_DIRECTORY_PATH); @@ -160,6 +176,7 @@ void should_resolve_exec_settings_with_unix_shell_when_executable_is_npm_in_path assertThat(executionSettings.getExecutablePath()).isEqualTo(ResolveExecutionSettings.UNIX_EXECUTABLE_PATH); assertThat(executionSettings.getArguments()).containsExactly( ResolveExecutionSettings.UNIX_EXECUTABLE_AUTOEXIT_FLAG, "\"" + npmExecutablePath + "\" run script"); + assertThat(executionSettings.getEnvironmentVariables()).isEqualTo(environmentVariables); verifyNoMoreInteractions(getNodeExecutablePath, getExecutablePath); } } diff --git a/plugin/src/test/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ExecSpecActionTest.java b/plugin/src/test/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ExecSpecActionTest.java index 65f7de14..00898be7 100644 --- a/plugin/src/test/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ExecSpecActionTest.java +++ b/plugin/src/test/java/org/siouan/frontendgradleplugin/infrastructure/gradle/ExecSpecActionTest.java @@ -1,17 +1,13 @@ package org.siouan.frontendgradleplugin.infrastructure.gradle; -import static java.util.Arrays.asList; -import static java.util.stream.Collectors.toCollection; -import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.siouan.frontendgradleplugin.infrastructure.gradle.ExecSpecAction.PATH_VARIABLE_NAME; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -20,7 +16,6 @@ import org.gradle.process.ExecSpec; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.siouan.frontendgradleplugin.domain.ExecutionSettings; @@ -28,15 +23,13 @@ @ExtendWith(MockitoExtension.class) class ExecSpecActionTest { - private static final Path WORKING_DIRECTORY_PATH = Paths.get("/tmp"); + private static final Path WORKING_DIRECTORY_PATH = Paths.get("/home"); - private static final Path EXECUTABLE_DIRECTORY_PATH = WORKING_DIRECTORY_PATH.resolve("bin"); + private static final Path EXECUTABLE_FILE_PATH = Paths.get("/opt/executable"); - private static final Path EXECUTABLE_FILE_PATH = EXECUTABLE_DIRECTORY_PATH.resolve("executable"); + private static final Path ADDITIONAL_EXECUTABLE_PATH = Paths.get("/bin"); - private static final List EXECUTABLE_PATHS = asList("/usr/bin", "/usr/lib"); - - private static final List ARGUMENTS = asList("arg1", "argument 2"); + private static final List ARGUMENTS = List.of("arg1", "argument 2"); @Mock private ExecSpec execSpec; @@ -45,59 +38,190 @@ class ExecSpecActionTest { private Consumer afterConfigured; @Test - void should_configure_exec_spec_with_uppercase_path_variable_and_without_executable_paths() { + void should_configure_exec_spec_with_no_user_environment_and_no_path_override_and_no_additional_executable_paths_and_no_system_path() { + final ExecutionSettings executionSettings = ExecutionSettings + .builder() + .workingDirectoryPath(WORKING_DIRECTORY_PATH) + .additionalExecutablePaths(Set.of()) + .executablePath(EXECUTABLE_FILE_PATH) + .arguments(ARGUMENTS) + .environmentVariables(Map.of()) + .build(); + final ExecSpecAction action = new ExecSpecAction(executionSettings, afterConfigured); + when(execSpec.getEnvironment()).thenReturn(Map.of()); + + action.execute(execSpec); + + verify(execSpec).setWorkingDir(WORKING_DIRECTORY_PATH.toString()); + verify(execSpec).setExecutable(EXECUTABLE_FILE_PATH.toString()); + verify(execSpec).setArgs(ARGUMENTS); + verify(afterConfigured).accept(execSpec); + verifyNoMoreInteractions(execSpec, afterConfigured); + } + + @Test + void should_configure_exec_spec_with_user_environment_and_no_path_override_and_no_additional_executable_paths_and_no_system_path() { + final ExecutionSettings executionSettings = ExecutionSettings + .builder() + .workingDirectoryPath(WORKING_DIRECTORY_PATH) + .additionalExecutablePaths(Set.of()) + .executablePath(EXECUTABLE_FILE_PATH) + .arguments(ARGUMENTS) + .environmentVariables(Map.of("VARIABLE", "value")) + .build(); + final ExecSpecAction action = new ExecSpecAction(executionSettings, afterConfigured); + when(execSpec.getEnvironment()).thenReturn(Map.of()); + + action.execute(execSpec); + + verify(execSpec).setWorkingDir(WORKING_DIRECTORY_PATH.toString()); + verify(execSpec).setExecutable(EXECUTABLE_FILE_PATH.toString()); + verify(execSpec).setArgs(ARGUMENTS); + verify(execSpec).environment(Map.of("VARIABLE", "value")); + verify(afterConfigured).accept(execSpec); + verifyNoMoreInteractions(execSpec, afterConfigured); + } + + @Test + void should_configure_exec_spec_with_user_environment_and_path_override_and_no_additional_executable_paths_and_no_system_path() { + final ExecutionSettings executionSettings = ExecutionSettings + .builder() + .workingDirectoryPath(WORKING_DIRECTORY_PATH) + .additionalExecutablePaths(Set.of()) + .executablePath(EXECUTABLE_FILE_PATH) + .arguments(ARGUMENTS) + .environmentVariables(Map.of("VARIABLE", "value", "PATH", "/usr/bin")) + .build(); + final ExecSpecAction action = new ExecSpecAction(executionSettings, afterConfigured); + when(execSpec.getEnvironment()).thenReturn(Map.of()); + + action.execute(execSpec); + + verify(execSpec).setWorkingDir(WORKING_DIRECTORY_PATH.toString()); + verify(execSpec).setExecutable(EXECUTABLE_FILE_PATH.toString()); + verify(execSpec).setArgs(ARGUMENTS); + verify(execSpec).environment(Map.of("VARIABLE", "value")); + verify(execSpec).environment(PATH_VARIABLE_NAME, "/usr/bin"); + verify(afterConfigured).accept(execSpec); + verifyNoMoreInteractions(execSpec, afterConfigured); + } + + @Test + void should_configure_exec_spec_with_user_environment_and_no_path_override_and_additional_executable_paths_and_no_system_path() { + final ExecutionSettings executionSettings = ExecutionSettings + .builder() + .workingDirectoryPath(WORKING_DIRECTORY_PATH) + .additionalExecutablePaths(Set.of(ADDITIONAL_EXECUTABLE_PATH)) + .executablePath(EXECUTABLE_FILE_PATH) + .arguments(ARGUMENTS) + .environmentVariables(Map.of("VARIABLE", "value")) + .build(); + final ExecSpecAction action = new ExecSpecAction(executionSettings, afterConfigured); + when(execSpec.getEnvironment()).thenReturn(Map.of()); + + action.execute(execSpec); + + verify(execSpec).setWorkingDir(WORKING_DIRECTORY_PATH.toString()); + verify(execSpec).setExecutable(EXECUTABLE_FILE_PATH.toString()); + verify(execSpec).setArgs(ARGUMENTS); + verify(execSpec).environment(Map.of("VARIABLE", "value")); + verify(execSpec).environment(PATH_VARIABLE_NAME, ADDITIONAL_EXECUTABLE_PATH.toString()); + verify(afterConfigured).accept(execSpec); + verifyNoMoreInteractions(execSpec, afterConfigured); + } + + @Test + void should_configure_exec_spec_with_user_environment_and_path_override_and_additional_executable_paths_and_no_system_path() { + final ExecutionSettings executionSettings = ExecutionSettings + .builder() + .workingDirectoryPath(WORKING_DIRECTORY_PATH) + .additionalExecutablePaths(Set.of(ADDITIONAL_EXECUTABLE_PATH)) + .executablePath(EXECUTABLE_FILE_PATH) + .arguments(ARGUMENTS) + .environmentVariables(Map.of("VARIABLE", "value", "PATH", "/usr/bin")) + .build(); + final ExecSpecAction action = new ExecSpecAction(executionSettings, afterConfigured); + when(execSpec.getEnvironment()).thenReturn(Map.of()); + + action.execute(execSpec); + + verify(execSpec).setWorkingDir(WORKING_DIRECTORY_PATH.toString()); + verify(execSpec).setExecutable(EXECUTABLE_FILE_PATH.toString()); + verify(execSpec).setArgs(ARGUMENTS); + verify(execSpec).environment(Map.of("VARIABLE", "value")); + verify(execSpec).environment(PATH_VARIABLE_NAME, ADDITIONAL_EXECUTABLE_PATH + File.pathSeparator + "/usr/bin"); + verify(afterConfigured).accept(execSpec); + verifyNoMoreInteractions(execSpec, afterConfigured); + } + + @Test + void should_configure_exec_spec_with_user_environment_and_no_path_override_and_no_additional_executable_paths_and_system_path() { final ExecutionSettings executionSettings = ExecutionSettings .builder() .workingDirectoryPath(WORKING_DIRECTORY_PATH) .additionalExecutablePaths(Set.of()) .executablePath(EXECUTABLE_FILE_PATH) .arguments(ARGUMENTS) + .environmentVariables(Map.of("VARIABLE", "value")) .build(); final ExecSpecAction action = new ExecSpecAction(executionSettings, afterConfigured); - when(execSpec.getEnvironment()).thenReturn(Map.of("PATH", String.join(File.pathSeparator, EXECUTABLE_PATHS))); + when(execSpec.getEnvironment()).thenReturn(Map.of("Path", "/system/bin")); action.execute(execSpec); - assertExecSpecWith(executionSettings); + verify(execSpec).setWorkingDir(WORKING_DIRECTORY_PATH.toString()); + verify(execSpec).setExecutable(EXECUTABLE_FILE_PATH.toString()); + verify(execSpec).setArgs(ARGUMENTS); + verify(execSpec).environment(Map.of("VARIABLE", "value")); + verify(execSpec).environment(PATH_VARIABLE_NAME, "/system/bin"); + verify(afterConfigured).accept(execSpec); + verifyNoMoreInteractions(execSpec, afterConfigured); } @Test - void should_configure_exec_spec_with_lowercase_path_variable_and_executable_paths() { - final Set executablePaths = new HashSet<>(); - executablePaths.add(Paths.get("\\Program Files\\node\\bin")); - executablePaths.add(Paths.get("/opt/yarn")); + void should_configure_exec_spec_with_user_environment_and_no_path_override_and_additional_executable_paths_and_system_path() { final ExecutionSettings executionSettings = ExecutionSettings .builder() .workingDirectoryPath(WORKING_DIRECTORY_PATH) - .additionalExecutablePaths(executablePaths) + .additionalExecutablePaths(Set.of(EXECUTABLE_FILE_PATH)) .executablePath(EXECUTABLE_FILE_PATH) .arguments(ARGUMENTS) + .environmentVariables(Map.of("VARIABLE", "value")) .build(); final ExecSpecAction action = new ExecSpecAction(executionSettings, afterConfigured); - when(execSpec.getEnvironment()).thenReturn(Map.of("Path", String.join(File.pathSeparator, EXECUTABLE_PATHS))); + when(execSpec.getEnvironment()).thenReturn(Map.of("Path", "/system/bin")); action.execute(execSpec); - assertExecSpecWith(executionSettings); + verify(execSpec).setWorkingDir(WORKING_DIRECTORY_PATH.toString()); + verify(execSpec).setExecutable(EXECUTABLE_FILE_PATH.toString()); + verify(execSpec).setArgs(ARGUMENTS); + verify(execSpec).environment(Map.of("VARIABLE", "value")); + verify(execSpec).environment(PATH_VARIABLE_NAME, EXECUTABLE_FILE_PATH + File.pathSeparator + "/system/bin"); + verify(afterConfigured).accept(execSpec); + verifyNoMoreInteractions(execSpec, afterConfigured); } - private void assertExecSpecWith(final ExecutionSettings executionSettings) { - verify(execSpec).setWorkingDir(executionSettings.getWorkingDirectoryPath().toString()); - verify(execSpec).setExecutable(executionSettings.getExecutablePath()); - verify(execSpec).setArgs(executionSettings.getArguments()); - final ArgumentCaptor pathVariableCaptor = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor pathValueCaptor = ArgumentCaptor.forClass(Object.class); - verify(execSpec).environment(pathVariableCaptor.capture(), pathValueCaptor.capture()); - assertThat(pathVariableCaptor.getValue().toLowerCase()).isEqualTo("path"); - final String pathValue = pathValueCaptor.getValue().toString(); - final List expectedPaths = executionSettings - .getAdditionalExecutablePaths() - .stream() - .map(Path::toString) - .collect(toCollection(ArrayList::new)); - expectedPaths.add("/usr/bin"); - expectedPaths.add("/usr/lib"); - assertThat(pathValue.split(File.pathSeparator)).containsExactlyElementsOf(expectedPaths); + @Test + void should_configure_exec_spec_with_user_environment_and_path_override_and_additional_executable_paths_and_system_path() { + final ExecutionSettings executionSettings = ExecutionSettings + .builder() + .workingDirectoryPath(WORKING_DIRECTORY_PATH) + .additionalExecutablePaths(Set.of(EXECUTABLE_FILE_PATH)) + .executablePath(EXECUTABLE_FILE_PATH) + .arguments(ARGUMENTS) + .environmentVariables(Map.of("VARIABLE", "value", "PATH", "/usr/bin")) + .build(); + final ExecSpecAction action = new ExecSpecAction(executionSettings, afterConfigured); + when(execSpec.getEnvironment()).thenReturn(Map.of("Path", "/system/bin")); + + action.execute(execSpec); + + verify(execSpec).setWorkingDir(WORKING_DIRECTORY_PATH.toString()); + verify(execSpec).setExecutable(EXECUTABLE_FILE_PATH.toString()); + verify(execSpec).setArgs(ARGUMENTS); + verify(execSpec).environment(Map.of("VARIABLE", "value")); + verify(execSpec).environment(PATH_VARIABLE_NAME, EXECUTABLE_FILE_PATH + File.pathSeparator + "/usr/bin"); verify(afterConfigured).accept(execSpec); verifyNoMoreInteractions(execSpec, afterConfigured); } diff --git a/plugin/src/test/java/org/siouan/frontendgradleplugin/infrastructure/gradle/GradleScriptRunnerAdapterTest.java b/plugin/src/test/java/org/siouan/frontendgradleplugin/infrastructure/gradle/GradleScriptRunnerAdapterTest.java index 7825cc37..3862a64f 100644 --- a/plugin/src/test/java/org/siouan/frontendgradleplugin/infrastructure/gradle/GradleScriptRunnerAdapterTest.java +++ b/plugin/src/test/java/org/siouan/frontendgradleplugin/infrastructure/gradle/GradleScriptRunnerAdapterTest.java @@ -11,6 +11,7 @@ import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.Set; import org.gradle.process.ExecOperations; @@ -50,8 +51,9 @@ void setUp() { @Test void should_run_script_when_settings_are_resolved() { final Path nodeInstallationDirectory = ANY_PATH.resolve("node"); + final Map environmentVariables = Map.of("VARIABLE", "value"); final ScriptProperties scriptProperties = new ScriptProperties(execOperations, ANY_PATH.resolve("frontend"), - ExecutableType.NPM, nodeInstallationDirectory, SCRIPT, LOCAL_PLATFORM); + ExecutableType.NPM, nodeInstallationDirectory, SCRIPT, LOCAL_PLATFORM, environmentVariables); final Set executablePaths = Set.of(); final List arguments = List.of(); final ExecutionSettings executionSettings = ExecutionSettings @@ -60,14 +62,16 @@ void should_run_script_when_settings_are_resolved() { .additionalExecutablePaths(executablePaths) .executablePath(nodeInstallationDirectory.resolve("npm")) .arguments(arguments) + .environmentVariables(environmentVariables) .build(); when(resolveExecutionSettings.execute(ResolveExecutionSettingsCommand .builder() - .packageJsonDirectoryPath(scriptProperties.packageJsonDirectoryPath()) - .executableType(scriptProperties.executableType()) - .nodeInstallDirectoryPath(scriptProperties.nodeInstallDirectoryPath()) - .platform(scriptProperties.platform()) - .script(scriptProperties.script()) + .packageJsonDirectoryPath(scriptProperties.getPackageJsonDirectoryPath()) + .executableType(scriptProperties.getExecutableType()) + .nodeInstallDirectoryPath(scriptProperties.getNodeInstallDirectoryPath()) + .platform(scriptProperties.getPlatform()) + .script(scriptProperties.getScript()) + .environmentVariables(environmentVariables) .build())).thenReturn(executionSettings); final ExecResult execResult = mock(ExecResult.class); when(execOperations.exec(any(ExecSpecAction.class))).thenReturn(execResult); @@ -84,6 +88,7 @@ void should_run_script_when_settings_are_resolved() { assertThat(eS.getAdditionalExecutablePaths()).isEqualTo( executionSettings.getAdditionalExecutablePaths()); assertThat(eS.getExecutablePath()).isEqualTo(executionSettings.getExecutablePath()); + assertThat(eS.getEnvironmentVariables()).isEqualTo(environmentVariables); }); assertThat(execSpecAction.getAfterConfiguredConsumer()).isNotNull(); }); diff --git a/site/src/components/gradle-scripts.vue b/site/src/components/gradle-scripts.vue index 597ed0d5..158bbd72 100644 --- a/site/src/components/gradle-scripts.vue +++ b/site/src/components/gradle-scripts.vue @@ -3,7 +3,7 @@