Проблема с динамическим комментарием Azure DevOps на GitHub и статусом выхода 1

У меня есть конвейер в Azure DevOps, который анализирует мой код Ansible, чтобы обнаружить ошибки перед его объединением.

Хотя мы используем необходимые проверки статуса в GitHub, я бы хотел, чтобы любые ошибки lint добавлялись обратно в виде комментариев.

Я сталкиваюсь с двумя проблемами.

# 1 - Невозможно установить комментарий

    - task: AzureCLI@2
  displayName: ${{ parameters.dispName }}
  continueOnError: true
  inputs:
    addSpnToEnvironment: true
    azureSubscription: ${{ parameters.serviceConnectionName }}
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      set -euo pipefail
      export ARM_CLIENT_ID=$servicePrincipalId
      export ARM_CLIENT_SECRET=$servicePrincipalKey
      export ARM_SUBSCRIPTION_ID=$(az account show --query id | xargs)
      export ARM_TENANT_ID=$tenantId
      export TF_CLI_ARGS = "-no-color"
      echo $PATH     
      ansible --version
      ansible-lint --version
      ansible-lint ${{ parameters.command }} 2>&1 | tee ${{ parameters.logFile }}.log
      temp=(grep -A 2 Error  ${{ parameters.logFile }}.log)
      if [ $? != 0 ]; then exit 1; fi
      

- template: comment.yaml
  parameters:
    comment: $temp

комментарий.yml

---

parameters:
- name: comment
  type: string


steps:

- task: GitHubComment@0 
  displayName: 'Add github comment'
  inputs:
    pull-requests: write
    gitHubConnection: 'github-comment'
    repositoryName: '$(Build.Repository.Name)'
    comment: ${{ parameters.comment }}
      

Этот файл comment.yaml работает, если я просто передаю статический комментарий, например «тест».

#2 — Выход из конвейера с кодом состояния 2

Если я изменю комментарий на просто статический комментарий, чтобы обойти вышеуказанную проблему, конвейер теперь завершит работу с кодом состояния 2, а не с кодом состояния 1, как я устанавливаю здесь:

  if [ $? != 0 ]; then exit 1; fi

Если код существования равен 2, GitHub не помечает конвейер как сбойный в случае ошибки проверки.

-------------------------------------------------- ------------------- Вот мой обновленный код:

---
parameters:
- name: serviceConnectionName
  type: string
- name: command
  type: string
- name: dispName
  type: string
- name: logFile
  type: string

steps:

- template: init-github.yaml
- template: install-ansible-lint.yaml

- task: AzureCLI@2
  displayName: ${{ parameters.dispName }}
  inputs:
    addSpnToEnvironment: true
    azureSubscription: ${{ parameters.serviceConnectionName }}
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      set -euo pipefail
      export ARM_CLIENT_ID=$servicePrincipalId
      export ARM_CLIENT_SECRET=$servicePrincipalKey
      export ARM_SUBSCRIPTION_ID=$(az account show --query id | xargs)
      export ARM_TENANT_ID=$tenantId
      export TF_CLI_ARGS = "-no-color"
      echo $PATH     
      ansible --version
      ansible-lint --version
      ansible-lint ${{ parameters.command }} 2>&1 | tee ${{ parameters.logFile }}.log
      error=$(grep -A 2 Error ${{ parameters.logFile }}.log)    
      echo "##vso[task.setvariable variable=Comment]$error"

- template: comment.yaml
  parameters:
    comment: $(Comment)

файл comment.yaml

---
    parameters:
    - name: comment
      type: string


    steps:
    
    - task: GitHubComment@0 
      displayName: 'Add github comment'
      inputs:
        pull-requests: write
        gitHubConnection: 'github-comment'
        repositoryName: '$(Build.Repository.Name)'
        comment: ${{ parameters.comment }}
    
    - task: Bash@3
      displayName: Fail Pipeline If Error
      inputs:
        targetType: 'inline'
        script: |
          if [ -n "${{ parameters.comment }}" ]; then
            echo "##vso[task.complete result=Failed;]"
          fi

Редкие достижения на Github ✨
Редкие достижения на Github ✨
Редкая коллекция доступна в профиле на GitHub ✨
0
0
77
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Локальная переменная temp в вашей задаче AzureCLI@2 недоступна в будущих задачах.

Вам необходимо добавить переменную с помощью команды регистрации Task.setvariable, чтобы следующие задачи могли использовать переменную с использованием синтаксиса макроса $(myVar). По умолчанию переменная будет доступна только задачам в одном задании.

Пример:

steps:
  - script: |
      GIT_COMMENT = "foobar"
      echo "##vso[task.setvariable variable=Comment]$GIT_COMMENT"
    displayName: 'Set pipeline variable: Comment'
  
  - script: |
      echo "Git comment: $(Comment)"
    displayName: 'Print pipeline variable: Comment'

См. Установка переменных в скриптах

Как упомянул @RuiJarimba, вам нужно добавить task.setvariable logging command, чтобы можно было использовать $(temp) в следующей задаче. Кроме того, добавьте $ к значению температуры: temp=$(grep -A 2 Failed ${{ parameters.logFile }}.log).

В качестве кода выхода вы можете оценить содержимое $(temp). Если оно не пусто, используйте echo "##vso[task.complete result=Failed;]", чтобы установить задачу как fail, чтобы она возвращалась с ошибкой при проверке статуса Gihub.

Используйте триггер PR, поскольку GitHubComment@0 автоматически определит идентификатор PR в моем конвейере тестирования:

trigger: none

pr: 
 branches:
   include:
     - main

pool:
  vmImage: 'ubuntu-latest'

parameters:
  - name: logFile
    default: ansible-lint-log
  - name: command
    default: main.yml


steps:
- script: sudo apt update && sudo apt install -y ansible
  displayName: 'Install Ansible'

- script: pip install ansible-lint
  displayName: 'Install Ansible Lint'

- script: |
    ansible --version
    ansible-lint --version
  displayName: 'Check Ansible and Ansible Lint versions'

- script: |
    ansible-lint ${{ parameters.command }} 2>&1 | tee ${{ parameters.logFile }}.log
    temp=$(grep -A 2 Failed  ${{ parameters.logFile }}.log)    # add $ for temp

    echo "##vso[task.setvariable variable=Comment]$temp"
    #if [ $? != 0 ]; then exit 1; fi
  displayName: 'Lint Ansible playbook and check for errors'


- template: comment.yaml
  parameters:
    comment: $(Comment)

Мой шаблон yaml:

parameters:
- name: comment
  type: string


steps:
- task: GitHubComment@0 
  displayName: 'Add github comment'
  inputs:
    pull-requests: write
    gitHubConnection: 'GithubConn1'
    repositoryName: '$(Build.Repository.Name)'
    comment: '${{ parameters.comment }}'

- task: Bash@3
  displayName: fail the task if there is an error
  inputs:
    targetType: 'inline'
    script: |
      if [ -n "${{ parameters.comment }}" ]; then
        echo "##vso[task.complete result=Failed;]"
      fi

Проверьте PR, добавленный комментарий и проверку статуса как неудавшуюся:

Спасибо за супер подробный ответ!

Dan Carlton 12.04.2024 13:45

Пожалуйста! Вы можете воспользоваться примером конвейера (фильтровать ошибки на основе вашего журнала) для проверки, будем рады помочь. :)

wade zhou - MSFT 12.04.2024 15:41

Итак, я попробовал это и столкнулся с проблемами. Задача проверки завершается неудачей (как и ожидалось), но выполнение других шагов не продолжается. Если я добавлю continueonerror: true, он продолжится, но конвейер никогда не выйдет из строя. Если комментарий действительно вставлен, это просто $(Commnet). Я обновил его выше, чтобы показать новый код. @Уэйд Чжоу

Dan Carlton 12.04.2024 16:16

Да, вам нужно использовать continueonerror: true, чтобы перейти к следующей задаче, но убедитесь, что ошибка сохранена в файле журнала. Команда ansible-lint ${{ parameters.command }} 2>&1 | tee ${{ parameters.logFile }}.log уже должна перенаправить как стандартный вывод (stdout), так и стандартную ошибку (stderr) в файл журнала, независимо от того, успешна ли команда ansible-lint или нет. Но если вы обнаружите, что это работает не так, как ожидалось, попробуйте ansible-lint ${{ parameters.command }} > ${{ parameters.logFile }}.log 2>&1

wade zhou - MSFT 12.04.2024 16:40

Итак, проблема в следующем: ' ansible-lint ${{parameters.command }} 2>&1 | tee ${{parameters.logFile }}.log 'Я попробовал ваши изменения, но это не имело значения. Без него в этой структуре выходные данные, похоже, не отправляются в файл журнала, но с этим continueOnError, похоже, игнорируется. 'scriptType: bash' 'scriptLocation: inlineScript' ' continueOnError: true' Ошибка вообще не будет продолжена.

Dan Carlton 12.04.2024 18:29

Итак, проблема на самом деле здесь temp=$(cat ansible-lint.log) и echo "##vso[task.setvariable variable=Comment]$temp" По какой-то причине температура кажется пустой, даже когда я знаю, что в журнале должно что-то быть.

Dan Carlton 12.04.2024 18:54
Ответ принят как подходящий

Итак, @Wade Zhou указал мне правильное направление. Кажется, что переменная была слишком велика, чтобы ее можно было передавать между шагами, поэтому я решил ее следующим образом.

Главный трубопровод:

---
pr:
  autoCancel: true
  drafts: true
  branches:
    include:
    - p0
  paths:
    exclude:
    - README.md
    - RELEASE_NOTES.md
    - .azuredevops/*
    - doc/*    
    
trigger: none


pool: Lottery Production Pool

variables:
- name: serviceConnectionName
  value: gcg-network-production

stages:
- stage: check
  jobs:
  - job: Check
    steps:
    - template: templates/run-ansible-lint.yaml
      parameters:
        serviceConnectionName: ${{ variables.serviceConnectionName }}
        logFile: ansible-lint
        dispName: Run ansible-lint
        command: -r lint/ group_vars/*.* host_vars/*.*
    - template: templates/comment.yaml
      parameters:
        dispName: Add Comments to PR

Шаблон ворса:

---
parameters:
- name: serviceConnectionName
  type: string
- name: command
  type: string
- name: dispName
  type: string
- name: logFile
  type: string
steps:
- template: init-github.yaml
- template: install-ansible-lint.yaml
- task: AzureCLI@2
  displayName: ${{ parameters.dispName }}
  inputs:
    addSpnToEnvironment: true
    continueOnError: true
    azureSubscription: ${{ parameters.serviceConnectionName }}
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      set -euo pipefail
      export ARM_CLIENT_ID=$servicePrincipalId
      export ARM_CLIENT_SECRET=$servicePrincipalKey
      export ARM_SUBSCRIPTION_ID=$(az account show --query id | xargs)
      export ARM_TENANT_ID=$tenantId
      export TF_CLI_ARGS = "-no-color"
      echo $PATH     
      ansible --version
      ansible-lint --version
      ansible-lint ${{ parameters.command }} 2>&1 | tee ansible-lint.log

Шаблон комментария

---
    steps:

    - task: Bash@3
      displayName: Extract Comment
      condition: always()
      inputs:
        targetType: 'inline'
        script: |
          comment=$(sed -z 's/\n/\%0D%0A/g' ansible-lint.log)
          echo "##vso[task.setvariable variable=Comment]$comment"

    - task: GitHubComment@0 
      displayName: 'Add github comment'
      condition: always()
      inputs:
        pull-requests: write
        gitHubConnection: 'github-comment'
        repositoryName: '$(Build.Repository.Name)'
        comment: "$(Comment)"

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

Рад узнать, что проблема решена! И извините за поздний ответ из-за выходных. Да, переменные devops не поддерживают несколько строк. Хитрость заключается в том, чтобы использовать sed для преобразования всех символов новой строки в файле ansible-lint.log. Спасибо, что поделились! Приятного кодирования!

wade zhou - MSFT 15.04.2024 03:43

Другие вопросы по теме