diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/EnvStep.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/EnvStep.java index da6de349..f8c55cc7 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/steps/EnvStep.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/EnvStep.java @@ -49,12 +49,19 @@ public class EnvStep extends Step { @DataBoundConstructor public EnvStep(List overrides) { - for (String pair : overrides) { - if (pair.indexOf('=') == -1) { - throw new IllegalArgumentException(pair); + if (overrides == null) { + this.overrides = Collections.emptyList(); + } else { + List stored = new ArrayList<>(); + for (String pair : overrides) { + if (pair == null || pair.indexOf('=') == -1) { + throw new IllegalArgumentException(String.valueOf(pair)); + } + // store a trimmed form to normalize whitespace (keys/values are trimmed later too) + stored.add(pair.trim()); } + this.overrides = stored; } - this.overrides = new ArrayList<>(overrides); } public List getOverrides() { @@ -75,7 +82,7 @@ public static class Execution extends AbstractStepExecutionImpl { Execution(List overrides, StepContext context) { super(context); - this.overrides = overrides; + this.overrides = overrides == null ? Collections.emptyList() : overrides; } @Override @@ -83,8 +90,14 @@ public boolean start() throws Exception { Map overridesM = new HashMap<>(); for (String pair : overrides) { int split = pair.indexOf('='); - assert split != -1; - overridesM.put(pair.substring(0, split), pair.substring(split + 1)); + if (split == -1) { + // defensive: in case an instance is deserialized from an older form + throw new IllegalStateException("Invalid environment override: " + pair); + } + // trim both key and value to be tolerant of user input like "FOO = bar " + String key = pair.substring(0, split).trim(); + String value = pair.substring(split + 1).trim(); + overridesM.put(key, value); } getContext() .newBodyInvoker() @@ -135,7 +148,7 @@ public boolean takesImplicitBlockArgument() { public Step newInstance(StaplerRequest2 req, JSONObject formData) throws FormException { String overridesS = formData.getString("overrides"); List overrides = new ArrayList<>(); - for (String line : overridesS.split("\r?\n")) { + for (String line : overridesS.split("\\r?\\n")) { line = line.trim(); if (!line.isEmpty()) { overrides.add(line); diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/EnvStepUnitTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/EnvStepUnitTest.java new file mode 100644 index 00000000..97c1e0c4 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/EnvStepUnitTest.java @@ -0,0 +1,29 @@ +package org.jenkinsci.plugins.workflow.steps; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +public class EnvStepUnitTest { + + @Test + void constructorAcceptsNull() { + EnvStep s = new EnvStep(null); + assertTrue(s.getOverrides().isEmpty()); + } + + @Test + void constructorRejectsMalformedEntry() { + assertThrows(IllegalArgumentException.class, () -> new EnvStep(Arrays.asList("BADPAIR"))); + } + + @Test + void constructorTrimsStoredPair() { + EnvStep s = new EnvStep(Arrays.asList("FOO = bar ")); + assertEquals(1, s.getOverrides().size()); + assertEquals("FOO = bar", s.getOverrides().get(0)); + } +}