防止 Jenkins 因来自 Jira 的 400 响应而导致构建过早失败 API

Prevent Jenkins from prematurely failing a build because of a 400 response from Jira API

这是我的情况。我正在 运行 使用通用 Webhook 触发器插件连接 Jenkins 服务器,该插件从 Jira Cloud 接收 JSON Webhook,然后 运行s 一个基于 Webhook 中信息的 Powershell 脚本使用适当的注释和状态转换更新 Jira。这个构建运行了好几个月,直到 Jenkins 的最新更新。

现在,当 Jira Webhook 触发时,Powershell 脚本 运行s 偶尔会失败。经过一番调试,原因似乎是在某行以前从未出过问题的代码上。

Powershell 代码中的一行向 Jira API 发出 POST 请求,以在相关任务上调用 Jira 状态转换。在理想情况下,任务 开始 状态为“待办事项”,第一个 POST 请求触发转换为“进行中”,然后部署 运行s。部署完成后,会出现另一个从“进行中”到“完成”的过渡。

但是,在某些情况下,任务不会以“待办事项”状态开始。当 POST 请求尝试转换 Jira 任务时,比如从“进行中”到“进行中”,会有一个 400 响应代码表示“错误请求”,因为转换是不允许的。这可以。以前,构建会收到 400 错误并继续执行脚本,我们希望它继续执行 。但是,新的行为是,现在接收 400 请求会使整个 Jenkins 构建失败,并且脚本中的下游步骤不会 运行.

我们有时需要在状态仍为 In Progress 时触发 Webhook,这些 400 错误对我们来说并不是什么大问题。 重要的是构建失败。如何阻止 Jenkins 使整个构建失败并在其中一种情况下停止我的 Powershell 脚本?

提前致谢。我觉得这是一个 Jenkins 配置问题,我无法在任何地方找到答案。

JSON 代码太长,无法在此处添加。

Powershell 脚本:

param ([string] $JIRA_TOKEN, [int] $BuildNumber)

. "C:\Users\Ameera.Khan\Documents\GitHub\tableau-migration-scripts\workbook_parse.ps1"

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12         #sets TLS method

Write-Host "Webhook recieved. Success."
$ExitCodePath = "E:\Webhook\TempFiles\ExitCode\ExitCode_$BuildNumber.txt"
$PostDeployIDPath = "E:\Webhook\TempFiles\PostDeployID\PostDeployID_$BuildNumber.txt"
$JiraWebhookPath = "E:\Webhook\TempFiles\Jira_Webhook$BuildNumber.JSON"
$WorkbooksPath = "E:\Webhook\TempFiles\Workbooks\workbooks_$BuildNumber.txt"

$body = [IO.File]::ReadAllText($JiraWebhookPath) #this reads the temp file that Jenkins wrote containing the JSON Body and stores it in a variable.
$JSON_body = $body | ConvertFrom-Json
$JSON_body.GetType()

# Here we pull out the TCMT plan(s) and the Dashboard Release Ready Ticket type from the JSON.
$TCMT_Plan = $JSON_Body.issue.fields.customfield_10107              #eg, "BCI_MA_MemberIntel.tcmx\nBCI_Medicare_Growth.tcmx"
$dev_workbook_name = $JSON_Body.issue.fields.customfield_10165      #eg, "atrio_memberintel_medicare_memberreporting_v2\nBCI_Medicare_MarketIntelPlanDesign_Dev"
$to_status = $JSON_Body.transition.to_status                        #should be "Release Ready"
$issue_type = $JSON_Body.issue.fields.issuetype.name                #should be "Dashboard Deployment"

# This block validates the parameters and stops the script from running if they're not right. 
if (!(($issue_type -eq "Dashboard Deployment") -Xor ($issue_type -eq "Bug")) -or ($to_status -ne "Release Ready") ) {
    Write-Host "This transition is not meant to be run."
    return
}
if ($dev_workbook_name) {
    Write-Host "This Webhook contains a Tableau Workbook name. We will run the Workbook."
}

$credential = $JIRA_TOKEN
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credential))
$encodedCreds = "Basic " + $encodedCreds
$Headers = @{
    "X-Atlassian-Token" = "no-check";
    "Authorization"     = $encodedCreds;
    "Content-Type"      = "application/json"
    "Accept"            = "application/json"
}

# We also set some startup variables, like ExitCodeArray and planFiles.
$prod_push = $JSON_Body.issue.fields.subtasks | where { $_.fields.issuetype.name -eq "Deploy" } #finds the Push to Prod subtask
$post_deploy_task = $JSON_Body.issue.fields.subtasks | where { $_.fields.issuetype.name -eq "Post Deployment Testing" } #finds the Post Deploy subtask
$Jira_deploy_subtask_id = $prod_push.key                                                        #should be PEP-##### of the Push subtask
$deploy_transition_status = $prod_push.fields.status.name
$ExitCodeArray = New-Object System.Collections.Generic.List[System.Object]
$planFiles = (($TCMT_Plan -split '\r?\n').Trim())                                               #this line splits the TCMT Plan string into multiple strings at \n. 
$workbookFiles = (($dev_workbook_name -split '\r?\n').Trim())   

# Save the workbooks within the planFiles into a E:\Webhook\workbooks_$BuildNumber.txt for the next pipeline step, Kinesis CI, to work properly.
workbook_parse -TCMT_Plan $TCMT_Plan -BuildNumber $BuildNumber
Add-Content -Path $WorkbooksPath -Value ($workbookFiles) 
$post_deploy_id = $post_deploy_task.key
$post_deploy_transition_status = $post_deploy_task.fields.status.name
$post_deploy_id | Out-File -FilePath $PostDeployIDPath

# Now that we have the subtask, we update the subtask to In Progress by providing the transition id for Open > In Progress in JSON format. 

if ($deploy_transition_status -eq "To Do") {
    $Uri = "https://carrothealth.atlassian.net/rest/api/2/issue/" + $Jira_deploy_subtask_id + "/transitions"
    $RequestBody = @{
        "transition" = @{
            id = "11" 
        };
    }
    # The Invoke-RestMethod method is equivalent to cURL and makes a web request based on the flags and parameters.
    Invoke-RestMethod -Method Post -Uri $Uri -H $Headers -Body ($RequestBody | ConvertTo-Json) -Verbose
}
else {
    Write-Host "The sub task is done, skipping to next part of deploy. "
}

...until the end of script.

Jenkins 管道脚本:

pipeline {
    agent any
    environment {
        JIRA_TOKEN = credentials('JIRA_TOKEN')
        OAUTH_CLIENT_ID = credentials('OAUTH_CLIENT_ID')
        OAUTH_CLIENT_SECRET = credentials('OAUTH_CLIENT_SECRET')
        TABLEAU_AUTOMATION_PASSWORD = credentials('TABLEAU_AUTOMATION_PASSWORD')
        TABLEAU_AUTOMATION_PASSWORD_KINESIS = credentials('TABLEAU_AUTOMATION_PASSWORD_KINESIS')
    }
    stages {
        stage('Write the Jira Webhook to a file') {
            steps {
                writeFile(file:"E:/Webhook/TempFiles/Jira_Webhook/${currentBuild.number}.json", text:body)
            }
        }
        stage('Create TCMT Plan in case of Tableau Workbook') {
            steps {
                powershell(script: "C:/Users/Ameera.Khan/anaconda3/python.exe C:/Users/Ameera.Khan/Documents/GitHub/tableau-migration-scripts/onTheFly.py '${currentBuild.number}'")
            }
        }
        stage('Migrate Content') {
            steps {
                powershell(script: "C:/Users/Ameera.Khan/Documents/GitHub/tableau-migration-scripts/tcmt_runner_Continuous_Deploy.ps1 -BuildNumber '${currentBuild.number}' -JIRA_TOKEN '${env.JIRA_TOKEN}'")
            }
        }
        stage('Post Deploy Testing') {
            steps {
                powershell(script: "C:/Users/Ameera.Khan/Documents/GitHub/tableau-migration-scripts/CI_Script.ps1 -BuildNumber '${currentBuild.number}' -JIRA_TOKEN '${env.JIRA_TOKEN}' -OAUTH_CLIENT_ID '${env.OAUTH_CLIENT_ID}' -OAUTH_CLIENT_SECRET '${env.OAUTH_CLIENT_SECRET}' -TABLEAU_AUTOMATION_PASSWORD_KINESIS '${env.TABLEAU_AUTOMATION_PASSWORD_KINESIS}'")
            }
        }
    }
}

错误日志:

VERBOSE: POST https://carrothealth.atlassian.net/rest/api/2/issue/PEP-37938/transitions with -1-byte payload
powershell.exe : Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At C:\Users\Ameera.Khan\AppData\Local\Jenkins\.jenkins\workspace\TableauCD@tmp\durable-2d7da495\powershellWrapper.ps1:3 char:1
+ & powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -Comm ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Invoke-RestMeth...0) Bad Request.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
 
At C:\Users\Ameera.Khan\Documents\GitHub\tableau-migration-scripts\tcmt_runner_Continuous_Deploy.ps1:91 char:1
+ Invoke-RestMethod -Method Post -Uri $Uri -H $Headers -Body ($RequestB ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc 

   eption

    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

在我的脚本中,我可以使用简单的 try / catch 方法避免通过错误构建失败。

所以尝试这样的事情:

# The Invoke-RestMethod method is equivalent to cURL and makes a web request based on the flags and parameters.

try {

    Invoke-RestMethod -Method Post -Uri $Uri -H $Headers -Body ($RequestBody | ConvertTo-Json) -Verbose

} catch {

    Write-Warning -Message 'Issue already in Progress'

}

如果您查看 PowerShell 管道支持文档。您可以指定一个明确的退出代码以将构建标记为成功,尽管有错误。

https://www.jenkins.io/blog/2017/07/26/powershell-pipeline/

node {
    powershell '''
        Write-Error 'Error! Problem Exists Between Keyboard And Chair'
        exit 0
    '''
}