如何读取Azure DevOps任务日志?

3
我在 Azure Pipeline 中有一个任务,执行一些动态测试。由于测试数量很多,每个单独的测试是否通过或失败是由日志中的内容决定的。
因此,Azure DevOps 步骤始终显示为绿色。我想通过读取日志来解决问题,然后根据日志中是否包含故障来决定下一步该怎么做。例如,如果任务变为绿色并且日志检测到失败,则我将决定不发布构件。
如何使用标准的 Azure API 在下一个任务中读取上一个任务的日志,然后根据日志做出决策?这样可以以标准方式解决此问题。
澄清:这些测试不是单元测试,实际上它们是一些自定义 Java 测试,通过从 Linux 机器上的自托管代理调用 .sh 文件触发运行。

它们是单元测试吗?如果它们失败了,它们应该使构建失败。 - Shayki Abramczyk
3个回答

2
如果您没有一种方法可以使用标准错误来失败管��,您可以使用Builds - Get Build Log来调查任务,并根据结果设置变量,在其他任务中使用custom conditions与此变量或仅失败所有管道。
因此,一个类似以下内容的PowerShell脚本:
$token = "YOUR-PAT"
Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
 
# Construct the REST URL to obtain Build ID
$uri = "$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/build/builds/logs/{logId}?api-version=5.1"
 
# Invoke the REST call and capture the results
$log= Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}

if($log -match "some error")
{
    # Option 1: set a variable
    Write-Host "##vso[task.setvariable variable=testsStatus]failed"
    # Now in the artifacts task use custom condition:
    # and(succeeded(), ne(variables['testsStatus'], 'failed'))

    # Option 1: fail the pipeline
    Write-Error "The tests not passed!"
}

(您可以使用 API 构建 - 获取构建日志 获取日志 ID)

0

编辑:经过澄清,我将我的评论分成两部分:您的自定义测试用例,以及先前在此处适用于使用标准单元测试框架的情况下的其余评论。

备选方案1:基于分析测试日志文件的自定义测试解决方案

首先,您需要一个脚本,例如 PowerShell 脚本,它解释日志文件,确定测试是否失败,并相应地设置 vso task.complete 结果属性(请参见下面的示例)。

让我们称这个文件为 evaluate-test-results.ps1,并假设它解释某种包含名为 haveTestsPassed 的重要属性的 testResults.json 数据,以决定测试是否通过:

evaluate-test-results.ps1 文件内容:

<#
.SYNOPSIS
Checks test results.
#>

param (
    [Parameter(Mandatory = $true)]
    [string]$testResultsJson
)

try {
    $testResults = $testResultsJson | ConvertFrom-Json

    if($testResults.haveTestsPassed)
    {
       Write-Host "##vso[task.complete result=Succeeded;]Tests have successfully passed"
    }
    else
    {
       Write-Host "##vso[task.complete result=Failed;]Tests have NOT passed"
    }
}
catch {
    Write-Host "##vso[task.complete result=Failed;]Error while parsing test results from JSON log file..."
}

然后,您可以在PowerShell@2任务中使用此脚本,如下所示:

- task: PowerShell@2
  displayName: "PowerShell: Evaluate test results from testResults.json"
  inputs:
    targetType: filePath
    filePath: 'evaluate-test-results.ps1'
    arguments: "-testResultsJson 'testResults.json'"
    failOnStderr: true

注意:

当 haveTestsPassed 为 false 时,您也可以通过 failOnStderr 属性抛出标准错误。然而,这种解决方案稍微正式一些。

备选方案2:标准单元测试框架的解决方案可能性

如果已配置 dotnet test 命令运行您的测试,则使用更简单的解决方案

如果您的测试绑定到 dotnet test 命令(例如 xUnit),则可以使用以下简单解决方案。在这种情况下,如果您的单元测试之一失败,此任务将默认失败,而无需使用 PublishTestResults@2 任务:

# This task will run the 'dotnet test' command, as if you would from a CLI
- task: DotNetCoreCLI@2
  displayName: Run and publish tests
  inputs:
    command: 'test'

如果您无法使用dotnet test命令

在这种情况下,您必须使用PublishTestResults@2任务来解释测试结果。相应地设置您的测试框架/工具和测试结果文件。确保设置failTaskOnFailedTests: true

- task: PublishTestResults@2
  inputs:
    testRunner: VSTest # or else...
    testResultsFiles: '**/*.trx' # or else...
    failTaskOnFailedTests: true

@Pukli Balazs - 我已经编辑了问题并提供了更多的澄清。问题是你想要设置的标志,我只能读取日志并设置它。所以我想知道是否有一个标准的日志读取机制可以用来查找表达式的任务。 - userx
@userx,感谢您的澄清!我在我的答案中为您创建了“备选方案1”部分。如果您有任何进一步的问题,请告诉我! - bradib0y

0

如果您正在寻找一种从 Azure 管道中的先前任务获取日志的方法,这是对我有效的解决方案。

# here we get the link for the previous task logs
previousTask=$(curl -s -X GET -H "Authorization: Bearer $(System.AccessToken)" -H "Content-Type: application/json" https://dev.azure.com/{organization}/{project}/_apis/build/builds/{buildId}/timeline/?api-version=5.1 | jq -r '.records[] | select(.name == "${{ parameters.displayNameOfTheTask }}") | .log.url' )

#put the logs in a file or you can simply grep on them
curl -s -X GET -H "Authorization: Bearer $(System.AccessToken)" -H "Content-Type: application/json" "${previousTask}" | sed 's/^.*[0-9]Z //g' > ${{ parameters.scanningFileLocation }}

#grep on that file
result=$(grep "${{ parameters.grepSearchInput }}" ${{ parameters.scanningFileLocation }})
echo $result
if [ -z "$result" ]
then
  echo "No expected error message!"
  cat ${{ parameters.scanningFileLocation }}
  exit 1;
else
  echo "Found expected error message!"
  rm -rf ${{ parameters.scanningFileLocation }}
fi


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接