Modifications after PR review
* Change entity filter to be an actual entity filter instead of a list of kinds or types * Modify/simplify types a little bit * Split common type libs to one for node and one isomorphic * Remove unnecessary items from FactChecker interface to simplify execution loop. Needs still matching README.md changes. Signed-off-by: Jussi Hallila <jussi@hallila.com>
This commit is contained in:
@@ -5,12 +5,12 @@
|
||||
```ts
|
||||
import { BooleanCheckResult } from '@backstage/plugin-tech-insights-common';
|
||||
import { CheckResponse } from '@backstage/plugin-tech-insights-common';
|
||||
import { CheckValidationResponse } from '@backstage/plugin-tech-insights-common';
|
||||
import { FactChecker } from '@backstage/plugin-tech-insights-common';
|
||||
import { CheckValidationResponse } from '@backstage/plugin-tech-insights-node';
|
||||
import { FactChecker } from '@backstage/plugin-tech-insights-node';
|
||||
import { Logger as Logger_2 } from 'winston';
|
||||
import { TechInsightCheck } from '@backstage/plugin-tech-insights-common';
|
||||
import { TechInsightCheckRegistry } from '@backstage/plugin-tech-insights-common';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-common';
|
||||
import { TechInsightCheck } from '@backstage/plugin-tech-insights-node';
|
||||
import { TechInsightCheckRegistry } from '@backstage/plugin-tech-insights-node';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-node';
|
||||
import { TopLevelCondition } from 'json-rules-engine';
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -52,13 +52,11 @@ export class JsonRulesEngineFactChecker
|
||||
checkRegistry,
|
||||
}: JsonRulesEngineFactCheckerOptions);
|
||||
// (undocumented)
|
||||
addCheck(check: TechInsightJsonRuleCheck): Promise<TechInsightJsonRuleCheck>;
|
||||
// (undocumented)
|
||||
getChecks(): Promise<TechInsightJsonRuleCheck[]>;
|
||||
// (undocumented)
|
||||
runChecks(
|
||||
entity: string,
|
||||
checks: string[],
|
||||
checks?: string[],
|
||||
): Promise<JsonRuleBooleanCheckResult[]>;
|
||||
// (undocumented)
|
||||
validate(check: TechInsightJsonRuleCheck): Promise<CheckValidationResponse>;
|
||||
@@ -79,7 +77,7 @@ export class JsonRulesEngineFactCheckerFactory {
|
||||
export type JsonRulesEngineFactCheckerFactoryOptions = {
|
||||
checks: TechInsightJsonRuleCheck[];
|
||||
logger: Logger_2;
|
||||
checkRegistry?: TechInsightCheckRegistry<any>;
|
||||
checkRegistry?: TechInsightCheckRegistry<TechInsightJsonRuleCheck>;
|
||||
};
|
||||
|
||||
// @public
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@backstage/plugin-tech-insights-backend-module-jsonfc",
|
||||
"version": "0.1.0",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
@@ -35,11 +35,11 @@
|
||||
"@backstage/config": "^0.1.8",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@backstage/plugin-tech-insights-common": "^0.1.0",
|
||||
"@backstage/plugin-tech-insights-node": "^0.1.0",
|
||||
"ajv": "^7.0.3",
|
||||
"json-rules-engine": "^6.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^2.0.2",
|
||||
"node-cron": "^3.0.0",
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { ConflictError, NotFoundError } from '@backstage/errors';
|
||||
import {
|
||||
TechInsightCheck,
|
||||
TechInsightCheckRegistry,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
|
||||
export class DefaultCheckRegistry<CheckType extends TechInsightCheck>
|
||||
implements TechInsightCheckRegistry<CheckType>
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
import {
|
||||
TechInsightCheckRegistry,
|
||||
TechInsightsStore,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
import {
|
||||
JSON_RULE_ENGINE_CHECK_TYPE,
|
||||
JsonRulesEngineFactCheckerFactory,
|
||||
|
||||
+16
-26
@@ -17,13 +17,12 @@
|
||||
import { JsonRuleBooleanCheckResult, TechInsightJsonRuleCheck } from '../types';
|
||||
import {
|
||||
FactChecker,
|
||||
FactResponse,
|
||||
TechInsightCheckRegistry,
|
||||
FlatTechInsightFact,
|
||||
TechInsightsStore,
|
||||
CheckValidationResponse,
|
||||
CheckValidationError,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
import { FactResponse } from '@backstage/plugin-tech-insights-common';
|
||||
import { Engine, EngineResult, TopLevelCondition } from 'json-rules-engine';
|
||||
import { DefaultCheckRegistry } from './CheckRegistry';
|
||||
import { Logger } from 'winston';
|
||||
@@ -71,15 +70,19 @@ export class JsonRulesEngineFactChecker
|
||||
this.repository = repository;
|
||||
this.logger = logger;
|
||||
checks.forEach(check => this.validate(check));
|
||||
this.checkRegistry = checkRegistry ?? new DefaultCheckRegistry(checks);
|
||||
this.checkRegistry =
|
||||
checkRegistry ??
|
||||
new DefaultCheckRegistry<TechInsightJsonRuleCheck>(checks);
|
||||
}
|
||||
|
||||
async runChecks(
|
||||
entity: string,
|
||||
checks: string[],
|
||||
checks?: string[],
|
||||
): Promise<JsonRuleBooleanCheckResult[]> {
|
||||
const engine = new Engine();
|
||||
const techInsightChecks = await this.checkRegistry.getAll(checks);
|
||||
const techInsightChecks = checks
|
||||
? await this.checkRegistry.getAll(checks)
|
||||
: await this.checkRegistry.list();
|
||||
const factIds = techInsightChecks.flatMap(it => it.factIds);
|
||||
const facts = await this.repository.getLatestFactsByIds(factIds, entity);
|
||||
techInsightChecks.forEach(techInsightCheck => {
|
||||
@@ -127,7 +130,7 @@ export class JsonRulesEngineFactChecker
|
||||
return {
|
||||
valid: false,
|
||||
message: msg,
|
||||
errors: validator.errors,
|
||||
errors: validator.errors ? validator.errors : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -166,21 +169,6 @@ export class JsonRulesEngineFactChecker
|
||||
return this.checkRegistry.list();
|
||||
}
|
||||
|
||||
async addCheck(
|
||||
check: TechInsightJsonRuleCheck,
|
||||
): Promise<TechInsightJsonRuleCheck> {
|
||||
const checkValidationResponse = await this.validate(check);
|
||||
if (!checkValidationResponse.valid) {
|
||||
const msg = `Check validation failed when adding check ${check.name} to check registry.`;
|
||||
this.logger.warn(msg);
|
||||
throw new CheckValidationError({
|
||||
message: checkValidationResponse.message || msg,
|
||||
errors: checkValidationResponse.errors,
|
||||
});
|
||||
}
|
||||
return await this.checkRegistry.register(check);
|
||||
}
|
||||
|
||||
private retrieveIndividualFactReferences(
|
||||
condition: TopLevelCondition | { fact: string },
|
||||
): string[] {
|
||||
@@ -255,8 +243,10 @@ export class JsonRulesEngineFactChecker
|
||||
};
|
||||
|
||||
if ('toJSON' in result) {
|
||||
// Results serialize "wrong" since the objects are creating their own serialization implementations
|
||||
// 'toJSON' should always be present in the result object but it is missing from the types
|
||||
// Results from json-rules-engine serialize "wrong" since the objects are creating their own serialization implementations.
|
||||
// 'toJSON' should always be present in the result object but it is missing from the types.
|
||||
// Parsing the stringified representation into a plain object here to be able to serialize it later
|
||||
// along with other items present in the returned response.
|
||||
const rule = JSON.parse(result.toJSON());
|
||||
return { ...returnable, rule: pick(rule, ['conditions']) };
|
||||
}
|
||||
@@ -312,7 +302,7 @@ export class JsonRulesEngineFactChecker
|
||||
export type JsonRulesEngineFactCheckerFactoryOptions = {
|
||||
checks: TechInsightJsonRuleCheck[];
|
||||
logger: Logger;
|
||||
checkRegistry?: TechInsightCheckRegistry<any>;
|
||||
checkRegistry?: TechInsightCheckRegistry<TechInsightJsonRuleCheck>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -325,7 +315,7 @@ export type JsonRulesEngineFactCheckerFactoryOptions = {
|
||||
export class JsonRulesEngineFactCheckerFactory {
|
||||
private readonly checks: TechInsightJsonRuleCheck[];
|
||||
private readonly logger: Logger;
|
||||
private readonly checkRegistry?: TechInsightCheckRegistry<any>;
|
||||
private readonly checkRegistry?: TechInsightCheckRegistry<TechInsightJsonRuleCheck>;
|
||||
|
||||
constructor({
|
||||
checks,
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { TopLevelCondition } from 'json-rules-engine';
|
||||
import { TechInsightCheck } from '@backstage/plugin-tech-insights-node';
|
||||
import {
|
||||
BooleanCheckResult,
|
||||
CheckResponse,
|
||||
TechInsightCheck,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,16 +77,18 @@ you will not have any fact retrievers present in your application. To have the i
|
||||
To create factRetrieverRegistration you need to implement `FactRetriever` interface defined in `@backstage/plugin-tech-insights-common` package. After you have implemented this interface you can wrap that into a registration object like follows:
|
||||
|
||||
```ts
|
||||
const myFactRetriever: FactRetriever = {
|
||||
import { createFactRetrieverRegistration } from './createFactRetriever';
|
||||
|
||||
const myFactRetriever = {
|
||||
/**
|
||||
* snip
|
||||
*/
|
||||
};
|
||||
|
||||
const myFactRetrieverRegistration = {
|
||||
cadence: '1 * 3 * * ', // On the first minute of the third day of the month
|
||||
factRetriever: myFactRetriever,
|
||||
};
|
||||
const myFactRetrieverRegistration = createFactRetrieverRegistration(
|
||||
'1 * 3 * * ', // On the first minute of the third day of the month
|
||||
myFactRetriever,
|
||||
);
|
||||
```
|
||||
|
||||
Then you can modify the example `techInsights.ts` file shown above like this:
|
||||
@@ -104,28 +106,25 @@ discovery,
|
||||
|
||||
### Creating Fact Retrievers
|
||||
|
||||
A Fact Retriever consist of three parts:
|
||||
A Fact Retriever consist of four parts:
|
||||
|
||||
1. `ref` - unique identifier of a fact retriever
|
||||
2. `schema` - A versioned schema defining the shape of data a fact retriever returns
|
||||
3. `handler` - An asynchronous function handling the logic of retrieving and returning facts for an entity
|
||||
1. `id` - unique identifier of a fact retriever
|
||||
2. `version`: A semver string indicating the current version of the schema and the handler
|
||||
3. `schema` - A versioned schema defining the shape of data a fact retriever returns
|
||||
4. `handler` - An asynchronous function handling the logic of retrieving and returning facts for an entity
|
||||
|
||||
An example implementation of a FactRetriever could for example be as follows:
|
||||
|
||||
```ts
|
||||
const myFactRetriever: FactRetriever = {
|
||||
ref: 'documentation-number-factretriever', // unique ref, identifier of the fact retriever
|
||||
id: 'documentation-number-factretriever', // unique identifier of the fact retriever
|
||||
version: '0.1.1', // SemVer version number of this fact retriever schema. This should be incremented if the implementation changes
|
||||
schema: {
|
||||
version: '0.1.1', // SemVer version number of this fact retriever schema. This should be incremented if the implementation changes
|
||||
|
||||
// the actual schema
|
||||
schema: {
|
||||
// Name/identifier of an individual fact that this retriever returns
|
||||
examplenumberfact: {
|
||||
type: 'integer', // Type of the fact
|
||||
description: 'A fact of a number', // Description of the fact
|
||||
entityTypes: ['component'], // An array of entity kinds that this fact is applicable to
|
||||
},
|
||||
// Name/identifier of an individual fact that this retriever returns
|
||||
examplenumberfact: {
|
||||
type: 'integer', // Type of the fact
|
||||
description: 'A fact of a number', // Description of the fact
|
||||
entityTypes: ['component'], // An array of entity kinds that this fact is applicable to
|
||||
},
|
||||
},
|
||||
handler: async ctx => {
|
||||
|
||||
@@ -6,17 +6,16 @@
|
||||
import { CheckResult } from '@backstage/plugin-tech-insights-common';
|
||||
import { Config } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import { FactChecker } from '@backstage/plugin-tech-insights-common';
|
||||
import { FactCheckerFactory } from '@backstage/plugin-tech-insights-common';
|
||||
import { FactRetrieverRegistration } from '@backstage/plugin-tech-insights-common';
|
||||
import { FactChecker } from '@backstage/plugin-tech-insights-node';
|
||||
import { FactCheckerFactory } from '@backstage/plugin-tech-insights-node';
|
||||
import { FactRetriever } from '@backstage/plugin-tech-insights-node';
|
||||
import { FactRetrieverRegistration } from '@backstage/plugin-tech-insights-node';
|
||||
import { Logger as Logger_2 } from 'winston';
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import { TechInsightCheck } from '@backstage/plugin-tech-insights-common';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-common';
|
||||
import { TechInsightCheck } from '@backstage/plugin-tech-insights-node';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-node';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "buildTechInsightsContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export const buildTechInsightsContext: <
|
||||
CheckType extends TechInsightCheck,
|
||||
@@ -25,6 +24,12 @@ export const buildTechInsightsContext: <
|
||||
options: TechInsightsOptions<CheckType, CheckResultType>,
|
||||
) => Promise<TechInsightsContext<CheckType, CheckResultType>>;
|
||||
|
||||
// @public
|
||||
export function createFactRetrieverRegistration(
|
||||
cadence: string,
|
||||
factRetriever: FactRetriever,
|
||||
): FactRetrieverRegistration;
|
||||
|
||||
// @public
|
||||
export function createRouter<
|
||||
CheckType extends TechInsightCheck,
|
||||
|
||||
@@ -33,10 +33,10 @@ exports.up = async function up(knex) {
|
||||
.notNullable()
|
||||
.comment('SemVer string defining the version of schema.');
|
||||
table
|
||||
.string('entityTypes')
|
||||
.string('entityFilter')
|
||||
.nullable()
|
||||
.comment(
|
||||
'A comma separated collection of entity kinds the fact retriever providing this schema affects. Defaults to null, which means all entity kinds.',
|
||||
'A serialized entity filter object used to determine which entities this schema is applicable to.',
|
||||
);
|
||||
table
|
||||
.text('schema')
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"@backstage/config": "^0.1.8",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@backstage/plugin-tech-insights-common": "^0.1.0",
|
||||
"@backstage/plugin-tech-insights-node": "^0.1.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"cross-fetch": "^3.0.6",
|
||||
"express": "^4.17.1",
|
||||
|
||||
@@ -24,3 +24,4 @@ export type {
|
||||
} from './service/techInsightsContextBuilder';
|
||||
|
||||
export type { PersistenceContext } from './service/persistence/DatabaseManager';
|
||||
export { createFactRetrieverRegistration } from './service/fact/createFactRetriever';
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
FactSchemaDefinition,
|
||||
TechInsightFact,
|
||||
TechInsightsStore,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
import { FactRetrieverRegistry } from './FactRetrieverRegistry';
|
||||
import { FactRetrieverEngine } from './FactRetrieverEngine';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
@@ -37,7 +37,7 @@ jest.mock('node-cron', () => {
|
||||
const testFactRetriever: FactRetriever = {
|
||||
id: 'test-factretriever',
|
||||
version: '0.0.1',
|
||||
entityTypes: ['component'],
|
||||
entityFilter: [{ kind: 'component' }],
|
||||
schema: {
|
||||
testnumberfact: {
|
||||
type: 'integer',
|
||||
@@ -101,10 +101,10 @@ describe('FactRetrieverEngine', () => {
|
||||
};
|
||||
|
||||
it('Should update fact retriever schemas on initialization', async () => {
|
||||
factSchemaAssertionCallback = ({ id, schema, version, entityTypes }) => {
|
||||
factSchemaAssertionCallback = ({ id, schema, version, entityFilter }) => {
|
||||
expect(id).toEqual('test-factretriever');
|
||||
expect(version).toEqual('0.0.1');
|
||||
expect(entityTypes).toEqual(['component']);
|
||||
expect(entityFilter).toEqual([{ kind: 'component' }]);
|
||||
expect(schema).toEqual({
|
||||
testnumberfact: {
|
||||
type: 'integer',
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
FactRetriever,
|
||||
FactRetrieverContext,
|
||||
TechInsightsStore,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
import { FactRetrieverRegistry } from './FactRetrieverRegistry';
|
||||
import { schedule, validate, ScheduledTask } from 'node-cron';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
FactRetriever,
|
||||
FactRetrieverRegistration,
|
||||
FactSchema,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
import { ConflictError, NotFoundError } from '@backstage/errors';
|
||||
|
||||
export class FactRetrieverRegistry {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2021 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 {
|
||||
FactRetriever,
|
||||
FactRetrieverRegistration,
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* A helper function to construct fact retriever registrations.
|
||||
*
|
||||
* Cron expressions help:
|
||||
* ┌────────────── second (optional)
|
||||
# │ ┌──────────── minute
|
||||
# │ │ ┌────────── hour
|
||||
# │ │ │ ┌──────── day of month
|
||||
# │ │ │ │ ┌────── month
|
||||
# │ │ │ │ │ ┌──── day of week
|
||||
# │ │ │ │ │ │
|
||||
# │ │ │ │ │ │
|
||||
# * * * * * *
|
||||
*
|
||||
*
|
||||
* @param cadence - cron expression to indicate when the fact retriever should be triggered
|
||||
* @param factRetriever - Implementation of fact retriever consisting of at least id, version, schema and handler
|
||||
*/
|
||||
export function createFactRetrieverRegistration(
|
||||
cadence: string,
|
||||
factRetriever: FactRetriever,
|
||||
): FactRetrieverRegistration {
|
||||
return {
|
||||
cadence,
|
||||
factRetriever,
|
||||
};
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import knexFactory, { Knex } from 'knex';
|
||||
import { Logger } from 'winston';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { TechInsightsDatabase } from './TechInsightsDatabase';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-common';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-node';
|
||||
|
||||
const migrationsDir = resolvePackagePath(
|
||||
'@backstage/plugin-tech-insights-backend',
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
import { DatabaseManager } from './DatabaseManager';
|
||||
import { DateTime, Duration } from 'luxon';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-common';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-node';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
const factSchemas = [
|
||||
{
|
||||
id: 'test-fact',
|
||||
version: '0.0.1-test',
|
||||
entityTypes: ['component'],
|
||||
entityFilter: JSON.stringify([{ kind: 'component' }]),
|
||||
schema: JSON.stringify({
|
||||
testNumberFact: {
|
||||
type: 'integer',
|
||||
@@ -35,7 +35,7 @@ const additionalFactSchemas = [
|
||||
{
|
||||
id: 'test-fact',
|
||||
version: '1.2.1-test',
|
||||
entityTypes: ['component'],
|
||||
entityFilter: JSON.stringify([{ kind: 'component' }]),
|
||||
schema: JSON.stringify({
|
||||
testNumberFact: {
|
||||
type: 'integer',
|
||||
@@ -50,7 +50,7 @@ const additionalFactSchemas = [
|
||||
{
|
||||
id: 'test-fact',
|
||||
version: '1.1.1-test',
|
||||
entityTypes: ['component'],
|
||||
entityFilter: JSON.stringify([{ kind: 'component' }]),
|
||||
schema: JSON.stringify({
|
||||
testStringFact: {
|
||||
type: 'string',
|
||||
@@ -63,7 +63,7 @@ const additionalFactSchemas = [
|
||||
const secondSchema = {
|
||||
id: 'second-test-fact',
|
||||
version: '0.0.1-test',
|
||||
entityTypes: ['service'],
|
||||
entityFilter: JSON.stringify([{ kind: 'service' }]),
|
||||
schema: JSON.stringify({
|
||||
testStringFact: {
|
||||
type: 'string',
|
||||
@@ -137,7 +137,7 @@ describe('Tech Insights database', () => {
|
||||
expect(schemas[0]).toMatchObject({
|
||||
id: 'test-fact',
|
||||
version: '0.0.1-test',
|
||||
entityTypes: ['component'],
|
||||
entityFilter: [{ kind: 'component' }],
|
||||
testNumberFact: {
|
||||
type: 'integer',
|
||||
description: 'Test fact with a number type',
|
||||
@@ -152,7 +152,7 @@ describe('Tech Insights database', () => {
|
||||
expect(schemas[0]).toMatchObject({
|
||||
id: 'test-fact',
|
||||
version: '1.2.1-test',
|
||||
entityTypes: ['component'],
|
||||
entityFilter: [{ kind: 'component' }],
|
||||
testNumberFact: {
|
||||
type: 'integer',
|
||||
description: 'Test fact with a number type',
|
||||
@@ -177,7 +177,7 @@ describe('Tech Insights database', () => {
|
||||
expect(schemas[0]).toMatchObject({
|
||||
id: 'test-fact',
|
||||
version: '1.2.1-test',
|
||||
entityTypes: ['component'],
|
||||
entityFilter: [{ kind: 'component' }],
|
||||
testNumberFact: {
|
||||
type: 'integer',
|
||||
description: 'Test fact with a number type',
|
||||
@@ -190,7 +190,7 @@ describe('Tech Insights database', () => {
|
||||
expect(schemas[1]).toMatchObject({
|
||||
id: 'second',
|
||||
version: '0.0.1-test',
|
||||
entityTypes: ['service'],
|
||||
entityFilter: [{ kind: 'service' }],
|
||||
testStringFact: {
|
||||
type: 'string',
|
||||
description: 'Test fact with a string type',
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
FlatTechInsightFact,
|
||||
TechInsightsStore,
|
||||
FactSchemaDefinition,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
import { rsort } from 'semver';
|
||||
import { groupBy, omit } from 'lodash';
|
||||
import { DateTime } from 'luxon';
|
||||
@@ -39,7 +39,7 @@ type RawDbFactSchemaRow = {
|
||||
id: string;
|
||||
version: string;
|
||||
schema: string;
|
||||
entityTypes?: string;
|
||||
entityFilter?: string;
|
||||
};
|
||||
|
||||
export class TechInsightsDatabase implements TechInsightsStore {
|
||||
@@ -63,12 +63,12 @@ export class TechInsightsDatabase implements TechInsightsStore {
|
||||
.map((it: RawDbFactSchemaRow) => ({
|
||||
...omit(it, 'schema'),
|
||||
...JSON.parse(it.schema),
|
||||
entityTypes: it.entityTypes ? it.entityTypes.split(',') : [],
|
||||
entityFilter: it.entityFilter ? JSON.parse(it.entityFilter) : null,
|
||||
}));
|
||||
}
|
||||
|
||||
async insertFactSchema(schemaDefinition: FactSchemaDefinition) {
|
||||
const { id, version, schema, entityTypes } = schemaDefinition;
|
||||
const { id, version, schema, entityFilter } = schemaDefinition;
|
||||
const existingSchemas = await this.db<RawDbFactSchemaRow>('fact_schemas')
|
||||
.where({ id })
|
||||
.and.where({ version })
|
||||
@@ -78,7 +78,7 @@ export class TechInsightsDatabase implements TechInsightsStore {
|
||||
await this.db<RawDbFactSchemaRow>('fact_schemas').insert({
|
||||
id,
|
||||
version,
|
||||
entityTypes: entityTypes && entityTypes.join(','),
|
||||
entityFilter: entityFilter ? JSON.stringify(entityFilter) : undefined,
|
||||
schema: JSON.stringify(schema),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ConfigReader } from '@backstage/config';
|
||||
import request from 'supertest';
|
||||
import express from 'express';
|
||||
import { PersistenceContext } from './persistence/DatabaseManager';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-common';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-node';
|
||||
import { DateTime } from 'luxon';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
|
||||
@@ -20,8 +20,9 @@ import { Config } from '@backstage/config';
|
||||
import {
|
||||
FactChecker,
|
||||
TechInsightCheck,
|
||||
CheckResult,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
|
||||
import { CheckResult } from '@backstage/plugin-tech-insights-common';
|
||||
import { Logger } from 'winston';
|
||||
import { DateTime } from 'luxon';
|
||||
import { PersistenceContext } from './persistence/DatabaseManager';
|
||||
|
||||
@@ -23,16 +23,16 @@ import {
|
||||
PluginEndpointDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
import {
|
||||
CheckResult,
|
||||
FactChecker,
|
||||
FactCheckerFactory,
|
||||
FactRetrieverRegistration,
|
||||
TechInsightCheck,
|
||||
} from '@backstage/plugin-tech-insights-common';
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
import {
|
||||
DatabaseManager,
|
||||
PersistenceContext,
|
||||
} from './persistence/DatabaseManager';
|
||||
import { CheckResult } from '@backstage/plugin-tech-insights-common';
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -80,6 +80,8 @@ export type TechInsightsContext<
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* Constructs needed persistence context, fact retriever engine
|
||||
* and optionally fact checker implementations to be used in the tech insights module.
|
||||
*
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Tech Insights Common
|
||||
|
||||
Common types and functionalities for tech insights, to be shared between tech-insights-backend and individual implementations of FactRetrievers, FactCheckers and their persistence options.
|
||||
Common types and functionalities for tech insights shared in an isomorphic manner between BE and FE implementations.
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { Config } from '@backstage/config';
|
||||
import { DateTime } from 'luxon';
|
||||
import { Logger as Logger_2 } from 'winston';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
|
||||
// @public
|
||||
export interface BooleanCheckResult extends CheckResult {
|
||||
@@ -30,42 +27,6 @@ export type CheckResult = {
|
||||
check: CheckResponse;
|
||||
};
|
||||
|
||||
// @public
|
||||
export class CheckValidationError extends Error {
|
||||
constructor({ message, errors }: { message: string; errors?: any });
|
||||
// (undocumented)
|
||||
errors?: any;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type CheckValidationResponse = {
|
||||
valid: boolean;
|
||||
message?: string;
|
||||
errors?: any;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface FactChecker<
|
||||
CheckType extends TechInsightCheck,
|
||||
CheckResultType extends CheckResult,
|
||||
> {
|
||||
addCheck(check: CheckType): Promise<CheckType>;
|
||||
getChecks(): Promise<CheckType[]>;
|
||||
runChecks(entity: string, checks: string[]): Promise<CheckResultType[]>;
|
||||
validate(check: CheckType): Promise<CheckValidationResponse>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface FactCheckerFactory<
|
||||
CheckType extends TechInsightCheck,
|
||||
CheckResultType extends CheckResult,
|
||||
> {
|
||||
// (undocumented)
|
||||
construct(
|
||||
repository: TechInsightsStore,
|
||||
): FactChecker<CheckType, CheckResultType>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type FactResponse = {
|
||||
[id: string]: {
|
||||
@@ -78,113 +39,5 @@ export type FactResponse = {
|
||||
};
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface FactRetriever {
|
||||
entityTypes?: string[];
|
||||
handler: (ctx: FactRetrieverContext) => Promise<TechInsightFact[]>;
|
||||
id: string;
|
||||
schema: FactSchema;
|
||||
version: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type FactRetrieverContext = {
|
||||
config: Config;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
logger: Logger_2;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type FactRetrieverRegistration = {
|
||||
factRetriever: FactRetriever;
|
||||
cadence?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type FactSchema = {
|
||||
[name: string]: {
|
||||
type: 'integer' | 'float' | 'string' | 'boolean' | 'datetime' | 'set';
|
||||
description: string;
|
||||
since?: string;
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "FactSchemaDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type FactSchemaDefinition = Omit<FactRetriever, 'handler'>;
|
||||
|
||||
// @public
|
||||
export type FlatTechInsightFact = TechInsightFact & {
|
||||
id: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface TechInsightCheck {
|
||||
description: string;
|
||||
factIds: string[];
|
||||
failureMetadata?: Record<string, any>;
|
||||
id: string;
|
||||
name: string;
|
||||
successMetadata?: Record<string, any>;
|
||||
type: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface TechInsightCheckRegistry<CheckType extends TechInsightCheck> {
|
||||
// (undocumented)
|
||||
get(checkId: string): Promise<CheckType>;
|
||||
// (undocumented)
|
||||
getAll(checks: string[]): Promise<CheckType[]>;
|
||||
// (undocumented)
|
||||
list(): Promise<CheckType[]>;
|
||||
// (undocumented)
|
||||
register(check: CheckType): Promise<CheckType>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type TechInsightFact = {
|
||||
entity: {
|
||||
namespace: string;
|
||||
kind: string;
|
||||
name: string;
|
||||
};
|
||||
facts: Record<
|
||||
string,
|
||||
| number
|
||||
| string
|
||||
| boolean
|
||||
| DateTime
|
||||
| number[]
|
||||
| string[]
|
||||
| boolean[]
|
||||
| DateTime[]
|
||||
>;
|
||||
timestamp?: DateTime;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface TechInsightsStore {
|
||||
getFactsBetweenTimestampsByIds(
|
||||
ids: string[],
|
||||
entity: string,
|
||||
startDateTime: DateTime,
|
||||
endDateTime: DateTime,
|
||||
): Promise<{
|
||||
[factRef: string]: FlatTechInsightFact[];
|
||||
}>;
|
||||
// (undocumented)
|
||||
getLatestFactsByIds(
|
||||
ids: string[],
|
||||
entity: string,
|
||||
): Promise<{
|
||||
[factRef: string]: FlatTechInsightFact;
|
||||
}>;
|
||||
getLatestSchemas(ids?: string[]): Promise<FactSchema[]>;
|
||||
insertFacts(id: string, facts: TechInsightFact[]): Promise<void>;
|
||||
insertFactSchema(schemaDefinition: FactSchemaDefinition): Promise<void>;
|
||||
}
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -30,11 +30,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.9.0",
|
||||
"@backstage/config": "^0.1.8",
|
||||
"@types/luxon": "^2.0.5",
|
||||
"luxon": "^2.0.2",
|
||||
"winston": "^3.2.1"
|
||||
"luxon": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.7.1"
|
||||
|
||||
@@ -14,7 +14,111 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './checks';
|
||||
export * from './facts';
|
||||
export * from './persistence';
|
||||
export * from './responses';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* Response type for checks.
|
||||
*/
|
||||
export interface CheckResponse {
|
||||
/**
|
||||
* Identifier of the Check
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Type identifier for the check.
|
||||
* Can be used to determine storage options, logical routing to correct FactChecker implementation
|
||||
* or to help frontend render correct component types based on this
|
||||
*/
|
||||
type: string;
|
||||
/**
|
||||
* Human readable name of the Check
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Description of the Check
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* A collection of references to fact rows used to run this checks against
|
||||
*/
|
||||
factIds: string[];
|
||||
|
||||
/**
|
||||
* Metadata related to a check.
|
||||
* Can contain links, additional description texts and other actionable data.
|
||||
*
|
||||
* Currently loosely typed, but in the future when patterns emerge, key shapes can be defined
|
||||
*/
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* Individual fact response type.
|
||||
* Keyed by the name of the fact
|
||||
*/
|
||||
export type FactResponse = {
|
||||
[id: string]: {
|
||||
/**
|
||||
* Reference and unique identifier of the fact row
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Type of the individual fact value
|
||||
*
|
||||
* Numbers are split into integers and floating point values.
|
||||
* `set` indicates a collection of values
|
||||
*/
|
||||
type: 'integer' | 'float' | 'string' | 'boolean' | 'datetime' | 'set';
|
||||
|
||||
/**
|
||||
* Description of the individual fact
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* Actual value of the fact
|
||||
*/
|
||||
value: number | string | boolean | DateTime | [];
|
||||
|
||||
/**
|
||||
* An optional SemVer version identifying when this fact was added to the FactSchema
|
||||
*/
|
||||
since?: string;
|
||||
|
||||
/**
|
||||
* Metadata related to an individual fact.
|
||||
* Can contain links, additional description texts and other actionable data.
|
||||
*
|
||||
* Currently loosely typed, but in the future when patterns emerge, key shapes can be defined
|
||||
*/
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic CheckResult
|
||||
*
|
||||
* Contains information about the facts used to calculate the check result
|
||||
* and information about the check itself. Both may include metadata to be able to display additional information.
|
||||
* A collection of these should be parseable by the frontend to display scorecards
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CheckResult = {
|
||||
facts: FactResponse;
|
||||
check: CheckResponse;
|
||||
};
|
||||
|
||||
/**
|
||||
* CheckResult of type Boolean.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BooleanCheckResult extends CheckResult {
|
||||
result: boolean;
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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 { DateTime } from 'luxon';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* Response type for checks.
|
||||
*/
|
||||
export interface CheckResponse {
|
||||
/**
|
||||
* Identifier of the Check
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Type identifier for the check.
|
||||
* Can be used to determine storage options, logical routing to correct FactChecker implementation
|
||||
* or to help frontend render correct component types based on this
|
||||
*/
|
||||
type: string;
|
||||
/**
|
||||
* Human readable name of the Check
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Description of the Check
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* A collection of references to fact rows used to run this checks against
|
||||
*/
|
||||
factIds: string[];
|
||||
|
||||
/**
|
||||
* Metadata related to a check.
|
||||
* Can contain links, additional description texts and other actionable data.
|
||||
*
|
||||
* Currently loosely typed, but in the future when patterns emerge, key shapes can be defined
|
||||
*/
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* Individual fact response type.
|
||||
* Keyed by the name of the fact
|
||||
*/
|
||||
export type FactResponse = {
|
||||
[id: string]: {
|
||||
/**
|
||||
* Reference and unique identifier of the fact row
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Type of the individual fact value
|
||||
*
|
||||
* Numbers are split into integers and floating point values.
|
||||
* `set` indicates a collection of values
|
||||
*/
|
||||
type: 'integer' | 'float' | 'string' | 'boolean' | 'datetime' | 'set';
|
||||
|
||||
/**
|
||||
* Description of the individual fact
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* Actual value of the fact
|
||||
*/
|
||||
value: number | string | boolean | DateTime | [];
|
||||
|
||||
/**
|
||||
* An optional SemVer version identifying when this fact was added to the FactSchema
|
||||
*/
|
||||
since?: string;
|
||||
|
||||
/**
|
||||
* Metadata related to an individual fact.
|
||||
* Can contain links, additional description texts and other actionable data.
|
||||
*
|
||||
* Currently loosely typed, but in the future when patterns emerge, key shapes can be defined
|
||||
*/
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
# Tech Insights Node
|
||||
|
||||
Common types and functionalities for tech insights backend implementations to be shared between tech-insights-backend and individual implementations of FactRetrievers, FactCheckers and their persistence options.
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "@backstage/plugin-tech-insights-node",
|
||||
"version": "0.1.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/tech-insights-node"
|
||||
},
|
||||
"keywords": [
|
||||
"backstage",
|
||||
"tech-insights"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "backstage-cli backend:dev",
|
||||
"build": "backstage-cli backend:build",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test",
|
||||
"prepack": "backstage-cli prepack",
|
||||
"postpack": "backstage-cli postpack",
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.9.0",
|
||||
"@backstage/config": "^0.1.8",
|
||||
"@backstage/plugin-tech-insights-common": "^0.1.0 ",
|
||||
"@types/luxon": "^2.0.5",
|
||||
"luxon": "^2.0.2",
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.7.1"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
+3
-51
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { TechInsightsStore } from './persistence';
|
||||
import { CheckResponse, FactResponse } from './responses';
|
||||
import { CheckResult } from '@backstage/plugin-tech-insights-common';
|
||||
|
||||
/**
|
||||
* A factory wrapper to construct FactChecker implementations.
|
||||
@@ -57,16 +57,7 @@ export interface FactChecker<
|
||||
* @param checks - A collection of checks to run against provided entity
|
||||
* @returns - A collection containing check/fact information and the actual results of the check
|
||||
*/
|
||||
runChecks(entity: string, checks: string[]): Promise<CheckResultType[]>;
|
||||
|
||||
/**
|
||||
* Adds and stores new checks so they can be run checks against.
|
||||
* Implementation should ideally run validation against the check.
|
||||
*
|
||||
* @param check - The actual check to be added.
|
||||
* @returns - An indicator if fact was successfully added
|
||||
*/
|
||||
addCheck(check: CheckType): Promise<CheckType>;
|
||||
runChecks(entity: string, checks?: string[]): Promise<CheckResultType[]>;
|
||||
|
||||
/**
|
||||
* Retrieves all available checks that can be used to run checks against.
|
||||
@@ -99,29 +90,6 @@ export interface TechInsightCheckRegistry<CheckType extends TechInsightCheck> {
|
||||
list(): Promise<CheckType[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic CheckResult
|
||||
*
|
||||
* Contains information about the facts used to calculate the check result
|
||||
* and information about the check itself. Both may include metadata to be able to display additional information.
|
||||
* A collection of these should be parseable by the frontend to display scorecards
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CheckResult = {
|
||||
facts: FactResponse;
|
||||
check: CheckResponse;
|
||||
};
|
||||
|
||||
/**
|
||||
* CheckResult of type Boolean.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BooleanCheckResult extends CheckResult {
|
||||
result: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic definition of a check for Tech Insights
|
||||
*
|
||||
@@ -181,21 +149,5 @@ export interface TechInsightCheck {
|
||||
export type CheckValidationResponse = {
|
||||
valid: boolean;
|
||||
message?: string;
|
||||
errors?: any;
|
||||
errors?: unknown[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Error object for Validation Errors
|
||||
*
|
||||
* Can be used to short circuit larger execution paths instead of passing validation response around
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class CheckValidationError extends Error {
|
||||
errors?: any;
|
||||
|
||||
constructor({ message, errors }: { message: string; errors?: any }) {
|
||||
super(message);
|
||||
this.errors = errors;
|
||||
}
|
||||
}
|
||||
@@ -175,14 +175,16 @@ export interface FactRetriever {
|
||||
schema: FactSchema;
|
||||
|
||||
/**
|
||||
* An optional list of entity type descriptors to indicate if this fact retriever is valid for an entity type.
|
||||
* An optional object/array of objects of entity filters to indicate if this fact retriever is valid for an entity type.
|
||||
* If omitted, the retriever should apply to all entities.
|
||||
*
|
||||
* Should be defined as:
|
||||
* ['component', 'group', 'user'] for top level items
|
||||
* ['component:service', 'component:website'] for component types.
|
||||
* Should be defined for example:
|
||||
* { field: 'kind', values: ['component'] }
|
||||
* { field: 'metadata.name', values: ['component-1', 'component-2'] }
|
||||
*/
|
||||
entityTypes?: string[];
|
||||
entityFilter?:
|
||||
| Record<string, string | symbol | (string | symbol)[]>[]
|
||||
| Record<string, string | symbol | (string | symbol)[]>;
|
||||
}
|
||||
|
||||
export type FactSchemaDefinition = Omit<FactRetriever, 'handler'>;
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2021 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 * as anything from './';
|
||||
|
||||
describe('tech-insights-node', () => {
|
||||
// Types only
|
||||
it('should exist', () => {
|
||||
expect(anything).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
export * from './checks';
|
||||
export * from './facts';
|
||||
export * from './persistence';
|
||||
Reference in New Issue
Block a user