конвейер azure devops | скрипт bash для запуска теста dotnet в нескольких проектах

#bash #.net-core #azure-devops

#bash #.net-core #azure-devops

Вопрос:

Я пытаюсь запустить dotnet test команду для определенных тестовых проектов в конвейере MS Azure devops.

Это работает:

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

Я не хочу указывать имена проектов, только какое-то правило (название проекта должно заканчиваться на «UnitTests», «Unit Tests» или «Unit_Tests»), но dotnet test <PROJECT> не допускает подстановочных знаков.
Похоже, что подстановочные знаки работают с dotnet test <DLL> (./**/* Unit?Tests.dll ) но это не удается, потому что он не находит файл deps.json в папке obj.

Мое решение — перебирать отфильтрованный список файлов проекта:

     for proj in ./**/*Unit?Tests.*proj 
    do
      dotnet test "$proj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY amp; 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 amp; TestCategory!=REQUIRES_API_KEY")
      if result = 1
      then
        exit 1
      fi
    done
 

Есть предложения?
Почему при dotnet test сбое (выход 1) шаг не завершается ошибкой?
Я попытался запустить в цикл только неудачный тестовый проект, и в этом случае он завершается неудачей.

[ОБНОВЛЕНИЕ]
Полный конвейер.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 amp; TestCategory!=REQUIRES_API_KEY"
    dotnet test "./ProjectOne Tests/ProjectOne Unit Tests.fsproj" -c Release --no-build --filter "TestCategory!=SKIP_ON_DEPLOY amp; 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 amp; 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, я попытался проверить журналы тестирования, чтобы проверить ошибку.

Here the powershell script alone:

 $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-запросе.
Логид недоступен, поэтому есть запрос на получение коллекции журналов, а затем второй запрос на получение конкретного последнего журнала (ответ кажется упорядоченным по дате, возможно, стоит перепроверить).

Обратите внимание, что если второй запрос возвращает 404, 500 или другой результат (не сбой), проверка ошибок не обнаружит фактических ошибок! Требуется правильная проверка ответа.

Я протестировал совпадение «Сбой!» в PowerShell, но я не тестировал команду throw в конвейере, потому что…

команда тестирования dotnet в цикле работает!

Потратив столько времени на то, чтобы понять, как читать и проверять журналы, с помощью отдельного сценария 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 amp; TestCategory!=REQUIRES_API_KEY"
    done
 

В списке с echo можно увидеть, какие тестовые проекты используются.

Комментарии:

1. Привет, просто проверяю, не блокирует ли вас эта проблема сейчас? Есть какие-либо обновления по этой проблеме?

2. Честно говоря, я все еще ищу что-то более простое, но определенно я посмотрю через пару дней. Спасибо.

Ответ №1:

когда тест проекта завершается неудачно, он не завершает этап, поэтому конвейер не останавливается! Почему при сбое теста dotnet (выход 1) шаг не завершается ошибкой?

В качестве обходного пути мы могли бы получить идентификатор dotnet test журнала задач через этот rest api, добавить задачу power shell и ввести приведенный ниже скрипт для анализа dotnet test журнала. нам нужно ввести код соответствия, например fails (exit 1) , если тест dotnet завершится неудачно, он остановит конвейер.

Мы должны добавить PAT к переменной и установить для нее значение secret, а затем использовать его в скрипте

 $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 в документе, вы можете проверить рисунок ниже.

введите описание изображения здесь

Комментарии:

1. Я создал личный токен доступа и переменную с именем «PAT» в сборке конвейера. Несмотря на то, что в документации говорится: пакетный скрипт: %VARIABLE-NAME% Сценарий PowerShell: $ {env:VARIABLE-NAME} Сценарий Bash: $ (ИМЯ ПЕРЕМЕННОЙ) на самом деле, чтобы он работал в сценарии PowerShell, мне пришлось использовать $(ИМЯ ПЕРЕМЕННОЙ). Хорошо, я создаю URL: $ URL = «$ (System. CollectionUri)/ $(System. TeamProject)/_apis/build/builds/ $(Build. BuildNumber)/logs/{LogID}?api-version=6.1-предварительный просмотр. 2» Предполагая, что «buildId» правильный, как я могу найти «LogID»? И мне действительно нужно использовать версию «предварительного просмотра» api?

2. Привет @Alex75, я обновил ответ, пожалуйста, проверьте его.

3. Привет, есть ли какие-либо обновления по этому билету? Не стесняйтесь, дайте мне знать, если у вас есть какие-либо вопросы. Если ответ может помочь, вы можете рассмотреть возможность его принятия. Спасибо