如何在 GitHub Actions 中缓存纱线包

Posted

技术标签:

【中文标题】如何在 GitHub Actions 中缓存纱线包【英文标题】:How to cache yarn packages in GitHub Actions 【发布时间】:2020-07-15 12:41:47 【问题描述】:

我正在使用 GitHub Actions 构建我的 TypeScript 项目。 每次我运行操作时,我都会等待 3 分钟以安装所有依赖项。

有没有办法缓存纱线依赖,所以构建时间会更快?

我试过这个:

     - name: Get yarn cache directory path
       id: yarn-cache-dir-path
       run: echo "::set-output name=dir::$(yarn cache dir)"

     - uses: actions/cache@v1
       id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
       with:
         path: $ steps.yarn-cache-dir-path.outputs.dir 
         key: $ runner.os -yarn-$ hashFiles('**/yarn.lock') 
         restore-keys: |
           $ runner.os -yarn-

    - name: Install yarn
      run: npm install -g yarn

    - name: Install project dependencies
      run: yarn

但构建时间仍然相同。

【问题讨论】:

【参考方案1】:
     - name: Get yarn cache directory path
       id: yarn-cache-dir-path
       run: echo "::set-output name=dir::$(yarn cache dir)"

     - uses: actions/cache@v1
       id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
       with:
         path: $ steps.yarn-cache-dir-path.outputs.dir 
         key: $ runner.os -yarn-$ hashFiles('**/yarn.lock') 
         restore-keys: |
           $ runner.os -yarn-

上面的缓存代码只缓存和恢复yarn缓存目录,不缓存node_modules目录。因此,如果您使用此代码(@Edric 的回答),

- name: Install project dependencies
  if: steps.yarn-cache.outputs.cache-hit != 'true' # Over here!
  run: yarn

node_modules 未创建,您将收到未找到依赖项的错误。

相反,你可以使用这个:

- name: Install project dependencies
  run: yarn --prefer-offline

这告诉yarn 始终运行,但尽可能使用缓存下载(在上述缓存目录中),而不是从服务器下载。


您也可以直接缓存node_modules目录,当缓存可用时跳过安装步骤。这实际上是不推荐的(见 cmets)。示例:

    - name: Get yarn cache directory path
      id: yarn-cache-dir-path
      run: echo "::set-output name=dir::$(yarn cache dir)"
    - name: Cache yarn cache
      uses: actions/cache@v2
      id: cache-yarn-cache
      with:
        path: $ steps.yarn-cache-dir-path.outputs.dir 
        key: $ runner.os -yarn-$ hashFiles('**/yarn.lock') 
        restore-keys: |
          $ runner.os -yarn-
    - name: Cache node_modules
      id: cache-node-modules
      uses: actions/cache@v2
      with:
        path: node_modules
        key: $ runner.os -$ matrix.node-version -nodemodules-$ hashFiles('**/yarn.lock') 
        restore-keys: |
          $ runner.os -$ matrix.node-version -nodemodules-
    - run: yarn
      if: |
        steps.cache-yarn-cache.outputs.cache-hit != 'true' ||
        steps.cache-node-modules.outputs.cache-hit != 'true'

【讨论】:

另外,yarn 本身几乎能够检测依赖项是否必须更新。例如,当第二次在本地运行yarn install 时,它会在不到 1 秒的时间内完成。我认为在任何情况下都不应跳过yarn 步骤。 谢谢你们的cmets,伙计们!我完全同意。我已经更新了答案以使其更清晰。 现在我们还检查了最后一个代码示例中缓存的 yarn.lock,其他任何人都可以澄清“不推荐”的适合使用吗?我已经测试了添加/删除软件包,并且似乎对我来说可靠地捕捉到了这些差异。谢谢 为什么不推荐缓存node_modules?? @Penguin @racemic 你可以缓存node_modules,它会工作得很好。但是node_modules 可能已损坏。每次重新运行yarn 并让yarn 决定是否从缓存中获取文件会更安全(假设yarn 在使用之前会尝试验证缓存)。【参考方案2】:

我不知道为什么其他答案没有提到使用内置的actions/setup-node@v2缓存npm和yarn依赖项的简单方法,所以我只添加文档,这更简单。

正如github package 的readme 所说:

steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
  with:
    node-version: '14'
    cache: 'npm' # or yarn
- run: npm install
- run: npm test

【讨论】:

其他答案要么不使用 setup-node 要么使用 v1。缓存是在 v2 中添加的。这应该是现在公认的答案。【参考方案3】:

正如缓存步骤的 id 字段旁边的评论中所述:

使用它来检查cache-hit (steps.yarn-cache.outputs.cache-hit != 'true')

您缺少确定是否应运行该步骤的条件 if 属性:

- name: Install yarn
  run: npm install -g yarn

- name: Install project dependencies
  if: steps.yarn-cache.outputs.cache-hit != 'true' # Over here!
  run: yarn

附:您可能应该使用另外为您设置 Yarn 的 Setup NodeJS GitHub Action:

- uses: actions/setup-node@v1
  with:
    node-version: '10.x' # The version spec of the version to use.

有关有效输入的完整列表,请参阅action.yml file。


编辑:事实证明,Yarn 包含在 software installed on the GitHub-hosted Ubuntu 18.04.4 LTS (ubuntu-latest/ubuntu-18.04) runner 列表中,因此无需包含全局安装 Yarn 的步骤。

【讨论】:

这是我的配置:pastebin.com/CCgFjEW0我已经在使用actions/setup-node@v1,所以我不需要安装yarn? 遗憾的是,条件“如果”没有帮助。 对于第一条评论,请参阅我对答案所做的编辑。至于第二条评论,您能否指出 如何 条件 if 属性没有帮助? 谢谢,这行得通。但是在运行笑话时操作失败。 jest --config=jest.config.js /bin/sh: 1: jest: not found error Command failed with exit code 127 另外,禁用缓存的操作成功。【参考方案4】:

这是专为 Yarn 设计的 1 行缓存:https://github.com/c-hive/gha-yarn-cache

- uses: actions/checkout@v2
- name: Setup Node.js
  uses: actions/setup-node@v1
  with:
    node-version: 12.x

- uses: c-hive/gha-yarn-cache@v1

- name: Install JS dependencies
  run: yarn install

- name: Test
  run: yarn test

它按照 GitHub 的建议进行缓存。支持 Yarn v1 和 v2。

【讨论】:

对于那些投反对票的人,请添加一些 cmets 为什么你投反对票:) 我猜这是现在内置的:github.com/actions/cache/blob/main/examples.md#node---yarn 在示例中这仍然是 1-liner vs 10 行。 是的,我也不认为这应该被否决。问题是“如何在 GitHub Actions 中缓存纱线包”,它回答了它。我相信其他答案提供了更多的深度,但这对于寻求快速解决方案的人来说真的很有帮助。出于好奇,您是否测试过这一班轮的性能?它是更快、更慢还是和更长的一样? 它在后台执行相同的命令。

以上是关于如何在 GitHub Actions 中缓存纱线包的主要内容,如果未能解决你的问题,请参考以下文章

在 GitHub Actions 工作流程中缓存 APT 包

如何在 Github Actions 工作流中从 Github 包访问 Maven 依赖项?

在 Windows 上的 GitHub Actions 中缓存依赖项

在 github 上的 Dependabot 警报后升级特定包纱线锁

Github 操作似乎无法在带有纱线工作区和 lerna 的 monorepo 中找到私有包

在 GitHub Actions 中缓存 node_modules