Azure Pipelines 通过示例构建 GitHub 存储库






3.91/5 (5投票s)
我们来了解一下 Azure Pipelines,以及如何在几分钟内为任何 GitHub 仓库添加灵活的 CI/CD 流程。
- 引言
- 背景
- 在 GitHub 中集成 Azure Pipelines
- YAML 还是非 YAML?
- 使用 Azure Pipelines 部署 GitHub Pages
- 基于 Lerna 的 Monorepo 工作流与 Azure Pipelines
- 关注点
- 历史
引言
去年,微软决定为其 Team Foundation Service、Visual Studio Online、Visual Studio Team Services 进行品牌重塑:**Azure DevOps** 诞生了。其中一个很棒的营销手段是推出一些子产品(以前是实际产品的功能),如 Azure Boards(管理问题)或 Azure Repos(源代码仓库)。另一个是 Azure Pipelines,它包含构建作业和发布定义。这是微软提供的 CI/CD 服务解决方案。
使用 Azure Pipelines 的一个很棒的卖点是“免费使用”的广告。简而言之,它允许我们为自己的项目使用多达 10 个并行构建作业。我想不用我多说,这是一个相当不错的优惠。事实上,市面上有许多 CI/CD 提供商(为开源项目提供免费服务),但没有一家能为(非开源项目)提供如此强大的功能。
为了让免费使用的卖点更有吸引力,微软将 Azure Pipelines 很好地集成到了他们最新(也是从战略角度来看,最有价值)的收购中:GitHub。
在这篇文章中,我想向您介绍 Azure Pipelines - GitHub 集成是如何工作的,以及您可以如何使用它。我们将通过三种不同的场景进行演示,并看看如何解决一些边缘情况。本文不是 Azure Pipelines 的入门指南,也不是 GitHub 的入门指南。
背景
我使用 TFS 已经很长时间了。当 VSO 出现时(第一个包含新的 Monaco 编辑器的产品,后来该编辑器成为了 VS Code 的核心,而 VS Code 正在风靡全球),我立刻被吸引了。尽管如此,从用户角度来看,它仍然非常 TFS 化,并且可能在市场上定位不佳。最终,它未能达到预期。
微软一直在努力提高该产品的采用率,但最终还是落后于竞争对手。最终,随着 VSTS(Visual Studio Team Services)的推出,微软(在我看来)取得了转机。即使产品在各个方面都比竞争对手落后一步,但总体而言,它无疑是(也许与 GitLab 并列)市场上最全面、最易用的解决方案。我在两家公司大量使用它,负责一个大型项目的架构,该产品本身表现出色。是的,有些时候感觉工具并没有赋予我们力量,但总的来说,它还是实现了目标。随着 Azure DevOps 的推出,设计和整体体验得到了进一步提升。
我在 GitHub 上托管了许多项目(我不会认为自己是重度用户,尽管我认为我使用它的频率相当高/频繁),并且我几乎总是尝试引入一些 CI/CD 来避免记住未来如何发布。毕竟,只需推送到 `master`(或者在那里创建一个带有最终审查的 PR)就应该足以创建一个新的发布。以前,我使用 Travis CI(主要是 Node.js / JS 项目)和 AppVeyor(主要是 .NET / C# 项目)来保持开源项目的稳定。有了 Azure Pipelines,提供了一种新的迷人方式,我无法抗拒。
在 GitHub 中集成 Azure Pipelines
有两种主要方式可以将 Azure Pipelines 集成到 GitHub 中(或者反之,取决于您的观点)。第一种方式是通过 GitHub。在市场中,我们可以找到 Azure Pipelines(搜索它!)。然后,我们需要授予此应用程序访问我们仓库的权限。别担心,您可以随时撤销任何访问权限。新组织不会自动获得访问权限,因此您最终仍需要访问这些 OAuth 设置,但我们稍后会详细介绍。
GitHub 市场可能会是这样的:
虽然第一种方式对于初次使用来说可能相当直接,但它并不具有可扩展性。一旦应用程序(Azure Pipelines)获得授权,您就无法再继续使用此方式。因此,第二种方式(最初有效,也适用于任何后续使用)是我的首选。
让我们登录 Azure DevOps 创建一个新的 Pipeline。让我们从一个空白 Pipeline 开始。在第一个问题中,我们就可以选择 GitHub 作为仓库的来源。
继续进行,我们会看到需要提供一个 OAuth 访问令牌。如果之前没有提供,我们现在将授予 Azure Pipelines 应用程序访问权限 - 问题解决了!至少直到您最终想要设置您所属的某个组织中的仓库。如果您看不到该仓库 - 或该组织中的任何仓库怎么办?那么,是时候看看该应用程序(即 Azure Pipelines)是否实际上被允许访问该组织的信息了。这可以通过以下方式完成:
- 在用户菜单“**设置**”中
- 在左侧菜单中选择“**应用程序**”
- “**授权的 OAuth 应用**”
- 点击 Azure Pipelines 显示详细的安全设置
通过这种方式,我们可以控制应用程序可以访问哪些组织。
一切设置完成后,我们可以创建一个简单的 Pipeline,看看它是否能够正确构建(并部署!)
如果一切顺利,我们始终可以为我们的仓库获取一个漂亮的徽章。它看起来是这样的:
要获取徽章,请在 Azure DevOps 中找到您的 Azure Pipeline,然后按“**...**”查看其他选项(例如编辑)。在其中,找到“**状态徽章**”并勾选。显示确切的代码(HTML 或 Markdown)是无用的,因为最重要信息是 Pipeline ID,无论如何您都需要获取它(所以您也可以直接从 Azure DevOps 获取完整代码)。
YAML 还是非 YAML?
当我们大量使用 VSTS(Azure DevOps 的前身)时,我们首先需要花费一些时间来建立一个良好的构建作业创建系统。主要问题是必须以图形方式创建构建作业。考虑到一个拥有 100 多个服务的后端(每个服务都有自己的仓库)加上工具、库和客户端,很容易看出这样的流程是无法扩展的。以图形方式编辑构建过程看起来与下面的屏幕相似:
是的,有一个叫做“任务组”的东西,它是一种(以图形方式)创建可重用步骤列表的方式。事实上,我们用它来稍微规避了可重用性问题。但最终,您会得到一个由 15 多个任务组组成的系统,它们之间存在依赖关系,并接受一些可能也相似的输入。同样,更改某些内容(例如,由于约定更改)可能会导致需要在多个地方进行更改。但这甚至不是最大的问题。
使用图形化步骤编辑器最大的问题是,构建作业的位置与其所基于的源代码是分离的。因此,我们无法将构建作业中的更改与源代码关联起来。此外,责任也不清晰。
借助 Azure DevOps,引入了一个(众所周知的)解决方案:可以使用 YAML 文件来指定整个过程的外观。
重要的是要理解这两种方法是互斥的。尽管图形表示使我们能够将其序列化为 YAML,但它仍然托管在某个未知的位置,而真正的 YAML 文件将托管在仓库本身中。
那么我们该选择哪种呢?我个人倾向于使用 YAML 表示,如果:
- 构建作业真的非常简单
- 其他人(维护者)需要查看/更改构建作业
- 项目由许多具有相似构建作业的仓库组成(需要工具)
另一方面,如果我有一个复杂的 Pipeline,我愿意先从图形编辑器开始。另外,如果确切的构建作业需要隐藏(或不太重要),我会避免在仓库中添加 YAML 文件。
如果情况不明确,我的建议是**先从图形编辑器开始,然后在必要时转到 YAML**。这是简单的方向,并且*应该*始终是可能的。
使用 Azure Pipelines 部署 GitHub Pages
我希望通过 Azure Pipelines 实现的一个功能是自动化将 Web 应用程序部署到 GitHub Pages。目前,这个 Web 应用程序需要手动部署,即从开发人员的机器通过命令行使用 `npm run deploy`。
本节的目标是自动化这个 React 单页应用程序 (SPA) 的发布过程(即构建和部署)。虽然在 Azure Pipelines 中开始(即集成基本 Pipeline)非常简单(我甚至会称之为微不足道),但自定义任务似乎有点麻烦。在这种情况下,我遇到了一个问题,即调用 `gh-pages` 命令,该命令实际上只会执行 `git push`。这被称为重复推送,正如我们将看到的,如果重复推送的目标与我们当前构建的同一分支相同,问题会更严重。但稍后会详细介绍。
解决所有问题的方案包括访问 GitHub 以进行推送的“无效设备或用户名”问题、“你是谁”的 Git 使用问题,或者“密码显示在日志中”的问题,这些都通过 3 个简单步骤来实现。
第 1 步 - 获取 GitHub PAT
进入您的 GitHub 设置,然后进入开发者设置选项卡。在那里,我们可以找到个人访问令牌 (PAT)。这些是非常强大的安全密钥,可以直接访问您的帐户。请非常小心地对待它们。但是,它们提供了一些好处:
- 它们可以被撤销
- 它们可以被定向(到不同的 API)/具有不同的声明
- 它们可以被延长/扩展
- 它们可以过期
我们应该创建一个新令牌,它只能访问特定仓库(拉取、推送等)。复制该值,并在下一步中使用。
第 2 步 - 变量
在 Azure DevOps 页面中打开 Azure Pipeline。转到变量,创建一个新变量(例如,命名为 `github_pat`)。确保勾选“机密”复选框。此环境变量的值是我们第一步中提取的值(PAT)。
第 3 步 - Pipeline YAML
现在,我们需要调整 `azure-pipelines.yml` 文件。假设我们从基本的 Node.js 构建过程开始(因为我们有一个 React SPA)。我们需要将其从基本版本转换为以下版本:
pool:
vmImage: 'Ubuntu 16.04'
trigger:
- source
steps:
- checkout: self
persistCredentials: true
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- script: |
git config user.email "yourmail"
git config user.name "yourname"
npm install
npm run deploy -- -r https://$(github_pat)@github.com/yourrepo.git
displayName: 'npm install and build'
它做什么?嗯,最重要的是,我们为位于 GitHub 上的仓库使用了一个显式的 URL。此 URL 包含以 PAT 形式提供的访问信息。PAT 从环境变量接收,不会显示在任何日志中。
为了在 `deploy` 脚本中使用 Git(该脚本实际上只在 `gh-pages` 下方运行,因此使用了 `-r` 标志),我们需要在本地设置 Git。相关的行是调用 `git config` 的那些。请确保在此处输入您的详细信息。
基于 Lerna 的 Monorepo 工作流与 Azure Pipelines
我刚刚开始在工作中一个较大的 JavaScript 项目中使用 monorepo。到目前为止,这项工作进展顺利,但 CI/CD 给我带来了问题。如果您想了解一些背景/工作流细节,请随时查看我的博客。简而言之,我们选择标准的 Lerna 工具来管理我们的 monorepo,但我们略微偏离了官方工作流(例如,不使用常规的 changelogs,而是使用显式的 changelogs,并完全控制发布的版本号)。
为了使 Lerna 的 monorepo 设置与 CI/CD 提供商(在本例中为 Azure DevOps)协同工作,我们需要稍微改进我们的 Pipeline。虽然 Lerna 命令肯定会起作用,但我们仍然需要在实际的 CI/CD Pipeline 上做一些工作。
让我们先看看我们实际想要实现的目标。下图显示了我们想要的过程:
这是一个相当标准的设置 - 我们想要构建验证(用于 Pull Request)+ 预览发布(用于 `develop` 分支的更改)+ 发布(用于 `master` 分支的更改)。但是,请注意,在发布 Pipeline 中,我们还进行了回推,以反映源代码中的更改(所有包的版本都已更新),并在 GitHub 上标记了最新的发布。
我们从一个镜像到 GitHub 的 Git 仓库开始。GitHub 仓库包含一些钩子,这些钩子会触发 Azure DevOps 中的一个进程。然后,我们需要区分三种可能的情况:
- 我们有 Pull Request 验证(仅构建和测试)
- 我们对 develop 有更改(构建、测试,如果一切顺利,则发布可用包的预览)
- 我们对 master 有更改(构建、测试,如果一切顺利,则发布完整内容,并将对 `package.json` 文件所做的更改推回,以及一个新的 Git 标签)
由于我们进行了回推,我们将对 master 进行另一项更改。这会触发另一个构建,因此我们需要非常谨慎。幸运的是,Azure DevOps 允许我们在构建期间批量处理更改(即,不要同时进行另一个构建)。批量处理的更改会获得一个特殊标志(即原因),该标志可以通过前置条件进行处理。因此,如果我们获得了 master 的批量更改,我们可以简单地忽略它们,因为它们是回推更改。
为了进行正确的回推更改,我们需要 Git 凭据(就像上一节中发布到 GitHub Pages 一样)。为此,我们应该在 GitHub 中创建一个个人访问令牌(简称 PAT)。PAT 非常敏感 - 只复制一次,将其作为机密放入 Pipeline 的变量中,然后永远不要再查看!如有疑问,请生成一个新的 PAT 并替换旧值。切勿重复使用 PAT,否则您将面临两个问题:
- 不知道哪个 PAT 可能已泄露,并且
- 不知道 PAT 到期/被撤销时会影响什么。
将 GitHub PAT 放入变量如下所示:
最后,有了这个变量,我们可以在 Pipeline 中引入一个新步骤。重要的是,此步骤必须在任何回推之前执行。
这可以是这样的(与 GitHub Pages 示例中我们在 YAML 中使用脚本不同):
在此步骤中,我们检出 `master` 分支(Lerna 希望看到它而不是确切的提交 SHA;实际上,这证明了将此步骤放置在 Pipeline 的*早期*阶段是合理的,但这些都是细节……)并修改仓库 URL(origin)以包含 PAT。我们需要进行这种魔法操作,因为 Lerna 不接受远程 URL 的覆盖(只接受不同的远程)。此外,我们还用一个用户配置了 Git,以避免任何错误消息,并清楚地表明提交是由我们的 CI 系统完成的。
请确保替换以下代码片段中的所有占位符名称!
git config --global user.email "your@bot"
git config --global user.name "Your Bot"
git remote rm origin
git remote add origin https://$gt@github.com/orga/repo.git
git fetch origin
git checkout master
兴趣点
如果您喜欢这篇文章,请告诉我。由于我在 Azure DevOps 方面的经验,我还有很多其他主题可以写(例如,关于如何(滥)使用 Azure Pipelines 来节省服务器成本的技巧集)。您对什么特别感兴趣?请告诉我!任何评论/意见都将不胜感激。
历史
- v1.0.0 | 初始发布 | 2019 年 2 月 26 日
- v1.1.0 | 添加目录 | 2019 年 3 月 4 日