构建矩阵
构建矩阵由多个并行运行的作业组成。
这在许多情况下很有用,但使用构建矩阵的两个主要原因是
- 减少整体构建执行时间
- 针对不同版本的运行时或依赖项运行测试
本页上的示例重点介绍了后一种用例。
在 .travis.yml
文件中定义矩阵有两种方法
- 使用矩阵扩展功能
- 列出各个作业配置
这两个功能可以组合使用。
矩阵扩展 #
某些键被定义为矩阵扩展键,这些键采用值数组,为每个值创建一个额外的作业。如果给出了多个矩阵扩展键,这将使创建的作业数量相乘。
例如,以下配置会生成一个扩展为8 个独立作业(2 * 2 * 2)的构建矩阵,将来自三个矩阵扩展键 rvm
、gemfile
和 env
的每个值组合在一起。
rvm:
- 2.5
- 2.2
gemfile:
- gemfiles/Gemfile.rails-3.2.x
- gemfiles/Gemfile.rails-3.0.x
env:
- ISOLATED=true
- ISOLATED=false
列出各个作业 #
此外,可以通过向键 jobs.include
添加条目来指定作业。
例如,如果上述矩阵扩展的组合并非全部相关,则可以像这样单独指定作业
jobs:
include:
- rvm: 2.5
gemfile: gemfiles/Gemfile.rails-3.2.x
env: ISOLATED=false
- rvm: 2.2
gemfile: gemfiles/Gemfile.rails-3.0.x
env: ISOLATED=true
对于私有和公共存储库,构建矩阵目前限制为最多 200 个作业。如果您使用的是开源计划,请记住 Travis CI 向社区免费提供此服务。因此请仅指定您实际需要的矩阵。
您还可以查看我们 Travis CI 构建配置参考 中的 语言 部分。
排除作业 #
构建矩阵扩展有时会生成不需要的组合。在这种情况下,使用键 jobs.exclude
排除某些组合,而不是单独列出所有作业,可能很方便。
例如,这将从构建矩阵中排除两个作业
jobs:
exclude:
- rvm: 1.9.3
gemfile: gemfiles/Gemfile.rails-2.3.x
env: ISOLATED=true
- rvm: jruby
gemfile: gemfiles/Gemfile.rails-2.3.x
env: ISOLATED=true
如果您要从构建矩阵中排除的作业共享相同的矩阵参数,则可以只指定这些参数并省略变化的部分。
假设您有
language: ruby
rvm:
- 1.9.3
- 2.0.0
- 2.1.0
env:
- DB=mongodb
- DB=redis
- DB=mysql
gemfile:
- Gemfile
- gemfiles/rails4.gemfile
- gemfiles/rails31.gemfile
- gemfiles/rails32.gemfile
这将生成一个 3×3×4 的构建矩阵。要排除所有 rvm
值为 2.0.0
并且gemfile
值为 Gemfile
的作业,您可以编写
jobs:
exclude:
- rvm: 2.0.0
gemfile: Gemfile
这等效于
jobs:
exclude:
- rvm: 2.0.0
gemfile: Gemfile
env: DB=mongodb
- rvm: 2.0.0
gemfile: Gemfile
env: DB=redis
- rvm: 2.0.0
gemfile: Gemfile
env: DB=mysql
排除具有 env
值的作业 #
排除具有 env
值的作业时,该值必须完全匹配。
例如,
language: ruby
rvm:
- 1.9.3
- 2.0.0
- 2.1.0
env:
- DB=mongodb SUITE=all
- DB=mongodb SUITE=compact
- DB=redis
- DB=mysql
jobs:
exclude:
- rvm: 1.9.3
env: DB=mongodb
定义了一个 3×4 矩阵,因为 env
值与矩阵中定义的任何作业都不匹配。
要排除所有具有 DB=mongodb
设置的 Ruby 1.9.3 作业,请编写
language: ruby
rvm:
- 1.9.3
- 2.0.0
- 2.1.0
env:
- DB=mongodb SUITE=all
- DB=mongodb SUITE=compact
- DB=redis
- DB=mysql
jobs:
exclude:
- rvm: 1.9.3
env: DB=mongodb SUITE=all # not 'env: DB=mongodb' or 'env: SUITE=all DB=mongodb'
- rvm: 1.9.3
env: DB=mongodb SUITE=compact # not 'env: SUITE=compact DB=mongodb'
显式包含作业 #
也可以使用 jobs.include
将条目包含在矩阵中
jobs:
include:
- rvm: ruby-head
gemfile: gemfiles/Gemfile.rails-3.2.x
env: ISOLATED=false
这会将特定作业添加到已经填充的构建矩阵中。
如果您只想测试依赖项的最新版本以及运行时的最新版本,这将很有用。
您可以使用这种方法创建一个仅包含特定组合的构建矩阵。例如,
language: python
jobs:
include:
- python: "2.7"
env: TEST_SUITE=suite_2_7
- python: "3.8"
env: TEST_SUITE=suite_3_8
- python: "pypy"
env: TEST_SUITE=suite_pypy
script: ./test.py $TEST_SUITE
创建一个具有 3 个作业的构建矩阵,该矩阵对每个版本的 Python 运行测试套件。
显式包含的作业继承数组中的第一个值 #
显式包含的作业将继承定义的扩展键的第一个值。
在此示例中,使用 3 个作业的 Python 构建矩阵,jobs.include
中的每个作业都将 python
值设置为 '3.8'
。您可以为特定条目显式设置 python 版本
language: python
python:
- '3.8'
- '3.7'
- '2.7'
jobs:
include:
- python: '3.8' # this is not strictly necessary
env: EXTRA_TESTS=true
- python: '3.7'
env: EXTRA_TESTS=true
script: env $EXTRA_TESTS ./test.py $TEST_SUITE
仅在构建矩阵中包含一个元素的显式包含的作业 #
作为特殊情况,如果您的构建矩阵只有一个元素并且您已显式包含作业,则不会进行矩阵扩展,并且显式作业将完全定义您的构建。例如
language: python
python:
- '3.8'
jobs:
include:
- env: EXTRA_TESTS=true
# only defines one job with `python: 3.8` and `env: EXTRA_TESTS=true`
如果您在这种情况下需要矩阵中的一个(唯一的)作业,请在构建指令中添加一个带有花括号的空白作业条目(因为该指令将继承矩阵中的所有值)
language: python
python:
- '3.8'
jobs:
include:
- {}
- env: EXTRA_TESTS=true
# defines two jobs:
# - python: 3.8
# - python: 3.8
# env: EXTRA_TESTS=true
允许失败的行 #
您可以在构建矩阵中定义允许失败的行。允许失败是指构建矩阵中的项目,这些项目在不导致整个构建失败的情况下被允许失败。这使您可以添加实验性和准备性构建以针对您尚未准备正式支持的版本或配置进行测试。
在构建矩阵中将允许失败定义为键值对
jobs:
allow_failures:
- rvm: 1.9.3
使用 allow_failures
匹配作业 #
当将作业与 allow_failures
中给出的定义匹配时,allow_failures
中的所有条件都必须完全满足,并且 allow_failures
元素中的所有键都必须存在于构建矩阵的顶层(即不在 jobs.include
中)。
allow_failures
示例 #
考虑一下
language: ruby
rvm:
- 2.0.0
- 2.1.6
env:
global:
- SECRET_VAR1=SECRET1
jobs:
- SECRET_VAR2=SECRET2
jobs:
allow_failures:
- env: SECRET_VAR1=SECRET1 SECRET_VAR2=SECRET2
在这里,没有作业被允许失败,因为没有作业具有 env
值 SECRET_VAR1=SECRET1 SECRET_VAR2=SECRET2
。
接下来,
language: php
php:
- 5.6
- 7.0
jobs:
include:
- php: 7.0
env: KEY=VALUE
allow_failures:
- php: 7.0
env: KEY=VALUE
如果没有顶层的 env
,则没有作业会被允许失败。
快速完成 #
如果构建矩阵中的一些行被允许失败,则构建将不会在它们完成之前被标记为已完成。
要尽快将构建标记为已完成,请将 fast_finish: true
添加到您 .travis.yml
文件的 jobs
部分,如下所示
jobs:
fast_finish: true
现在,构建结果将尽快在所有必需的作业完成时确定,并将根据这些结果确定,而其余的 allow_failures
作业将继续运行。
每个作业使用不同的编程语言 #
您也可以使用 jobs.include
功能为构建中的每个作业使用不同的语言。例如,
dist: xenial
language: php
php:
- '5.6'
jobs:
include:
- language: python
python: 3.8
script:
- python -c "print('Hi from Python!')"
- language: node_js
node_js: 12
script:
- node -e "console.log('Hi from NodeJS!')"
- language: java
jdk: openjdk8
script:
- javac -help
这会创建一个具有 3 个作业的构建,如下所示
- 一个 Python 3.8 作业
- 一个 Node.js 12 作业
- 一个 Java OpenJDK 8 作业
作业名称 #
列出的作业 jobs.include
可以通过使用键 name
来命名,如下所示
jobs:
include:
- name: Job 1
script: echo "Running job 1"
此名称将显示在构建矩阵 UI 上,便于快速识别大型矩阵中的作业。
通过矩阵扩展功能生成的作业无法命名。
作业唯一性和重复作业 #
作业需要是唯一的,重复作业将在 构建配置验证 过程中被丢弃。
例如,此配置将仅使用一个作业 YAML 锚点和别名
_shared_job: &shared_job
script: echo "shared script config"
jobs:
include:
- <<: *shared_job
- <<: *shared_job
在极少数情况下,仍然可能需要执行多个具有相同配置的作业。在这种情况下,可以通过指定任何其他键(例如作业名称)来实现作业唯一性。
_shared_job: &shared_job
script: echo "shared script config"
jobs:
include:
- name: Job 1
<<: *shared_job
- name: Job 2
<<: *shared_job