Один пайплайн для нескольких репозиториев, разные шаблоны для разных проектов

Среда: Azure DevOps Server 2022.0 с Windows-агентами.

У нас есть несколько больших проектов Windows в разных репозиториях Git. Они должны создаваться в одном YAML-конвейере с использованием шаблонов, специфичных для проекта. Я создал репозиторий YAML для любого конвейера.

Я хотел бы, чтобы триггерный репозиторий установил переменную, которую я могу использовать в дальнейшем как часть имени шаблона и в идентификаторе сборки. Мало того, я хотел бы иметь возможность указать для ручного запуска, какой проект использовать, и использовать эту информацию таким же образом.

Azure-pipelines.yml:

resources:
  repositories:
    - repository: AAA
      type: git
      name: AAA
      ref: main
      trigger:
        branches:
          include:
            - main

    - repository: BBB
      type: git
      name: BBB
      ref: main
      trigger:
        branches:
          include:
            - main

    - repository: YAML
      type: git
      name: YAML-Automation
      ref: main
      trigger:
        - none

parameters:
- name: projectToBuild
  displayName: "Project to build:"
  type: string
  default: AAA
  values:
  - AAA
  - BBB
  - CCC

variables:
  productName: $(Build.Repository.Name)
  productVersion: 5.0.1

name: $(Build.Repository.Name)_$(productVersion)_$(Date:yyMMdd)$(Rev:rr)

Я думаю, поскольку триггер из репо происходит после компиляции кода YAML, информация недоступна, когда установлено «имя». Но когда я вывожу переменную, она показывает правильную информацию:

Когда срабатывает репо BBB,

echo Build.Repository.Name =  $(Build.Repository.Name) 

показывает BBB, но у сборки есть название #YAML-Automation_5.0.1_24070505

Оформление заказа должно быть только для YAML-репозитория и для триггерного репозитория, поэтому мне снова нужно имя триггерного репозитория, которое пусто.

Далее я хотел бы использовать, например, шаблон jobStuff-$(productname).yml, но ProductName пуст, и он не работает.

Наконец, для ручного запуска я хотел бы использовать значение выбора проекта вручную, projectToBuild, в качестве входных данных для ProductName. Предполагаю, что для этого потребуется просто «if manual», как в $[eq(variables['Build.Reason '], 'Руководство')].

Должен ли мой общий подход сработать? Что я могу сделать, чтобы получить имя триггера в полезной переменной?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
126
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам необходимо управлять переменными и обеспечивать доступность информации о триггерном репозитории при необходимости. Вот пример того, как структурировать ваш azure-pipelines.yml:

resources:
  repositories:
    - repository: AAA
      type: git
      name: AAA
      ref: main
      trigger:
        branches:
          include:
            - main

    - repository: BBB
      type: git
      name: BBB
      ref: main
      trigger:
        branches:
          include:
            - main

    - repository: YAML
      type: git
      name: YAML-Automation
      ref: main
      trigger: none

parameters:
- name: projectToBuild
  displayName: "Project to build:"
  type: string
  default: ''
  values:
  - AAA
  - BBB
  - CCC

variables:
  productName: ${{ coalesce(parameters.projectToBuild, variables['Build.Repository.Name']) }}
  productVersion: 5.0.1

name: $(productName)_$(productVersion)_$(Date:yyMMdd)$(Rev:rr)

stages:
- stage: Build
  jobs:
    - job: BuildJob
      displayName: Build $(productName)
      steps:
        - checkout: self

        - ${{ if eq(variables['productName'], 'AAA') }}:
          - template: jobStuff-AAA.yml

        - ${{ if eq(variables['productName'], 'BBB') }}:
          - template: jobStuff-BBB.yml

        - ${{ if eq(variables['productName'], 'CCC') }}:
          - template: jobStuff-CCC.yml

        - script: |
            echo "Build.Repository.Name: $(Build.Repository.Name)"
            echo "Product Name: $(productName)"

Что касается предопределенных переменных , переменная $(Build.Repository.Name) НЕ доступна в шаблонах, поэтому установка переменной productName и ее использование в выражениях шаблона, таких как ${{ if ... }}, вероятно, не будет работать должным образом.

Rui Jarimba 06.07.2024 02:33

Отлично, кажется, все работает, спасибо! Я не подумал coalesce, умница! Однако, похоже, он НЕ работает внутри вызываемых шаблонов. Я попробовал передать productName в качестве параметра, это не имело никакого значения. Поскольку у меня есть шаблоны, зависящие от продукта, на нескольких уровнях шаблонов, было бы здорово, если бы вы тоже могли придумать решение.

HaraldJ 06.07.2024 13:31

@HaraldJ еще одна вещь: переменную $(Build.Repository.Name) нельзя использовать как часть номера сборки. См. Предопределенные переменные.

Rui Jarimba 06.07.2024 14:35
Ответ принят как подходящий

Согласно Предопределенным переменным, при использовании переменной $(Build.Repository.Name) есть некоторые ограничения:

  • Его нельзя использовать в шаблонных выражениях, таких как jobStuff${{ variables['Build.Repository.Name'] }}.yaml.
  • Он не может быть частью номера сборки или тегом контроля версий.

Чтобы решить эти ограничения и даже частично уменьшить сложность конвейера, я предлагаю использовать отдельный конвейер для каждого продукта.

Пример

Создайте базовый конвейер со всеми ресурсами, переменными и т. д., используемыми всеми продуктами, и используйте шаблон задания продукта:

# base-pipeline.yaml

parameters:
  - name: productName
    displayName: Name of the product to build
    type: string

  # Product version can either be set as a common variable for all pipelines/products 
  #, or, as an alternative, as a parameter in each pipeline (in case each product has a different version)
  - name: productVersion
    displayName: Version of the product to build
    type: string
    default: $(productVersion)

# Add resources that are used by all products/pipelines here
resources:
  repositories:
    - repository: YAML
      type: git
      name: YAML-Automation
      ref: main
      trigger:
        - none

variables:
  # Common variables that are used by all products/pipelines, such as productVersion etc
  - template: /pipelines/variables/common-variables.yaml

  # optionally include a product specific variables template
  # - template: /pipelines/variables/${{ parameters.productName }}-variables.yaml

jobs:
  - template: /pipelines/jobs/jobStuff-${{ parameters.productName }}.yml
    parameters:
      productVersion: ${{ parameters.productVersion }}
      # other parameters here

Для каждого продукта (например, foo) создайте отдельный конвейер, идущий от base-pipeline.yaml:

# foo-pipeline.yaml

# Product version can either be set as a common variable for all pipelines/products 
#, or, as an alternative, as a parameter in each pipeline (in case each product has a different version)
# parameters:
#   - name: productVersion
#     displayName: Version of the product to build
#     type: string
#     default: 5.0.1

# This is a dedicated pipeline for 'foo' product, so name can be hard-coded
name: foo_$(productVersion)_$(Date:yyMMdd)$(Rev:rr)

# optionally use a parameter for product version
# name: foo_${{ parameters.productVersion }}_$(Date:yyMMdd)$(Rev:rr)

# Add product/pipeline specific resources here
resources:
  repositories:
    - repository: foo
      type: git
      name: foo
      ref: main
      trigger:
        branches:
          include:
            - main

pool:
  vmImage: 'windows-latest'

extends:
  template: /pipelines/base-pipeline.yaml
  parameters:
    productName: foo # <--------------- Product name is hard-coded
    # productVersion: ${{ parameters.productVersion }}

Примечания:

  • Создание выделенного конвейера для каждого продукта может показаться большой дополнительной работой, но, расширив базовый конвейер, вы можете устранить некоторое дублирование и даже некоторую сложность, поскольку вам не нужно использовать этапы или задания условия или if/ else, чтобы решить, какой продукт запускать.
  • productVersion можно установить независимо для каждого продукта (или, как альтернатива, вы можете, например, использовать глобальную переменную, если все продукты должны использовать одну и ту же версию)
  • Что касается запуска вручную, просто поставьте в очередь соответствующий конвейер продукта (например, foo-pipeline.yaml).

Большое вам спасибо! Это отличное решение, и оно действительно решает мою проблему! Я обнаружил, что «репозитории» нельзя использовать ни в foo-, ни в base-конвейере (см. здесь, поэтому я переместил их в foo, и вроде бы все работает отлично.

HaraldJ 08.07.2024 14:47

@HaraldJ рад помочь. С одной стороны конвейеров и файлов больше, но с другой код легче поддерживать :-)

Rui Jarimba 08.07.2024 14:49

@HaraldJ PS: подумайте о том, чтобы проголосовать против и/или принять мой ответ. Спасибо!

Rui Jarimba 08.07.2024 14:50

не знаю, связано ли это: использование YAML в отдельном репозитории Git с предложенным вами отличным решением «расширения» внезапно заставляет DevOps использовать другой рабочий каталог для каждого задания: первое задание использует _work/1, второе _work/ 2 и т. д. Раньше такого не случалось, и, поскольку все сборки находятся в каталоге _work/1, все, кроме первого задания, завершается неудачей. И я совсем растерялся, надеясь, что у вас есть идеи или вы знаете, в чем моя ошибка!

HaraldJ 09.07.2024 14:27

@HaraldJ невозможно понять, что происходит, не видя кода. Используете ли вы жестко заданные пути или предопределенные переменные? Пожалуйста, создайте для этого новый вопрос и не забудьте включить весь соответствующий код YAML и детали.

Rui Jarimba 09.07.2024 14:34

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

Развертывание Azure DevOps SQL DacPac не работает с подключением службы
Azure Devops Pipeline, покажите ссылку на отчет Sonar на сводной странице запуска конвейера
NU1100: невозможно разрешить пакет nuget Azure DevOps
Я хочу опубликовать zip-файл, а затем загрузить его непосредственно из канала Azure Artifact. Какая задача мне поможет в этом?
Как связать рабочие элементы для сборки конвейера yaml при использовании ветвей выпуска?
Термин «скрипт:» не распознается как имя командлета, функции, файла сценария или исполняемой программы
Ошибка обнаружения текущей ветки: фатальный: ref HEAD не является символической ссылкой в ​​выпуске mvn — Azure Pipeline
Как настроить проверку утверждения конвейера Azure для развертывания в приложениях-функциях Azure?
Ошибка: невозможно зарегистрировать свойство «TestType» как тип значения «System.Guid», поскольку оно уже зарегистрировано как «System.String»
Использование API Azure Devops в Python для получения всех измененных файлов в PR