GitHub Actions更新yarn.lock后构建失败的原因及解决方法
问题描述
使用如下GitHub Actions流程:
当Dependabot更新yarn.lock后构建失败,错误信息如下:
Run yarn build Usage Error: The project in /home/runner/work/na-lab-client/na-lab-client/package.json doesn't seem to have been installed - running an install there might help $ yarn run [--inspect] [--inspect-brk] [-T,--top-level] [-B,--binaries-only] <scriptName> ... Error: Process completed with exit code 1.
疑问
- 该错误为何发生?
- 如何解决该错误?
尝试情况:
不使用依赖缓存时,
Build任务自行安装依赖即可运行成功;部署环境中构建也能成功。
我的ci.yml代码如下:
name: CI on: pull_request: branches: [main] push: branches: [main] env: CACHED_DEPENDENCY_PATHS: ${{ github.workspace }}/.yarn/unplugged CACHED_BUILD_PATHS: ${{ github.workspace }}/.next BUILD_CACHE_KEY: ${{ github.sha }} DEFAULT_NODE_VERSION: '16' jobs: job_install_dependencies: name: Install Dependencies runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Check out current commit (${{ github.sha }}) uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v2 with: node-version: ${{ env.DEFAULT_NODE_VERSION }} - name: Compute dependency cache key id: compute_lockfile_hash run: echo "::set-output name=hash::${{ hashFiles('yarn.lock') }}" - name: Check dependency cache uses: actions/cache@v3 id: cache_dependencies with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ steps.compute_lockfile_hash.outputs.hash }} - name: Install dependencies if: steps.cache_dependencies.outputs.cache-hit == '' run: yarn install --immutable outputs: dependency_cache_key: ${{ steps.compute_lockfile_hash.outputs.hash }} job_build: name: Build needs: [job_install_dependencies] runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Check out current commit (${{ github.sha }}) uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v2 with: node-version: ${{ env.DEFAULT_NODE_VERSION }} - name: Check dependency cache uses: actions/cache@v3 with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }} - name: Check build cache uses: actions/cache@v3 id: cache_built_packages with: path: ${{ env.CACHED_BUILD_PATHS }} key: ${{ env.BUILD_CACHE_KEY }} - name: Build if: steps.cache_built_packages.outputs.cache-hit == '' run: yarn build outputs: dependency_cache_key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }} job_codechecks: if: github.event_name != 'push' runs-on: ubuntu-latest name: Run codechecks needs: [job_install_dependencies] steps: - name: Check out current commit (${{ github.sha }}) uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v2 with: node-version: ${{ env.DEFAULT_NODE_VERSION }} - name: Check dependency cache uses: actions/cache@v3 with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }} - name: Run codechecks run: yarn codechecks env: CC_SECRET: ${{ secrets.CC_SECRET }} job_continuous_integration: runs-on: ubuntu-latest name: Check test & lint needs: [job_install_dependencies] steps: - name: Check out current commit (${{ github.sha }}) uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v2 with: node-version: ${{ env.DEFAULT_NODE_VERSION }} - name: Check dependency cache uses: actions/cache@v3 with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }} - name: Check Lint if: github.event_name != 'push' run: yarn lint - name: Check Stylelint if: github.event_name != 'push' run: yarn lint:style - name: Check Unit Test if: github.event_name != 'push' run: yarn test job_codecov_test_coverage: name: Set codecov unit test coverage runs-on: ubuntu-latest needs: [job_install_dependencies] steps: - name: Check out current commit (${{ github.sha }}) uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v2 with: node-version: ${{ env.DEFAULT_NODE_VERSION }} - name: Check dependency cache uses: actions/cache@v3 with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }} - name: Create Unit Test Coverage run: yarn test:coverage - name: Set unit test coverage uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true job_e2e_test: timeout-minutes: 60 name: Check e2e test runs-on: ubuntu-latest needs: [job_install_dependencies] steps: - name: Check out current commit (${{ github.sha }}) uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v2 with: node-version: ${{ env.DEFAULT_NODE_VERSION }} - name: Check dependency cache uses: actions/cache@v3 with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ needs.job_install_dependencies.outputs.dependency_cache_key }} - name: Install Playwright Browsers run: yarn playwright install --with-deps - name: Run Playwright tests run: yarn test:e2e - name: Report playwright tests uses: actions/upload-artifact@v3 if: always() with: name: playwright-report path: playwright-report/ retention-days: 30 job_nextjs_bundle_analysis: name: Nextjs bundle analysis runs-on: ubuntu-latest needs: [job_build] steps: - name: Check out current commit (${{ github.sha }}) uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v2 with: node-version: ${{ env.DEFAULT_NODE_VERSION }} - name: Check dependency cache uses: actions/cache@v3 with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} key: ${{ needs.job_build.outputs.dependency_cache_key }} - name: Check build cache uses: actions/cache@v3 with: path: ${{ env.CACHED_BUILD_PATHS }} key: ${{ env.BUILD_CACHE_KEY }} - name: Analyze bundle sizes uses: transferwise/actions-next-bundle-analyzer@master with: workflow-id: ci.yml base-branch: main env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
问题解答
问题1:错误原因
- 缓存路径不完整:当前仅缓存
.yarn/unplugged目录,但使用--immutable的Yarn Berry(Yarn 3+)运行yarn build需要.yarn/cache、.yarn/install-state.gz、.pnp.cjs等关键文件,这些文件缺失会让Yarn判定依赖未完成安装。 - 跨Job缓存一致性问题:
job_install_dependencies安装依赖后,未缓存全部必要文件,导致后续job_build拉取缓存后缺少依赖安装状态标记,Yarn无法识别依赖已就绪。 - Dependabot更新后缓存未触发正确安装:虽然
job_install_dependencies会在缓存未命中时执行安装,但缓存路径不全导致即使缓存命中,依赖状态也不完整,后续Job无法正常使用。
问题2:解决方法
方案1:修正缓存路径,包含Yarn Berry全部关键文件
更新环境变量CACHED_DEPENDENCY_PATHS,覆盖所有Yarn运行必需的依赖相关文件/目录:
env: CACHED_DEPENDENCY_PATHS: | ${{ github.workspace }}/.yarn/cache ${{ github.workspace }}/.yarn/unplugged ${{ github.workspace }}/.yarn/install-state.gz ${{ github.workspace }}/.pnp.cjs
所有使用依赖缓存的Job(job_install_dependencies、job_build等)均使用该更新后的路径。
方案2:在Build Job中添加依赖校验步骤
即使缓存命中,也执行yarn install --immutable校验依赖状态,该命令会快速验证依赖完整性,缺失则自动补充,不重复下载已存在的依赖:
在job_build的Check dependency cache步骤后添加:
- name: Ensure dependencies are installed run: yarn install --immutable
方案3:优化缓存Key生成逻辑(可选)
将yarn.lock和.yarnrc.yml(若存在)的哈希共同作为缓存Key,避免因Yarn配置变更导致缓存不匹配:
- name: Compute dependency cache key id: compute_lockfile_hash run: echo "::set-output name=hash::${{ hashFiles('yarn.lock', '.yarnrc.yml') }}"
方案4:移除跨Job缓存,每个Job自行处理依赖(简单直接)
如果跨Job缓存维护成本过高,可删除job_install_dependencies,在每个需要依赖的Job中直接执行yarn install --immutable,虽增加少量执行时间,但能彻底避免缓存一致性问题。
内容的提问来源于stack exchange,提问作者Hyesung Oh
相关产品推荐
相关产品推荐

