Skip to content
This repository was archived by the owner on May 27, 2025. It is now read-only.

Commit 344db38

Browse files
authored
Allow secrets in settings (#378)
1 parent acb2327 commit 344db38

2 files changed

Lines changed: 121 additions & 6 deletions

File tree

src/helpers.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,17 @@ export function readSettings<T>(serviceName: string, settingsFileName: string):
2727
throw new Error(`[${serviceName}] Unable to load configuration file ${settingsFileName}.`);
2828
}
2929

30-
let parseErrors: JSONC.ParseError[];
30+
const parseErrors: JSONC.ParseError[] = [];
3131

3232
const settings = JSONC.parse(rawConfig, parseErrors) as T;
3333

3434
// This extra level of validation really shouldn't be necessary since the
3535
// file passed schema validation. Still, better safe than crashing.
3636
if (parseErrors && parseErrors.length > 0) {
37-
throw new Error(
38-
`[${serviceName}] Unable to load configuration file: ${parseErrors
39-
.map(error => log.error("${serviceName}", `${error?.error}`))
40-
.join("\n")}`,
41-
);
37+
const parseErrorsAsString = parseErrors.map(parseError => JSON.stringify(parseError)).join(" ");
38+
log.error(serviceName, parseErrorsAsString);
39+
const errorMessage = `[${serviceName}] Unable to load configuration file: ${parseErrorsAsString}`;
40+
throw new Error(errorMessage);
4241
}
4342

4443
return settings;

tests/helpers.test.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Neil Enns. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
import {closeSync, existsSync, openSync, unlinkSync, writeFileSync} from 'fs';
6+
import * as JSONC from "jsonc-parser";
7+
import * as helpers from "./../src/helpers";
8+
9+
describe("helpers", () => {
10+
const settingsFilePath = `${__dirname}/settings.json`;
11+
12+
beforeEach(() => {
13+
closeSync(openSync(settingsFilePath, 'w'));
14+
});
15+
16+
afterEach(() => {
17+
jest.clearAllMocks();
18+
if (existsSync(settingsFilePath)) {
19+
unlinkSync(settingsFilePath);
20+
}
21+
});
22+
23+
test("Verify can load settings.json", () => {
24+
const serviceName = "Settings";
25+
const expectedSettings = {"foo": "bar"};
26+
writeFileSync(settingsFilePath, JSON.stringify(expectedSettings));
27+
28+
const actualSettings = helpers.readSettings(serviceName, settingsFilePath);
29+
30+
expect(actualSettings).toEqual(expectedSettings);
31+
});
32+
33+
test("Verify cannot load settings.json because it does not exist", () => {
34+
//eslint-disable-next-line no-console
35+
console.log = jest.fn();
36+
const serviceName = "Settings";
37+
unlinkSync(settingsFilePath);
38+
39+
const actualSettings = helpers.readSettings(serviceName, settingsFilePath);
40+
41+
//eslint-disable-next-line no-console
42+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("[Settings] Unable to read the configuration file: ENOENT: no such file or directory"));
43+
expect(actualSettings).toBeNull();
44+
});
45+
46+
test("Verify throws if rawConfig empty", () => {
47+
const serviceName = "Settings";
48+
const expectedSettings = "";
49+
writeFileSync(settingsFilePath, expectedSettings);
50+
51+
expect(() => {helpers.readSettings(serviceName, settingsFilePath)}).toThrow(Error);
52+
});
53+
54+
test("Verify throws with message if rawConfig empty", () => {
55+
const serviceName = "Settings";
56+
const expectedSettings = "";
57+
writeFileSync(settingsFilePath, expectedSettings);
58+
59+
try {
60+
helpers.readSettings(serviceName, settingsFilePath);
61+
} catch (error) {
62+
expect(error.message).toBe(`[${serviceName}] Unable to load configuration file ${settingsFilePath}.`);
63+
}
64+
});
65+
66+
test("Verify throws if json invalid", () => {
67+
const serviceName = "Settings";
68+
const expectedSettings = {};
69+
writeFileSync(settingsFilePath, JSON.stringify(expectedSettings));
70+
const mockAddListener = jest.spyOn(JSONC, 'parse');
71+
mockAddListener.mockImplementation((rawConfig, parseErrors) => {
72+
parseErrors.push({
73+
error: 1,
74+
offset: 2,
75+
length: 3,
76+
});
77+
return {};
78+
});
79+
80+
expect(() => {helpers.readSettings(serviceName, settingsFilePath)}).toThrow(Error);
81+
});
82+
83+
test("Verify throws with message if json invalid", () => {
84+
const serviceName = "Settings";
85+
const expectedSettings = {};
86+
writeFileSync(settingsFilePath, JSON.stringify(expectedSettings));
87+
const mockAddListener = jest.spyOn(JSONC, 'parse');
88+
const parseError1 = {
89+
error: 1,
90+
offset: 2,
91+
length: 3,
92+
};
93+
const parseError2 = {
94+
error: 3,
95+
offset: 2,
96+
length: 1,
97+
};
98+
mockAddListener.mockImplementation((rawConfig, parseErrors) => {
99+
parseErrors.push(parseError1);
100+
parseErrors.push(parseError2);
101+
return {};
102+
});
103+
//eslint-disable-next-line no-console
104+
console.log = jest.fn();
105+
106+
try {
107+
helpers.readSettings(serviceName, settingsFilePath);
108+
} catch (error) {
109+
const parseErrorsAsString = `${JSON.stringify(parseError1)} ${JSON.stringify(parseError2)}`;
110+
//eslint-disable-next-line no-console
111+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining(`[${serviceName}] ${parseErrorsAsString}`));
112+
expect(error.message).toBe(`[${serviceName}] Unable to load configuration file: ${parseErrorsAsString}`);
113+
}
114+
});
115+
});
116+

0 commit comments

Comments
 (0)