diff --git a/lib/modules/manager/gradle-wrapper/artifacts.spec.ts b/lib/modules/manager/gradle-wrapper/artifacts.spec.ts index 9551f9d27e6ffd67a23b4d811e3157d6ce705a83..70b7231865ac426ee2e3161dc1fad3ac0a3d7955 100644 --- a/lib/modules/manager/gradle-wrapper/artifacts.spec.ts +++ b/lib/modules/manager/gradle-wrapper/artifacts.spec.ts @@ -1,4 +1,5 @@ -import { readFile, stat } from 'fs-extra'; +import type { Stats } from 'fs'; +import { readFile } from 'fs-extra'; import { resolve } from 'upath'; import { envMock, exec, mockExecAll } from '../../../../test/exec-util'; import * as httpMock from '../../../../test/http-mock'; @@ -54,7 +55,12 @@ describe('modules/manager/gradle-wrapper/artifacts', () => { resetPrefetchedImages(); fs.readLocalFile.mockResolvedValue('test'); - fs.stat.mockImplementation((p) => stat(p)); + fs.statLocalFile.mockResolvedValue( + partial<Stats>({ + isFile: () => true, + mode: 0o555, + }) + ); }); afterEach(() => { @@ -98,6 +104,12 @@ describe('modules/manager/gradle-wrapper/artifacts', () => { }); it('gradlew not found', async () => { + fs.statLocalFile.mockResolvedValue( + partial<Stats>({ + isFile: () => false, + mode: 0o555, + }) + ); GlobalConfig.set({ ...adminConfig, localDir: 'some-dir' }); const res = await gradleWrapper.updateArtifacts({ packageFileName: 'gradle-wrapper.properties', diff --git a/lib/modules/manager/gradle-wrapper/artifacts.ts b/lib/modules/manager/gradle-wrapper/artifacts.ts index d3da5a3d55dcd308894e19f1c5c03373a6d2c664..220edc5eb36a8b594d3bea60830bf2d3cbff111a 100644 --- a/lib/modules/manager/gradle-wrapper/artifacts.ts +++ b/lib/modules/manager/gradle-wrapper/artifacts.ts @@ -1,12 +1,10 @@ import is from '@sindresorhus/is'; import { quote } from 'shlex'; -import upath from 'upath'; -import { GlobalConfig } from '../../../config/global'; import { TEMPORARY_ERROR } from '../../../constants/error-messages'; import { logger } from '../../../logger'; import { exec } from '../../../util/exec'; import type { ExecOptions } from '../../../util/exec/types'; -import { readLocalFile, stat, writeLocalFile } from '../../../util/fs'; +import { readLocalFile, writeLocalFile } from '../../../util/fs'; import { getRepoStatus } from '../../../util/git'; import type { StatusResult } from '../../../util/git/types'; import { Http } from '../../../util/http'; @@ -62,16 +60,9 @@ export async function updateArtifacts({ config, }: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> { try { - const projectDir = GlobalConfig.get('localDir'); logger.debug({ updatedDeps }, 'gradle-wrapper.updateArtifacts()'); - const gradlew = gradleWrapperFileName(); - const gradlewPath = upath.resolve(projectDir, `./${gradlew}`); - let cmd = await prepareGradleCommand( - gradlew, - projectDir!, - await stat(gradlewPath).catch(() => null), - `wrapper` - ); + const gradlewFile = gradleWrapperFileName(); + let cmd = await prepareGradleCommand(gradlewFile, `wrapper`); if (!cmd) { logger.info('No gradlew found - skipping Artifacts update'); return null; diff --git a/lib/modules/manager/gradle-wrapper/utils.ts b/lib/modules/manager/gradle-wrapper/utils.ts index c990f20819f9e491fe98276a4a16f5a707c86627..8fb41e5753ff73afe625d03025c4d5f19677f016 100644 --- a/lib/modules/manager/gradle-wrapper/utils.ts +++ b/lib/modules/manager/gradle-wrapper/utils.ts @@ -1,9 +1,7 @@ -import type { Stats } from 'fs'; import os from 'os'; -import upath from 'upath'; import { GlobalConfig } from '../../../config/global'; import { logger } from '../../../logger'; -import { chmod } from '../../../util/fs'; +import { chmodLocalFile, statLocalFile } from '../../../util/fs'; import { newlineRegex, regEx } from '../../../util/regex'; import gradleVersioning from '../../versioning/gradle'; import { id as npmVersioning } from '../../versioning/npm'; @@ -27,16 +25,16 @@ export function gradleWrapperFileName(): string { export async function prepareGradleCommand( gradlewName: string, - cwd: string, - gradlew: Stats | null, args: string | null ): Promise<string | null> { + const gradlewFile = gradleWrapperFileName(); + const gradlewStat = await statLocalFile(gradlewFile); // istanbul ignore if - if (gradlew?.isFile() === true) { + if (gradlewStat?.isFile() === true) { // if the file is not executable by others - if ((gradlew.mode & 0o1) === 0) { + if ((gradlewStat.mode & 0o1) === 0) { // add the execution permission to the owner, group and others - await chmod(upath.join(cwd, gradlewName), gradlew.mode | 0o111); + await chmodLocalFile(gradlewName, gradlewStat.mode | 0o111); } if (args === null) { return gradlewName; diff --git a/lib/util/fs/index.spec.ts b/lib/util/fs/index.spec.ts index 09b66be3efd876726d14934a8db68f85a7d0dfaa..31c2dc4ecfe503bfa7546b76e594c63c153cc1f6 100644 --- a/lib/util/fs/index.spec.ts +++ b/lib/util/fs/index.spec.ts @@ -6,6 +6,7 @@ import { envMock } from '../../../test/exec-util'; import { env, mockedFunction } from '../../../test/util'; import { GlobalConfig } from '../../config/global'; import { + chmodLocalFile, ensureCacheDir, ensureLocalDir, findLocalSiblingOrParent, @@ -15,6 +16,7 @@ import { localPathIsFile, readLocalDirectory, readLocalFile, + statLocalFile, writeLocalFile, } from '.'; @@ -240,4 +242,40 @@ describe('util/fs/index', () => { expect(res).toBeNull(); }); }); + + describe('chmodLocalFile', () => { + it('works', async () => { + await withDir( + async (tmpDir) => { + GlobalConfig.set({ localDir: tmpDir.path }); + await writeLocalFile('foo', 'bar'); + await chmodLocalFile('foo', 0o000); + expect(await readLocalFile('foo')).toBeNull(); + await chmodLocalFile('foo', 0o444); + expect((await readLocalFile('foo'))!.toString()).toBe('bar'); + }, + { unsafeCleanup: true } + ); + }); + }); + + describe('statLocalFile', () => { + it('works', async () => { + await withDir( + async (tmpDir) => { + GlobalConfig.set({ localDir: tmpDir.path }); + + expect(await statLocalFile('foo')).toBeNull(); + + await writeLocalFile('foo', 'bar'); + await chmodLocalFile('foo', 0o123); + + const res = await statLocalFile('foo'); + expect(res!.isFile()).toBeTrue(); + expect(res!.mode & 0o777).toBe(0o123); + }, + { unsafeCleanup: true } + ); + }); + }); }); diff --git a/lib/util/fs/index.ts b/lib/util/fs/index.ts index ad7076bf6e50aa2a25aa868b22ac8fe5b74f477b..2b1f5a3bc5a068ab668b8458c50f23edde9bf17a 100644 --- a/lib/util/fs/index.ts +++ b/lib/util/fs/index.ts @@ -195,3 +195,24 @@ export async function findUpLocal( // Return null if found file is outside of localDir return null; } + +export function chmodLocalFile( + fileName: string, + mode: string | number +): Promise<void> { + const localDir = GlobalConfig.get('localDir'); + const fullFileName = upath.join(localDir, fileName); + return fs.chmod(fullFileName, mode); +} + +export async function statLocalFile( + fileName: string +): Promise<fs.Stats | null> { + const localDir = GlobalConfig.get('localDir'); + const fullFileName = upath.join(localDir, fileName); + try { + return await fs.stat(fullFileName); + } catch (_) { + return null; + } +} diff --git a/lib/util/fs/proxies.ts b/lib/util/fs/proxies.ts index f291ff1e572f0c7f1dc1122c8bf31424a7fa2f1a..3c4e42d330bef07c8e60bb640ae9dfe935bfed85 100644 --- a/lib/util/fs/proxies.ts +++ b/lib/util/fs/proxies.ts @@ -6,14 +6,6 @@ export function stat(path: string | Buffer): Promise<fs.Stats> { return fs.stat(path); } -// istanbul ignore next -export function chmod( - path: string | Buffer, - mode: string | number -): Promise<void> { - return fs.chmod(path, mode); -} - export async function readFile(fileName: string): Promise<Buffer>; export async function readFile( fileName: string,