Skip to content

Commit

Permalink
build: switch hcl parser (#21988)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceice committed May 5, 2023
1 parent 44f2298 commit 4924973
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 49 deletions.
52 changes: 30 additions & 22 deletions 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 {
Expand All @@ -16,9 +18,6 @@ import {

jest.unmock('.');

jest.mock('fs-extra');
const fs: any = _fs;

describe('logger/index', () => {
it('inits', () => {
expect(logger).toBeDefined();
Expand Down Expand Up @@ -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<WriteStream>({
writable: true,
write(x: string): boolean {
chunk = x;
return true;
},
})
);

addStream({
name: 'logfile',
Expand All @@ -117,12 +119,15 @@ describe('logger/index', () => {

it('handles cycles', () => {
let logged: Record<string, any> = {};
fs.createWriteStream.mockReturnValueOnce({
writable: true,
write(x: string) {
logged = JSON.parse(x);
},
});
jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce(
partial<WriteStream>({
writable: true,
write(x: string): boolean {
logged = JSON.parse(x);
return true;
},
})
);

addStream({
name: 'logfile',
Expand All @@ -142,12 +147,15 @@ describe('logger/index', () => {

it('sanitizes secrets', () => {
let logged: Record<string, any> = {};
fs.createWriteStream.mockReturnValueOnce({
writable: true,
write(x: string) {
logged = JSON.parse(x);
},
});
jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce(
partial<WriteStream>({
writable: true,
write(x: string): boolean {
logged = JSON.parse(x);
return true;
},
})
);

addStream({
name: 'logfile',
Expand Down
1 change: 0 additions & 1 deletion lib/modules/manager/bundler/artifacts.spec.ts
Expand Up @@ -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');
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/manager/terraform/extract.ts
Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions lib/modules/manager/terraform/hcl/index.spec.ts
Expand Up @@ -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({
Expand Down Expand Up @@ -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: [
{
Expand All @@ -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: {
Expand Down
10 changes: 6 additions & 4 deletions 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<TerraformDefinitionFile | null> {
try {
return hcl_parser.parseToObject(content)[0];
return await parse(fileName, content);
} catch (err) /* istanbul ignore next */ {
return null;
}
Expand Down
3 changes: 2 additions & 1 deletion 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_);
Expand Down
25 changes: 19 additions & 6 deletions 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';
Expand All @@ -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<typeof fs>('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;
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
17 changes: 15 additions & 2 deletions 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
Expand Down Expand Up @@ -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),
Expand All @@ -107,6 +109,17 @@ export class Fixtures {
}
}

export function readFile(
fileName: string,
options: IOptions
): Promise<TDataOut> {
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
Expand Down
12 changes: 7 additions & 5 deletions yarn.lock
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit 4924973

Please sign in to comment.