allow configs to be passed directly to loadBackendConfig

Signed-off-by: Oleg S <97077423+RobotSail@users.noreply.github.com>
This commit is contained in:
Oleg S
2023-02-28 09:26:48 -05:00
parent e20346c25c
commit 15d0bb68e5
4 changed files with 71 additions and 3 deletions
@@ -16,7 +16,8 @@
import { ConfigService } from '@backstage/backend-plugin-api';
import { ConfigReader } from '@backstage/config';
import { JsonValue } from '@backstage/types';
import type { JsonObject, JsonValue } from '@backstage/types';
import { mergeJson } from '@backstage/types';
export class ObservableConfigProxy implements ConfigService {
private config: ConfigService = new ConfigReader({});
@@ -61,6 +62,12 @@ export class ObservableConfigProxy implements ConfigService {
},
};
}
mergeConfig(configData: JsonObject) {
if (this.parent) {
throw new Error('immutable');
}
this.setConfig(new ConfigReader(mergeJson(this.config.get(), configData)));
}
private select(required: true): ConfigService;
private select(required: false): ConfigService | undefined;
@@ -24,10 +24,11 @@ import {
ConfigTarget,
LoadConfigOptionsRemote,
} from '@backstage/config-loader';
import { Config, ConfigReader } from '@backstage/config';
import { type Config, ConfigReader } from '@backstage/config';
import { getPackages } from '@manypkg/get-packages';
import { ObservableConfigProxy } from './ObservableConfigProxy';
import { isValidUrl } from '../lib/urls';
import type { JsonObject } from '@backstage/types';
/** @public */
export async function createConfigSecretEnumerator(options: {
@@ -70,6 +71,7 @@ export async function createConfigSecretEnumerator(options: {
export async function loadBackendConfig(options: {
remote?: LoadConfigOptionsRemote;
argv: string[];
config?: JsonObject;
}): Promise<{ config: Config }> {
const args = parseArgs(options.argv);
@@ -109,12 +111,12 @@ export async function loadBackendConfig(options: {
}),
},
});
console.info(
`Loaded config from ${appConfigs.map(c => c.context).join(', ')}`,
);
config.setConfig(ConfigReader.fromConfigs(appConfigs));
config.mergeConfig(options.config ?? {});
return { config };
}
+1
View File
@@ -21,5 +21,6 @@
*/
export type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './json';
export { mergeJson } from './json';
export type { Observable, Observer, Subscription } from './observable';
export type { HumanDuration } from './time';
+58
View File
@@ -41,3 +41,61 @@ export interface JsonArray extends Array<JsonValue> {}
* @public
*/
export type JsonValue = JsonObject | JsonArray | JsonPrimitive;
/**
* Attempts to merge two JsonObjects together. In the case of collisions, this function
* prefers values from b, unless the value is an object, in which case it recursively
* merges the values.
*
* @param a The base object
* @param b The object to merge into a
* @returns The merged object
*/
export const mergeJson = (a: JsonObject, b: JsonObject): JsonObject => {
const final: JsonObject = {};
const bKeys = new Set(Object.keys(b));
const aKeys = new Set(Object.keys(a));
const intersectingKeys = new Set([...aKeys].filter(x => bKeys.has(x)));
// add all mutually exclusive keys to the final object
for (const key of aKeys.values()) {
if (!intersectingKeys.has(key)) {
final[key] = a[key];
continue;
}
}
for (const key of bKeys.values()) {
if (!intersectingKeys.has(key)) {
final[key] = b[key];
continue;
}
}
// values now are all overlapping and are either primitives, arrays, or objects.
// for all primitives and arrays, we want to assign the value from b
// for all objects, we want to recursively merge the values
for (const key of intersectingKeys.values()) {
// check if value is an array or primitive
const value = b[key];
if (Array.isArray(value) || typeof value !== 'object') {
final[key] = value;
continue;
}
// check if either value is undefined and default to the defined one
const aValue = a[key];
const bValue = b[key];
if (!aValue) {
final[key] = bValue;
continue;
}
if (!bValue) {
final[key] = aValue;
continue;
}
// recursively merge the values
final[key] = mergeJson(aValue as JsonObject, bValue as JsonObject);
}
return final;
};