diff --git a/lib/logger/index.spec.ts b/lib/logger/index.spec.ts index ccf5403a29f189..c8422d469e2be6 100644 --- a/lib/logger/index.spec.ts +++ b/lib/logger/index.spec.ts @@ -1,4 +1,6 @@ -import _fs from 'fs-extra'; +import type { WriteStream } from 'node:fs'; +import fs from 'fs-extra'; +import { partial } from '../../test/util'; import { add } from '../util/host-rules'; import { addSecretForSanitizing as addSecret } from '../util/sanitize'; import { @@ -16,9 +18,6 @@ import { jest.unmock('.'); -jest.mock('fs-extra'); -const fs: any = _fs; - describe('logger/index', () => { it('inits', () => { expect(logger).toBeDefined(); @@ -97,12 +96,15 @@ describe('logger/index', () => { it('supports file-based logging', () => { let chunk = ''; - fs.createWriteStream.mockReturnValueOnce({ - writable: true, - write(x: string) { - chunk = x; - }, - }); + jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce( + partial({ + writable: true, + write(x: string): boolean { + chunk = x; + return true; + }, + }) + ); addStream({ name: 'logfile', @@ -117,12 +119,15 @@ describe('logger/index', () => { it('handles cycles', () => { let logged: Record = {}; - fs.createWriteStream.mockReturnValueOnce({ - writable: true, - write(x: string) { - logged = JSON.parse(x); - }, - }); + jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce( + partial({ + writable: true, + write(x: string): boolean { + logged = JSON.parse(x); + return true; + }, + }) + ); addStream({ name: 'logfile', @@ -142,12 +147,15 @@ describe('logger/index', () => { it('sanitizes secrets', () => { let logged: Record = {}; - fs.createWriteStream.mockReturnValueOnce({ - writable: true, - write(x: string) { - logged = JSON.parse(x); - }, - }); + jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce( + partial({ + writable: true, + write(x: string): boolean { + logged = JSON.parse(x); + return true; + }, + }) + ); addStream({ name: 'logfile', diff --git a/lib/modules/manager/bundler/artifacts.spec.ts b/lib/modules/manager/bundler/artifacts.spec.ts index a2eab121cdc71f..841f8ecc899d2d 100644 --- a/lib/modules/manager/bundler/artifacts.spec.ts +++ b/lib/modules/manager/bundler/artifacts.spec.ts @@ -23,7 +23,6 @@ import { updateArtifacts } from '.'; const datasource = mocked(_datasource); const bundlerHostRules = mocked(_bundlerHostRules); -jest.mock('fs-extra'); jest.mock('../../../util/exec/env'); jest.mock('../../datasource'); jest.mock('../../../util/fs'); diff --git a/lib/modules/manager/terraform/extract.ts b/lib/modules/manager/terraform/extract.ts index 605f4d364b41ba..e15cc17af3d58b 100644 --- a/lib/modules/manager/terraform/extract.ts +++ b/lib/modules/manager/terraform/extract.ts @@ -37,7 +37,7 @@ export async function extractPackageFile( ); const dependencies = []; - const hclMap = hcl.parseHCL(content); + const hclMap = await hcl.parseHCL(content, fileName); if (is.nullOrUndefined(hclMap)) { logger.trace({ fileName }, 'failed to parse HCL file'); return null; diff --git a/lib/modules/manager/terraform/hcl/index.spec.ts b/lib/modules/manager/terraform/hcl/index.spec.ts index bd9be234275687..70cf21a38a79a6 100644 --- a/lib/modules/manager/terraform/hcl/index.spec.ts +++ b/lib/modules/manager/terraform/hcl/index.spec.ts @@ -8,8 +8,8 @@ const lockedVersion = Fixtures.get('lockedVersion.tf'); describe('modules/manager/terraform/hcl/index', () => { describe('parseHCL()', () => { - it('should return flat modules', () => { - const res = parseHCL(modulesTF); + it('should return flat modules', async () => { + const res = await parseHCL(modulesTF, 'file.tf'); expect(res?.module).toBeDefined(); expect(Object.keys(res!.module!)).toBeArrayOfSize(6); expect(res).toMatchObject({ @@ -50,8 +50,8 @@ describe('modules/manager/terraform/hcl/index', () => { }); }); - it('should return nested terraform block', () => { - const res = parseHCL(lockedVersion); + it('should return nested terraform block', async () => { + const res = await parseHCL(lockedVersion, 'file.tf'); expect(res).toMatchObject({ terraform: [ { @@ -67,8 +67,8 @@ describe('modules/manager/terraform/hcl/index', () => { }); }); - it('should return resource blocks', () => { - const res = parseHCL(resourcesTF); + it('should return resource blocks', async () => { + const res = await parseHCL(resourcesTF, 'file.tf'); expect(res).toMatchObject({ resource: { docker_container: { diff --git a/lib/modules/manager/terraform/hcl/index.ts b/lib/modules/manager/terraform/hcl/index.ts index 61803c995dda4d..8691daf3801a5f 100644 --- a/lib/modules/manager/terraform/hcl/index.ts +++ b/lib/modules/manager/terraform/hcl/index.ts @@ -1,10 +1,12 @@ -import * as hcl_parser from 'hcl2-parser'; - +import { parse } from '@cdktf/hcl2json'; import type { TerraformDefinitionFile } from './types'; -export function parseHCL(content: string): TerraformDefinitionFile | null { +export async function parseHCL( + content: string, + fileName: string +): Promise { try { - return hcl_parser.parseToObject(content)[0]; + return await parse(fileName, content); } catch (err) /* istanbul ignore next */ { return null; } diff --git a/lib/util/git/private-key.spec.ts b/lib/util/git/private-key.spec.ts index d3921992b2df42..9ecbbe74f0b261 100644 --- a/lib/util/git/private-key.spec.ts +++ b/lib/util/git/private-key.spec.ts @@ -1,9 +1,10 @@ +import { Fixtures } from '../../../test/fixtures'; import { mocked } from '../../../test/util'; import * as exec_ from '../exec'; import { configSigningKey, writePrivateKey } from './private-key'; import { setPrivateKey } from '.'; -jest.mock('fs-extra'); +jest.mock('fs-extra', () => Fixtures.fsExtra()); jest.mock('../exec'); const exec = mocked(exec_); diff --git a/lib/workers/global/index.spec.ts b/lib/workers/global/index.spec.ts index daae4d825c3036..8c371725b1569a 100644 --- a/lib/workers/global/index.spec.ts +++ b/lib/workers/global/index.spec.ts @@ -1,11 +1,11 @@ import { expect } from '@jest/globals'; import { ERROR, WARN } from 'bunyan'; -import * as _fs from 'fs-extra'; +import fs from 'fs-extra'; import { logger, mocked } from '../../../test/util'; import * as _presets from '../../config/presets'; import { CONFIG_PRESETS_INVALID } from '../../constants/error-messages'; import { DockerDatasource } from '../../modules/datasource/docker'; -import * as _platform from '../../modules/platform'; +import * as platform from '../../modules/platform'; import * as secrets from '../../util/sanitize'; import * as repositoryWorker from '../repository'; import * as configParser from './config/parse'; @@ -16,20 +16,33 @@ jest.mock('../repository'); jest.mock('../../util/fs'); jest.mock('../../config/presets'); -jest.mock('fs-extra'); -const fs = mocked(_fs); -const platform = mocked(_platform); +jest.mock('fs-extra', () => { + const realFs = jest.requireActual('fs-extra'); + return { + ensureDir: jest.fn(), + remove: jest.fn(), + readFile: jest.fn((file: string, options: any) => { + if (file.endsWith('.wasm.gz')) { + return realFs.readFile(file, options); + } + return undefined; + }), + writeFile: jest.fn(), + outputFile: jest.fn(), + }; +}); // imports are readonly const presets = mocked(_presets); const addSecretForSanitizing = jest.spyOn(secrets, 'addSecretForSanitizing'); const parseConfigs = jest.spyOn(configParser, 'parseConfigs'); +const initPlatform = jest.spyOn(platform, 'initPlatform'); describe('workers/global/index', () => { beforeEach(() => { logger.getProblems.mockImplementationOnce(() => []); - platform.initPlatform.mockImplementation((input) => Promise.resolve(input)); + initPlatform.mockImplementation((input) => Promise.resolve(input)); delete process.env.AWS_SECRET_ACCESS_KEY; delete process.env.AWS_SESSION_TOKEN; }); diff --git a/package.json b/package.json index 091bdf49379505..f840ca80aff0c7 100644 --- a/package.json +++ b/package.json @@ -142,6 +142,7 @@ "@aws-sdk/client-rds": "3.314.0", "@aws-sdk/client-s3": "3.312.0", "@breejs/later": "4.1.0", + "@cdktf/hcl2json": "0.16.1", "@cheap-glitch/mi-cron": "1.0.1", "@iarna/toml": "3.0.0", "@opentelemetry/api": "1.4.1", @@ -198,7 +199,6 @@ "graph-data-structure": "3.3.0", "handlebars": "4.7.7", "hasha": "5.2.2", - "hcl2-parser": "1.0.3", "ignore": "5.2.4", "ini": "4.1.0", "js-yaml": "4.1.0", diff --git a/test/fixtures.ts b/test/fixtures.ts index 3b3198122074ca..35afd650a566ee 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1,8 +1,10 @@ -import type fs from 'node:fs'; +import fs from 'node:fs'; import type { PathLike, Stats } from 'node:fs'; import { jest } from '@jest/globals'; import callsite from 'callsite'; import { DirectoryJSON, fs as memfs, vol } from 'memfs'; +import type { TDataOut } from 'memfs/lib/encoding'; +import type { IOptions } from 'memfs/lib/volume'; import upath from 'upath'; // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion @@ -93,7 +95,7 @@ export class Fixtures { ...memfs, pathExists: jest.fn(pathExists), remove: jest.fn(memfs.promises.rm), - readFile: jest.fn(memfs.promises.readFile), + readFile: jest.fn(readFile), writeFile: jest.fn(memfs.promises.writeFile), outputFile: jest.fn(outputFile), stat: jest.fn(stat), @@ -107,6 +109,17 @@ export class Fixtures { } } +export function readFile( + fileName: string, + options: IOptions +): Promise { + if (fileName.endsWith('.wasm') || fileName.endsWith('.wasm.gz')) { + return fs.promises.readFile(fileName, options as any); + } + + return memfs.promises.readFile(fileName, options); +} + export async function outputFile( file: string, data: string | Buffer | Uint8Array diff --git a/yarn.lock b/yarn.lock index ad417556653eca..2b353c2f2ca49e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1525,6 +1525,13 @@ resolved "https://registry.yarnpkg.com/@breejs/later/-/later-4.1.0.tgz#9246907f46cc9e9c9af37d791ab468d98921bcc1" integrity sha512-QgGnZ9b7o4k0Ai1ZbTJWwZpZcFK9d+Gb+DyNt4UT9x6IEIs5HVu0iIlmgzGqN+t9MoJSpSPo9S/Mm51UtHr3JA== +"@cdktf/hcl2json@0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@cdktf/hcl2json/-/hcl2json-0.16.1.tgz#c5d4c965e150d29579d6b53a9fe6c946fca7e614" + integrity sha512-c0AcAzpUYREmkonxai3Jjd7P0c0/TMB+ga3Ir/02MDSdyV8VQ+1CLK2nVMJJqJTsGZkxrZGVj/jlwA6coDYaqg== + dependencies: + fs-extra "^11.1.1" + "@cheap-glitch/mi-cron@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@cheap-glitch/mi-cron/-/mi-cron-1.0.1.tgz#111f4ce746c269aedf74533ac806881763a68f99" @@ -5809,11 +5816,6 @@ hasha@5.2.2: is-stream "^2.0.0" type-fest "^0.8.0" -hcl2-parser@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/hcl2-parser/-/hcl2-parser-1.0.3.tgz#096d0ff5a3c46707ace54fcb7571317f5828ff0e" - integrity sha512-NQUm/BFF+2nrBfeqDhhsy4DxxiLHgkeE3FywtjFiXnjSUaio3w4Tz1MQ3vGJBUhyArzOXJ24pO7JwE5LAn7Ncg== - he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"