Run substitute prior to include processing

Signed-off-by: JP Dhabolt john.p.dhabolt@gmail.com
Signed-off-by: JP Dhabolt <jdhabolt@agero.com>
This commit is contained in:
JP Dhabolt
2021-03-30 16:23:30 +00:00
parent a46a98c3b0
commit a003fdb21b
4 changed files with 47 additions and 14 deletions
@@ -14,11 +14,14 @@
* limitations under the License.
*/
import { JsonValue } from '@backstage/config';
import * as os from 'os';
import { resolve as resolvePath } from 'path';
import { createIncludeTransform } from './include';
const root = os.platform() === 'win32' ? 'C:\\' : '/';
const substituteMe = '${MY_SUBSTITUTION}';
const mySubstitution = 'fooSubstitution';
const env = jest.fn(async (name: string) => {
return ({
@@ -26,6 +29,24 @@ const env = jest.fn(async (name: string) => {
} as { [name: string]: string })[name];
});
const substitute = jest.fn(
async (
value: JsonValue,
): Promise<{ applied: boolean; value?: JsonValue }> => {
if (typeof value !== 'string') {
return { applied: false };
}
if (value.includes(substituteMe)) {
return {
applied: true,
value: value.replace(substituteMe, mySubstitution),
};
}
return { applied: false };
},
);
const readFile = jest.fn(async (path: string) => {
const content = ({
[resolvePath(root, 'my-secret')]: 'secret',
@@ -33,6 +54,7 @@ const readFile = jest.fn(async (path: string) => {
[resolvePath(root, 'my-data.yaml')]: 'some:\n yaml:\n key: 7',
[resolvePath(root, 'my-data.yml')]: 'different: { key: hello }',
[resolvePath(root, 'invalid.yaml')]: 'foo: [}',
[resolvePath(root, `${mySubstitution}/my-data.json`)]: '{"foo":"bar"}',
} as { [key: string]: string })[path];
if (!content) {
@@ -41,7 +63,7 @@ const readFile = jest.fn(async (path: string) => {
return content;
});
const includeTransform = createIncludeTransform(env, readFile);
const includeTransform = createIncludeTransform(env, readFile, substitute);
describe('includeTransform', () => {
it('should not transform unknown values', async () => {
@@ -136,4 +158,14 @@ describe('includeTransform', () => {
'failed to parse included file invalid.yaml, YAMLSyntaxError: Flow sequence contains an unexpected }',
);
});
it('should call substitute prior to handling includes directive', async () => {
await expect(
includeTransform({ $include: `${substituteMe}/my-data.json` }, root),
).resolves.toEqual({
applied: true,
value: { foo: 'bar' },
newBaseDir: `/${mySubstitution}`,
});
});
});
@@ -35,6 +35,7 @@ const includeFileParser: {
export function createIncludeTransform(
env: EnvFunc,
readFile: ReadFileFunc,
substitute: TransformFunc,
): TransformFunc {
return async (input: JsonValue, baseDir: string) => {
if (!isObject(input)) {
@@ -53,7 +54,11 @@ export function createIncludeTransform(
return { applied: false };
}
const includeValue = input[includeKey];
const rawIncludedValue = input[includeKey];
const substituteResults = await substitute(rawIncludedValue!, baseDir);
const includeValue = substituteResults.applied
? substituteResults.value
: rawIncludedValue;
if (typeof includeValue !== 'string') {
throw new Error(`${includeKey} include value is not a string`);
}
@@ -23,13 +23,8 @@ export type ReadFileFunc = (path: string) => Promise<string>;
export type TransformFunc = (
value: JsonValue,
baseDir: string,
) => Promise<
| {
applied: false;
}
| {
applied: true;
value: JsonValue | undefined;
newBaseDir?: string | undefined;
}
>;
) => Promise<{
applied: boolean;
value?: JsonValue;
newBaseDir?: string;
}>;
+3 -2
View File
@@ -75,9 +75,10 @@ export async function loadConfig(
fs.readFile(resolvePath(dir, path), 'utf8');
const input = yaml.parse(await readFile(configPath));
const substitutionTransform = createSubstitutionTransform(env);
const data = await applyConfigTransforms(dir, input, [
createIncludeTransform(env, readFile),
createSubstitutionTransform(env),
createIncludeTransform(env, readFile, substitutionTransform),
substitutionTransform,
]);
configs.push({ data, context: basename(configPath) });