如何复用Gradle编译缓存加速GitHub Actions多模块项目测试?
问题解决:Gradle在GitHub Actions中未复用编译缓存的方案
核心原因
- 文件元数据丢失:GitHub Actions上传/下载工件时,部分文件的修改时间、权限被改变,Gradle依赖这些元数据判断任务是否
UP-TO-DATE,一旦元数据变更就会触发重新编译。 - 缓存与工件冲突:同时用
actions/cache恢复~/.gradle和工件恢复项目目录,会导致项目级构建状态(根目录.gradle)与全局缓存不一致,Gradle无法识别之前的编译结果。 - 环境不一致:如果
compile和testJob使用不同操作系统,路径分隔符、文件系统差异会导致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
相关产品推荐
相关产品推荐

