refactor(fs): Move chmod to chmodLocalFile (#16306)

* refactor(fs): Move `chmod` to `chmodLocalFile`

* More refactoring and tests

* Fix tests

* Apply suggestions from code review

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>

* Fix prettier

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
This commit is contained in:
Sergei Zharinov 2022-06-29 09:03:49 +03:00 committed by GitHub
parent 0687799b28
commit 851d8f4f7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 82 additions and 30 deletions

View file

@ -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',

View file

@ -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;

View file

@ -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;

View file

@ -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 }
);
});
});
});

View file

@ -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;
}
}

View file

@ -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,