allow app-config of the catalog processingInterval
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { Config as Config_2 } from '@backstage/config';
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
import type { JsonArray as JsonArray_2 } from '@backstage/types';
|
||||
import { JsonObject as JsonObject_2 } from '@backstage/types';
|
||||
import type { JsonPrimitive as JsonPrimitive_2 } from '@backstage/types';
|
||||
@@ -80,4 +82,12 @@ export type JsonPrimitive = JsonPrimitive_2;
|
||||
|
||||
// @public @deprecated
|
||||
export type JsonValue = JsonValue_2;
|
||||
|
||||
// @public
|
||||
export function readDurationFromConfig(
|
||||
config: Config_2,
|
||||
options?: {
|
||||
key?: string;
|
||||
},
|
||||
): HumanDuration;
|
||||
```
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"clean": "backstage-cli package clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
|
||||
@@ -26,5 +26,6 @@ export type {
|
||||
JsonPrimitive,
|
||||
JsonValue,
|
||||
} from './deprecatedTypes';
|
||||
export { readDurationFromConfig } from './readDurationFromConfig';
|
||||
export { ConfigReader } from './reader';
|
||||
export type { AppConfig, Config } from './types';
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
readDurationFromConfig,
|
||||
propsOfHumanDuration,
|
||||
} from './readDurationFromConfig';
|
||||
import { ConfigReader } from './reader';
|
||||
|
||||
describe('readDurationFromConfig', () => {
|
||||
it('reads all known keys', () => {
|
||||
const config = new ConfigReader({
|
||||
milliseconds: 1,
|
||||
seconds: 2,
|
||||
minutes: 3,
|
||||
hours: 4,
|
||||
days: 5,
|
||||
weeks: 6,
|
||||
months: 7,
|
||||
years: 8,
|
||||
});
|
||||
expect(readDurationFromConfig(config)).toEqual({
|
||||
milliseconds: 1,
|
||||
seconds: 2,
|
||||
minutes: 3,
|
||||
hours: 4,
|
||||
days: 5,
|
||||
weeks: 6,
|
||||
months: 7,
|
||||
years: 8,
|
||||
});
|
||||
});
|
||||
|
||||
it('reads all known keys, for a subkey', () => {
|
||||
const config = new ConfigReader({
|
||||
sub: {
|
||||
key: {
|
||||
milliseconds: 1,
|
||||
seconds: 2,
|
||||
minutes: 3,
|
||||
hours: 4,
|
||||
days: 5,
|
||||
weeks: 6,
|
||||
months: 7,
|
||||
years: 8,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(readDurationFromConfig(config, { key: 'sub.key' })).toEqual({
|
||||
milliseconds: 1,
|
||||
seconds: 2,
|
||||
minutes: 3,
|
||||
hours: 4,
|
||||
days: 5,
|
||||
weeks: 6,
|
||||
months: 7,
|
||||
years: 8,
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects wrong type of target, for a subkey', () => {
|
||||
const config = new ConfigReader({
|
||||
sub: { key: 7 },
|
||||
});
|
||||
expect(() => readDurationFromConfig(config, { key: 'sub.key' })).toThrow(
|
||||
"Failed to read duration from config, TypeError: Invalid type in config for key 'sub.key' in 'mock-config', got number, wanted object",
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects no keys', () => {
|
||||
const config = new ConfigReader({});
|
||||
expect(() => readDurationFromConfig(config)).toThrow(
|
||||
`Failed to read duration from config, Error: Needs one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects no keys, for a subkey', () => {
|
||||
const config = new ConfigReader({ sub: { key: {} } });
|
||||
expect(() => readDurationFromConfig(config, { key: 'sub.key' })).toThrow(
|
||||
`Failed to read duration from config at 'sub.key', Error: Needs one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects unknown keys', () => {
|
||||
const config = new ConfigReader({
|
||||
minutes: 3,
|
||||
invalid: 'value',
|
||||
});
|
||||
expect(() => readDurationFromConfig(config)).toThrow(
|
||||
`Failed to read duration from config, Error: Unknown property 'invalid'; expected one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`,
|
||||
);
|
||||
});
|
||||
|
||||
it.each(propsOfHumanDuration)('rejects non-number %p', prop => {
|
||||
const config = new ConfigReader({
|
||||
[prop]: 'value',
|
||||
});
|
||||
expect(() => readDurationFromConfig(config)).toThrow(
|
||||
`Failed to read duration from config, Error: Unable to convert config value for key '${prop}' in 'mock-config' to a number`,
|
||||
);
|
||||
});
|
||||
|
||||
it.each(propsOfHumanDuration)('rejects non-number %p, for a subkey', prop => {
|
||||
const config = new ConfigReader({
|
||||
sub: {
|
||||
key: {
|
||||
[prop]: 'value',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(() => readDurationFromConfig(config, { key: 'sub.key' })).toThrow(
|
||||
`Failed to read duration from config, Error: Unable to convert config value for key 'sub.key.${prop}' in 'mock-config' to a number`,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
|
||||
export const propsOfHumanDuration = [
|
||||
'years',
|
||||
'months',
|
||||
'weeks',
|
||||
'days',
|
||||
'hours',
|
||||
'minutes',
|
||||
'seconds',
|
||||
'milliseconds',
|
||||
];
|
||||
|
||||
/**
|
||||
* Reads a duration from a config object.
|
||||
*
|
||||
* @public
|
||||
* @remarks
|
||||
*
|
||||
* This does not support optionality; if you want to support optional durations,
|
||||
* you need to first check the presence of the target with `config.has(...)` and
|
||||
* then call this function.
|
||||
*
|
||||
* @param config - A configuration object
|
||||
* @param key - If specified, read the duration from the given subkey
|
||||
* under the config object
|
||||
* @returns A duration object
|
||||
*/
|
||||
export function readDurationFromConfig(
|
||||
config: Config,
|
||||
options?: {
|
||||
key?: string;
|
||||
},
|
||||
): HumanDuration {
|
||||
let root: Config;
|
||||
let found = false;
|
||||
const result: Record<string, number> = {};
|
||||
|
||||
try {
|
||||
root = options?.key ? config.getConfig(options.key) : config;
|
||||
for (const prop of propsOfHumanDuration) {
|
||||
const value = root.getOptionalNumber(prop);
|
||||
if (value !== undefined) {
|
||||
result[prop] = value;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// This needs no contextual key prefix since the config reader adds it to
|
||||
// its own errors
|
||||
throw new InputError(`Failed to read duration from config, ${error}`);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!found) {
|
||||
const good = propsOfHumanDuration.map(p => `'${p}'`).join(', ');
|
||||
throw new Error(`Needs one or more of ${good}`);
|
||||
}
|
||||
|
||||
const invalidProps = root
|
||||
.keys()
|
||||
.filter(prop => !propsOfHumanDuration.includes(prop));
|
||||
if (invalidProps.length) {
|
||||
const what = invalidProps.length === 1 ? 'property' : 'properties';
|
||||
const bad = invalidProps.map(p => `'${p}'`).join(', ');
|
||||
const good = propsOfHumanDuration.map(p => `'${p}'`).join(', ');
|
||||
throw new Error(
|
||||
`Unknown ${what} ${bad}; expected one or more of ${good}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// For our own errors, even though we don't know where we are anchored in
|
||||
// the config hierarchy, we try to be helpful and at least add the subkey if
|
||||
// we have it
|
||||
let prefix = 'Failed to read duration from config';
|
||||
if (options?.key) {
|
||||
prefix += ` at '${options.key}'`;
|
||||
}
|
||||
throw new InputError(`${prefix}, ${error}`);
|
||||
}
|
||||
|
||||
return result as HumanDuration;
|
||||
}
|
||||
Reference in New Issue
Block a user