常见构建问题

我的测试坏了,但昨天还在工作 #

当测试在没有任何重大代码更改的情况下突然中断时,一个非常常见的原因是上游依赖项发生了更改。

这可能是 Ubuntu 软件包或项目的任何语言依赖项,例如 RubyGems、NPM 软件包、Pip、Composer 等。

要确定是否为这种情况

  • 重新启动一个曾经成功的构建,例如最后一个已知的成功构建。如果该构建也突然失败,则很有可能依赖项已更新并导致中断。

  • 检查构建日志中的依赖项列表,通常输出包括版本,并查看是否有任何更改。

有时,这也可能是由更新的间接依赖项引起的。

  • 在确定更新了哪个依赖项后,将其锁定到最后一个已知版本。

  • 此外,我们定期更新构建环境,这会引入更新版本的语言和正在运行的服务。

我的构建脚本在没有任何错误的情况下被终止 #

有时,您会看到构建脚本导致错误,并且日志中的消息类似于 Killed

这通常是由于脚本或其运行的程序之一耗尽了构建沙箱中可用的内存,目前为 3GB。此外,还有两个内核可用,突发使用。

根据所使用的工具,这可能是由以下几个原因引起的

  • Ruby 测试套件消耗了过多的内存
  • 使用过多进程或线程(例如使用 parallel_test gem)并行运行的测试
  • 例如,包含大量模板的文件,g++ 需要过多的内存才能编译。

并行进程 #

对于同时运行的并行进程,请尝试减少数量。两个到四个进程应该没问题,超过此数量,资源可能会耗尽。

Ruby 进程 #

对于 Ruby 进程,请检查本地机器上的内存消耗,它可能会显示类似的原因。它可能是由内存泄漏或垃圾收集器的自定义设置引起的,例如尽可能延迟扫描。降低这些数字应该会有所帮助。

我的构建意外失败 #

构建意外失败的一个可能原因是在 .travis.yml直接调用 set -e(也称为 set errexit),或 source 一个执行此操作的脚本。这会导致脚本中任何导致非零返回状态的错误立即停止并使构建失败。

请注意,在外部脚本中使用 set -e 不会导致此问题,因为 errexit 仅在外部脚本中有效。

另请参阅 复杂构建步骤

另一个原因可能是存储库设置克隆或导入设置为 OFF. 在这种情况下,不会共享存储库中的任何信息,并且某些使用存储库之间私有依赖项的构建可能会中断。如果您希望避免所有存储库停止共享依赖项的情况,请转到存储库设置并明确将克隆或导入设置为 ON. 在这种情况下,您的构建将照常运行。

语言解释器(Ruby、Python、PHP、Node.js 等)的段错误 #

如果您的构建由于语言解释器中意外的段错误而失败,这可能是由扩展代码(gem、模块等)的损坏或无效缓存引起的。这可能发生在任何解释型语言中,例如 Ruby、Python、PHP、Node.js 等。

解决此问题的方法是

  • 清除缓存或
  • 从 .travis.yml 中删除缓存密钥(您可以在后续提交中将其添加回来)。

Ruby:即使构建失败,RSpec 也返回 0 #

在某些情况下,当运行 rake rspec 甚至直接运行 rspec 时,即使构建失败,命令也会返回 0。这通常是由于某些 RubyGem 覆盖了另一个 RubyGem 的 at_exit 处理程序,在本例中为 RSpec 的处理程序。

解决方法是在代码中安装此 at_exit 处理程序,如 本文 中所述。

if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9"
  module Kernel
    alias :__at_exit :at_exit
    def at_exit(&block)
      __at_exit do
        exit_status = $!.status if $!.is_a?(SystemExit)
        block.call
        exit exit_status if exit_status
      end
    end
  end
end

如果项目使用 Code Climate 集成 或 Simplecov,则此问题也可能出现在 Simplecov 的 0.8 分支中。解决方法是降级到最后一个 0.7 版本,直到问题得到解决。

Capybara:我收到有关找不到元素的错误 #

在涉及 JavaScript 的情况下,您偶尔会看到指示元素丢失、按钮、链接或某些其他资源(由异步 JavaScript 更新或创建)的错误。

这可能表明用于 Selenium 或其驱动程序之一的超时设置过低。

Capybara 有一个超时设置,您可以将其增加到至少 15 秒

Capybara.default_max_wait_time = 15

Poltergeist 有其自己的超时设置

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, timeout: 15)
end

如果在最初增加超时后仍然看到超时,请将其设置为更高的值以进行一次测试运行。如果错误仍然存在,则页面上可能存在更深层次的问题,例如编译资产。

Ruby:安装 debugger_ruby-core-source 库失败 #

不幸的是,这个 Ruby 库在 Ruby 的补丁级别版本中也有断裂的历史。它通常是 linecache 或其他 Ruby 调试库的依赖项。

我们建议将这些库移动到 Gemfile 中的单独组,然后在 Travis CI 上安装 RubyGems 而无需此组。由于这些库仅对本地开发有用,因此您甚至可以在构建的安装过程中获得加速。

# Gemfile
group :debug do
  gem 'debugger'
  gem 'debugger-linecache'
  gem 'rblineprof'
end

# .travis.yml
bundler_args: --without development debug

Ruby:日志 10 分钟无输出后,测试冻结并取消 #

在某些情况下,使用timecop gem 可能会导致看似零星的“冻结”,这是由于Timecop.returnTimecop.freezeTimecop.travel 的调用顺序问题引起的。例如,如果使用 RSpec,请确保配置 Timecop.return 在所有示例之后运行。

# in, e.g. spec/spec_helper.rb
RSpec.configure do |c|
  c.after :all do
    Timecop.return
  end
end

Mac:macOS Mavericks (10.9) 代码签名错误 #

在 Mavericks 中,代码签名和钥匙串应用程序发生了很大变化。

问题的迹象可能是错误消息,指出找不到身份,并且“不允许用户交互”。

钥匙串必须标记为默认钥匙串,必须显式解锁,并且构建需要确保在构建到达关键点之前钥匙串没有被锁定。以下命令集可以解决此问题

KEY_CHAIN=ios-build.keychain
security create-keychain -p travis $KEY_CHAIN
# Make the keychain the default so identities are found
security default-keychain -s $KEY_CHAIN
# Unlock the keychain
security unlock-keychain -p travis $KEY_CHAIN
# Set keychain locking timeout to 3600 seconds
security set-keychain-settings -t 3600 -u $KEY_CHAIN

Mac:macOS Sierra (10.12) 代码签名错误 #

随着 macOS Sierra (10.12) 在我们的基础设施中推出,我们发现构建作业在构建过程的代码签名步骤中挂起。以下是一些关于如何识别此问题并修复它的信息。

如果您的 .travis.yml 文件中的 osx_imagexcode8.3 或更高版本,则您的构建正在 macOS Sierra (10.12) 上运行。请参阅macOS 构建环境文档,了解每个映像关联的 macOS 版本。

构建日志中的以下行可能表示此问题的发生

示例:签名

▸ Signing /Users/travis/Library/Developer/Xcode/DerivedData/PresenterKit-ggzwtlifkopsnbffbqrmtydtmafv/Build/Intermediates/CodeCoverage/Products/Debug-iphonesimulator/project.xctest

No output has been received in the last 10m0s, this potentially indicates a stalled build or something wrong with the build itself.
Check the details on how to adjust your build configuration on: https://docs.travis-ci.cn/user/common-build-problems/#build-times-out-because-no-output-was-received

The build has been terminated

示例:嵌入 Pods 框架

▸ Running script '[CP] Embed Pods Frameworks'

No output has been received in the last 10m0s, this potentially indicates a stalled build or something wrong with the build itself.
Check the details on how to adjust your build configuration on: https://docs.travis-ci.cn/user/common-build-problems/#build-times-out-because-no-output-was-received

The build has been terminated

要解决此问题,您需要在导入证书之后添加以下命令

security set-key-partition-list -S apple-tool:,apple: -s -k keychainPass keychainName

其中

  • keychainPass 是钥匙串的密码
  • keychainName 是钥匙串的名称

以下是一个在上下文中放置命令的示例

# Create the keychain with a password
security create-keychain -p travis ios-build.keychain

# Make the custom keychain default, so xcodebuild will use it for signing
security default-keychain -s ios-build.keychain

# Unlock the keychain
security unlock-keychain -p travis ios-build.keychain

# Add certificates to keychain and allow codesign to access them
security import ./Provisioning/certs/apple.cer -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
security import ./Provisioning/certs/distribution.cer -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
security import ./Provisioning/certs/distribution.p12 -k ~/Library/Keychains/ios-build.keychain -P $KEY_PASSWORD -T /usr/bin/codesign

security set-key-partition-list -S apple-tool:,apple: -s -k travis ios-build.keychain

重要:必须创建一个带有密码的钥匙串,才能使命令security set-key-partition-list 工作。

Fastlane #

如果您使用Fastlane 对您的应用程序进行签名(例如,使用Fastlane Match),则需要在您的 Fastfile 中执行类似以下操作

    create_keychain(
      name: ENV["MATCH_KEYCHAIN_NAME"],
      password: ENV["MATCH_PASSWORD"],
      default_keychain: true,
      unlock: true,
      timeout: 3600,
      add_to_search_list: true
    )

    match(
      type: "adhoc",
      keychain_name: ENV["MATCH_KEYCHAIN_NAME"],
      keychain_password: ENV["MATCH_PASSWORD"],
      readonly: true
    )

如果您直接使用 import_certificate 导入证书,则必须将钥匙串的密码作为参数传递,例如:

keychain_name = "ios-build.keychain"
keychain_password = SecureRandom.base64

create_keychain(
    name: keychain_name,
    password: keychain_password,
    default_keychain: true,
    unlock: true,
    timeout: 3600,
    add_to_search_list: true
)

import_certificate(
    certificate_path: "fastlane/Certificates/dist.p12",
    certificate_password: ENV["KEY_PASSWORD"],
    keychain_name: keychain_name
    keychain_password: keychain_password
)

您还可以在此 GitHub 问题中从此评论开始获得更多详细信息。

Mac:运行 CocoaPods 时出错 #

CocoaPods 的使用目前可能会因几个原因而失败。

需要更新版本的 CocoaPods #

大多数 Pods 现在需要 CocoaPods 0.32.1,但我们仍然预安装了 0.21。如果您看到此错误,请将其添加到您的 .travis.yml

before_install:
  - gem install cocoapods -v '0.32.1'

找不到 CocoaPods #

CocoaPods 目前尚未安装在所有可用的 Ruby 版本上,不幸的是,这意味着在使用默认 Ruby(2.0.0)时会失败。

要解决此问题,您可以按照上述方法手动安装 CocoaPods,或者可以在您的 .travis.yml 中切换到 Ruby 1.9.3,这应该可以正常工作。

rvm: 1.9.3

CocoaPods 出现分段错误而失败 #

在 Ruby 2.0.0 上,CocoaPods 出现过因分段错误而崩溃的情况。

您可以使用 Ruby 1.9.3 来解决此问题,该版本尚未出现这些问题。将此添加到您的 .travis.yml

rvm: 1.9.3

系统:未安装所需的语言包 #

Travis CI 构建环境目前仅安装了 en_US 语言包。如果您遇到类似以下错误:“错误:不支持的区域设置”,则可能需要在测试运行期间安装其他语言包。

可以通过将以下内容添加到您的 .travis.yml 中来实现

before_install:
  - sudo apt-get update && sudo apt-get --reinstall install -qq language-pack-en language-pack-de

以上添加将重新安装 en_US 语言包以及 de_DE 语言包。

如果您在基于容器的基础设施上运行并且无法访问 sudo 命令,请使用 APT 插件安装区域设置。

addons:
  apt:
    packages:
      - language-pack-en
      - language-pack-de

Linux:apt 无法使用 404 错误安装软件包 #

这通常是由旧的软件包数据库引起的,可以通过将以下内容添加到 .travis.yml 中来修复

before_install:
  - sudo apt-get update

Windows:常见构建问题和已知问题 #

有关 Windows 上的常见构建问题、已知问题和解决方法的列表,请访问[Travis CI 社区论坛]。(https://travis-ci.cnmunity/t/current-known-issues-please-read-this-before-posting-a-new-topic/264)。Travis CI 社区论坛 提供了有关客户遇到的问题以及如何解决这些问题的更好可见性。

Travis CI 不会保留构建之间的状态 #

Travis CI 使用虚拟机快照来确保构建之间不保留任何状态。如果您通过向数据存储写入内容、创建文件或通过 apt 安装软件包来修改 CI 环境,则不会影响后续构建。

SSH 无法按预期工作 #

Travis CI 通过 SSH 在隔离的虚拟机中运行所有命令。修改 SSH 会话状态的命令是“粘性”的,并在整个构建过程中持续存在。例如,如果您 cd 到某个目录,则所有后续命令都将从此目录运行。

Git 子模块未正确更新 #

当存储库根目录中存在 .gitmodules 文件时,Travis CI 会自动初始化和更新子模块。

要关闭此功能,请设置

git:
  submodules: false

如果您的项目需要 Git 子模块的特定选项,而 Travis CI 未开箱即用地支持这些选项,请关闭自动集成并使用 before_install 钩子来初始化和更新它们。

例如,要更新嵌套子模块

before_install:
  - git submodule update --init --recursive

Git 无法克隆我的子模块 #

如果您的项目使用 Git 子模块,请确保使用公共 Git URL。例如,在 GitHub 上,不要使用

git@github.com:someuser/somelibrary.git

请使用

https://github.com/someuser/somelibrary.git

否则,Travis CI 构建器将无法克隆您的项目,因为它们没有您的私有 SSH 密钥。

我的构建超时 #

构建可能会超时,这可能发生在依赖项安装期间或构建本身期间,例如,由于某个命令需要较长时间才能运行,同时没有产生任何输出。

我们的构建具有全局超时和基于输出的超时。如果构建 10 分钟内未收到任何输出,则假定它由于未知原因而停滞,随后将被终止。

有时,依赖项的安装可能会超时。Bundler 和 RubyGems 就是一个相关的例子。我们的服务器之间的网络连接有时会影响与 APT、Maven 或其他存储库的连接。

有几种方法可以解决此问题。

安装依赖项时超时 #

如果您在尝试下载依赖项时遇到网络超时,请使用依赖项管理器内置的重试功能,或将安装命令包装在 travis_retry 函数中。

Bundler #

Bundler 默认重试三次,但如果需要增加此数字,请在您的 .travis.yml 中使用以下语法

bundler_args: --retry 5

travis_retry #

对于没有内置重试功能的命令,请使用 travis_retry 函数最多重试三次,如果返回代码非零。

install: travis_retry pip install myawesomepackage

我们的大多数内部构建命令都使用 travis_retry 进行包装,以减少网络超时带来的影响。

请注意,travis_retry 不适用于构建的 deploy 步骤,尽管它适用于其他步骤

构建超时,因为未收到输出 #

当长时间运行的命令或编译步骤定期超过 10 分钟未产生任何输出时,您可以调整构建配置以考虑这一点。

我们构建系统中的 shell 环境提供了一个函数来解决此问题,至少可以延长超过 10 分钟的时间。

如果您的命令超过 10 分钟未产生输出,则可以在其前面加上 travis_wait,这是我们的构建环境导出的一个函数。例如

    install: travis_wait mvn install

生成一个运行 mvn install 的进程。travis_wait 然后每分钟向构建日志写入一行短内容,持续 20 分钟,从而延长命令完成的时间。

如果您预计命令需要超过 20 分钟,请在命令前面加上 travis_wait n,其中 n 是等待时间延长的分钟数。

继续上面的示例,将等待时间延长到 30 分钟

    install: travis_wait 30 mvn install

我们建议谨慎使用 travis_wait,因为过度使用它可能会延长构建时间,而可能存在更深层的问题。如有疑问,请先发送电子邮件给我们,看看是否可以先改进此特定命令。

travis_wait 的限制 #

travis_wait 通过启动一个进程,将其发送到后台,并监视后台进程来工作。如果传递给 travis_wait 的命令不持久,则 travis_wait 不会延长超时时间。

在调试模式下运行构建 #

在私有存储库和已启用此功能的公共存储库中,可以以调试模式运行构建和作业。使用此功能,您可以与构建运行的实时 VM 进行交互。

有关更多信息,请查阅调试 VM 文档

日志长度超出限制 #

每个构建的日志限制为大约 4 MB。当它达到该长度时,构建将终止,您将在构建日志的末尾看到以下消息

The log length has exceeded the limit of 4 Megabytes (this usually means that test suite is raising the same exception over and over).

The build has been terminated.

FTP/SMTP/其他协议无法正常工作 #

由于安全和公平使用方面的基础设施要求,某些协议(例如 FTP 和 SMTP)不受直接支持。最好使用替代的“无状态”协议,例如 HTTPS,但隧道也已知有效,例如在 FTP 的特定情况下使用 SFTP,或为各种协议使用 VPN 连接,例如。

addons:
  apt:
    packages:
    - openvpn

before_install:
- sudo openvpn path/to/conf.ovpn &>>openvpn-client.log &

我推送了一个提交,但找不到其对应的构建 #

Travis CI 收到的构建请求事件列在您仓库的“请求”页面中。您可以在“更多选项”下拉菜单下找到它,然后选择“请求”。

More Options dropdown menu, choosing Requests

每当您的构建处理完毕时,您将看到消息:“构建已成功创建”。

如果您的提交未触发构建,则可能是以下构建请求消息

  • “无法授权构建请求”,通常表示帐户订阅已过期或构建积分已用完。
  • “通过提交消息跳过构建”,此提交包含跳过命令
  • “GitHub payload 缺少合并提交”,请确认您的拉取请求已打开且可合并。您可能在特定分支中存在未解决的冲突。
  • “根据配置排除分支”或“根据配置未包含分支”,请确保您的分支未明确排除未包含在您的.travis.yml文件中。
  • “通过仓库设置禁用构建类型”,请确保您的推送或拉取请求构建仍处于活动状态。
  • “构建配置未创建任何作业。”,请确保.travis.yml文件中的条件能够创建作业。

请注意,当标记超过三个提交时,Travis CI 不会收到 Webhook 事件。因此,如果您执行git push --tags,并且本地存在超过三个标签,而 GitHub 上未知,则 Travis 不会收到任何这些事件的通知,并且不会构建标记的提交。

我的构建中磁盘空间不足 #

大约可用的磁盘空间列在构建环境概述中。

找出特定镜像上可用空间的最佳方法是在构建脚本中运行df -h。如果您在 Ubuntu 构建中需要更多空间,我们建议使用language: minimal,这将引导您到一个预安装工具和语言较少的基镜像。此镜像大约有 ~24GB 的可用空间。

将工件上传到 Sonatype #

当通过nexus-staging-maven-plugin发布到 Sonatype OSS 存储库时,TravisCI 使用的 IP 地址会因我们的NAT 层而发生变化。要解决此问题,请使用stagingProfileId,如本文档中所述

Travis CLI 无法识别我的有效 Github 令牌 #

当使用Travis CLI 工具与 Travis CI 平台交互时,如果收到insufficient_oauth_permissions错误或类似错误,请确保通过--github-token提供的 Github 令牌具有repo范围,如本文档中所述

我的构建中显示重复/未知作业 #

在指定阶段时,用户通常无意中使用语法上正确的 YAML 将隐式作业添加到阶段的作业列表中。

language: c
...
jobs:
  include:
  - stage: Breakfast
  - name: Peanut Butter and Bread
    script: ./brew_hot_coffee.sh

以上定义创建了一个名为Breakfast的阶段和 2 个作业。第一个作业是一个隐式作业,它继承了指定编程语言的所有默认值。在上面的示例中,将使用C的默认值,而第二个作业是Peanut Butter and Bread,这是您明确定义的。

要删除此隐式作业,您需要将以上内容编辑为如下所示

language: c
...
jobs:
  include:
  - stage: Breakfast
    name: Peanut Butter and Bread
    script: ./brew_hot_coffee.sh

这仅在名为Breakfast的阶段下创建了一个作业,即Peanut Butter and Bread,如您所定义的。需要注意的是,在 YAML 中,-符号用于创建项目列表,而前面的示例创建了两个项目的列表,而您实际上想要的是一个。您可以在如何定义构建阶段和官方文档中阅读有关 YAML 列表语法的更多信息。

Node:脚本在依赖项安装之前执行会导致构建失败 #

在向 NodeJS 构建添加自定义设置说明时,请将其添加到before_script阶段,而不是在依赖项安装之前。 before_script阶段是在添加自定义设置脚本的最安全的地方。此问题的一些症状包括由于添加了新的依赖项而导致以前成功的构建突然失败。

Node:NPM/YARN 抛出Error: connect ENETUNREACH或构建在安装阶段挂起,即 NodeJs 16+ 版本在 LXD 镜像(ppc64le、arm64 和 s390x)上执行npm installyarn install #

这似乎是一个已知的错误,详细信息可以在 https://github.com/npm/cli/issues/4163 中查看。添加以下内容以解决此问题

env:
  global:
    - NODE_OPTIONS="--dns-result-order=ipv4first"