缓存依赖项和目录

Travis CI 可以缓存不经常更改的内容,以加快构建过程。**要使用缓存功能**,请在仓库设置中将*构建推送的分支*设置为*开启*。

  • Travis CI 会为每个构建获取缓存,包括分支和拉取请求。
  • 如果分支没有自己的缓存,Travis CI 会获取仓库默认分支的缓存。
  • 每个分支和语言版本/编译器版本/JDK 版本/Gemfile 位置/等等都有一个缓存。
  • 只有对缓存目录的正常推送进行的修改才会被存储。

请注意,缓存内容可供仓库上的任何构建使用,包括拉取请求,因此请确保您不会将任何敏感信息放入缓存中。

创建缓存时,不会跟踪符号链接。请考虑缓存普通文件和目录而不是符号链接。

缓存目录(Bundler、依赖项) #

缓存使 Travis CI 能够在构建之间存储目录,这对于存储编译或下载时间较长的依赖项很有用。

请注意,如果第三方项目(例如 Bundler)更改了存储依赖项的位置,您可能需要 手动指定目录,而不是使用该特定的 缓存快捷方式。如果有任何问题、问题或反馈,请 联系我们

构建阶段 #

Travis CI 在构建的 script 阶段之后但在 after_successafter_failure 之前上传缓存。

无法上传缓存不会标记作业失败。

Bundler #

在 Ruby 和 Objective-C 项目中,通过 Bundler 安装依赖项可能会占构建时间的很大一部分。在构建之间缓存包可以显著减少构建运行所需的时间。

启用 Bundler 缓存 #

要在您的 .travis.yml 中启用 Bundler 缓存

language: ruby
cache: bundler

每当您更新包时,Travis CI 也会更新缓存。

确定包路径 #

Travis CI 会尽力确定 Bundler 用于存储依赖项的路径。

如果您有 自定义 Bundler 参数,并且这些参数包括 --path 选项,Travis CI 会使用该路径。如果缺少 --path 但存在 --deployment,它将使用 vendor/bundle

否则,它会自动添加 --path 选项。在这种情况下,它将使用环境变量 BUNDLE_PATH 的值,或者如果它不存在,则使用 vendor/bundle

缓存和覆盖 install 步骤 #

覆盖 install 步骤可能会导致指令 cache: bundler 错过目录。在这种情况下,请观察 Bundler 安装宝石的位置,并使用 cache.directories 缓存该目录。

清理包 #

当您使用

cache: bundler

命令 bundle clean 会在上传缓存之前执行。

在不希望这样做的情况下,您可以使用 任意目录 来解决它。有关更多信息,请参见 此 GitHub 问题

为非 Ruby 项目缓存 RVM Ruby 版本 #

有一些项目使用不是基于 Ruby 的机器,但执行了一些 Ruby 代码。例如,一个具有 Ruby 功能测试套件的 NodeJS 应用程序。

对于这些情况,使用 rvm install 2.3.1 安装 ruby 版本可能需要超过 3 分钟。对于这些情况,您可以缓存 ruby 安装。

 cache:
    directories:
     - /home/travis/.rvm/

CocoaPods #

在 Objective-C 项目中,通过 CocoaPods 安装依赖项可能会占用大量构建时间。在构建之间缓存已编译的 Pods 有助于缩短这段时间。

启用 CocoaPods 缓存 #

您可以在仓库中通过将以下内容添加到您的.travis.yml 中启用 CocoaPods 缓存

language: objective-c
cache: cocoapods

如果您想要同时启用 Bundler 缓存和 CocoaPods 缓存,可以将它们列出来

language: objective-c
cache:
  bundler: true
  cocoapods: true

请注意,如果您已经在 Git 仓库中销售 Pods 目录,那么 CocoaPods 缓存将不起作用。

确定 Podfile 路径 #

默认情况下,Travis CI 会假设您的 Podfile 位于仓库的根目录。如果情况并非如此,您可以像这样指定 Podfile 的位置

language: objective-c
podfile: path/to/Podfile

npm 缓存 #

请注意,从 2019 年 7 月起,npm 在 Travis CI 上默认被缓存

要禁用 npm 缓存,请使用

cache:
  npm: false

要显式缓存 npm,请使用

language: node_js

node_js: '6' # or another

cache: npm

这会缓存 $HOME/.npmnode_modules,具体取决于仓库的结构。有关更多详细信息,请参见 Node.js 文档

yarn 缓存 #

对于使用 yarn 进行缓存,请使用

language: node_js

node_js: '6' # or another

cache: yarn

这会缓存 $HOME/.cache/yarn

pip 缓存 #

对于缓存 pip 文件,请使用

language: python

cache: pip

缓存 $HOME/.cache/pip

ccache 缓存 #

如果您使用 ccache,请使用

language: c # or other C/C++ variants

cache: ccache

缓存 $HOME/.ccache 并自动将 /usr/lib/ccache 添加到您的 $PATH

macOS 上的 ccache #

ccache 未安装在 macOS 环境中,但您可以通过添加以下内容来安装它

install:
  - brew install ccache
  - export PATH="/usr/local/opt/ccache/libexec:$PATH"

请注意,这会创建您默认 gcc 和 g++ 编译器的包装器。

R 包缓存 #

对于缓存 R 包,请使用

language: R

cache: packages

这会缓存 $HOME/R/Library,并设置 R_LIB_USER=$HOME/R/Library 环境变量。

Rust Cargo 缓存 #

对于缓存 Cargo 包,请使用

language: rust

cache: cargo

这会缓存 $HOME/.cargo$TRAVIS_BUILD_DIR/target

任意目录 #

您可以通过在您的 .travis.yml 中列出任意目录(例如 Gradle、Maven、Composer 和 npm 缓存目录)来在构建之间缓存这些目录

cache:
  directories:
  - .autoconf
  - $HOME/.m2

如您所见,您可以使用环境变量作为目录路径的一部分。在可能进行变量扩展之后,路径

  • 如果以 / 开头,则为绝对路径。
  • 如果不以 / 开头,则相对于 $TRAVIS_BUILD_DIR

请注意,travis 用户需要对该目录具有写入权限。

不应缓存的内容 #

缓存的目的是使安装特定于语言的依赖项变得轻松快捷,因此,与 Bundler、pip、Composer、npm、Gradle、Maven 等工具相关的任何内容都应存储在缓存中。

大型文件安装速度快,但下载速度慢,无法从缓存中受益,因为它们从缓存中下载的时间与从原始来源下载的时间一样长。

  • Android SDK
  • Debian 包
  • JDK 包
  • 编译后的二进制文件
  • Docker 镜像

Docker 镜像不会被缓存,因为我们为每次构建都提供一个全新的虚拟机。

获取和存储缓存 #

  • Travis CI 会为每个构建获取缓存,包括分支和拉取请求。
  • 每个分支和语言版本/编译器版本/JDK 版本/Gemfile 位置等都只有一个缓存。有关详细信息,请参见 缓存和构建矩阵
  • 如果分支没有自己的缓存,Travis CI 会获取默认分支缓存。
  • 只有对缓存目录的正常推送进行的修改才会被存储。

拉取请求构建和缓存 #

拉取请求构建按以下顺序检查缓存位置,使用第一个找到的缓存位置

  • 拉取请求缓存。
  • 拉取请求目标分支缓存。
  • 存储库默认分支缓存。

如果先前位置中都不包含有效缓存,则构建将继续进行,但不会使用缓存。

在第一个拉取请求构建运行后,它会创建一个新的拉取请求缓存。

有关拉取请求缓存的一些重要事项

  • 如果存储库的“推送分支构建”设置为“OFF”,则目标分支和主分支永远不会被缓存。
  • 如果主分支上的缓存很旧,例如在大部分工作都在分支上进行的工作流中,则缓存的用处会更小。
  • 如果拉取请求正在使用缓存,但您不希望它使用缓存,则需要清除拉取请求缓存和目标分支的缓存。

before_cache 阶段 #

使用缓存时,在上传新的缓存存档之前运行命令可能很有用。

例如,依赖关系管理实用程序可能将日志文件写入您正在缓存的目录,而您不希望它们影响缓存。使用 before_cache 阶段删除日志文件

cache:
  directories:
    - $HOME/.cache/pip
before_cache:
  - rm -f $HOME/.cache/pip/log/debug.log

此阶段的失败不会将作业标记为失败。

清除缓存 #

有时您会在缓存的目录之一中存储不良数据而弄坏了缓存,或者当语言运行时发生变化时,您的缓存可能变得无效。

使用以下方法之一访问您的缓存,并在必要时删除它

缓存过期 #

目前,https://app.travis-ci.com 上存储库的缓存存档在 45 天后过期。这意味着如果特定缓存存档在过期延迟后没有更改,它将被删除。

构建配置参考 #

您可以在我们的 Travis CI 构建配置参考 中找到有关 缓存 的构建配置格式的更多信息。

配置 #

启用多个缓存功能 #

当您想要启用多个缓存功能且语言支持它们时,您可以将它们列为数组

language: objective-c
cache:
- bundler
- cocoapods

这在缓存 任意目录 或任何指令不受语言支持时不起作用。

如果您想将它与其他缓存模式结合使用,请使用哈希映射。以下是一个缓存 Node.js 模块的 Ruby 存储库示例

language: ruby
cache:
  bundler: true
  directories:
  - node_modules # NPM packages

这是另一个示例;一个缓存 cargo 和 Ruby gem 的 Rust 存储库

language: rust
cache:
  cargo: true
  directories:
    - vendor/bundle
install:
  - bundle install --deployment # to cache vendor/bundle

显式禁用缓存 #

您可以通过在 .travis.yml 中将 cache 选项设置为 false 来显式禁用所有缓存

cache: false

也可以禁用单个缓存模式

language: objective-c
cache:
  bundler: false
  cocoapods: true

设置超时 #

缓存默认情况下具有 3 分钟的超时时间。超时是为了防止可能导致构建卡死的任何问题。此类问题可能是由工作服务器和 S3 之间的网络问题或缓存太大而无法及时打包和上传引起的。但是,在某些情况下,您可能希望设置更长的超时时间,尤其是在您需要缓存大量数据时。为了更改超时时间,您可以使用 timeout 属性,并以秒为单位指定所需的时间

cache:
  timeout: 1000

缓存和构建矩阵 #

当您在 构建矩阵 中有多个作业时,每个作业的某些特性将用于识别每个作业应使用的缓存。

这些因素是

  1. 操作系统名称(目前,linuxosxwindows
  2. 操作系统发行版(对于 Linux,focalbionicxenialtrustyprecise
  3. macOS 镜像名称(例如,xcode7.2
  4. .travis.yml 或“设置”面板中设置的可见环境变量的名称和值
  5. 语言运行时版本(如果适用,则针对 language 键中指定的语言)
  6. 对于支持 Bundler 的作业,使用 Gemfile 的名称

如果这些特性在构建矩阵中的多个作业中共享,它们将在网络上共享相同的 URL。这可能会破坏缓存,或者缓存中可能包含无法在使用它的所有作业中使用的文件。在这种情况下,我们建议您在每个作业中添加一个公用环境变量名称以创建唯一的缓存条目

CACHE_NAME=JOB1

请注意,在考虑环境变量时,值必须完全匹配,包括空格。例如,使用

env:
  - FOO=1 BAR=2
  - FOO=1  BAR=2
  - BAR=2 FOO=1

三个作业中的每一个都将使用自己的缓存。

缓存和读取权限 #

在缓存 自定义文件和目录 时,请确保您指定的位置对用户可读可写。

如果不是,则缓存实用程序在调用 tar 创建缓存存档时会报告错误。

例如

FAILED: tar -Pzcf /Users/travis/.casher/push.tgz /path/to/unreadable/directory

tar: /path/to/unreadable/directory: Cannot stat: No such file or directory

缓存是如何工作的? #

Travis CI 会保存配置中列出的所有目录的存档,并将其上传到存储提供商,使用安全且受保护的 URL,确保上传存档的安全性隐私。

请注意,这使得我们的缓存不是网络本地的,它仍然受限于网络带宽和 DNS 解析。这会影响您可以在缓存中存储的内容以及应该存储的内容。如果您在缓存中存储的存档大小超过几百兆字节,则不太可能看到很大的速度提升。

在构建之前,我们会检查是否存在缓存存档。如果存在,我们会将其下载并解压缩到指定的位置。

在构建之后,我们会检查目录中的更改,使用这些更改创建新的存档,并将其上传到远程存储。

上传目前是构建周期的一部分,但我们正在研究如何将它移到构建之外,以便更快地提供构建反馈。