diff --git a/packages/config-loader/src/lib/transform/include.test.ts b/packages/config-loader/src/lib/transform/include.test.ts index 1724159e56..81c6cfb63b 100644 --- a/packages/config-loader/src/lib/transform/include.test.ts +++ b/packages/config-loader/src/lib/transform/include.test.ts @@ -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}`, + }); + }); }); diff --git a/packages/config-loader/src/lib/transform/include.ts b/packages/config-loader/src/lib/transform/include.ts index 1a6963672a..bffc2e0184 100644 --- a/packages/config-loader/src/lib/transform/include.ts +++ b/packages/config-loader/src/lib/transform/include.ts @@ -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`); } diff --git a/packages/config-loader/src/lib/transform/types.ts b/packages/config-loader/src/lib/transform/types.ts index c13f01d016..e7ebb0fddc 100644 --- a/packages/config-loader/src/lib/transform/types.ts +++ b/packages/config-loader/src/lib/transform/types.ts @@ -23,13 +23,8 @@ export type ReadFileFunc = (path: string) => Promise; 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; +}>; diff --git a/packages/config-loader/src/loader.ts b/packages/config-loader/src/loader.ts index 54e4ab5208..95e5b570ca 100644 --- a/packages/config-loader/src/loader.ts +++ b/packages/config-loader/src/loader.ts @@ -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) });