Las tuberías de Jenkins ejecutan el código Groovy en el estilo de paso de continuación utilizando el intérprete groovy-cps . Esto no es Vanilla Groovy que puede ejecutar directamente en el IDE o en Groovy Shell.
Groovy CPS transforma su código para admitir el estilo de paso continuo y la expresión correcta de Groovy como:
a = b = c = 0
se transforma en algo que se parece más a:
eval(
var("a"),
assign(
eval(
var("b"),
assign(
eval(
var("c"),
assign(0)
)
)
)
)
)
El problema con esta expresión en el intérprete de CPS es que la asignación no devuelve ningún valor y, por lo tanto, el null
valor se asigna a la variable b
, y lo mismo le sucede a la variable a
.
Si desea profundizar en el bloque de invocaciones de CPS, puede clonar el proyecto groovy-cps y escribir un caso de prueba simple en la com.cloudbees.groovy.cps.CpsTransformerTest
clase.
@Test
void testMultiVariablesInlineCPS() {
def cps = parseCps('''
int a, b, c
a = b = c = 0
''')
println cps
}
Luego puede poner un punto de interrupción en el println cps
y ejecutar el depurador. Cuando abra la ventana de inspección, verá una imagen similar a esta:
Como nota al margen, tenga en cuenta que el compilador Groovy también transforma sus asignaciones de una sola línea cuando compila el código en el código de bytes. Si compila un script Groovy simple como:
int a, b, c
a = b = c = 0
println "$a $b $c"
y luego abres su archivo de clase en el IDE para descompilar el bytecode al equivalente de Java, verás algo como esto:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.GStringImpl;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class test extends Script {
public test() {
CallSite[] var1 = $getCallSiteArray();
}
public test(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, test.class, args);
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
int a = 0;
int b = 0;
int c = 0;
byte var5 = 0;
return var1[1].callCurrent(this, new GStringImpl(new Object[]{Integer.valueOf(var5), Integer.valueOf(var5), Integer.valueOf(var5)}, new String[]{"", " ", " ", ""}));
}
}