简体   繁体   English

如何使用 Azure DevOps Server 2019 中的 YAML 构建从多个发布分支配置 CI 构建?

[英]How to configure CI builds from multiple release branches using YAML builds in Azure DevOps Server 2019?

We have multiple release branches in our product (currently this is unavoidable).我们的产品中有多个发布分支(目前这是不可避免的)。 For this question, suppose we have two:对于这个问题,假设我们有两个:

  1. master掌握
  2. release/r-858发布/r-858

Both have classic CI builds.两者都有经典的 CI 构建。 Now I want to replace them with YAML builds.现在我想用 YAML 构建替换它们。 Our requirement is simple - have two distinct build definitions pointing to a YAML script - one for master , one for release/r-858我们的要求很简单 - 有两个不同的构建定义指向 YAML 脚本 - 一个用于master ,一个用于release/r-858

At the beginning I thought it is a trivial exercise:一开始我以为这是一个微不足道的练习:

  1. Create YAML build script in master .master中创建 YAML 构建脚本。 Set the CI trigger to master .将 CI 触发器设置为master
  2. Cherry-pick (never mind why not merge) to release/r-858 - set the CI trigger to release/r-858 . Cherry-pick(不要介意为什么不合并)来release/r-858 - 将 CI 触发器设置为release/r-858

Not ideal, because the two scripts only differ in their CI trigger.不理想,因为这两个脚本仅在 CI 触发器上有所不同。 But "I am learning, it is good enough for now" saying me to myself.但是“我正在学习,现在已经足够了”对我自己说。

However, this simple scheme does not work!但是,这个简单的方案行不通! The build I created for release/r-858 is triggered on changes in master!我为 release/r-858 创建的构建是在 master 更改时触发的!

I double check every setting I know about builds - all look correct.我仔细检查了我所知道的关于构建的每一个设置——一切看起来都是正确的。

Please, observe:请注意:

The master build主构建

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

The release/r-858 build发布/r-858 构建

在此处输入图像描述

Uh oh, look at that.哦,看那个。 It shows the YAML on the master branch, Well?它在主分支上显示 YAML,嗯? maybe it is an innocent presentation bug: Let us check the branch I am supposed to build from:也许这是一个无辜的演示错误:让我们检查一下我应该构建的分支:

在此处输入图像描述

Yup, the file is different - I am playing with the trigger trying to solve the very same problem this question is about.是的,文件不同 - 我正在使用触发器尝试解决这个问题所涉及的相同问题。 The original code had release/r-858 instead of $(Build.SourceBranch) as the CI trigger, but since it did not help I started playing with all kinds of trigger values.原始代码使用release/r-858而不是$(Build.SourceBranch)作为 CI 触发器,但由于它没有帮助我开始使用各种触发器值。

To remove any doubt, here is the proof the branch corresponds to release/r-858:为了消除任何疑问,这里是分支对应于 release/r-858 的证明:

C:\xyz\58 [arch/shelve/798914 ≡ +0 ~17 -0 !]> git lg -2
cfdb6a9a86a |  (HEAD -> arch/shelve/798914, origin/arch/shelve/798914) Rename azure-pipelines-ci-58.yml to azure-pipelines-ci.yml and sync it with the master version (68 seconds ago) [Kharitonov, Mark] (2020-08-14 09:09:46 -0400)
a931e3bd96b |  (origin/release/r-858, release/r-858) Merged PR 90230: 793282 Work Assignments Merge (28 minutes ago) [Mihailichenco, Serghei] (2020-08-14 12:02:20 -0400)
C:\xyz\58 [arch/shelve/798914 ≡ +0 ~17 -0 !]>

Anyway, more build properties:无论如何,更多的构建属性:

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

The problem问题

So a developer pushed some code to master and now the release/r-858 build is running:因此,开发人员将一些代码推送到 master,现在 release/r-858 构建正在运行:

在此处输入图像描述

在此处输入图像描述

Why is this?为什么是这样? One of our guys asked a similar question in the Microsoft Developer Community forum , but that thread does not make sense to me.我们的一个人在Microsoft 开发人员社区论坛中提出了类似的问题,但该主题对我来说没有意义。

What am I doing wrong here?我在这里做错了什么?

Edit 1编辑 1

Imagine a big enterprise monolithic application.想象一个大型企业单体应用程序。 It is deployed in production at version 858. At the same time, developers work on the next version and also hot fixes and service packs for the version already deployed in prod.它在 858 版中部署在生产环境中。同时,开发人员致力于下一个版本以及已在 prod 中部署的版本的热修复和服务包。

A change can be made only in master or only in release/r-858 or in both (not at the same time, though).只能在 master 或 release/r-858 或两者中进行更改(但不能同时进行)。 Many teams are working at the same time on many different aspects of the application and hence QA has many pods where the application is deployed.许多团队同时在应用程序的许多不同方面工作,因此 QA 有许多部署应用程序的 pod。 As I have mentioned above - about 150 pods for the bleeding edge (master) and about the same amount for the already released code, because there is active work to test hot fixes and service packs.正如我上面提到的 - 大约 150 个 pod 用于前沿(主)和大约相同数量的已发布代码,因为有积极的工作来测试热修复和服务包。

I appreciate this arrangement is not ideal.我很欣赏这种安排并不理想。 It is such not because we love it, but because one has to deal with decade old decisions.这不是因为我们喜欢它,而是因为一个人必须处理十年前的决定。 We are working to change it, but it takes time.我们正在努力改变它,但这需要时间。

Anyway, the current process is to have 2 build definitions (in reality there are more for different reasons).无论如何,当前的过程是有 2 个构建定义(实际上有更多不同的原因)。 So far we used classic CI builds, now we want to migrate to YAML (which we already use for micro services, but not the monolith).到目前为止,我们使用的是经典的 CI 构建,现在我们想要迁移到 YAML(我们已经将其用于微服务,但不是单体)。

Now I understand that we can have different release pipelines based off the same build definition, but different branch filters.现在我明白了,我们可以基于相同的构建定义拥有不同的发布管道,但使用不同的分支过滤器。

And maybe we will.也许我们会的。 But I do not understand why it is wrong to have different build definitions here, given that each branch is a long living release branch.但是我不明白为什么在这里有不同的构建定义是错误的,因为每个分支都是一个长期存在的发布分支。

Edit 2编辑 2

You can ignore $(Build.SourceBranch) and imaging release/r-858 instead.您可以忽略$(Build.SourceBranch)和映像release/r-858 The net result is exactly the same.最终结果完全相同。 In the scenario I bring above code is committed to master, not release/r-858.在我带来的场景中,上面的代码提交给 master,而不是 release/r-858。

Edit 3编辑 3

It is very confusing.这非常令人困惑。 Suppose I am creating a new YAML build.假设我正在创建一个新的 YAML 构建。 The dialog says "select YAML in any branch", but they point is that once selected this branch becomes the default branch of the build.该对话框显示“在任何分支中选择 YAML”,但他们指出,一旦选择此分支,该分支将成为构建的默认分支。 That is the branch we can see here:那就是我们可以在这里看到的分支:

在此处输入图像描述

If I have a single YAML file in the master branch, the build with the default branch release/r-858 cannot even use it, unless it is merged to release/r-858.如果我在 master 分支中有一个 YAML 文件,则默认分支release/r-858的构建甚至无法使用它,除非它合并到 release/r-858。 I tried it - I:我试过了 - 我:

  1. created a new YAML build创建了一个新的 YAML 构建
  2. selected the YAML file from the master branch从主分支中选择 YAML 文件
  3. ran and right away cancelled the build运行并立即取消构建
  4. then went to edit the build and changes the branch of the build from master to release/r-858 - it allowed me to save the build, even if the YAML does not exist in that branch然后去编辑构建并将构建的分支从 master 更改为 release/r-858 - 它允许我保存构建,即使该分支中不存在 YAML

But then when I tried to run the build again I got this:但是当我再次尝试运行构建时,我得到了这个:

在此处输入图像描述

An error occurred while loading the YAML build pipeline. File /Build/azure-pipelines-ci.yml not found in repository bla-bla-bla branch refs/heads/release/r-858 version 5893f559292e56cf6db48687fd910bd2916e3cef.

And indeed, looking at the raw build definition, the process section contains the YAML file path, but not the branch:事实上,查看原始构建定义,进程部分包含 YAML 文件路径,但不包含分支:

    "process": {
        "yamlFilename": "Build/azure-pipelines-ci.yml",
        "type": 2,
        "resources": {},
        "target": null
    },

The branch only appears in the repository section of the definition:该分支仅出现在定义的存储库部分中:

    "repository": {
        "defaultBranch": "refs/heads/release/r-858",
        ...
    },

It is clear to me that a single build definition can be used to CI build many branches.我很清楚,一个构建定义可用于 CI 构建多个分支。 But this model I need to implement is build definition per release branch.但是我需要实现的这个 model 是每个发布分支的构建定义。 I cannot have a single build definition for the following reasons:由于以下原因,我不能有一个单一的构建定义:

  1. Different release branches have different agent pools, because of the different development intensity.由于开发强度不同,不同的发布分支有不同的代理池。 Remember, this is on on-prem Azure DevOps Server with self hosted agents.请记住,这是在带有自托管代理的本地 Azure DevOps 服务器上。 Can we express this requirement with a single build definition?我们可以用一个构建定义来表达这个要求吗?
  2. Different build variable values which we want to control without sending a Pull Request to YAML file repository.我们想要控制的不同构建变量值,而不向 YAML 文件存储库发送拉取请求。 How do you do it with a single build definition?您如何使用单个构建定义来做到这一点? For example, one of the variables controls the version Major.Minor.例如,其中一个变量控制版本 Major.Minor。 They are different in each release branch.它们在每个发布分支中都不同。

So, I do not see any way to avoid multiple build definitions in our situation.因此,在我们的情况下,我看不到任何避免多个构建定义的方法。 The root cause for this are the release branches, but we cannot throw them away in the near future.造成这种情况的根本原因是发布分支,但我们不能在不久的将来丢弃它们。

So, we have 2 build definitions.所以,我们有 2 个构建定义。 That forces us to have 2 YAML - one per branch, because a build definition with the default branch of release/r-858 expects to find YAML in that branch, otherwise we cannot trigger the build manually.这迫使我们有 2 个 YAML - 每个分支一个,因为默认分支为 release/r-858 的构建定义希望在该分支中找到 YAML,否则我们无法手动触发构建。 Which is a must, even if the build has a CI trigger.这是必须的,即使构建有 CI 触发器。

So, 2 build definitions, 2 YAMLs (one per branch).因此,2 个构建定义,2 个 YAML(每个分支一个)。 So far my hands were forced.到目前为止,我的手是被迫的。 But now I am told that the release branch build would be triggered by the master YAML just because the release branch build is linked to the same YAML file name ignoring the default branch of the build!但是现在我被告知发布分支构建将由主 YAML 触发,因为发布分支构建链接到相同的 YAML 文件名,忽略了构建的默认分支!

Because this is what happens - a commit is checked in to master and the release branch build is invoked in addition to the master branch build.因为这是发生的事情 - 提交被签入到 master 并且除了 master 分支构建之外还调用了发布分支构建。 Both build definitions build exactly the same branch (master) using the master YAML script.两个构建定义都使用主 YAML 脚本构建完全相同的分支(主)。 But because the release branch build has different set of variables the end result is plain wrong.但是因为发布分支构建有不同的变量集,所以最终结果是完全错误的。

This is not reasonable.这是不合理的。 I am going to create a dummy repo to reproduce it cleanly and post here.我将创建一个虚拟 repo 以干净地复制它并在此处发布。

Edit 4编辑 4

As promised - a trivial reproduction.正如所承诺的 - 一个微不足道的复制。 Given:鉴于:

  1. master branch build test-master-CI master 分支构建 test-master-CI
  2. release branch build test-r58-CI发布分支构建测试-r58-CI

Since having two build definitions necessarily means two YAMLs (one per branch), here they are:由于有两个构建定义必然意味着两个 YAML(每个分支一个),因此它们是:

C:\xyz\DevOps\Test [master ≡]> cat .\azure-pipelines.yml
trigger:
  branches:
    include:
      - master

name: $(BuildVersionPrefix).$(DayOfYear)$(Date:HH)

steps:
  - script: echo master
C:\xyz\DevOps\Test [master ≡]> git co release/r-858
Switched to branch 'release/r-858'
Your branch is up to date with 'origin/release/r-858'.
C:\xyz\DevOps\Test [release/r-858 ≡]> cat .\azure-pipelines.yml
trigger:
  branches:
    include:
      - release/r-858

name: $(BuildVersionPrefix).$(DayOfYear)$(Date:HH)

steps:
  - script: echo release/r-858
C:\Dayforce\DevOps\Test [release/r-858 ≡]>

Where BuildVersionPrefix = 59.0 for master and 58.3 for release/r-858其中BuildVersionPrefix = 59.0 为 master 和 58.3 为 release/r-858

When I trigger each build manually I get this:当我手动触发每个构建时,我得到了这个:

在此处输入图像描述

Now I commit a change to master.现在我对 master 进行更改。 Lo and behold - both builds are triggered:瞧 - 两个构建都被触发:

在此处输入图像描述

In both cases the YAML from the master branch is used.在这两种情况下,都使用来自 master 分支的 YAML。 BUT the release branch defines BuildVersionPrefix = 58.3 and so the master build executed by the release branch build definition has bogus version.但是发布分支定义了 BuildVersionPrefix = 58.3,因此发布分支构建定义执行的主构建具有虚假版本。

Is this really how the feature is supposed to work?这真的是该功能应该如何工作的吗? That makes the CI YAML trigger useless for my scenario.这使得 CI YAML 触发器对我的场景毫无用处。 Thank you Matt for helping me to realize that.感谢马特帮助我意识到这一点。

I think I get where the confusion comes from.我想我明白了混乱的来源。 When you are configuring the pipeline, you are specifying the branch (notice the description says the file in any branch) and the file name.当您配置管道时,您正在指定分支(请注意,描述说明文件在任何分支中)和文件名。

在此处输入图像描述

What you are doing is just duplicating the monitoring though.您正在做的只是复制监控。 If you were to really inspect it, I think you will see that when you push to release branch, it isn't trigger the master YAML pipeline... it is just triggering the release YAML steps a second time.如果你真的要检查它,我想你会看到,当你推送到发布分支时,它不会触发主 YAML 管道......它只是第二次触发发布 YAML 步骤。 That is because the pipeline is just monitoring changes to the repo and responding based on the YAML configuration.这是因为管道只是监视对 repo 的更改并根据 YAML 配置进行响应。 In this case, you pushed to release and it evaluated that there was a YAML that matched that trigger (the release branch's copy) and triggered for both build definitions.在这种情况下,您推送到发布,它评估有一个 YAML 与该触发器(发布分支的副本)匹配并为两个构建定义触发。

I verified this on a mocked-up pipeline.我在模拟管道上验证了这一点。 I had selected different branches on the creation, but the only thing that really impacts I believe is the default branch it would use for scheduled builds.我在创建时选择了不同的分支,但我认为唯一真正影响的是它将用于计划构建的默认分支。 I created a simple echo statement in both of these it was using the release branches YAML configuration.我在这两个中创建了一个简单的 echo 语句,它使用发布分支 YAML 配置。

在此处输入图像描述

I think if you really want to achieve the desired results you are expecting, you will want to use the override triggers that you define on the definition instead of relying on what is in the YAML trigger.我认为,如果您真的想达到您期望的结果,您将需要使用您在定义中定义的覆盖触发器,而不是依赖于 YAML 触发器中的内容。

在此处输入图像描述

I had the same issue and Matt helped me solve this.我有同样的问题,马特帮我解决了这个问题。

I'm only writing this as the only way to get this working for me was to create a build YAML file on one branch (with the correct configuration).我只是写这个,因为让这个工作对我有用的唯一方法是在一个分支上创建一个构建 YAML 文件(使用正确的配置)。 Then create the other YAML file on another branch.然后在另一个分支上创建另一个 YAML 文件。 And then create the pipelines in the new shiny YAML editor within Devops.然后在 Devops 中的新 shiny YAML 编辑器中创建管道。

The key is, when in the "Configure" section of a new pipeline, select: "Existing Azure Pipelines YAML file" which allows you to select a branch and a YAML file within that branch. The key is, when in the "Configure" section of a new pipeline, select: "Existing Azure Pipelines YAML file" which allows you to select a branch and a YAML file within that branch.

在此处输入图像描述

This allowed me to have the SystemOne branch build and test the system one site and the SystemTwo branch build and test the system two site.这使我能够让 SystemOne 分支构建和测试系统一站点,而 SystemTwo 分支构建和测试系统二站点。

I also added triggers inside the SystemOne.yml using a wild card.我还使用通配符在 SystemOne.yml 中添加了触发器。 EG例如

trigger:
batch: true
branches: 
  include:
    - SystemOne/*

And the same for the SystemTwo.yml. SystemTwo.yml 也是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM