diff --git a/packages/build-tools/src/builders/__tests__/android.test.ts b/packages/build-tools/src/builders/__tests__/android.test.ts index b6c706d601..611467c293 100644 --- a/packages/build-tools/src/builders/__tests__/android.test.ts +++ b/packages/build-tools/src/builders/__tests__/android.test.ts @@ -13,6 +13,10 @@ import { injectConfigureVersionGradleConfig, injectCredentialsGradleConfig, } from '../../steps/utils/android/gradleConfig'; +import { + logGradleCacheEnv, + restoreGradleCacheAsync, +} from '../../steps/functions/restoreBuildCache'; jest.mock('../common', () => ({ runBuilderWithHooksAsync: jest.fn(async (ctx, buildFn) => { @@ -41,10 +45,13 @@ jest.mock('../../common/setup', () => ({ })); jest.mock('../../steps/functions/restoreBuildCache', () => ({ cacheStatsAsync: jest.fn(), + logGradleCacheEnv: jest.fn(), restoreCcacheAsync: jest.fn(), + restoreGradleCacheAsync: jest.fn(async () => ({ env: {} })), })); jest.mock('../../steps/functions/saveBuildCache', () => ({ saveCcacheAsync: jest.fn(), + saveGradleCacheAsync: jest.fn(), })); jest.mock('../../steps/utils/android/gradleConfig', () => ({ ...jest.requireActual('../../steps/utils/android/gradleConfig'), @@ -145,6 +152,30 @@ describe(androidBuilder, () => { expect(injectConfigureVersionGradleConfig).not.toHaveBeenCalled(); }); + it('logs Gradle cache environment variables returned by restoreGradleCacheAsync', async () => { + jest.mocked(restoreGradleCacheAsync).mockResolvedValueOnce({ + env: { + 'ORG_GRADLE_PROJECT_org.gradle.caching': 'true', + }, + }); + const ctx = new BuildContext(createTestAndroidJob(), { + workingdir: '/workingdir', + logBuffer: { getLogs: () => [], getPhaseLogs: () => [] }, + logger: createMockLogger(), + env: { + EAS_BUILD_RUNNER: 'eas-build', + __API_SERVER_URL: 'http://api.expo.test', + }, + uploadArtifact: jest.fn(), + }); + + await androidBuilder(ctx); + + expect(logGradleCacheEnv).toHaveBeenCalledWith(expect.anything(), { + 'ORG_GRADLE_PROJECT_org.gradle.caching': 'true', + }); + }); + it('marks the configure Android version phase as warning for legacy eas-build.gradle', async () => { const job: Android.Job = { ...createTestAndroidJob(), diff --git a/packages/build-tools/src/builders/android.ts b/packages/build-tools/src/builders/android.ts index 6ccff6ca09..bf91763486 100644 --- a/packages/build-tools/src/builders/android.ts +++ b/packages/build-tools/src/builders/android.ts @@ -18,6 +18,7 @@ import { setupAsync } from '../common/setup'; import { Artifacts, BuildContext, SkipNativeBuildError } from '../context'; import { cacheStatsAsync, + logGradleCacheEnv, restoreCcacheAsync, restoreGradleCacheAsync, } from '../steps/functions/restoreBuildCache'; @@ -88,12 +89,16 @@ async function buildAsync(ctx: BuildContext): Promise { env: ctx.env, secrets: ctx.job.secrets, }); - await restoreGradleCacheAsync({ + const { env } = await restoreGradleCacheAsync({ logger: ctx.logger, workingDirectory, env: ctx.env, secrets: ctx.job.secrets, }); + if (Object.keys(env).length > 0) { + Object.assign(ctx.env, env); + logGradleCacheEnv(ctx.logger, env); + } }); await ctx.runBuildPhase(BuildPhase.POST_INSTALL_HOOK, async () => { diff --git a/packages/build-tools/src/steps/functions/restoreBuildCache.ts b/packages/build-tools/src/steps/functions/restoreBuildCache.ts index de9826b0ef..2f3462cc10 100644 --- a/packages/build-tools/src/steps/functions/restoreBuildCache.ts +++ b/packages/build-tools/src/steps/functions/restoreBuildCache.ts @@ -57,12 +57,19 @@ export function createRestoreBuildCacheFunction(): BuildFunction { }); if (platform === Platform.ANDROID) { - await restoreGradleCacheAsync({ + const { env: gradleCacheEnv } = await restoreGradleCacheAsync({ logger, workingDirectory, env, secrets: stepCtx.global.staticContext.job.secrets, }); + if (Object.keys(gradleCacheEnv).length > 0) { + stepCtx.global.updateEnv({ + ...stepCtx.global.env, + ...gradleCacheEnv, + }); + logGradleCacheEnv(logger, gradleCacheEnv); + } } }, }); @@ -200,19 +207,16 @@ export async function restoreGradleCacheAsync({ workingDirectory: string; env: Record; secrets?: { robotAccessToken?: string }; -}): Promise { +}): Promise<{ env: Record }> { if (env.EAS_GRADLE_CACHE !== '1') { - return; + return { env: {} }; } - try { - const gradlePropertiesPath = path.join(workingDirectory, 'android', 'gradle.properties'); - const gradlePropertiesContent = await fs.promises.readFile(gradlePropertiesPath, 'utf-8'); - await fs.promises.writeFile( - gradlePropertiesPath, - `${gradlePropertiesContent}\n\norg.gradle.caching=true\n` - ); + const gradleCacheEnv = { + 'ORG_GRADLE_PROJECT_org.gradle.caching': 'true', + }; + try { // Configure cache cleanup via init script (works with both Gradle 8 and 9, // org.gradle.cache.cleanup property was removed in Gradle 9) const initScriptDir = path.join(os.homedir(), '.gradle', 'init.d'); @@ -294,6 +298,18 @@ export async function restoreGradleCacheAsync({ logger.warn('Failed to restore Gradle cache: ', err); } } + + return { env: gradleCacheEnv }; +} + +export function logGradleCacheEnv(logger: bunyan, env: Record): void { + logger.info( + `Enabling Gradle cache. Running Gradle with additional environment variables.\n${Object.entries( + env + ) + .map(([key, value]) => `${key}=${value}`) + .join('\n')}` + ); } export async function cacheStatsAsync({