Closed harbulot closed 1 year ago
@harbulot thanks for reporting this issue, We created #45 to fix it. We'd also very much appreciate any feedback on the pull request and the solution :)
Thank you @yahavi, that's a very fast reply!
I've compiled and tested your patch on a Jenkins installation.
I think there are still a few issues regarding quotations marks.
This displays the test.*
properties, in plain text and in XML (to see potentially escaped characters)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>echo-properties-test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>textoutput</id>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<echoproperties prefix="test." />
</target>
</configuration>
</execution>
<execution>
<id>xmloutput</id>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<echoproperties prefix="test." format="xml" />
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I've also put this into .mvn/maven-config
for reference (This needs at least Maven 3.9.0):
-Dtest.maven-config.test1=MavenConfigTest1
-Dtest.maven-config.test2=Maven Config Test 2
-Dtest.maven-config.test3="Maven Config Test 3"
-Dtest.maven-config.test4='Maven Config Test 4'
I'd use the Bash shell invocation as what I'd tend to expect naturally around quotation marks behaviour.
BASH_VAR_1="Bash Var 1"
BASH_VAR_2='Bash "quote"'
mvn validate -Dtest.bashcli.test1="Test Property 1" -Dtest.bashcli.testvar1="$BASH_VAR_1" -Dtest.bashcli.testvar2="$BASH_VAR_2"
[INFO] [echoproperties] test.bashcli.test1=Test Property 1
[INFO] [echoproperties] test.bashcli.testvar1=Bash Var 1
[INFO] [echoproperties] test.bashcli.testvar2=Bash "quote"
[INFO] [echoproperties] test.maven-config.test1=MavenConfigTest1
[INFO] [echoproperties] test.maven-config.test2=Maven Config Test 2
[INFO] [echoproperties] test.maven-config.test3="Maven Config Test 3"
[INFO] [echoproperties] test.maven-config.test4='Maven Config Test 4'
...
[INFO] [echoproperties] <?xml version="1.0" encoding="UTF-8"?><properties>
[INFO] [echoproperties] <property name="test.bashcli.test1" value="Test Property 1" />
[INFO] [echoproperties] <property name="test.bashcli.testvar1" value="Bash Var 1" />
[INFO] [echoproperties] <property name="test.bashcli.testvar2" value="Bash "quote"" />
[INFO] [echoproperties] <property name="test.maven-config.test1" value="MavenConfigTest1" />
[INFO] [echoproperties] <property name="test.maven-config.test2" value="Maven Config Test 2" />
[INFO] [echoproperties] <property name="test.maven-config.test3" value=""Maven Config Test 3"" />
[INFO] [echoproperties] <property name="test.maven-config.test4" value="'Maven Config Test 4'" />
[INFO] [echoproperties] </properties>
What we can see from this example is that the quotation marks around "Test Property 1"
and "$BASH_VAR_1"
and "$BASH_VAR_2"
are actually handled by the shell: they are not part of the actual values.
This is in part due to using the features of "$@" with quotes in the mvn
command itself.
Even if mvn
wasn't a shell script but a plain command-line applications, you would expect the argv
(or equivalent) to be an array with:
validate
-Dtest.bashcli.test1=Test Property 1
-Dtest.bashcli.testvar1=Bash Var 1
-Dtest.bashcli.testvar2=Bash "quote"
In contrast, the properties defined in .mvn/maven-config
are only delimited by the end of line (in Maven 3.9.0, not before), so whatever quotation marks are used are actually part of the value:
test.maven-config.test1=MavenConfigTest1
test.maven-config.test2=Maven Config Test 2
test.maven-config.test3="Maven Config Test 3"
test.maven-config.test4='Maven Config Test 4'
jf
BASH_VAR_1="Bash Var 1"
BASH_VAR_2='Bash "quote"'
jf mvn validate -Dtest.bashcli.test1="Test Property 1" -Dtest.bashcli.testvar1="$BASH_VAR_1" -Dtest.bashcli.testvar2="$BASH_VAR_2"
This was just to compare, but this produces the same results as without jf
.
(This is based on commit 3e248b19c8f63d06cdf9669d219c9688563db256)
jf "mvn validate -Dtest.jfcli.test1=TestProperty1 -Dtest.jfcli.test2=\"Test Property 2\""
[main] INFO org.apache.maven.plugins.antrun.AntRunMojo - [echoproperties] test.jfcli.test1=TestProperty1
[main] INFO org.apache.maven.plugins.antrun.AntRunMojo - [echoproperties] test.jfcli.test2="Test Property 2"
PR #45 is clearly an improvement, since we can now use values with spaces. However the quotation mark is included in the value, which is generally not expected.
The implication is that you couldn't have values with spaces without also having the enclosing quotes as part of the value (that's not something a shell forces you to have, and it doesn't always make sense).
I'm not sure if it's fair to have that expectation, but it would also be good to be able to pass variables (same as one would do in a shell script).
script {
env.setProperty("TEST_PROP_3", "Test Property 3")
env.setProperty("TEST_PROP_4", "Test \"Property\" 4")
}
jf "mvn validate -Dtest.jfcli.test3=\"${TEST_PROP_3}\" -Dtest.jfcli.test4=\"${TEST_PROP_4}\""
This works, but also includes the quotes around:
[main] INFO org.apache.maven.plugins.antrun.AntRunMojo - [echoproperties] test.jfcli.test3="Test Property 3"
[main] INFO org.apache.maven.plugins.antrun.AntRunMojo - [echoproperties] test.jfcli.test4="Test "Property" 4"
script {
env.setProperty("TEST_PROP_5", "Test with one double-quote \" only")
}
jf "mvn validate -Dtest.jfcli.test5=\"${TEST_PROP_5}\""
This one fails with this in the logs:
$ /var/lib/jenkins/tools/io.jenkins.plugins.jfrog.JfrogInstallation/jfrog-cli/jf 'mvn validate -Dtest.jfcli.test5="Test' with one double-quote '" only"'
'jf mvn validate -Dtest.jfcli.test5="Test' is not a jf command. See --help
The previous sucessful example showed this command:
$ /var/lib/jenkins/tools/io.jenkins.plugins.jfrog.JfrogInstallation/jfrog-cli/jf mvn validate '-Dtest.jfcli.test3="Test Property 3"' '-Dtest.jfcli.test4="Test "Property" 4"'
I don't think there's a simple solution to this problem.
Even if you manage to find a regex that gets rid of the paired double quotes surrounding each token, that would only work for fixed values. Anything coming from variables would at least need to be escape, if it's even possible in the general case.
I realise the syntax would be less user-friendly (and I'm not sure if it's possible), but perhaps the jf
step could take an array as an argument instead of a string that's subsequently split. It seems otherwise difficult to design something that can safely take values coming from variables.
The problem here is pretty much the same that led to Runtime.exec(String)
to be deprecated in Java 18, in favour if Runtime.exec(String[])
I don't really have any experience with writing Jenkins plugins, but I've tried this fairly simple change:
diff --git a/src/main/java/io/jenkins/plugins/jfrog/JfStep.java b/src/main/java/io/jenkins/plugins/jfrog/JfStep.java
index 0224ee7..96aed93 100644
--- a/src/main/java/io/jenkins/plugins/jfrog/JfStep.java
+++ b/src/main/java/io/jenkins/plugins/jfrog/JfStep.java
@@ -41,14 +41,14 @@ public class JfStep<T> extends Builder implements SimpleBuildStep {
public static final String JFROG_CLI_BUILD_NAME = "JFROG_CLI_BUILD_NAME";
public static final String JFROG_CLI_BUILD_NUMBER = "JFROG_CLI_BUILD_NUMBER";
public static final String JFROG_CLI_BUILD_URL = "JFROG_CLI_BUILD_URL";
- protected String args;
+ protected String[] args;
@DataBoundConstructor
- public JfStep(String args) {
+ public JfStep(String[] args) {
this.args = args;
}
- public String getArgs() {
+ public String[] getArgs() {
return args;
}
@@ -78,7 +78,7 @@ public class JfStep<T> extends Builder implements SimpleBuildStep {
jfrogBinaryPath = FilenameUtils.separatorsToUnix(jfrogBinaryPath);
}
builder.add(jfrogBinaryPath);
- builder.add(StringUtils.split(args));
+ builder.add(args);
if (isWindows) {
builder = builder.toWindowsCommand();
}
The jf
calls now expect an array:
jf(["mvn-config","--repo-deploy-releases","libs-release-local","--repo-deploy-snapshots","libs-snapshot-local"])
script {
env.setProperty("TEST_PROP_3", "Test Property 3")
env.setProperty("TEST_PROP_4", "Test \"Property\" 4")
env.setProperty("TEST_PROP_5", "Test with one double-quote \" only")
}
jf(["mvn","validate",
"-Dtest.jfcli.test1=TestProperty1",
"-Dtest.jfcli.test2=Test Property 2",
"-Dtest.jfcli.test3=${TEST_PROP_3}",
"-Dtest.jfcli.test4=${TEST_PROP_4}",
"-Dtest.jfcli.test5=${TEST_PROP_5}"])
The output seems to work fine now, even with variables:
[echoproperties] test.jfcli.test1=TestProperty1
[echoproperties] test.jfcli.test2=Test Property 2
[echoproperties] test.jfcli.test3=Test Property 3
[echoproperties] test.jfcli.test4=Test "Property" 4
[echoproperties] test.jfcli.test5=Test with one double-quote " only
The downside is that it's a breaking change in terms of usage of the jf
step.
Thanks for this feedback, @harbulot! We created https://github.com/jfrog/jenkins-jfrog-plugin/pull/48 to implement your suggestion. We'd appreciate your feedback on that.
That's great @yahavi , thank you! Supporting both strings and lists sounds like a good idea.
I've tried the patch and it works with both (handy for fixed commands that don't need parameters (e.g. jf 'rt build-add-git'
).
I'd just suggest expanding a bit in the README. Perhaps something along these lines:
If the JFrog CLI command contains some arguments with spaces, you can rather provide the arguments as a list:
jf(['mvn', 'clean', 'install', '-Ddeploy.testProperty=Property with space'])
In this case, the quotes that would be required in a shell are not necessary (and would be part of the value itself, if used). The above step is equivalent to a shell invokation as follows:
jf mvn clean install -Ddeploy.testProperty="Property with space"
Passing the arguments as a list can also be useful to avoid space and escaping problems if some of those arguments rely on script variables.
I've also noticed a couple of minor typos in the patch (commented on PR #48 directly).
Thanks again for the suggestion. I'm not a native English speaker and it was helpful. I applied your suggestions in my branch - https://github.com/yahavi/jenkins-jfrog-plugin/tree/list#using-jfrog-cli-in-your-pipeline-jobs
However, I'm afraid that having a JFrog CLI shell command in the README will be confusing:
jf mvn clean install -Ddeploy.testProperty="Property with space"
My solution was to upload an image to make it non-copyable.
I must have missed something in the README update, but that's not necessarily correct. This note probably shouldn't be there, and can be misleading:
IMPORTANT: Notice the single quotes wrapping the command right after the jf step definition.
When reading the README, I'm not sure whether this "IMPORTANT" note refers to the sentence above (single string argument) or below (list argument)
When using a list, it would actually be perfectly fine to have something like this:
def CUSTOM_PROP="This is my build property with spaces"
//...
jf(['mvn','clean','install',"-Dtest.prop=${CUSTOM_PROP}"]) // Using Groovy string interpolation with double-quotes
A list argument makes it safer to use double-quote wrapping (depending on what jf
command is actually used, but no worse than jf
with a single string argument).
Hi again @harbulot, Thanks for this feedback. We will consider your suggestions for the README and add them in another PR.
Update - Jenkins Artifactory plugin 1.2.0 is released and will be available shortly in the Jenkins plugin manager. This version includes this feature. We're looking forward to your feedback.
Thank you @yahavi, the 1.2.0 release works!
Describe the bug
It seems impossible to pass Maven options with values that contain spaces. This would generally apply to any
jf
command that may contain spaces.Current behavior
This results in this error:
Reproduction steps
This seems to be due to the fact the
jf
argument string is simply split by whitespace inJfStep
:I tried to work around this by setting
MAVEN_OPTS
, but Maven itself more or less has the same problem: https://issues.apache.org/jira/browse/MNG-4559In general, this also raises questions about character escaping. For example, even without whitespace, the quotes would be including in the property deployment if you use
-Ddeploy.testProperty="TestProperty"
.Expected behavior
We should be able to use
-Ddeploy.testProperty="Test Property"
as a valid option.JFrog plugin version
1.0.5
JFrog CLI version
2.34.6
Operating system type and version
Linux
Workaround
For Maven, here is a potential workaround, which relies on writing those options in a
.mvn/maven.config
file in the workspace. This might require more work if such a file already exists in the source tree. (This workaround also requires a number of additional script permissions, in particular w.r.t creating and modifying files, which may or may not be desirable.)This only works with Maven 3.9.0 (and later, presumably), and requires one setting per line in this file, as mentioned in the Maven documentation:
Arguments with spaces fail altogether with Maven 3.8.7 (even if it's just one):