From 2b3e959ef47e37b2e944356e4c26bb12ae451e97 Mon Sep 17 00:00:00 2001 From: Jussi Hallila Date: Thu, 28 Oct 2021 16:20:44 +0200 Subject: [PATCH] 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 --- packages/backend/package.json | 2 +- packages/backend/src/plugins/techInsights.ts | 72 +++++---- .../api-report.md | 16 +- .../package.json | 6 +- .../src/service/CheckRegistry.ts | 2 +- .../JsonRulesEngineFactChecker.test.ts | 2 +- .../src/service/JsonRulesEngineFactChecker.ts | 42 ++--- .../src/types.ts | 2 +- plugins/tech-insights-backend/README.md | 39 +++-- plugins/tech-insights-backend/api-report.md | 19 ++- .../migrations/202109061111_fact_schemas.js | 4 +- plugins/tech-insights-backend/package.json | 1 + plugins/tech-insights-backend/src/index.ts | 1 + .../service/fact/FactRetrieverEngine.test.ts | 8 +- .../src/service/fact/FactRetrieverEngine.ts | 2 +- .../src/service/fact/FactRetrieverRegistry.ts | 2 +- .../src/service/fact/createFactRetriever.ts | 49 ++++++ .../service/persistence/DatabaseManager.ts | 2 +- .../persistence/TechInsightsDatabase.test.ts | 18 +-- .../persistence/TechInsightsDatabase.ts | 10 +- .../src/service/router.test.ts | 2 +- .../src/service/router.ts | 5 +- .../src/service/techInsightsContextBuilder.ts | 6 +- plugins/tech-insights-common/README.md | 2 +- plugins/tech-insights-common/api-report.md | 147 ------------------ plugins/tech-insights-common/package.json | 5 +- plugins/tech-insights-common/src/index.ts | 112 ++++++++++++- plugins/tech-insights-common/src/responses.ts | 101 ------------ plugins/tech-insights-node/.eslintrc.js | 3 + plugins/tech-insights-node/README.md | 3 + plugins/tech-insights-node/package.json | 46 ++++++ .../src/checks.ts | 54 +------ .../src/facts.ts | 12 +- plugins/tech-insights-node/src/index.test.ts | 24 +++ plugins/tech-insights-node/src/index.ts | 19 +++ .../src/persistence.ts | 0 .../src/setupTests.ts | 0 37 files changed, 393 insertions(+), 447 deletions(-) create mode 100644 plugins/tech-insights-backend/src/service/fact/createFactRetriever.ts delete mode 100644 plugins/tech-insights-common/src/responses.ts create mode 100644 plugins/tech-insights-node/.eslintrc.js create mode 100644 plugins/tech-insights-node/README.md create mode 100644 plugins/tech-insights-node/package.json rename plugins/{tech-insights-common => tech-insights-node}/src/checks.ts (77%) rename plugins/{tech-insights-common => tech-insights-node}/src/facts.ts (92%) create mode 100644 plugins/tech-insights-node/src/index.test.ts create mode 100644 plugins/tech-insights-node/src/index.ts rename plugins/{tech-insights-common => tech-insights-node}/src/persistence.ts (100%) rename plugins/{tech-insights-common => tech-insights-node}/src/setupTests.ts (100%) diff --git a/packages/backend/package.json b/packages/backend/package.json index a56b302954..f1d58252a4 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -49,7 +49,7 @@ "@backstage/plugin-search-backend-module-pg": "^0.2.1", "@backstage/plugin-techdocs-backend": "^0.10.5", "@backstage/plugin-tech-insights-backend": "^0.1.0", - "@backstage/plugin-tech-insights-common": "^0.1.0", + "@backstage/plugin-tech-insights-node": "^0.1.0", "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.0", "@backstage/plugin-todo-backend": "^0.1.13", "@gitbeaker/node": "^30.2.0", diff --git a/packages/backend/src/plugins/techInsights.ts b/packages/backend/src/plugins/techInsights.ts index d51c0c7575..9927d98f87 100644 --- a/packages/backend/src/plugins/techInsights.ts +++ b/packages/backend/src/plugins/techInsights.ts @@ -16,14 +16,15 @@ import { createRouter, buildTechInsightsContext, + createFactRetrieverRegistration, } from '@backstage/plugin-tech-insights-backend'; import { Router } from 'express'; import { PluginEnvironment } from '../types'; -import { - JSON_RULE_ENGINE_CHECK_TYPE, - JsonRulesEngineFactCheckerFactory, -} from '@backstage/plugin-tech-insights-backend-module-jsonfc'; import { CatalogClient } from '@backstage/catalog-client'; +import { + JsonRulesEngineFactCheckerFactory, + JSON_RULE_ENGINE_CHECK_TYPE, +} from '@backstage/plugin-tech-insights-backend-module-jsonfc'; export default async function createPlugin({ logger, @@ -37,41 +38,38 @@ export default async function createPlugin({ database, discovery, factRetrievers: [ - { - cadence: '1 1 1 * *', // At 01:01 on day-of-month 1. - factRetriever: { - id: 'testRetriever', - version: '1.1.1', - entityTypes: ['component'], - schema: { - examplenumberfact: { - type: 'integer', - description: '', - }, - }, - handler: async _ctx => { - const catalogClient = new CatalogClient({ - discoveryApi: discovery, - }); - const entities = await catalogClient.getEntities(); - - return Promise.resolve( - entities.items.map(it => { - return { - entity: { - namespace: it.metadata.namespace!!, - kind: it.kind, - name: it.metadata.name, - }, - facts: { - examplenumberfact: 2, - }, - }; - }), - ); + createFactRetrieverRegistration('* * * * *', { + id: 'testRetriever', + version: '1.1.2', + entityFilter: [{ kind: 'component' }], // EntityFilter to be used in the future (creating checks, graphs etc.) to figure out which entities this fact retrieves data for. + schema: { + examplenumberfact: { + type: 'integer', + description: 'Example fact returning a number', }, }, - }, + handler: async _ctx => { + const catalogClient = new CatalogClient({ + discoveryApi: discovery, + }); + const entities = await catalogClient.getEntities(); + + return Promise.resolve( + entities.items.map(it => { + return { + entity: { + namespace: it.metadata.namespace!!, + kind: it.kind, + name: it.metadata.name, + }, + facts: { + examplenumberfact: 2, + }, + }; + }), + ); + }, + }), ], factCheckerFactory: new JsonRulesEngineFactCheckerFactory({ checks: [ diff --git a/plugins/tech-insights-backend-module-jsonfc/api-report.md b/plugins/tech-insights-backend-module-jsonfc/api-report.md index 3d214566c5..7093fbfc2b 100644 --- a/plugins/tech-insights-backend-module-jsonfc/api-report.md +++ b/plugins/tech-insights-backend-module-jsonfc/api-report.md @@ -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; - // (undocumented) getChecks(): Promise; // (undocumented) runChecks( entity: string, - checks: string[], + checks?: string[], ): Promise; // (undocumented) validate(check: TechInsightJsonRuleCheck): Promise; @@ -79,7 +77,7 @@ export class JsonRulesEngineFactCheckerFactory { export type JsonRulesEngineFactCheckerFactoryOptions = { checks: TechInsightJsonRuleCheck[]; logger: Logger_2; - checkRegistry?: TechInsightCheckRegistry; + checkRegistry?: TechInsightCheckRegistry; }; // @public diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index c11f20ee38..a1db34a97e 100644 --- a/plugins/tech-insights-backend-module-jsonfc/package.json +++ b/plugins/tech-insights-backend-module-jsonfc/package.json @@ -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": { diff --git a/plugins/tech-insights-backend-module-jsonfc/src/service/CheckRegistry.ts b/plugins/tech-insights-backend-module-jsonfc/src/service/CheckRegistry.ts index 016fb05b31..dec84a8634 100644 --- a/plugins/tech-insights-backend-module-jsonfc/src/service/CheckRegistry.ts +++ b/plugins/tech-insights-backend-module-jsonfc/src/service/CheckRegistry.ts @@ -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 implements TechInsightCheckRegistry diff --git a/plugins/tech-insights-backend-module-jsonfc/src/service/JsonRulesEngineFactChecker.test.ts b/plugins/tech-insights-backend-module-jsonfc/src/service/JsonRulesEngineFactChecker.test.ts index a31ae90c70..77b3e6c8b1 100644 --- a/plugins/tech-insights-backend-module-jsonfc/src/service/JsonRulesEngineFactChecker.test.ts +++ b/plugins/tech-insights-backend-module-jsonfc/src/service/JsonRulesEngineFactChecker.test.ts @@ -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, diff --git a/plugins/tech-insights-backend-module-jsonfc/src/service/JsonRulesEngineFactChecker.ts b/plugins/tech-insights-backend-module-jsonfc/src/service/JsonRulesEngineFactChecker.ts index ab90a3d828..ae1f18a373 100644 --- a/plugins/tech-insights-backend-module-jsonfc/src/service/JsonRulesEngineFactChecker.ts +++ b/plugins/tech-insights-backend-module-jsonfc/src/service/JsonRulesEngineFactChecker.ts @@ -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(checks); } async runChecks( entity: string, - checks: string[], + checks?: string[], ): Promise { 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 { - 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; + checkRegistry?: TechInsightCheckRegistry; }; /** @@ -325,7 +315,7 @@ export type JsonRulesEngineFactCheckerFactoryOptions = { export class JsonRulesEngineFactCheckerFactory { private readonly checks: TechInsightJsonRuleCheck[]; private readonly logger: Logger; - private readonly checkRegistry?: TechInsightCheckRegistry; + private readonly checkRegistry?: TechInsightCheckRegistry; constructor({ checks, diff --git a/plugins/tech-insights-backend-module-jsonfc/src/types.ts b/plugins/tech-insights-backend-module-jsonfc/src/types.ts index 23d5849eda..592fee248d 100644 --- a/plugins/tech-insights-backend-module-jsonfc/src/types.ts +++ b/plugins/tech-insights-backend-module-jsonfc/src/types.ts @@ -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'; /** diff --git a/plugins/tech-insights-backend/README.md b/plugins/tech-insights-backend/README.md index 32265c1ced..2de16b65b0 100644 --- a/plugins/tech-insights-backend/README.md +++ b/plugins/tech-insights-backend/README.md @@ -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 => { diff --git a/plugins/tech-insights-backend/api-report.md b/plugins/tech-insights-backend/api-report.md index 6bd161c092..826789dd1d 100644 --- a/plugins/tech-insights-backend/api-report.md +++ b/plugins/tech-insights-backend/api-report.md @@ -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, ) => Promise>; +// @public +export function createFactRetrieverRegistration( + cadence: string, + factRetriever: FactRetriever, +): FactRetrieverRegistration; + // @public export function createRouter< CheckType extends TechInsightCheck, diff --git a/plugins/tech-insights-backend/migrations/202109061111_fact_schemas.js b/plugins/tech-insights-backend/migrations/202109061111_fact_schemas.js index 64f6c11e83..6094daa4b7 100644 --- a/plugins/tech-insights-backend/migrations/202109061111_fact_schemas.js +++ b/plugins/tech-insights-backend/migrations/202109061111_fact_schemas.js @@ -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') diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index fba5daae45..cf1e1d1c6f 100644 --- a/plugins/tech-insights-backend/package.json +++ b/plugins/tech-insights-backend/package.json @@ -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", diff --git a/plugins/tech-insights-backend/src/index.ts b/plugins/tech-insights-backend/src/index.ts index fd7f3ccd53..2a74bc6b88 100644 --- a/plugins/tech-insights-backend/src/index.ts +++ b/plugins/tech-insights-backend/src/index.ts @@ -24,3 +24,4 @@ export type { } from './service/techInsightsContextBuilder'; export type { PersistenceContext } from './service/persistence/DatabaseManager'; +export { createFactRetrieverRegistration } from './service/fact/createFactRetriever'; diff --git a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.test.ts b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.test.ts index ef53ae8412..4dc002465b 100644 --- a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.test.ts +++ b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.test.ts @@ -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', diff --git a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts index 6dc3396819..aa2207cca8 100644 --- a/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts +++ b/plugins/tech-insights-backend/src/service/fact/FactRetrieverEngine.ts @@ -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'; diff --git a/plugins/tech-insights-backend/src/service/fact/FactRetrieverRegistry.ts b/plugins/tech-insights-backend/src/service/fact/FactRetrieverRegistry.ts index 59d1483720..719f8bf504 100644 --- a/plugins/tech-insights-backend/src/service/fact/FactRetrieverRegistry.ts +++ b/plugins/tech-insights-backend/src/service/fact/FactRetrieverRegistry.ts @@ -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 { diff --git a/plugins/tech-insights-backend/src/service/fact/createFactRetriever.ts b/plugins/tech-insights-backend/src/service/fact/createFactRetriever.ts new file mode 100644 index 0000000000..b744d3b826 --- /dev/null +++ b/plugins/tech-insights-backend/src/service/fact/createFactRetriever.ts @@ -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, + }; +} diff --git a/plugins/tech-insights-backend/src/service/persistence/DatabaseManager.ts b/plugins/tech-insights-backend/src/service/persistence/DatabaseManager.ts index 75fb313f80..126c253fa5 100644 --- a/plugins/tech-insights-backend/src/service/persistence/DatabaseManager.ts +++ b/plugins/tech-insights-backend/src/service/persistence/DatabaseManager.ts @@ -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', diff --git a/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.test.ts b/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.test.ts index 44a376d5da..85d6098ce3 100644 --- a/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.test.ts +++ b/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.test.ts @@ -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', diff --git a/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts b/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts index af45539b32..31a2997af5 100644 --- a/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts +++ b/plugins/tech-insights-backend/src/service/persistence/TechInsightsDatabase.ts @@ -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('fact_schemas') .where({ id }) .and.where({ version }) @@ -78,7 +78,7 @@ export class TechInsightsDatabase implements TechInsightsStore { await this.db('fact_schemas').insert({ id, version, - entityTypes: entityTypes && entityTypes.join(','), + entityFilter: entityFilter ? JSON.stringify(entityFilter) : undefined, schema: JSON.stringify(schema), }); } diff --git a/plugins/tech-insights-backend/src/service/router.test.ts b/plugins/tech-insights-backend/src/service/router.test.ts index 075f67ccfe..8a7b6bdbb3 100644 --- a/plugins/tech-insights-backend/src/service/router.test.ts +++ b/plugins/tech-insights-backend/src/service/router.test.ts @@ -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'; diff --git a/plugins/tech-insights-backend/src/service/router.ts b/plugins/tech-insights-backend/src/service/router.ts index d02796117b..752534928f 100644 --- a/plugins/tech-insights-backend/src/service/router.ts +++ b/plugins/tech-insights-backend/src/service/router.ts @@ -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'; diff --git a/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts b/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts index bf30cdcf38..7305f1778c 100644 --- a/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts +++ b/plugins/tech-insights-backend/src/service/techInsightsContextBuilder.ts @@ -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. * diff --git a/plugins/tech-insights-common/README.md b/plugins/tech-insights-common/README.md index 651c0e969d..af14ef0e0d 100644 --- a/plugins/tech-insights-common/README.md +++ b/plugins/tech-insights-common/README.md @@ -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. diff --git a/plugins/tech-insights-common/api-report.md b/plugins/tech-insights-common/api-report.md index e83ba18137..ddb38cfa85 100644 --- a/plugins/tech-insights-common/api-report.md +++ b/plugins/tech-insights-common/api-report.md @@ -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; - getChecks(): Promise; - runChecks(entity: string, checks: string[]): Promise; - validate(check: CheckType): Promise; -} - -// @public -export interface FactCheckerFactory< - CheckType extends TechInsightCheck, - CheckResultType extends CheckResult, -> { - // (undocumented) - construct( - repository: TechInsightsStore, - ): FactChecker; -} - // @public export type FactResponse = { [id: string]: { @@ -78,113 +39,5 @@ export type FactResponse = { }; }; -// @public -export interface FactRetriever { - entityTypes?: string[]; - handler: (ctx: FactRetrieverContext) => Promise; - 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; - }; -}; - -// 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; - -// @public -export type FlatTechInsightFact = TechInsightFact & { - id: string; -}; - -// @public -export interface TechInsightCheck { - description: string; - factIds: string[]; - failureMetadata?: Record; - id: string; - name: string; - successMetadata?: Record; - type: string; -} - -// @public -export interface TechInsightCheckRegistry { - // (undocumented) - get(checkId: string): Promise; - // (undocumented) - getAll(checks: string[]): Promise; - // (undocumented) - list(): Promise; - // (undocumented) - register(check: CheckType): Promise; -} - -// @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; - insertFacts(id: string, facts: TechInsightFact[]): Promise; - insertFactSchema(schemaDefinition: FactSchemaDefinition): Promise; -} - // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/tech-insights-common/package.json b/plugins/tech-insights-common/package.json index 37d66a9379..4c287c26f3 100644 --- a/plugins/tech-insights-common/package.json +++ b/plugins/tech-insights-common/package.json @@ -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" diff --git a/plugins/tech-insights-common/src/index.ts b/plugins/tech-insights-common/src/index.ts index 982ae0ac41..4bfc660748 100644 --- a/plugins/tech-insights-common/src/index.ts +++ b/plugins/tech-insights-common/src/index.ts @@ -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; +} + +/** + * @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; + }; +}; + +/** + * 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; +} diff --git a/plugins/tech-insights-common/src/responses.ts b/plugins/tech-insights-common/src/responses.ts deleted file mode 100644 index c3dee1df48..0000000000 --- a/plugins/tech-insights-common/src/responses.ts +++ /dev/null @@ -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; -} - -/** - * @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; - }; -}; diff --git a/plugins/tech-insights-node/.eslintrc.js b/plugins/tech-insights-node/.eslintrc.js new file mode 100644 index 0000000000..16a033dbc6 --- /dev/null +++ b/plugins/tech-insights-node/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint.backend')], +}; diff --git a/plugins/tech-insights-node/README.md b/plugins/tech-insights-node/README.md new file mode 100644 index 0000000000..4065611837 --- /dev/null +++ b/plugins/tech-insights-node/README.md @@ -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. diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json new file mode 100644 index 0000000000..e5620322fd --- /dev/null +++ b/plugins/tech-insights-node/package.json @@ -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" + ] +} diff --git a/plugins/tech-insights-common/src/checks.ts b/plugins/tech-insights-node/src/checks.ts similarity index 77% rename from plugins/tech-insights-common/src/checks.ts rename to plugins/tech-insights-node/src/checks.ts index 90fa7ee34f..e5f10aff6d 100644 --- a/plugins/tech-insights-common/src/checks.ts +++ b/plugins/tech-insights-node/src/checks.ts @@ -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; - - /** - * 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; + runChecks(entity: string, checks?: string[]): Promise; /** * Retrieves all available checks that can be used to run checks against. @@ -99,29 +90,6 @@ export interface TechInsightCheckRegistry { list(): Promise; } -/** - * 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; - } -} diff --git a/plugins/tech-insights-common/src/facts.ts b/plugins/tech-insights-node/src/facts.ts similarity index 92% rename from plugins/tech-insights-common/src/facts.ts rename to plugins/tech-insights-node/src/facts.ts index a46e7bd95d..b912895ec6 100644 --- a/plugins/tech-insights-common/src/facts.ts +++ b/plugins/tech-insights-node/src/facts.ts @@ -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[] + | Record; } export type FactSchemaDefinition = Omit; diff --git a/plugins/tech-insights-node/src/index.test.ts b/plugins/tech-insights-node/src/index.test.ts new file mode 100644 index 0000000000..5e5f8c9d77 --- /dev/null +++ b/plugins/tech-insights-node/src/index.test.ts @@ -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(); + }); +}); diff --git a/plugins/tech-insights-node/src/index.ts b/plugins/tech-insights-node/src/index.ts new file mode 100644 index 0000000000..70ef27e159 --- /dev/null +++ b/plugins/tech-insights-node/src/index.ts @@ -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'; diff --git a/plugins/tech-insights-common/src/persistence.ts b/plugins/tech-insights-node/src/persistence.ts similarity index 100% rename from plugins/tech-insights-common/src/persistence.ts rename to plugins/tech-insights-node/src/persistence.ts diff --git a/plugins/tech-insights-common/src/setupTests.ts b/plugins/tech-insights-node/src/setupTests.ts similarity index 100% rename from plugins/tech-insights-common/src/setupTests.ts rename to plugins/tech-insights-node/src/setupTests.ts