从 Travis 迁移到 Azure Pipelines

Azure DevOps Services

本指南旨在帮助你从 Travis 迁移到 Azure Pipelines。 本指南介绍如何从 Travis 配置转换为 Azure Pipelines 配置。

我们需要你的帮助来完善本指南! 请提交评论或直接贡献你的更改。

主要区别

Travis 和 Azure Pipelines 之间存在许多差异,包括:

  • Travis 生成具有“阶段”、“作业”和“时期”,而 Azure Pipelines 具有可以按你选择的任意顺序或分组排列和执行的步骤。

  • Azure Pipelines 允许将作业定义和步骤存储在相同或不同存储库中的单独 YAML 文件中,从而允许跨多个管道共享步骤。

  • Azure Pipelines 为在 Microsoft 管理的 Linux、Windows 和 macOS 映像上进行生成和测试提供完全支持。 有关托管代理的详细信息,请参阅 Microsoft 托管代理

先决条件

语言

Travis 使用 language 关键字来确定要为生成设置的必备生成环境。 例如,若要选择 Node.JS 16.x:

.travis.yml

language: node_js
node_js:
  - 16

默认情况下,Microsoft 托管代理包含多种语言的 SDK。 若要使用特定语言版本,可能需要使用语言选择任务来设置环境。

例如,若要选择 Node.JS 16.x:

azure-pipelines.yml

steps:
- task: UseNode@1
  inputs:
    version: '16.x'

语言映射

Travis 中的关键字 language 意味着应使用语言工具的该版本以及应隐式执行许多生成步骤。 在 Azure Pipelines 中,需要指定要运行的命令。

下面是从 language 关键字到针对最常用的语言自动执行的命令的转换指南:

语言 命令
c
cpp
./configure
make
make install
csharp nuget restore [solution.sln]
msbuild /p:Configuration=Release [solution.sln]
clojure lein deps
lein test
go go get -t -v ./...
make go test
java
groovy
Gradle:
gradle assemble
gradle check

Maven:
mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
mvn test -B

Ant:
ant test
node_js npm install npm ci yarn
npm test
objective-c
swift
pod install bundle exec pod install
xcodebuild -scheme [scheme] build test \| xcpretty
perl cpanm --quiet --installdeps --notest .

Build.PL:
perl ./Build.pl
./Build test

Makefile.PL:
perl Makefile.PL
make test

Makefile:
make test
php phpunit
python pip install -r requirements.txt
ruby bundle install --jobs=3 --retry=3
rake

此外,可以启用不太常见的语言,但需要另一个依赖项安装步骤或 docker 容器内的执行:

语言 命令
crystal docker run -v $(pwd):/src -w /src crystallang/crystal shards install
docker run -v $(pwd):/src -w /src crystallang/crystal crystal spec
d sudo wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list
sudo apt-get update
sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring
sudo apt-get update
sudo apt-get install dmd-compiler dub
dub test --compiler=dmd
dart wget https://dl-ssl.google.com/linux/linux_signing_key.pub -O - \| sudo apt-key add -
wget https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list -O /etc/apt/sources.list.d/dart_stable.list
sudo apt-get update
sudo apt-get install dart
/usr/lib/dart/bin/pub get
/usr/lib/dart/bin/pub run test
erlang sudo apt-get install rebar
rebar get-deps
rebar compile
rebar skip_deps=true eunit
elixir sudo apt-get install elixir
mix local.rebar --force
mix local.hex --force
mix deps.get
mix test
haskell sudo apt-get install cabal-install
cabal install --only-dependencies --enable-tests
cabal configure --enable-tests
cabal build
cabal test
haxe sudo apt-get install haxe
yes \| haxelib install [hxml]
haxe [hxml]
julia sudo apt-get install julia
julia -e "using Pkg; Pkg.build(); end"
julia --check-bounds=yes -e "Pkg; Pkg.test(coverage=true); end"
nix docker run -v $(pwd):/src -w /src nixos/nix nix-build
perl6 sudo apt-get install rakudo
PERL6LIB=lib prove -v -r --exec=perl6 t/
rust curl -sSf https://sh.rustup.rs | sh -s -- -y
cargo build --verbose
cargo test --verbose
scala echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | /etc/apt/sources.list.d/sbt.list
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823
sudo apt-get update
sudo apt-get install sbt
sbt ++2.11.6 test
smalltalk docker run -v $(pwd):/src -w /src hpiswa/smalltalkci smalltalkci

多种语言选择

还可以配置一个可支持以多种语言生成不同应用程序的环境。 例如,若要确保生成环境同时面向 Node.JS 16.x 和 Ruby 3.2 或更高版本:

azure-pipelines.yml

steps:
- task: UseNode@1
  inputs:
    version: '8.x'
- task: UseRubyVersion@0
  inputs:
    versionSpec: '>= 3.2'

阶段

在 Travis 中,步骤在一组固定的命名时期(如 before_installbefore_script)中定义。 Azure Pipelines 没有已命名的时期,并且步骤可以通过任何对管道有意义的方式进行分组、命名和组织。

例如:

.travis.yml

before_install:
    - npm install -g bower
install:
    - npm install
    - bower install
script:
    - npm run build
    - npm test

azure-pipelines.yml

steps:
- script: npm install -g bower
- script: npm install
- script: bower install
- script: npm run build
- script: npm test

或者,可将步骤组合在一起,并进行命名(可选):

azure-pipelines.yml

steps:
- script: |
    npm install -g bower
    npm install
    bower install
  displayName: 'Install dependencies'
- script: npm run build
- script: npm test

并行作业

Travis 通过让你定义一个阶段(一组并行执行的作业)来提供并行。 Travis 生成可以有多个阶段;一个阶段中的所有作业都完成后,下一阶段将开始。

使用 Azure Pipelines,可以使每个步骤或阶段依赖于任何其他步骤。 通过这种方式,可以指定哪些步骤以串行方式运行,哪些步骤可以并行运行。 因此,可以在完成一个步骤后通过并行运行多个步骤进行扇出,然后使用随后运行的单个步骤重新扇入。 此模型提供用于在必要时定义复杂工作流的选项。 现在,下面是一个简单的示例:

简单并行执行插图

例如,若要运行生成脚本,然后在其完成后并行运行单元测试和集成测试,并在所有测试完成后将工件打包,然后运行部署到预生产:

.travis.yml

jobs:
  include:
  - stage: build
    script: ./build.sh
  - stage: test
    script: ./test.sh unit_tests
  - script: ./test.sh integration_tests
  - stage: package
    script: ./package.sh
  - stage: deploy
    script: ./deploy.sh pre_prod

azure-pipelines.yml

jobs:
- job: build
  steps:
  - script: ./build.sh
- job: test1
  dependsOn: build
  steps:
  - script: ./test.sh unit_tests
- job: test2
  dependsOn: build
  steps:
  - script: ./test.sh integration_tests
- job: package
  dependsOn:
  - test1
  - test2
  script: ./package.sh
- job: deploy
  dependsOn: package
  steps:
  - script: ./deploy.sh pre_prod

高级并行执行

在 Azure Pipelines 中,对于管道的编排方式,你有更多的选项和控制。

例如,一个团队有一组快速运行的单元测试,以及另一组速度较慢的集成测试。 该团队希望在单元完成后立即开始为发布创建 .ZIP 文件,因为他们对该生成提供了良好的包很有信心。 但在部署到预生产之前,他们希望等到所有测试都通过:

高级并行执行插图

在 Azure Pipelines 中,他们可以这样做:

azure-pipelines.yml

jobs:
- job: build
  steps:
  - script: ./build.sh
- job: test1
  dependsOn: build
  steps:
  - script: ./test.sh unit_tests
- job: test2
  dependsOn: build
  steps:
  - script: ./test.sh integration_tests
- job: package
  dependsOn: test1
  script: ./package.sh
- job: deploy
  dependsOn:
  - test1
  - test2
  - package
  steps:
  - script: ./deploy.sh pre_prod

步骤重用

在 Travis 中,可以使用矩阵通过单个配置运行多个执行。 在 Azure Pipelines 中,可以采用相同的方式使用矩阵,但也可以使用模板实现配置重用。

示例:矩阵中的环境变量

运行多个稍有变化的生成的最常见方法之一是使用环境变量更改执行。 例如,生成脚本可以查看是否存在环境变量,并更改软件的生成方式或测试方式。

可以使用矩阵多次运行某个生成配置,为环境变量中的每个值都运行一次。 例如,若要运行给定脚本三次,每次使用一个环境变量的不同设置:

.travis.yml

os: osx
env:
  matrix:
  - MY_ENVIRONMENT_VARIABLE: 'one'
  - MY_ENVIRONMENT_VARIABLE: 'two'
  - MY_ENVIRONMENT_VARIABLE: 'three'
script: echo $MY_ENVIRONMENT_VARIABLE

azure-pipelines.yml

pool:
  vmImage: 'macOS-latest'
strategy:
  matrix:
    set_env_to_one:
      MY_ENVIRONMENT_VARIABLE: 'one'
    set_env_to_two:
      MY_ENVIRONMENT_VARIABLE: 'two'
    set_env_to_three:
      MY_ENVIRONMENT_VARIABLE: 'three'
steps:
- script: echo $(MY_ENVIRONMENT_VARIABLE)

示例:矩阵中的语言版本

另一种常见方案是针对多个不同语言环境运行。 Travis 支持使用 language 关键字进行隐式定义,而 Azure Pipelines 需要显式任务来定义如何配置该语言版本。

可以使用 Azure Pipelines 中的环境变量矩阵选项为不同语言版本启用矩阵。 例如,可以在对应于要使用的语言版本的每个矩阵变量中设置环境变量,然后在第一步中使用该环境变量运行语言配置任务:

.travis.yml

os: linux
matrix:
  include:
  - rvm: 2.3.7
  - rvm: 2.4.4
  - rvm: 2.5.1
script: ruby --version

azure-pipelines.yml

vmImage: 'ubuntu-latest'
strategy:
  matrix:
    ruby 2.3:
      ruby_version: '2.3.7'
    ruby 2.4:
      ruby_version: '2.4.4'
    ruby 2.5:
      ruby_version: '2.5.1'
steps:
- task: UseRubyVersion@0
  inputs:
    versionSpec: $(ruby_version)
- script: ruby --version

示例:矩阵中的操作系统

在多个操作系统中运行生成也很常见。 Travis 支持使用 os 关键字进行此定义,而 Azure Pipelines 允许你通过使用 vmImage 关键字选择要在其中运行的池来配置操作系统。

例如,可以在对应于要使用的操作系统映像的每个矩阵变量中设置环境变量。 然后,可以将计算机池设置为已设置的变量:

.travis.yml

matrix:
  include:
  - os: linux
  - os: windows
  - os: osx
script: echo Hello, world!

azure-pipelines.yml

strategy:
  matrix:
    linux:
      imageName: 'ubuntu-latest'
    mac:
      imageName: 'macOS-latest'
    windows:
      imageName: 'windows-latest'

pool:
  vmImage: $(imageName)

steps:
- script: echo Hello, world!

成功和失败处理

Travis 允许你使用 after_success 时期指定在生成成功时运行的步骤或使用 after_failure 时期指定在生成失败时运行的步骤。 借助 Azure Pipelines,可以基于任何步骤的结果定义成功和失败条件,从而实现更灵活、更强大的管道。

.travis.yml

build: ./build.sh
after_success: echo Success 
after_failure: echo Failed 

azure-pipelines.yml

steps:
- script: ./build.sh
- script: echo Success
  condition: succeeded()
- script: echo Failed
  condition: failed()

高级的成功和失败处理

在 Azure Pipelines 中,可以针对作业之间的流控制为一组灵活的依赖项和条件进行编程。
可以将作业配置为基于以前作业的成功或失败或基于环境变量运行。 甚至可以将作业配置为始终运行,而不考虑其他作业是否成功。

例如,如果要在生成失败(但仅当它是在主分支上作为生成运行的情况下)时运行脚本:

azure-pipelines.yml

jobs:
- job: build
  steps:
  - script: ./build.sh
- job: alert
  dependsOn: build
  condition: and(failed(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  steps:
  - script: ./sound_the_alarms.sh

预定义变量

Travis 和 Azure Pipelines 都设置了多个环境变量,使你能够检查 CI 系统的执行环境并与之交互。

在大多数情况下,都有与 Travis 中的环境变量匹配的 Azure Pipelines 变量。 下面是 Travis 中常用的环境变量及其在 Azure Pipelines 中的类似项的列表:

Travis Azure Pipelines 说明
CI=trueTRAVIS=true TF_BUILD=True 表明你的生成正在 CI 系统中运行;对于也要在开发期间在本地运行的脚本很有用。
TRAVIS_BRANCH CI 生成:
BUILD_SOURCEBRANCH

拉取请求生成:
SYSTEM_PULLREQUEST_TARGETBRANCH
该生成排队的分支的名称,或拉取请求的目标分支的名称。
TRAVIS_BUILD_DIR BUILD_SOURCESDIRECTORY 签出源的位置和默认工作目录。
TRAVIS_BUILD_NUMBER BUILD_BUILDID 当前生成调用的唯一数字标识符。
TRAVIS_COMMIT CI 生成:
BUILD_SOURCEVERSION
当前正在生成的提交 ID。
TRAVIS_COMMIT 拉取请求生成:
git rev-parse HEAD^2
对于拉取请求验证生成,Azure Pipelines 将 BUILD_SOURCEVERSION 设置为将拉取请求合并到主分支的结果合并提交;此命令标识了拉取请求提交本身。
TRAVIS_COMMIT_MESSAGE BUILD_SOURCEVERSIONMESSAGE 要生成的提交的日志消息。
TRAVIS_EVENT_TYPE BUILD_REASON 该生成排队的原因;值的映射位于下面的“生成原因”表中。
TRAVIS_JOB_NAME AGENT_JOBNAME 当前作业的名称(如果指定)。
TRAVIS_OS_NAME AGENT_OS 运行作业的操作系统;值的映射位于下面的“操作系统”表中。
TRAVIS_PULL_REQUEST Azure Repos:
SYSTEM_PULLREQUEST_PULLREQUESTID

GitHub:
SYSTEM_PULLREQUEST_PULLREQUESTNUMBER
触发此生成的拉取请求编号。 (对于 GitHub 生成,这是一个并非拉取请求编号的唯一标识符。)
TRAVIS_PULL_REQUEST_BRANCH SYSTEM_PULLREQUEST_SOURCEBRANCH 拉取请求来源的分支的名称。
TRAVIS_PULL_REQUEST_SHA 拉取请求生成:
git rev-parse HEAD^2
对于拉取请求验证生成,Azure Pipelines 将 BUILD_SOURCEVERSION 设置为将拉取请求合并到主分支的结果合并提交;此命令标识了拉取请求提交本身。
TRAVIS_PULL_REQUEST_SLUG 分支存储库的名称(如果拉取请求源自分支)。 这在 Azure Pipelines 中没有类似项。
TRAVIS_REPO_SLUG BUILD_REPOSITORY_NAME 为其配置此生成的存储库的名称。
TRAVIS_TEST_RESULT AGENT_JOBSTATUS 如果前面的所有步骤都成功(返回了 0),Travis 会将此值设置为 0。 对于 Azure Pipelines,请检查是否满足 AGENT_JOBSTATUS=Succeeded
TRAVIS_TAG BUILD_SOURCEBRANCH 如果此生成因创建标记而排队,则这是该标记的名称。 对于 Azure Pipelines,BUILD_SOURCEBRANCH 设置为完整的 Git 引用名称,例如 refs/tags/tag_name
TRAVIS_BUILD_STAGE_NAME Travis 中阶段的名称。 如前所述,Azure Pipelines 使用作业处理流控制。 可以引用 AGENT_JOBNAME

生成原因:

TRAVIS_EVENT_TYPE 变量包含映射到 Azure Pipelines BUILD_REASON 变量提供的值的值:

Travis Azure Pipelines 说明
push IndividualCI 该生成是来自推送的持续集成生成。
pull_request PullRequest 该生成已排队以验证拉取请求。
api Manual REST API 或网页上的手动请求已将该生成排队。
cron Schedule 已计划该生成。

操作系统:

TRAVIS_OS_NAME 变量包含映射到 Azure Pipelines AGENT_OS 变量提供的值的值:

Travis Azure Pipelines 说明
linux Linux 该生成在 Linux 上运行。
osx Darwin 该生成在 macOS 上运行。
windows Windows_NT 该生成在 Windows 上运行。

有关详细信息,请参阅 预定义环境变量

如果没有你所需数据的变量,则可以使用 shell 命令获取它。 例如,对于包含所生成拉取请求提交 ID 的环境变量,一个好的替代方法是运行 git 命令:git rev-parse HEAD^2

生成特定分支

默认情况下,Travis 和 Azure Pipelines 均在所有分支上执行 CI 生成。 同样,这两个系统都允许将这些生成限制到特定的分支。 在 Azure Pipelines 中,要生成的分支列表应列在 include 列表中,而不要生成的分支应列在 `exclude 列表中。 支持通配符。

例如,若要仅生成主分支以及以单词“releases”开头的分支:

.travis.yml

branches:
  only:
  - main
  - /^releases.*/

azure-pipelines.yml

trigger:
  branches:
    include:
    - main
    - releases*

输出缓存

Travis 支持缓存依赖项和中间生成输出,以缩短生成时间。 Azure Pipelines 不支持缓存中间生成输出,但提供与 Azure Artifacts 的集成以便存储依赖项。

Git 子模块

默认情况下,Travis 和 Azure Pipelines 都以“递归方式”克隆 git 存储库。 这意味着子模块由代理克隆,它很有用,因为子模块通常包含依赖项。 但是,额外的克隆需要时间,因此,如果不需要依赖项,则可以禁用克隆子模块:

.travis.yml

git:
  submodules: false

azure-pipelines.yml

checkout:
  submodules: false