jenkins - 在 Jenkins 管道中发送松弛消息时 cps 不匹配

标签 jenkins groovy jenkins-pipeline jenkins-groovy

我在 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 功能带到另一个函数,并从函数内部调用它,但我一直遇到同样的错误,老实说,我很安静地失去了这一点

最佳答案

slackSend 是一个管道步骤,因此不能从 @NonCPS 上下文调用。只有少数异常(exception),例如 echo,它在 @NonCPS 上下文中工作。参见 Use of Pipeline steps from @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
}

关于jenkins - 在 Jenkins 管道中发送松弛消息时 cps 不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74834269/

相关文章:

jenkins - Jenkins 中的 'Poll SCM' 和 'Build periodically' 哪个优先级更高?

grails - GSP包含-带参数-在g:内?

java - Gradle 中 $PROPERTY 的默认值

docker - 运行 docker-in-docker 时 Jenkins 声明性管道问题

php - 仅对修改后的文件运行 Ant exec 任务

jenkins - 在 Jenkins Workflow 插件中获取输入批准者用户名

java.lang.NullPointerException : Cannot invoke method get() on null object

Maven 不会接受 Spock 测试

Jenkins 定期构建 - 计划

jenkins - 如何在Jenkins管道脚本中访问参数?