allow configs to be passed directly to loadBackendConfig
Signed-off-by: Oleg S <97077423+RobotSail@users.noreply.github.com>
This commit is contained in:
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user