Среда: 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 '], 'Руководство')].
Должен ли мой общий подход сработать? Что я могу сделать, чтобы получить имя триггера в полезной переменной?
Вам необходимо управлять переменными и обеспечивать доступность информации о триггерном репозитории при необходимости.
Вот пример того, как структурировать ваш 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)"
Отлично, кажется, все работает, спасибо! Я не подумал coalesce
, умница! Однако, похоже, он НЕ работает внутри вызываемых шаблонов. Я попробовал передать productName
в качестве параметра, это не имело никакого значения. Поскольку у меня есть шаблоны, зависящие от продукта, на нескольких уровнях шаблонов, было бы здорово, если бы вы тоже могли придумать решение.
@HaraldJ еще одна вещь: переменную $(Build.Repository.Name)
нельзя использовать как часть номера сборки. См. Предопределенные переменные.
Согласно Предопределенным переменным, при использовании переменной $(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 }}
Примечания:
productVersion
можно установить независимо для каждого продукта (или, как альтернатива, вы можете, например, использовать глобальную переменную, если все продукты должны использовать одну и ту же версию)foo-pipeline.yaml
).Большое вам спасибо! Это отличное решение, и оно действительно решает мою проблему! Я обнаружил, что «репозитории» нельзя использовать ни в foo-, ни в base-конвейере (см. здесь, поэтому я переместил их в foo, и вроде бы все работает отлично.
@HaraldJ рад помочь. С одной стороны конвейеров и файлов больше, но с другой код легче поддерживать :-)
@HaraldJ PS: подумайте о том, чтобы проголосовать против и/или принять мой ответ. Спасибо!
не знаю, связано ли это: использование YAML в отдельном репозитории Git с предложенным вами отличным решением «расширения» внезапно заставляет DevOps использовать другой рабочий каталог для каждого задания: первое задание использует _work/1, второе _work/ 2 и т. д. Раньше такого не случалось, и, поскольку все сборки находятся в каталоге _work/1, все, кроме первого задания, завершается неудачей. И я совсем растерялся, надеясь, что у вас есть идеи или вы знаете, в чем моя ошибка!
@HaraldJ невозможно понять, что происходит, не видя кода. Используете ли вы жестко заданные пути или предопределенные переменные? Пожалуйста, создайте для этого новый вопрос и не забудьте включить весь соответствующий код YAML и детали.
Что касается предопределенных переменных , переменная
$(Build.Repository.Name)
НЕ доступна в шаблонах, поэтому установка переменнойproductName
и ее использование в выражениях шаблона, таких как${{ if ... }}
, вероятно, не будет работать должным образом.