groovy 在Jenkins管道中发送松弛消息时CPS不匹配

u3r8eeie  于 2022-12-22  发布在  Jenkins
关注(0)|答案(1)|浏览(172)

我在post always阶段从声明性管道调用此函数:

import groovy.json.JsonSlurper
import com.cloudbees.groovy.cps.NonCPS
@NonCPS
def call(){
    String path = "C:\\Users\\tests"
    String jsonFileToRead = new File(path).listFiles().findAll { it.name.endsWith(".json") }
        .sort { -it.lastModified() }?.head()
    JsonSlurper jsonSlurper = new JsonSlurper()
    Map data = jsonSlurper.parse(new File(jsonFileToRead))
    Map testResults = [:]
    int totalTests = data.results.size()
    int totalFailures = 0
    int totalSuccess = 0
    def results = []

    //Map test names and results from json file
    for (int i = 0; i < data.results.size(); i++) {
        testResults.put(i, [data['results'][i]['TestName'], data['results'][i]['result']])
    }

    //Iterate through the map and send to slack test name and results and then a summary of the total tests, failures and success
    for (test in testResults.values()){
        String testName =  test[0]
        String testResult = test[1]
        String msg = "Test: " + testName + " Result: " + testResult
        if(testResult == "fail")
        {
            totalFailures++ 
            println msg
            try {
                slackSend color : "danger", message: "${msg}", channel: '#somechannel'
            } catch (Throwable e) {
                error "Caught ${e.toString()}" 
            }   
        }
        else if(testResult == "pass")
        {
            totalSuccess++
            println msg
            try {
                slackSend color : "good", message: "${msg}", channel: '#somechannel'
            } catch (Throwable e) {
                error "Caught ${e.toString()}" 
            }            
        }
        else
        {
            println "Unknown test result: " + testResult
        }
    }
    def resultsSummary = "Total Tests: " + totalTests + " Total Failures: " + totalFailures + " Total Success: " + totalSuccess
    slackSend color : "good", message: "${resultsSummary}", channel: '#somechannel'
    println resultsSummary

但我一直收到这个错误,即使我使用的是@NonCPS。我有点困惑,好像我注解掉了调用slackSend功能的3行,一切都很好,我在控制台中输出了正确的消息,管道成功完成,但如果我像这样运行它,即使我只是尝试发送摘要并注解掉其他2个slackSend,我也会收到这个错误:

13:53:23  [Pipeline] echo
13:53:23  Test: triggers_attackMove Result: pass
13:53:23  [Pipeline] slackSend
13:53:23  Slack Send Pipeline step running, values are - baseUrl: <empty>, teamDomain: forgottenempires, channel: #test_harness_logs_phoenix, color: good, botUser: true, tokenCredentialId: Slack_bot_test, notifyCommitters: false, iconEmoji: :goose, username: Jenkins Wizard, timestamp: <empty>
13:53:23  [Pipeline] error
13:53:24  [Pipeline] }
13:53:24  [Pipeline] // script
13:53:24  Error when executing always post condition:
13:53:24  hudson.AbortException: Caught CpsCallableInvocation{methodName=slackSend, call=com.cloudbees.groovy.cps.impl.CpsFunction@149776fc, receiver=null, arguments=[org.jenkinsci.plugins.workflow.cps.DSL$ThreadTaskImpl@25def8]}
13:53:24    at org.jenkinsci.plugins.workflow.steps.ErrorStep$Execution.run(ErrorStep.java:64)
13:53:24    at org.jenkinsci.plugins.workflow.steps.ErrorStep$Execution.run(ErrorStep.java:51)
13:53:24    at org.jenkinsci.plugins.workflow.steps.SynchronousStepExecution.start(SynchronousStepExecution.java:37)
13:53:24    at org.jenkinsci.plugins.workflow.cps.DSL.invokeStep(DSL.java:322)
13:53:24    at org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:196)
enter code here
....

我尝试用@NonCPS装饰器将slackSend功能转移到另一个函数,并从该函数内部调用它,但我一直得到相同的错误,老实说,我完全弄不懂这一点

q35jwt9p

q35jwt9p1#

slackSend是一个管道步骤,因此不能从@NonCPS上下文调用。只有少数例外(如echo)可以从@NonCPS上下文调用。有关详细信息,请参阅使用@NonCPS中的管道步骤。
在这种情况下,我的方法是从调用步骤的函数中删除@NonCPS,只将实际需要@NonCPS的代码移到单独的@NonCPS函数中,在您的情况下,这可能只是使用FileJsonSlurper类的代码。
此外,我们需要确保@NonCPS函数返回的任何数据都是可序列化的JsonSlurper返回的LazyMap不是。正如OP所评论的,最简单的解决方案是使用JsonSlurperClassic,它返回一个常规的、可序列化的Map(或者在根是数组的情况下返回List)。

@NonCPS
Map readData(){
    String path = "C:\\Users\\tests"
    String jsonFileToRead = new File(path).listFiles().findAll { it.name.endsWith(".json") }
        .sort { -it.lastModified() }?.head()
    def jsonSlurper = new JsonSlurperClassic()
    return jsonSlurper.parse(new File(jsonFileToRead))
}

// Note: Must not be @NonCPS because pipeline steps are called!
def call(){
    Map data = readData()
    Map testResults = [:]
    int totalTests = data.results.size()
    int totalFailures = 0
    int totalSuccess = 0
    def results = []

    //Map test names and results from json file
    for (int i = 0; i < data.results.size(); i++) {
        testResults.put(i, [data['results'][i]['TestName'], data['results'][i]['result']])
    }

    //Iterate through the map and send to slack test name and results and then a summary of the total tests, failures and success
    for (test in testResults.values()){
        String testName =  test[0]
        String testResult = test[1]
        String msg = "Test: " + testName + " Result: " + testResult
        if(testResult == "fail")
        {
            totalFailures++ 
            println msg
            try {
                slackSend color : "danger", message: "${msg}", channel: '#somechannel'
            } catch (Throwable e) {
                error "Caught ${e.toString()}" 
            }   
        }
        else if(testResult == "pass")
        {
            totalSuccess++
            println msg
            try {
                slackSend color : "good", message: "${msg}", channel: '#somechannel'
            } catch (Throwable e) {
                error "Caught ${e.toString()}" 
            }            
        }
        else
        {
            println "Unknown test result: " + testResult
        }
    }
    def resultsSummary = "Total Tests: " + totalTests + " Total Failures: " + totalFailures + " Total Success: " + totalSuccess
    slackSend color : "good", message: "${resultsSummary}", channel: '#somechannel'
    println resultsSummary
}

相关问题