构建矩阵

构建矩阵由多个并行运行的作业组成。

这在许多情况下很有用,但使用构建矩阵的两个主要原因是

本页上的示例重点介绍了后一种用例。

.travis.yml 文件中定义矩阵有两种方法

  • 使用矩阵扩展功能
  • 列出各个作业配置

这两个功能可以组合使用。

矩阵扩展 #

某些键被定义为矩阵扩展键,这些键采用值数组,为每个值创建一个额外的作业。如果给出了多个矩阵扩展键,这将使创建的作业数量相乘。

例如,以下配置会生成一个扩展为8 个独立作业(2 * 2 * 2)的构建矩阵,将来自三个矩阵扩展键 rvmgemfileenv 的每个值组合在一起。

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

在这里,没有作业被允许失败,因为没有作业具有 envSECRET_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