Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipeline YAML may get processed as Groovy DSL when CpsFlowFactoryAction2 is present #28

Open
oleg-nenashev opened this issue Jul 18, 2020 · 1 comment
Assignees

Comments

@oleg-nenashev
Copy link
Member

oleg-nenashev commented Jul 18, 2020

Describe the bug
I hit this issue in the simple demo for jenkinsci/jenkinsfile-runner#316 . Jenkinsfile Runner uses the SCM source and the virtual FilesystemSCM, and presumptions in the Pipeline as YAML's code may lead to incorrect behavior if CpsFlowFactoryAction2 is present in the created Pipeline.

THIS IS NOT A BUG IN PIPELINE AS YAML, but some code hardening may make sense

Step 0. Jenkinsfile Runner adds the SetJenkinsfileLocation action which implements CpsFlowFactoryAction2. https://github.com/jenkinsci/jenkinsfile-runner/blob/9f41f51b6dc320b9dd5c0fa6d81f179518597d37/payload/src/main/java/io/jenkins/jenkinsfile/runner/SetJenkinsfileLocation.java

Step 1. PipelineCpsScmFlowDefinition converts YAML to Groovy DSL and then calls CpsFlowDefinition constructor

@Override
    public CpsFlowExecution create(FlowExecutionOwner owner, TaskListener listener, List<? extends Action> actions) throws Exception {
        CpsFlowExecution cpsFlowExecution =  super.create(owner, listener, actions);
        String yamlJenkinsFileContent = cpsFlowExecution.getScript();
       
       ....
 
        String jenkinsFileContent = pipelineModel.get().toPrettyGroovy();
        return new CpsFlowDefinition(jenkinsFileContent,cpsFlowExecution.isSandbox()).create(owner,listener, actions);
    }

Step 2. CpsFlowDefinition flow execution creator consults with actions passed as arguments. One of actions is SetJenkinsfileLocation. This action makes the method to calls return ((CpsFlowFactoryAction2) a).create(this, owner, actions); instead of creating the default constructor as coded below. The actually called create() method creates the execution from scratch and ignores the converted DSL. So it calls a standard

image

    @Override
    @SuppressWarnings("deprecation")
    public CpsFlowExecution create(FlowExecutionOwner owner, TaskListener listener, List<? extends Action> actions) throws IOException {
        for (Action a : actions) {
            if (a instanceof CpsFlowFactoryAction) {
                CpsFlowFactoryAction fa = (CpsFlowFactoryAction) a;
                return fa.create(this,owner,actions);
            } else if (a instanceof CpsFlowFactoryAction2) {
                return ((CpsFlowFactoryAction2) a).create(this, owner, actions);
            }
        }
        Queue.Executable exec = owner.getExecutable();
        FlowDurabilityHint hint = (exec instanceof Run) ? DurabilityHintProvider.suggestedFor(((Run)exec).getParent()) : GlobalDefaultFlowDurabilityLevel.getDefaultDurabilityHint();
        return new CpsFlowExecution(sandbox ? script : ScriptApproval.get().using(script, GroovyLanguage.get()), sandbox, owner, hint);
    }

Step 3. A standard Groovy Converter is called. Execution fails with...

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 5: expecting EOF, found ':' @ line 5, column 10.
     - stage: "Print Hello"
            ^

1 error

        at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
        at org.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.java:150)
        at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:120)
        at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:132)
        at org.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:350)
        at org.codehaus.groovy.antlr.AntlrParserPlugin.transformCSTIntoAST(AntlrParserPlugin.java:144)
        at org.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java:110)
        at org.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:234)
        at org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:168)
        at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:943)
        at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:605)
        at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
        at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
        at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)

To Reproduce
Run a demo from jenkinsci/jenkinsfile-runner#316

Expected behavior
Pipeline as YAML code is more robust against custom CpsFlowFactoryAction2 implementations. Additional coverage for Pipeline replay/restart functionality might be needed

Additional context
For me the resolution will be clearly on the Jenkinsfile Runner side. This is rather code hardening, not a bug

@aytuncbeken
Copy link
Contributor

Hi @oleg-nenashev ,

I am not sure what to do here. Is there any example ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants