【问题标题】:azure devops pipeline | bash script to run dotnet test on multiple projectsazure devops 管道 |在多个项目上运行 dotnet 测试的 bash 脚本
【发布时间】:2020-12-12 20:31:02
【问题描述】:

我正在尝试在 MS Azure devops 管道中定义的测试项目上运行 dotnet test 命令。

这是有效的:

- script: |
    dotnet test "./Project One/Project One Unit Tests.fsproj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY & TestCategory!=REQUIRES_API_KEY"
    dotnet test "./Project Two/Project Two Unit Tests.fsproj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY & TestCategory!=REQUIRES_API_KEY"
  displayName: 'run tests in cascade'   

我不想指定项目名称,只指定一些规则(项目名称必须以“UnitTests”、“Unit Tests”或“Unit_Tests”结尾)但dotnet test <PROJECT> 不允许使用通配符。 似乎通配符适用于 dotnet test <DLL> (./**/*Unit?Tests.dll) 但它失败了,因为它在 obj 文件夹中找不到 deps.json 文件。

我的解决方案是循环通过过滤的项目文件列表:

    for proj in ./**/*Unit?Tests.*proj 
    do
      dotnet test "$proj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY & TestCategory!=REQUIRES_API_KEY"
    done

它正在运行测试,但与级联调用不同,这里当项目测试失败时,它不会使步骤失败,因此管道不会停止!

我试图从运行中获取结果,但没有成功(这不起作用):

    for proj in ./**/*Unit?Tests.*proj 
    do
      result=$(dotnet test "$proj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY & TestCategory!=REQUIRES_API_KEY")
      if result = 1
      then
        exit 1
      fi
    done

有什么建议吗? 为什么当 dotnet test 失败(退出 1)时,该步骤不会失败? 我试图只将失败的测试项目放入循环中,但在这种情况下它会失败。

[更新]
完整的 pipeline.yaml

trigger:
- master

pool:
  vmImage: 'ubuntu-latest'

variables:
  project file: "Alex75.MySolution/Alex75.MyProject.fsproj"

steps:  

- script: dotnet build -c Release
  displayName: 'Build'
  
- script: |
    dotnet test "./ProjectTwo Unit Tests/ProjectTwo Unit Tests.fsproj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY & TestCategory!=REQUIRES_API_KEY"
    dotnet test "./ProjectOne Tests/ProjectOne Unit Tests.fsproj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY & TestCategory!=REQUIRES_API_KEY"
  displayName: 'Test'
  condition: false

- script: | 
    for proj in ./**/*Unit?Tests.*proj 
    do
      echo "run tests in $proj"
      dotnet test "$proj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY & TestCategory!=REQUIRES_API_KEY"
    done
  displayName: 'Test (Unit Test projects)'
  condition: true

- powershell: |
    $URL = "$(System.CollectionUri)/$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/logs?api-version=5.1"
    Write-Host "URL = $URL"
  
    $logs = Invoke-RestMethod -Uri $URL -Headers @{authorization = "Basic $(PAT)"} -Method Get 
    $lastLogId = $Logs.value[$Logs.value.count-1].id
    Write-Host "lastLogId = $lastLogId"  
    $URL = "$(System.CollectionUri)/$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/logs/$lastLogId?api-version=5.1"
    $result = Invoke-RestMethod -Uri $URL -Headers @{authorization = "Basic $(PAT)"} -Method Get 
    Write-Host $result

    Write-Host "Start Check result..."

    $lines = $result.Split([Environment]::NewLine)
    foreach($line in $lines) {
        if($line -match "Failed!")
        {
            throw 'dotnet test fails ($line)'
        }
    }

    Write-Host "Test result check completed."

  displayName: 'Check tests result'

PowerShell 脚本

使用@vito-liu-msft的例子我尝试检查测试日志来检查错误。

这里单独使用 powershell 脚本:

$URL = "$(System.CollectionUri)/$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/logs?api-version=5.1"
Write-Host "URL = $URL"
  
$logs = Invoke-RestMethod -Uri $URL -Headers @{authorization = "Basic $(PAT)"} -Method Get 
$lastLogId = $Logs.value[$Logs.value.count-1].id
Write-Host "lastLogId = $lastLogId"  

$URL = "$(System.CollectionUri)/$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/logs/$lastLogId?api-version=5.1"
$result = Invoke-RestMethod -Uri $URL -Headers @{authorization = "Basic $(PAT)"} -Method Get 
Write-Host $result

Write-Host "Start Check result..."

$lines = $result.Split([Environment]::NewLine)
foreach($line in $lines) {
    if($line -match "Failed!")
    {
        throw 'dotnet test fails ($line)'
    }
}

Write-Host "Test result check completed."

PAT 是创建时的个人访问令牌,无需转换 在 HTTP 请求中使用它之前。
LogId 不可用,因此请求获取 logs 集合,然后请求获取特定的最后一个日志(响应似乎按日期排序,也许是值得仔细检查)。

请注意,如果第二个请求返回 404、500 或其他结果(不是失败),错误检查将不会发现最终错误!需要对响应进行适当的检查。

我在 PowerShell 中测试了 -match "Failed!" 但我还没有在管道中测试 throw 命令,因为...

dotnet test 循环中的命令正在运行!

在花了这么多时间试图弄清楚如何阅读和检查日志之后,我发现了一个单独的 PowerShell 脚本,我发现最初的简单解决方案有效!
是的,构建失败是因为测试失败(它还显示了指向问题的精确错误)并且步骤失败了。
(所以下一步,检查测试结果,被跳过了!)

我认为我应该在过滤测试项目之前犯一些错误,以便失败的项目没有运行(并且没有引发任何错误)所以我认为它没有“拦截”错误,并且构建没有停下来。
可能是我在更改时混合了 2 个不同的管道文件。

无论如何,这是有罪的步骤(脚本):

    for proj in ./**/*Unit?Tests.*proj 
    do
      echo "run tests in $proj"
      dotnet test "$proj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY & TestCategory!=REQUIRES_API_KEY"
    done

在带有 echo 的列表中,可以查看使用了哪些测试项目。

【问题讨论】:

  • 您好,刚刚检查一下这个问题现在是否仍然阻碍您?这个问题有更新吗?
  • 老实说,我仍然在寻找更简单的东西,但我肯定会在几天内看看。谢谢。

标签: bash .net-core azure-devops


【解决方案1】:

当项目测试失败时,该步骤不会失败,因此管道不会停止! 为什么当 dotnet test 失败(退出 1)时 step 没有失败?

作为一种解决方法,我们可以通过此rest api 获取dotnet test 任务日志ID,添加任务power shell 并输入以下脚本来分析dotnet test 日志。我们需要输入匹配码,比如fails (exit 1),如果dotnet测试失败会停止流水线。

我们应该将PAT添加到变量中并将其设置为秘密,然后在脚本中使用它

$connectionToken="{PAT}"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$URL = "https://dev.azure.com/{organization}/{project}/_apis/build/builds/{buildId}/logs/{logId}?api-version=6.1-preview.2"
$Result = Invoke-RestMethod -Uri $URL -Headers @{authorization = "Basic $base64AuthInfo"} -Method Get 
Write-Host $result
$lines = $result.Split([Environment]::NewLine)

        $passed = 0;
        $failed = 0;

        foreach($line in $lines) {
            if ($line -match "{match sentence}") { 
              throw 'dotnet test fails (exit 1)'

            }
        }

更新1

如何找到“logId”?

我们可以使用这个REST API 来检查logId

GET https://dev.azure.com/{organization}/{project}/_apis/build/builds/{buildId}/logs?api-version=6.1-preview.2

结果:

而且我真的必须使用 api“预览”版本吗?

我们也可以使用其他版本,例如5.1,我们可以在文档中切换REST API版本,您可以查看下图。

【讨论】:

  • 我在管道构建中创建了一个个人访问令牌和一个名为“PAT”的变量。尽管文档说:批处理脚本:%VARIABLE-NAME% PowerShell 脚本:${env:VARIABLE-NAME} Bash 脚本:$(VARIABLE-NAME) 实际上要使其在 PowerShell 脚本中工作,我必须使用 $(VARIABLE NAME )。好的,我创建 URL: $URL = "$(System.CollectionUri)/$(System.TeamProject)/_apis/build/builds/$(Build.BuildNumber)/logs/{logId}?api-version=6.1- preview.2" 假设 "buildId" 是正确的,我怎样才能找到 "logId" ?而且我真的必须使用api“预览”版本吗?
  • 嗨@Alex75,我已经更新了答案,请检查一下。
  • 您好,这张票有更新吗?如果您有任何问题,请随时告诉我。如果答案有帮助,您可以考虑接受。谢谢
猜你喜欢
  • 2022-12-01
  • 2022-08-16
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 2019-03-26
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
相关资源
最近更新 更多