Почему Groovey .equals () завершается ошибкой в ​​конвейерном скрипте jenkins при интерполяции параметров в строку в двойных кавычках? - PullRequest
0 голосов
/ 24 апреля 2019

(Примечание: я смотрел на похожие вопросы (например, this , где проблема заключается в невозможности обрезать вывод команд оболочки), но я думаю, что этот случай отличается.)

У меня есть конвейерный скрипт в Groovy, который использует параметры (через properties([parameters([...). Когда я интерполирую значение параметра в строку в двойных кавычках, он не проходит проверку .equals() против обоих захваченных (под этим я подразумеваю "захваченный и .trim () d! ") вывод (это мой вариант использования) и даже простой строковый литерал.

Я могу обойти проблему, используя .trim(), (хотя вы можете видеть, как с помощью их повторения и проверки .length(), что .trim() нет ничего), но я подозреваю, что только "работает «потому что он делает неявное .toString() - что также является успешным обходным путем.

Мне это кажется ошибкой, но это буквально моя первая неделя работы с Groovy, так что, возможно, я что-то упускаю - кто-нибудь может объяснить, что?

Даже простой литерал "foo" терпит неудачу (т.е. "foo".equals("${params.foo_the_parameter}"). Является ли интерполированный параметр каким-либо другим видом объекта или чем-то еще?

[ EDIT Получив ответ от @Matias Bjarland, я изменил код, приведенный ниже, чтобы использовать println вместо шелл-эхо, потому что это делает вывод более кратким. Предложенное им решение отражено в комментируемом блоке.]

Мой заводной код:

node() {
    properties([
        parameters([
            string(
                defaultValue: 'foo',
                description: 'This is foo',
                name: 'foo_the_parameter'
            )
        ])
    ])

    /* this is what I learned from the accepted answer
    bob="${params.foo_the_parameter}"
    println("class of interpolated param is ${bob.class}")
    simple_foo="foo"
    println("class of \"foo\" is ${simple_foo.class}")
    */
    echoed_foo = sh(script:"echo 'foo'", returnStdout: true).trim()
    println "echoed foo is [$echoed_foo], params foo is [${params.foo_the_parameter}]";
    echo_foo_length = echoed_foo.length()
    dqs_foo_length = "${params.foo_the_parameter}".length()
    println "their lengths are: echo: [$echo_foo_length] and dqs: [$dqs_foo_length]";
    if (echoed_foo.equals("${params.foo_the_parameter}")) {
        println "SUCCESS they are equals()"
    }
    else {
        println "FAIL they are not equals()" //this one fires
    }
    if (echoed_foo.equals("${params.foo_the_parameter}".trim())) {
        println "SUCCESS they are equals() after the dqs gets a trim()" //this one fires
    }
    else {
        println "FAIL they are not equals()after the dqs gets a trim()"
    }
    if (echoed_foo.equals("${params.foo_the_parameter}".toString())) {
        println "SUCCESS they are equals() after the dqs gets a toString()" //this one fires
    }
    else {
        println "FAIL they are not equals()after the dqs gets a toString()"
    }

    if ("foo".equals("${params.foo_the_parameter}")) {
        println "SUCCESS at least a simple literal \"foo\" works"
    }
    else {
        println "FAIL even a simple literal \"foo\" fails to be .equals() with the interpolated parameter" //this one fires
    }
}

Вывод Дженкинса:

Started by user Michael South
[Office365connector] No webhooks to notify
Obtained jenkins.groovy from git git@github.redacted.com:msouth/test_groovy_equals.git
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] node
Running on subnet_mon_02 in /opt/jenkins/m1/workspace/field-analytics-org/test_string_equals
[Pipeline] {
[Pipeline] properties
[Pipeline] sh
[test_string_equals] Running shell script
+ echo foo
[Pipeline] echo
echoed foo is [foo], params foo is [foo]
[Pipeline] echo
their lengths are: echo: [3] and dqs: [3]
[Pipeline] echo
FAIL they are not equals()
[Pipeline] echo
SUCCESS they are equals() after the dqs gets a trim()
[Pipeline] echo
SUCCESS they are equals() after the dqs gets a toString()
[Pipeline] echo
FAIL even a simple literal "foo" fails to be .equals() with the interpolated parameter
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
[Office365connector] No webhooks to notify
Finished: SUCCESS

Ответы [ 2 ]

2 голосов
/ 25 апреля 2019

В Groovy вы можете просто использовать == для сравнения строк

В Java вы используете String.equals(), потому что str1 == str2 не делает то, что вы ожидаете: Java сравнивает ссылки вместозначения.

В Groovy вы можете просто написать str1 == str2, и он сделает то, что ожидал.Groovy сравнивает значения с помощью String.compareTo() и возвращает true, когда результат равен 0.

GString g = "${'foo'}"
String s = "foo"

assert g == "foo" && s == "foo"
assert g instanceof GString && s instanceof String
assert !s.equals(g) && !g.equals(s)
assert g.compareTo(s) == 0 && s.compareTo(g) == 0
assert g == s && s == g 
1 голос
/ 24 апреля 2019

Не уверен, что это то, что вы бьете, но подумайте о следующем отличном коде:

def x = 'World'
def gstr = "Hello ${x}!"
def str  = 'Hello World!'

println "class of gstr: ${gstr.class}"
println "class of str:  ${str.class}"

println(gstr.equals(str))
println(gstr.toString().equals(str))

который при запуске печатает:

~> groovy solution.groovy
class of gstr: class org.codehaus.groovy.runtime.GStringImpl
class of str:  class java.lang.String
false
true

~> 

Другими словами, интерполяция строки приведет к экземпляру groovy GString , который не обязательно равен строке с тем же содержимым. Принудительная оценка с использованием .toString() решает эту конкретную проблему.

Цитирование отличной документации по интерполяции строк :

Любое выражение Groovy можно интерполировать во все строковые литералы, кроме одинарных и тройных одинарных строк в кавычках. Интерполяция - это процесс замены заполнителя в строке его значением при вычислении строки. Выражения-заполнители окружены $ {} или префиксом $ для точечных выражений. Значение выражения внутри заполнителя оценивается в его строковое представление, когда GString передается методу, принимающему String в качестве аргумента, путем вызова toString () для этого выражения.

Другими словами, вы должны либо назначить экземпляр GString для строки Java-плана, используя несколько вариантов:

String str1 = gstr
def str2 = gstr as String
def str3 = (String) gstr

, вызовите метод, который принимает строку (которая приведет строку GString к строке), или вызовите gstr.toString() для принудительного преобразования.

Надеюсь, это поможет.

...