You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何复用Gradle编译缓存加速GitHub Actions多模块项目测试?

问题解决:Gradle在GitHub Actions中未复用编译缓存的方案

核心原因

  1. 文件元数据丢失:GitHub Actions上传/下载工件时,部分文件的修改时间、权限被改变,Gradle依赖这些元数据判断任务是否UP-TO-DATE,一旦元数据变更就会触发重新编译。
  2. 缓存与工件冲突:同时用actions/cache恢复~/.gradle和工件恢复项目目录,会导致项目级构建状态(根目录.gradle)与全局缓存不一致,Gradle无法识别之前的编译结果。
  3. 环境不一致:如果compile和test Job使用不同操作系统,路径分隔符、文件系统差异会导致Gradle构建状态失效。

解决方案一:修复跨Job的状态传递

步骤1:统一Job环境

确保compile和test Job使用同一操作系统(比如ubuntu-latest),避免环境差异引发的问题。

步骤2:拆分缓存与工件的职责

  • compile Job:仅缓存全局Gradle依赖(~/.gradle/caches、~/.gradle/wrapper),不缓存项目级.gradle目录;编译完成后,将整个项目目录(含所有模块build、根.gradle、配置文件)上传为工件。
  • test Job:直接下载工件覆盖当前目录,再恢复全局依赖缓存,无需重新拉取代码或处理项目级缓存。

示例配置

compile Job

compile:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - name: 配置JDK21
      uses: actions/setup-java@v4
      with:
        java-version: '21'
        distribution: 'temurin'
    - name: 缓存Gradle依赖
      uses: actions/cache@v4
      with:
        path: |
          ~/.gradle/caches
          ~/.gradle/wrapper
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
        restore-keys: |
          ${{ runner.os }}-gradle-
    - name: 编译所有模块
      run: ./gradlew testClasses --no-daemon
    - name: 上传编译后的项目
      uses: actions/upload-artifact@v4
      with:
        name: compiled-project
        path: .
        retention-days: 1

test Job

test:
  needs: [compile, random]
  runs-on: ubuntu-latest
  strategy:
    matrix:
      target: ${{ fromJson(needs.random.outputs.modules) }}
  steps:
    - name: 下载编译后的项目
      uses: actions/download-artifact@v4
      with:
        name: compiled-project
        path: .
    - name: 配置JDK21
      uses: actions/setup-java@v4
      with:
        java-version: '21'
        distribution: 'temurin'
    - name: 恢复Gradle依赖缓存
      uses: actions/cache@v4
      with:
        path: |
          ~/.gradle/caches
          ~/.gradle/wrapper
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
        restore-keys: |
          ${{ runner.os }}-gradle-
    - name: 运行模块测试
      run: ./gradlew ":${{ matrix.target }}:test" --continue --stacktrace --no-daemon

解决方案二:简化工作流,去掉独立compile Job

如果模块间依赖不复杂,直接在test Job中编译目标模块的必要依赖,利用Gradle增量构建和缓存,省去跨Job传递工件的开销:

test:
  needs: random
  runs-on: ubuntu-latest
  strategy:
    matrix:
      target: ${{ fromJson(needs.random.outputs.modules) }}
  steps:
    - uses: actions/checkout@v4
    - name: 配置JDK21
      uses: actions/setup-java@v4
      with:
        java-version: '21'
        distribution: 'temurin'
    - name: 缓存Gradle依赖与构建状态
      uses: actions/cache@v4
      with:
        path: |
          ~/.gradle/caches
          ~/.gradle/wrapper
          **/.gradle
          **/build
        key: ${{ runner.os }}-gradle-${{ github.sha }}-${{ matrix.target }}
        restore-keys: |
          ${{ runner.os }}-gradle-${{ github.sha }}-
          ${{ runner.os }}-gradle-
    - name: 运行模块测试(自动编译依赖)
      run: ./gradlew ":${{ matrix.target }}:test" --continue --stacktrace --no-daemon

关键注意点

  • 加--no-daemon:避免GitHub Actions临时runner中的Gradle守护进程出现状态混乱。
  • 缓存key加入github.sha:确保每个代码提交的缓存独立,旧缓存不会干扰新构建。
  • 依赖复杂优先选方案一:能完整传递所有依赖模块的编译状态,避免重复编译。

内容的提问来源于stack exchange,提问作者SoT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 03:08:11