Renames and new types

This commit is contained in:
Marek Calus
2020-10-28 23:45:43 +01:00
parent 155094e18d
commit dbadbe7982
8 changed files with 115 additions and 94 deletions
+2 -2
View File
@@ -28,7 +28,7 @@ export default async function createPlugin(env: PluginEnvironment) {
entitiesCatalog,
locationsCatalog,
higherOrderOperation,
configGenerator,
locationAnalyzer,
} = await builder.build();
useHotCleanup(
@@ -40,7 +40,7 @@ export default async function createPlugin(env: PluginEnvironment) {
entitiesCatalog,
locationsCatalog,
higherOrderOperation,
configGenerator,
locationAnalyzer,
logger: env.logger,
});
}
+1 -1
View File
@@ -18,6 +18,6 @@ export type { Location, LocationSpec } from './types';
export {
locationSchema,
locationSpecSchema,
repoPathSchema,
analyzeLocationSchema,
} from './validation';
export { LOCATION_ANNOTATION } from './annotation';
@@ -35,9 +35,9 @@ export const locationSchema = yup
.noUnknown()
.required();
export const repoPathSchema = yup
.object<{ repoPath: string }>({
repoPath: yup.string().required(),
export const analyzeLocationSchema = yup
.object<{ location: LocationSpec }>({
location: locationSpecSchema,
})
.noUnknown()
.required();
@@ -14,32 +14,36 @@
* limitations under the License.
*/
import { Entity } from '@backstage/catalog-model';
import { Logger } from 'winston';
import { ConfigGenerator } from './types';
import {
AnalyzeLocationRequest,
AnalyzeLocationResponse,
LocationAnalyzer,
} from './types';
export class ConfigGeneratorClient implements ConfigGenerator {
logger: Logger;
export class LocationAnalyzerClient implements LocationAnalyzer {
private readonly logger: Logger;
constructor(logger: Logger) {
this.logger = logger;
}
async generateConfig(repoPath: string): Promise<Entity[]> {
const [ownerName, repoName] = [
repoPath.split('/')[0],
repoPath.split('/')[1],
];
const config = {
async generateConfig(
request: AnalyzeLocationRequest,
): Promise<AnalyzeLocationResponse> {
const [ownerName, repoName] = request.location.target.split('/').slice(-2);
const entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: repoName,
description: '',
annotations: { 'github.com/project-slug': repoPath },
annotations: { 'github.com/project-slug': `${ownerName}/${repoName}` },
},
spec: { type: 'service', owner: ownerName, lifecycle: 'experimental' },
};
return [config];
return {
existingEntityFiles: [],
generateEntities: [{ entity, fields: [] }],
};
}
}
+61 -2
View File
@@ -20,6 +20,7 @@ import type {
Location,
LocationSpec,
} from '@backstage/catalog-model';
import { RecursivePartial } from './processors/ldap/util';
//
// HigherOrderOperation
@@ -70,6 +71,64 @@ export type ReadLocationError = {
// ConfigGenerator
//
export type ConfigGenerator = {
generateConfig(repoPath: string): Promise<Entity[]>;
export type LocationAnalyzer = {
generateConfig(
location: AnalyzeLocationRequest,
): Promise<AnalyzeLocationResponse>;
};
export type AnalyzeLocationRequest = {
location: LocationSpec;
};
export type AnalyzeLocationResponse = {
existingEntityFiles: AnalyzeLocationExistingEntity[];
generateEntities: AnalyzeLocationGenerateEntity[];
};
// If the folder pointed to already contained catalog info yaml files, they are
// read and emitted like this so that the frontend can inform the user that it
// located them and can make sure to register them as well if they weren't
// already
type AnalyzeLocationExistingEntity = {
location: LocationSpec;
isRegistered: boolean;
entity: Entity;
};
// This is some form of representation of what the analyzer could deduce.
// We should probably have a chat about how this can best be conveyed to
// the frontend. It'll probably contain a (possibly incomplete) entity, plus
// enough info for the frontend to know what form data to show to the user
// for overriding/completing the info.
type AnalyzeLocationGenerateEntity = {
// Some form of partial representation of the entity
entity: RecursivePartial<Entity>;
// Lists the suggestions that the user may want to override
fields: AnalyzeLocationEntityField[];
};
// This is where I get really vague. Something like this perhaps? Or it could be
// something like a json-schema that contains enough info for the frontend to
// be able to present a form and explanations
type AnalyzeLocationEntityField = {
// e.g. "spec.owner"? The frontend needs to know how to "inject" the field into the
// entity again if the user wants to change it
field: string;
// The outcome of the analysis for this particular field
state:
| 'analysis_suggested_value'
| 'analysis_suggested_no_value'
| 'needs_user_input';
// If the analysis did suggest a value, this is where it would be. Not sure if we want
// to limit this to strings or if we want it to be any JsonValue
value: string | null;
// A text to show to the user to inform about the choices made. Like, it could say
// "Found a CODEOWNERS file that covers this target, so we suggest leaving this
// field empty; which would currently make it owned by X" where X is taken from the
// codeowners file.
description: string;
};
@@ -52,7 +52,7 @@ import {
UrlReaderProcessor,
} from '../ingestion';
import { CatalogRulesEnforcer } from '../ingestion/CatalogRules';
import { ConfigGeneratorClient } from '../ingestion/ConfigGenerator';
import { LocationAnalyzerClient } from '../ingestion/LocationAnalyzer';
import { BuiltinKindsEntityProcessor } from '../ingestion/processors/BuiltinKindsEntityProcessor';
import { LdapOrgReaderProcessor } from '../ingestion/processors/LdapOrgReaderProcessor';
import {
@@ -60,7 +60,7 @@ import {
textPlaceholderResolver,
yamlPlaceholderResolver,
} from '../ingestion/processors/PlaceholderProcessor';
import { ConfigGenerator } from '../ingestion/types';
import { LocationAnalyzer } from '../ingestion/types';
export type CatalogEnvironment = {
logger: Logger;
@@ -204,7 +204,7 @@ export class CatalogBuilder {
entitiesCatalog: EntitiesCatalog;
locationsCatalog: LocationsCatalog;
higherOrderOperation: HigherOrderOperation;
configGenerator: ConfigGenerator;
locationAnalyzer: LocationAnalyzer;
}> {
const { config, database, logger } = this.env;
@@ -232,13 +232,13 @@ export class CatalogBuilder {
locationReader,
logger,
);
const configGenerator = new ConfigGeneratorClient(logger);
const locationAnalyzer = new LocationAnalyzerClient(logger);
return {
entitiesCatalog,
locationsCatalog,
higherOrderOperation,
configGenerator,
locationAnalyzer,
};
}
+11 -8
View File
@@ -15,13 +15,16 @@
*/
import { errorHandler } from '@backstage/backend-common';
import { locationSpecSchema, repoPathSchema } from '@backstage/catalog-model';
import {
locationSpecSchema,
analyzeLocationSchema,
} from '@backstage/catalog-model';
import type { Entity } from '@backstage/catalog-model';
import express from 'express';
import Router from 'express-promise-router';
import { Logger } from 'winston';
import { EntitiesCatalog, LocationsCatalog } from '../catalog';
import { ConfigGenerator, HigherOrderOperation } from '../ingestion/types';
import { LocationAnalyzer, HigherOrderOperation } from '../ingestion/types';
import {
translateQueryToEntityFilters,
translateQueryToFieldMapper,
@@ -32,7 +35,7 @@ export interface RouterOptions {
entitiesCatalog?: EntitiesCatalog;
locationsCatalog?: LocationsCatalog;
higherOrderOperation?: HigherOrderOperation;
configGenerator?: ConfigGenerator;
locationAnalyzer?: LocationAnalyzer;
logger: Logger;
}
@@ -43,7 +46,7 @@ export async function createRouter(
entitiesCatalog,
locationsCatalog,
higherOrderOperation,
configGenerator,
locationAnalyzer: locationAnalyzer,
} = options;
const router = Router();
@@ -135,10 +138,10 @@ export async function createRouter(
});
}
if (configGenerator) {
router.post('/generate-config', async (req, res) => {
const input = await validateRequestBody(req, repoPathSchema);
const output = await configGenerator.generateConfig(input.repoPath);
if (locationAnalyzer) {
router.post('/analyze-location', async (req, res) => {
const input = await validateRequestBody(req, analyzeLocationSchema);
const output = await locationAnalyzer.generateConfig(input);
res.status(201).send(output);
});
}
+15 -60
View File
@@ -3691,50 +3691,18 @@
react-router "^6.0.0-beta.0"
react-use "^15.3.3"
"@roadiehq/backstage-plugin-github-pull-requests@^0.5.2":
version "0.5.2"
resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-0.5.2.tgz#455355fe5cdcc43c22b80a8ef3697378084680a1"
integrity sha512-GM+nWQZ+aehMclN70Pp35UQe3I46SQCjWiGZ6/0TfDzrueHln39L2UspUj1L/713xDDtDK8ZnTJdFn/qKx7j4A==
"@rollup/plugin-commonjs@^14.0.0":
version "14.0.0"
resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz#4285f9ec2db686a31129e5a2b415c94aa1f836f0"
integrity sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw==
dependencies:
"@backstage/catalog-model" "^0.1.1-alpha.25"
"@backstage/core" "^0.1.1-alpha.25"
"@backstage/plugin-catalog" "^0.1.1-alpha.25"
"@backstage/theme" "^0.1.1-alpha.25"
"@material-ui/core" "^4.11.0"
"@material-ui/icons" "^4.9.1"
"@material-ui/lab" "^4.0.0-alpha.56"
"@octokit/rest" "^18.0.0"
"@octokit/types" "^5.0.1"
"@types/react-dom" "^16.9.8"
history "^5.0.0"
moment "^2.27.0"
react "^16.13.1"
react-dom "^16.13.1"
react-router "6.0.0-beta.0"
react-use "^15.3.3"
"@roadiehq/backstage-plugin-travis-ci@^0.2.5":
version "0.2.5"
resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-travis-ci/-/backstage-plugin-travis-ci-0.2.5.tgz#588cd8b4a4dd4bd426c0012f8d35eae4504b55f4"
integrity sha512-4aJizmvIeunpl8D/YDvzagNzikPU51DSZFz1tN0XCwRR+buTPknV141qsKP+yxUbs6nx3Xuh+T/vNkb9lk6FlA==
dependencies:
"@backstage/catalog-model" "^0.1.1-alpha.24"
"@backstage/core" "^0.1.1-alpha.24"
"@backstage/core-api" "^0.1.1-alpha.24"
"@backstage/plugin-catalog" "^0.1.1-alpha.24"
"@backstage/theme" "^0.1.1-alpha.24"
"@material-ui/core" "^4.9.1"
"@material-ui/icons" "^4.9.1"
"@material-ui/lab" "4.0.0-alpha.45"
date-fns "^2.15.0"
history "^5.0.0"
moment "^2.27.0"
react "^16.13.1"
react-dom "^16.13.1"
react-lazylog "^4.5.2"
react-router "6.0.0-beta.0"
react-router-dom "6.0.0-beta.0"
react-use "^15.3.3"
"@rollup/pluginutils" "^3.0.8"
commondir "^1.0.1"
estree-walker "^1.0.1"
glob "^7.1.2"
is-reference "^1.1.2"
magic-string "^0.25.2"
resolve "^1.11.0"
"@rollup/plugin-commonjs@^16.0.0":
version "16.0.0"
@@ -3749,19 +3717,6 @@
magic-string "^0.25.7"
resolve "^1.17.0"
"@rollup/plugin-commonjs@^14.0.0":
version "14.0.0"
resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz#4285f9ec2db686a31129e5a2b415c94aa1f836f0"
integrity sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw==
dependencies:
"@rollup/pluginutils" "^3.0.8"
commondir "^1.0.1"
estree-walker "^1.0.1"
glob "^7.1.2"
is-reference "^1.1.2"
magic-string "^0.25.2"
resolve "^1.11.0"
"@rollup/plugin-json@^4.0.2":
version "4.1.0"
resolved "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3"
@@ -9881,7 +9836,7 @@ dateformat@^3.0.0:
resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
dayjs@^1.9.4:
dayjs@^1.9.1, dayjs@^1.9.4:
version "1.9.4"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.9.4.tgz#fcde984e227f4296f04e7b05720adad2e1071f1b"
integrity sha512-ABSF3alrldf7nM9sQ2U+Ln67NRwmzlLOqG7kK03kck0mw3wlSSEKv/XhKGGxUjQcS57QeiCyNdrFgtj9nWlrng==
@@ -14227,7 +14182,7 @@ is-promise@^2.1, is-promise@^2.1.0:
resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
is-reference@^1.2.1:
is-reference@^1.1.2, is-reference@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
@@ -16125,7 +16080,7 @@ macos-release@^2.2.0:
resolved "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==
magic-string@^0.25.7:
magic-string@^0.25.2, magic-string@^0.25.7:
version "0.25.7"
resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
@@ -20782,7 +20737,7 @@ resolve@1.17.0, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0
dependencies:
path-parse "^1.0.6"
resolve@^1.18.1:
resolve@^1.11.0, resolve@^1.18.1:
version "1.18.1"
resolved "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130"
integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==