@backstage-community/plugin-tech-insights-backend 0.6.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +93 -259
- package/dist/index.cjs.js +1 -11
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -3
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @backstage-community/plugin-tech-insights-backend
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 9871d0b: **BREAKING**: The service no longer accepts the deprecated `TokenManager` instance, but instead the `AuthService` is now required where it used to be optional. If you are using the new backend system module, this does not affect you.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [9871d0b]
|
|
12
|
+
- @backstage-community/plugin-tech-insights-node@1.0.0
|
|
13
|
+
|
|
14
|
+
## 0.6.3
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [1d33996]
|
|
19
|
+
- @backstage-community/plugin-tech-insights-common@0.2.18
|
|
20
|
+
- @backstage-community/plugin-tech-insights-node@0.6.7
|
|
21
|
+
|
|
3
22
|
## 0.6.2
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Tech Insights Backend
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
as well as a framework to run fact retrievers and store fact values in to a data store.
|
|
3
|
+
The backend plugin for Tech Insights.
|
|
4
|
+
|
|
5
|
+
It provides the API for the frontend tech insights, scorecards and fact visualization functionality, as well as a framework to run fact retrievers and store fact values in to a data store.
|
|
6
|
+
|
|
7
|
+
Looking for the old backend installation docs? Visit [here](./docs/old-backend-system.md).
|
|
6
8
|
|
|
7
9
|
## Installation
|
|
8
10
|
|
|
@@ -13,133 +15,104 @@ as well as a framework to run fact retrievers and store fact values in to a data
|
|
|
13
15
|
yarn --cwd packages/backend add @backstage-community/plugin-tech-insights-backend
|
|
14
16
|
```
|
|
15
17
|
|
|
16
|
-
###
|
|
18
|
+
### Add the plugin to your backend
|
|
17
19
|
|
|
18
20
|
```ts title="packages/backend/src/index.ts"
|
|
21
|
+
// Add the following to `packages/backend/src/index.ts`
|
|
19
22
|
backend.add(import('@backstage-community/plugin-tech-insights-backend'));
|
|
20
23
|
```
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
## Built-in Defaults
|
|
26
|
+
|
|
27
|
+
### Included FactRetrievers
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
`FactRetrievers` are only registered if configured in the `app-config.yaml`. Meaning that while you have the tech insights backend installed, you will not have any fact retrievers present in your application.
|
|
26
30
|
|
|
27
|
-
-
|
|
28
|
-
- `entityOwnershipFactRetriever`
|
|
29
|
-
- `techdocsFactRetriever`
|
|
31
|
+
There are three built-in FactRetrievers that come with Tech Insights:
|
|
30
32
|
|
|
31
|
-
`
|
|
33
|
+
- `entityMetadataFactRetriever`: Generates facts which indicate the completeness of entity metadata
|
|
34
|
+
- `entityOwnershipFactRetriever`: Generates facts which indicate the quality of data in the `spec.owner` field
|
|
35
|
+
- `techdocsFactRetriever`: Generates facts related to the completeness of techdocs configuration for entities
|
|
36
|
+
|
|
37
|
+
#### Registering the built-in FactRetrievers
|
|
38
|
+
|
|
39
|
+
The following example registers the built-in fact retrievers to run every 6 hours, while retaining the latest two weeks of fact data.
|
|
32
40
|
|
|
33
41
|
```yaml title="app-config.yaml"
|
|
34
42
|
techInsights:
|
|
35
43
|
factRetrievers:
|
|
44
|
+
entityMetadataFactRetriever:
|
|
45
|
+
# How often the fact retriever should run
|
|
46
|
+
cadence: '*/15 * * * *'
|
|
47
|
+
# How long to keep the fact data
|
|
48
|
+
lifecycle: { timeToLive: { weeks: 2 } }
|
|
36
49
|
entityOwnershipFactRetriever:
|
|
37
50
|
cadence: '*/15 * * * *'
|
|
38
51
|
lifecycle: { timeToLive: { weeks: 2 } }
|
|
52
|
+
techdocsFactRetriever:
|
|
53
|
+
cadence: '*/15 * * * *'
|
|
54
|
+
lifecycle: { timeToLive: { weeks: 2 } }
|
|
39
55
|
```
|
|
40
56
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
You'll need to add the plugin to the router in your `backend` package. You can
|
|
44
|
-
do this by creating a file called `packages/backend/src/plugins/techInsights.ts`. An example content for `techInsights.ts` could be something like this.
|
|
45
|
-
|
|
46
|
-
```ts
|
|
47
|
-
import {
|
|
48
|
-
createRouter,
|
|
49
|
-
buildTechInsightsContext,
|
|
50
|
-
} from '@backstage-community/plugin-tech-insights-backend';
|
|
51
|
-
import { Router } from 'express';
|
|
52
|
-
import { PluginEnvironment } from '../types';
|
|
53
|
-
|
|
54
|
-
export default async function createPlugin(
|
|
55
|
-
env: PluginEnvironment,
|
|
56
|
-
): Promise<Router> {
|
|
57
|
-
const builder = buildTechInsightsContext({
|
|
58
|
-
logger: env.logger,
|
|
59
|
-
config: env.config,
|
|
60
|
-
database: env.database,
|
|
61
|
-
discovery: env.discovery,
|
|
62
|
-
scheduler: env.scheduler,
|
|
63
|
-
tokenManager: env.tokenManager,
|
|
64
|
-
factRetrievers: [], // Fact retrievers registrations you want tech insights to use
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return await createRouter({
|
|
68
|
-
...(await builder),
|
|
69
|
-
logger: env.logger,
|
|
70
|
-
config: env.config,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
With the `techInsights.ts` router setup in place, add the router to
|
|
76
|
-
`packages/backend/src/index.ts`:
|
|
57
|
+
The optional `lifecycle` configuration value limits the lifetime of fact data. The value can be either `maxItems` or TTL (time to live). Valid options are either a number for `maxItems` or a Luxon duration-like object for TTL.
|
|
77
58
|
|
|
78
|
-
```
|
|
79
|
-
|
|
59
|
+
```yaml
|
|
60
|
+
# Lifecycle configuration examples
|
|
61
|
+
lifecycle: { timeToLive: { weeks: 2 } }
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const createEnv = makeCreateEnv(config);
|
|
63
|
+
# Deletes all but 7 latest facts for each id/entity pair
|
|
64
|
+
lifecycle: { maxItems: 7 };
|
|
84
65
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const apiRouter = Router();
|
|
89
|
-
+ apiRouter.use('/tech-insights', await techInsights(techInsightsEnv));
|
|
90
|
-
...
|
|
91
|
-
apiRouter.use(notFoundHandler());
|
|
92
|
-
}
|
|
66
|
+
# Deletes all facts older than 2 weeks (TTL)
|
|
67
|
+
lifecycle: { timeToLive: 1209600000 } # Luxon duration like object
|
|
68
|
+
lifecycle: { timeToLive: { weeks: 2 } }; # Human readable value
|
|
93
69
|
```
|
|
94
70
|
|
|
95
|
-
|
|
71
|
+
#### Running fact retrievers in a multi-instance installation
|
|
96
72
|
|
|
97
|
-
|
|
98
|
-
you will not have any fact retrievers present in your application. To have the implemented FactRetrieverEngine within this package to be able to retrieve and store fact data into the database, you need to add these.
|
|
73
|
+
The Tech Insights plugin utilizes `PluginTaskScheduler` to schedule and coordinate task invocation across instances. See [the PluginTaskScheduler documentation](https://backstage.io/docs/reference/backend-tasks.plugintaskscheduler) for more information.
|
|
99
74
|
|
|
100
|
-
|
|
75
|
+
### Included FactChecker
|
|
101
76
|
|
|
102
|
-
|
|
103
|
-
import { createFactRetrieverRegistration } from '@backstage-community/plugin-tech-insights-backend';
|
|
77
|
+
**NOTE**: You need a Fact Checker configured to get access to the backend routes that will allow the facts to be checked. If you don't have one configured, you will see 404s and potentially other errors.
|
|
104
78
|
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* snip
|
|
108
|
-
*/
|
|
109
|
-
};
|
|
79
|
+
There is a default FactChecker implementation provided in the [@backstage-community/plugin-tech-insights-backend-module-jsonfc](../tech-insights-backend-module-jsonfc/README.md) module. This implementation uses `json-rules-engine` as the underlying functionality to run checks.
|
|
110
80
|
|
|
111
|
-
|
|
112
|
-
cadence: '1 * 2 * * ', // On the first minute of the second day of the month
|
|
113
|
-
factRetriever: myFactRetriever,
|
|
114
|
-
});
|
|
115
|
-
```
|
|
81
|
+
You must install the module into your backend system to use the fact checker.
|
|
116
82
|
|
|
117
|
-
|
|
83
|
+
```bash
|
|
84
|
+
# From your Backstage root directory
|
|
85
|
+
yarn --cwd packages/backend add @backstage-community/plugin-tech-insights-backend-module-jsonfc
|
|
86
|
+
```
|
|
118
87
|
|
|
119
|
-
```ts
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
88
|
+
```diff title="packages/backend/src/index.ts"
|
|
89
|
+
// Add the following to `packages/backend/src/index.ts`
|
|
90
|
+
backend.add(import('@backstage-community/plugin-tech-insights-backend'));
|
|
91
|
+
+backend.add(import('@backstage-community/plugin-tech-insights-backend-module-jsonfc'));
|
|
123
92
|
```
|
|
124
93
|
|
|
125
|
-
|
|
94
|
+
Then, configure the checks in the `app-config.yaml` file. The following example configures a _check_ to verify a group has been set as the `spec.owner` for an entity. The check uses the `entityOwnershipFactRetriever` fact retriever to get the data.
|
|
126
95
|
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
96
|
+
```yaml title="app-config.yaml"
|
|
97
|
+
techInsights:
|
|
98
|
+
factRetrievers: ...
|
|
99
|
+
factChecker:
|
|
100
|
+
checks:
|
|
101
|
+
groupOwnerCheck:
|
|
102
|
+
type: json-rules-engine
|
|
103
|
+
name: Group Owner Check
|
|
104
|
+
description: Verifies that a group has been set as the spec.owner for this entity
|
|
105
|
+
factIds:
|
|
106
|
+
- entityOwnershipFactRetriever
|
|
107
|
+
rule:
|
|
108
|
+
conditions:
|
|
109
|
+
all:
|
|
110
|
+
- fact: hasGroupOwner
|
|
111
|
+
operator: equal
|
|
112
|
+
value: true
|
|
138
113
|
```
|
|
139
114
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
The Tech Insights plugin utilizes the `PluginTaskScheduler` for scheduling tasks and coordinating the task invocation across instances. See [the PluginTaskScheduler documentation](https://backstage.io/docs/reference/backend-tasks.plugintaskscheduler) for more information.
|
|
115
|
+
## Creating custom implementations of FactRetrievers
|
|
143
116
|
|
|
144
117
|
### Creating Fact Retrievers
|
|
145
118
|
|
|
@@ -156,7 +129,7 @@ An example implementation of a FactRetriever could for example be as follows:
|
|
|
156
129
|
```ts
|
|
157
130
|
import { FactRetriever } from '@backstage-community/plugin-tech-insights-node';
|
|
158
131
|
|
|
159
|
-
const myFactRetriever: FactRetriever = {
|
|
132
|
+
export const myFactRetriever: FactRetriever = {
|
|
160
133
|
id: 'documentation-number-factretriever', // unique identifier of the fact retriever
|
|
161
134
|
version: '0.1.1', // SemVer version number of this fact retriever schema. This should be incremented if the implementation changes
|
|
162
135
|
entityFilter: [{ kind: 'component' }], // EntityFilter to be used in the future (creating checks, graphs etc.) to figure out which entities this fact retrieves data for.
|
|
@@ -195,7 +168,7 @@ const myFactRetriever: FactRetriever = {
|
|
|
195
168
|
|
|
196
169
|
// All facts that this retriever returns
|
|
197
170
|
facts: {
|
|
198
|
-
examplenumberfact: 2,
|
|
171
|
+
examplenumberfact: 2,
|
|
199
172
|
},
|
|
200
173
|
// (optional) timestamp to use as a Luxon DateTime object
|
|
201
174
|
};
|
|
@@ -204,43 +177,33 @@ const myFactRetriever: FactRetriever = {
|
|
|
204
177
|
};
|
|
205
178
|
```
|
|
206
179
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
This module comes with a possibility to additionally add a fact checker and expose fact checking endpoints from the API. To be able to enable this feature you need to add a FactCheckerFactory implementation to be part of the `DefaultTechInsightsBuilder` constructor call.
|
|
210
|
-
|
|
211
|
-
There is a default FactChecker implementation provided in module `@backstage-community/plugin-tech-insights-backend-module-jsonfc`. This implementation uses `json-rules-engine` as the underlying functionality to run checks. If you want to implement your own FactChecker, for example to be able to handle other than `boolean` result types, you can do so by implementing `FactCheckerFactory` and `FactChecker` interfaces from `@backstage-community/plugin-tech-insights-common` package.
|
|
212
|
-
|
|
213
|
-
To add the default FactChecker into your Tech Insights you need to install the module into your backend application:
|
|
214
|
-
|
|
215
|
-
```bash
|
|
216
|
-
# From your Backstage root directory
|
|
217
|
-
yarn --cwd packages/backend add @backstage-community/plugin-tech-insights-backend-module-jsonfc
|
|
218
|
-
```
|
|
180
|
+
Additional FactRetrievers are added to the Tech Insights backend by creating a new backend module and registering the FactRetriever with the `techInsightsFactRetrieversExtensionPoint` extension point. This, along with other extension points, are available in the [@backstage-community/plugin-tech-insights-node](../tech-insights-node/README.md) library.
|
|
219
181
|
|
|
220
|
-
|
|
182
|
+
```ts title="plugins/tech-insights-backend-module-my-fact-retriever/src/module.ts"
|
|
183
|
+
import { techInsightsFactRetrieversExtensionPoint } from '@backstage-community/plugin-tech-insights-node';
|
|
184
|
+
import { myFactRetriever } from './myFactRetriever';
|
|
221
185
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
});
|
|
186
|
+
export const techInsightsModuleMyFactRetriever = createBackendModule({
|
|
187
|
+
pluginId: 'tech-insights',
|
|
188
|
+
moduleId: 'my-fact-retriever',
|
|
189
|
+
register(reg) {
|
|
190
|
+
reg.registerInit({
|
|
191
|
+
deps: {
|
|
192
|
+
providers: techInsightsFactRetrieversExtensionPoint,
|
|
193
|
+
},
|
|
194
|
+
async init({ providers }) {
|
|
195
|
+
providers.addFactRetrievers({
|
|
196
|
+
myFactRetriever,
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
});
|
|
239
202
|
```
|
|
240
203
|
|
|
241
|
-
|
|
204
|
+
### Adding a fact checker
|
|
242
205
|
|
|
243
|
-
|
|
206
|
+
If you want to implement your own FactChecker, for example to be able to handle other than `boolean` result types, you can do so by implementing `FactCheckerFactory` and `FactChecker` interfaces from `@backstage-community/plugin-tech-insights-common` package.
|
|
244
207
|
|
|
245
208
|
#### Modifying check persistence
|
|
246
209
|
|
|
@@ -255,132 +218,3 @@ const myFactCheckerFactory = new JsonRulesEngineFactCheckerFactory({
|
|
|
255
218
|
}),
|
|
256
219
|
|
|
257
220
|
```
|
|
258
|
-
|
|
259
|
-
## Included FactRetrievers
|
|
260
|
-
|
|
261
|
-
There are three FactRetrievers that come out of the box with Tech Insights:
|
|
262
|
-
|
|
263
|
-
- `entityMetadataFactRetriever`: Generates facts which indicate the completeness of entity metadata
|
|
264
|
-
- `entityOwnershipFactRetriever`: Generates facts which indicate the quality of data in the spec.owner field
|
|
265
|
-
- `techdocsFactRetriever`: Generates facts related to the completeness of techdocs configuration for entities
|
|
266
|
-
|
|
267
|
-
## Backend Example
|
|
268
|
-
|
|
269
|
-
Here's an example backend setup that will use the three included fact retrievers so you can get an idea of how this all works. This will be the entire contents of your `techInsights.ts` file found at `\packages\backend\src\plugins` as per [Adding the plugin to your `packages/backend`](#adding-the-plugin-to-your-packagesbackend)
|
|
270
|
-
|
|
271
|
-
```ts
|
|
272
|
-
import {
|
|
273
|
-
createRouter,
|
|
274
|
-
buildTechInsightsContext,
|
|
275
|
-
createFactRetrieverRegistration,
|
|
276
|
-
entityOwnershipFactRetriever,
|
|
277
|
-
entityMetadataFactRetriever,
|
|
278
|
-
techdocsFactRetriever,
|
|
279
|
-
} from '@backstage-community/plugin-tech-insights-backend';
|
|
280
|
-
import { Router } from 'express';
|
|
281
|
-
import { PluginEnvironment } from '../types';
|
|
282
|
-
import {
|
|
283
|
-
JsonRulesEngineFactCheckerFactory,
|
|
284
|
-
JSON_RULE_ENGINE_CHECK_TYPE,
|
|
285
|
-
} from '@backstage-community/plugin-tech-insights-backend-module-jsonfc';
|
|
286
|
-
|
|
287
|
-
const ttlTwoWeeks = { timeToLive: { weeks: 2 } };
|
|
288
|
-
|
|
289
|
-
export default async function createPlugin(
|
|
290
|
-
env: PluginEnvironment,
|
|
291
|
-
): Promise<Router> {
|
|
292
|
-
const techInsightsContext = await buildTechInsightsContext({
|
|
293
|
-
logger: env.logger,
|
|
294
|
-
config: env.config,
|
|
295
|
-
database: env.database,
|
|
296
|
-
discovery: env.discovery,
|
|
297
|
-
tokenManager: env.tokenManager,
|
|
298
|
-
scheduler: env.scheduler,
|
|
299
|
-
factRetrievers: [
|
|
300
|
-
createFactRetrieverRegistration({
|
|
301
|
-
cadence: '0 */6 * * *', // Run every 6 hours - https://crontab.guru/#0_*/6_*_*_*
|
|
302
|
-
factRetriever: entityOwnershipFactRetriever,
|
|
303
|
-
lifecycle: ttlTwoWeeks,
|
|
304
|
-
}),
|
|
305
|
-
createFactRetrieverRegistration({
|
|
306
|
-
cadence: '0 */6 * * *',
|
|
307
|
-
factRetriever: entityMetadataFactRetriever,
|
|
308
|
-
lifecycle: ttlTwoWeeks,
|
|
309
|
-
}),
|
|
310
|
-
createFactRetrieverRegistration({
|
|
311
|
-
cadence: '0 */6 * * *',
|
|
312
|
-
factRetriever: techdocsFactRetriever,
|
|
313
|
-
lifecycle: ttlTwoWeeks,
|
|
314
|
-
}),
|
|
315
|
-
],
|
|
316
|
-
factCheckerFactory: new JsonRulesEngineFactCheckerFactory({
|
|
317
|
-
logger: env.logger,
|
|
318
|
-
checks: [
|
|
319
|
-
{
|
|
320
|
-
id: 'groupOwnerCheck',
|
|
321
|
-
type: JSON_RULE_ENGINE_CHECK_TYPE,
|
|
322
|
-
name: 'Group Owner Check',
|
|
323
|
-
description:
|
|
324
|
-
'Verifies that a Group has been set as the owner for this entity',
|
|
325
|
-
factIds: ['entityOwnershipFactRetriever'],
|
|
326
|
-
rule: {
|
|
327
|
-
conditions: {
|
|
328
|
-
all: [
|
|
329
|
-
{
|
|
330
|
-
fact: 'hasGroupOwner',
|
|
331
|
-
operator: 'equal',
|
|
332
|
-
value: true,
|
|
333
|
-
},
|
|
334
|
-
],
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
id: 'titleCheck',
|
|
340
|
-
type: JSON_RULE_ENGINE_CHECK_TYPE,
|
|
341
|
-
name: 'Title Check',
|
|
342
|
-
description:
|
|
343
|
-
'Verifies that a Title, used to improve readability, has been set for this entity',
|
|
344
|
-
factIds: ['entityMetadataFactRetriever'],
|
|
345
|
-
rule: {
|
|
346
|
-
conditions: {
|
|
347
|
-
all: [
|
|
348
|
-
{
|
|
349
|
-
fact: 'hasTitle',
|
|
350
|
-
operator: 'equal',
|
|
351
|
-
value: true,
|
|
352
|
-
},
|
|
353
|
-
],
|
|
354
|
-
},
|
|
355
|
-
},
|
|
356
|
-
},
|
|
357
|
-
{
|
|
358
|
-
id: 'techDocsCheck',
|
|
359
|
-
type: JSON_RULE_ENGINE_CHECK_TYPE,
|
|
360
|
-
name: 'TechDocs Check',
|
|
361
|
-
description:
|
|
362
|
-
'Verifies that TechDocs has been enabled for this entity',
|
|
363
|
-
factIds: ['techdocsFactRetriever'],
|
|
364
|
-
rule: {
|
|
365
|
-
conditions: {
|
|
366
|
-
all: [
|
|
367
|
-
{
|
|
368
|
-
fact: 'hasAnnotationBackstageIoTechdocsRef',
|
|
369
|
-
operator: 'equal',
|
|
370
|
-
value: true,
|
|
371
|
-
},
|
|
372
|
-
],
|
|
373
|
-
},
|
|
374
|
-
},
|
|
375
|
-
},
|
|
376
|
-
],
|
|
377
|
-
}),
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
return await createRouter({
|
|
381
|
-
...techInsightsContext,
|
|
382
|
-
logger: env.logger,
|
|
383
|
-
config: env.config,
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
```
|
package/dist/index.cjs.js
CHANGED
|
@@ -16,7 +16,6 @@ var Router = require('express-promise-router');
|
|
|
16
16
|
var errors = require('@backstage/errors');
|
|
17
17
|
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
18
18
|
var pLimit = require('p-limit');
|
|
19
|
-
var backendCommon = require('@backstage/backend-common');
|
|
20
19
|
var config = require('@backstage/config');
|
|
21
20
|
|
|
22
21
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
@@ -624,7 +623,7 @@ const buildTechInsightsContext = async (options) => {
|
|
|
624
623
|
database,
|
|
625
624
|
logger,
|
|
626
625
|
scheduler,
|
|
627
|
-
|
|
626
|
+
auth
|
|
628
627
|
} = options;
|
|
629
628
|
const buildFactRetrieverRegistry = () => {
|
|
630
629
|
if (!options.factRetrieverRegistry) {
|
|
@@ -641,11 +640,6 @@ const buildTechInsightsContext = async (options) => {
|
|
|
641
640
|
const persistenceContext = options.persistenceContext ?? await initializePersistenceContext(database, {
|
|
642
641
|
logger
|
|
643
642
|
});
|
|
644
|
-
const { auth } = backendCommon.createLegacyAuthAdapters({
|
|
645
|
-
auth: options.auth,
|
|
646
|
-
tokenManager,
|
|
647
|
-
discovery
|
|
648
|
-
});
|
|
649
643
|
const factRetrieverEngine = await DefaultFactRetrieverEngine.create({
|
|
650
644
|
scheduler,
|
|
651
645
|
repository: persistenceContext.techInsightsStore,
|
|
@@ -654,7 +648,6 @@ const buildTechInsightsContext = async (options) => {
|
|
|
654
648
|
config,
|
|
655
649
|
discovery,
|
|
656
650
|
logger,
|
|
657
|
-
tokenManager,
|
|
658
651
|
auth
|
|
659
652
|
}
|
|
660
653
|
});
|
|
@@ -760,7 +753,6 @@ const techInsightsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
760
753
|
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
761
754
|
logger: backendPluginApi.coreServices.logger,
|
|
762
755
|
scheduler: backendPluginApi.coreServices.scheduler,
|
|
763
|
-
tokenManager: backendPluginApi.coreServices.tokenManager,
|
|
764
756
|
auth: backendPluginApi.coreServices.auth
|
|
765
757
|
},
|
|
766
758
|
async init({
|
|
@@ -770,7 +762,6 @@ const techInsightsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
770
762
|
httpRouter,
|
|
771
763
|
logger,
|
|
772
764
|
scheduler,
|
|
773
|
-
tokenManager,
|
|
774
765
|
auth
|
|
775
766
|
}) {
|
|
776
767
|
const factRetrievers = Object.entries(
|
|
@@ -792,7 +783,6 @@ const techInsightsPlugin = backendPluginApi.createBackendPlugin({
|
|
|
792
783
|
logger,
|
|
793
784
|
persistenceContext,
|
|
794
785
|
scheduler,
|
|
795
|
-
tokenManager,
|
|
796
786
|
auth
|
|
797
787
|
});
|
|
798
788
|
httpRouter.use(
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/service/fact/createFactRetriever.ts","../src/service/fact/factRetrievers/entityMetadataFactRetriever.ts","../src/service/fact/factRetrievers/entityOwnershipFactRetriever.ts","../src/service/fact/factRetrievers/utils.ts","../src/service/fact/factRetrievers/techdocsFactRetriever.ts","../src/service/persistence/TechInsightsDatabase.ts","../src/service/persistence/persistenceContext.ts","../src/service/router.ts","../src/service/fact/FactRetrieverEngine.ts","../src/service/fact/FactRetrieverRegistry.ts","../src/service/techInsightsContextBuilder.ts","../src/plugin/config.ts","../src/plugin/plugin.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { HumanDuration } from '@backstage/types';\nimport {\n FactLifecycle,\n FactRetriever,\n FactRetrieverRegistration,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { Duration } from 'luxon';\n\n/**\n * @public\n *\n * @param cadence - cron expression to indicate when the fact retriever should be triggered\n * @param factRetriever - Implementation of fact retriever consisting of at least id, version, schema and handler\n * @param lifecycle - Optional lifecycle definition indicating the cleanup logic of facts when this retriever is run\n * @param timeout - Optional duration to determine how long the fact retriever should be allowed to run, defaults to 5 minutes\n *\n */\nexport type FactRetrieverRegistrationOptions = {\n cadence: string;\n factRetriever: FactRetriever;\n lifecycle?: FactLifecycle;\n timeout?: Duration | HumanDuration;\n initialDelay?: Duration | HumanDuration;\n};\n\n/**\n * @public\n *\n * A helper function to construct fact retriever registrations.\n * @param cadence - Cron expression to indicate when the fact retriever should be triggered\n * @param factRetriever - Implementation of fact retriever consisting of at least id, version, schema and handler\n * @param lifecycle - Optional lifecycle definition indicating the cleanup logic of facts when this retriever is run\n * @param timeout - Optional duration to determine how long the fact retriever should be allowed to run, defaults to 5 minutes\n * @param initialDelay - Optional initial delay to determine how long the fact retriever should wait before the initial run, defaults to 5 seconds\n *\n *\n * @remarks\n *\n * Cron expressions help:\n * ┌────────────── second (optional)\n # │ ┌──────────── minute\n # │ │ ┌────────── hour\n # │ │ │ ┌──────── day of month\n # │ │ │ │ ┌────── month\n # │ │ │ │ │ ┌──── day of week\n # │ │ │ │ │ │\n # │ │ │ │ │ │\n # * * * * * *\n *\n * Valid lifecycle values:\n * \\{ ttl: \\{ weeks: 2 \\} \\} -- This fact retriever will remove items that are older than 2 weeks when it is run\n * \\{ maxItems: 7 \\} -- This fact retriever will leave 7 newest items in the database when it is run\n *\n */\nexport function createFactRetrieverRegistration(\n options: FactRetrieverRegistrationOptions,\n): FactRetrieverRegistration {\n const { cadence, factRetriever, lifecycle, timeout, initialDelay } = options;\n return {\n cadence,\n factRetriever,\n lifecycle,\n timeout,\n initialDelay,\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport isEmpty from 'lodash/isEmpty';\n\n/**\n * Generates facts which indicate the completeness of entity metadata.\n *\n * @public\n */\nexport const entityMetadataFactRetriever: FactRetriever = {\n id: 'entityMetadataFactRetriever',\n version: '0.0.1',\n title: 'Entity Metadata',\n description:\n 'Generates facts which indicate the completeness of entity metadata',\n schema: {\n hasTitle: {\n type: 'boolean',\n description: 'The entity has a title in metadata',\n },\n hasDescription: {\n type: 'boolean',\n description: 'The entity has a description in metadata',\n },\n hasTags: {\n type: 'boolean',\n description: 'The entity has tags in metadata',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n hasTitle: Boolean(entity.metadata?.title),\n hasDescription: Boolean(entity.metadata?.description),\n hasTags: !isEmpty(entity.metadata?.tags),\n },\n };\n });\n },\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\n\n/**\n * Generates facts which indicate the quality of data in the spec.owner field.\n *\n * @public\n */\nexport const entityOwnershipFactRetriever: FactRetriever = {\n id: 'entityOwnershipFactRetriever',\n version: '0.0.1',\n title: 'Entity Ownership',\n description:\n 'Generates facts which indicate the quality of data in the spec.owner field',\n entityFilter: [\n { kind: ['component', 'domain', 'system', 'api', 'resource', 'template'] },\n ],\n schema: {\n hasOwner: {\n type: 'boolean',\n description: 'The spec.owner field is set',\n },\n hasGroupOwner: {\n type: 'boolean',\n description: 'The spec.owner field is set and refers to a group',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n hasOwner: Boolean(entity.spec?.owner),\n hasGroupOwner: Boolean(\n entity.spec?.owner &&\n !(entity.spec?.owner as string).startsWith('user:'),\n ),\n },\n };\n });\n },\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport camelCase from 'lodash/camelCase';\nimport { Entity } from '@backstage/catalog-model';\nimport { get } from 'lodash';\nimport {\n FactLifecycle,\n MaxItems,\n TTL,\n} from '@backstage-community/plugin-tech-insights-node';\n\nexport const generateAnnotationFactName = (annotation: string) =>\n camelCase(`hasAnnotation-${annotation}`);\n\nexport const entityHasAnnotation = (entity: Entity, annotation: string) =>\n Boolean(get(entity, ['metadata', 'annotations', annotation]));\n\nexport const isTtl = (lifecycle: FactLifecycle): lifecycle is TTL => {\n return !!(lifecycle as TTL).timeToLive;\n};\n\nexport const isMaxItems = (lifecycle: FactLifecycle): lifecycle is MaxItems => {\n return !!(lifecycle as MaxItems).maxItems;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { entityHasAnnotation, generateAnnotationFactName } from './utils';\n\nconst techdocsAnnotation = 'backstage.io/techdocs-ref';\nconst techdocsAnnotationFactName =\n generateAnnotationFactName(techdocsAnnotation);\n\n/**\n * Generates facts related to the completeness of techdocs configuration for entities.\n *\n * @public\n */\nexport const techdocsFactRetriever: FactRetriever = {\n id: 'techdocsFactRetriever',\n version: '0.0.1',\n title: 'Tech Docs',\n description:\n 'Generates facts related to the completeness of techdocs configuration for entities',\n schema: {\n [techdocsAnnotationFactName]: {\n type: 'boolean',\n description: 'The entity has a TechDocs reference annotation',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n [techdocsAnnotationFactName]: entityHasAnnotation(\n entity,\n techdocsAnnotation,\n ),\n },\n };\n });\n },\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport {\n FactLifecycle,\n FactSchemaDefinition,\n FlatTechInsightFact,\n TechInsightFact,\n TechInsightsStore,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { FactSchema } from '@backstage-community/plugin-tech-insights-common';\nimport { rsort } from 'semver';\nimport { groupBy, omit } from 'lodash';\nimport { DateTime } from 'luxon';\nimport {\n CompoundEntityRef,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { isMaxItems, isTtl } from '../fact/factRetrievers/utils';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype Transaction = Knex.Transaction;\n\nexport type RawDbFactRow = {\n id: string;\n version: string;\n timestamp: Date | string;\n entity: string;\n facts: string;\n};\n\ntype RawDbFactSchemaRow = {\n id: string;\n version: string;\n schema: string;\n entityFilter?: string;\n};\n\n/**\n * Default TechInsightsDatabase implementation.\n *\n * @internal\n */\nexport class TechInsightsDatabase implements TechInsightsStore {\n private readonly CHUNK_SIZE = 50;\n\n constructor(\n private readonly db: Knex,\n private readonly logger: LoggerService,\n ) {}\n\n async getLatestSchemas(ids?: string[]): Promise<FactSchema[]> {\n const queryBuilder = this.db<RawDbFactSchemaRow>('fact_schemas');\n if (ids) {\n queryBuilder.whereIn('id', ids);\n }\n const existingSchemas = await queryBuilder.orderBy('id', 'desc').select();\n\n const groupedSchemas = groupBy(existingSchemas, 'id');\n return Object.values(groupedSchemas)\n .map(schemas => {\n const sorted = rsort(schemas.map(it => it.version));\n return schemas.find(it => it.version === sorted[0])!;\n })\n .map((it: RawDbFactSchemaRow) => ({\n ...omit(it, 'schema'),\n ...JSON.parse(it.schema),\n entityFilter: it.entityFilter ? JSON.parse(it.entityFilter) : null,\n }));\n }\n\n async insertFactSchema(schemaDefinition: FactSchemaDefinition) {\n const { id, version, schema, entityFilter } = schemaDefinition;\n const existingSchemas = await this.db<RawDbFactSchemaRow>('fact_schemas')\n .where({ id })\n .and.where({ version })\n .select();\n\n if (!existingSchemas || existingSchemas.length === 0) {\n await this.db<RawDbFactSchemaRow>('fact_schemas').insert({\n id,\n version,\n entityFilter: entityFilter ? JSON.stringify(entityFilter) : undefined,\n schema: JSON.stringify(schema),\n });\n }\n }\n\n async insertFacts({\n id,\n facts,\n lifecycle,\n }: {\n id: string;\n facts: TechInsightFact[];\n lifecycle?: FactLifecycle;\n }): Promise<void> {\n if (facts.length === 0) return;\n const currentSchema = await this.getLatestSchema(id);\n const factRows = facts.map(it => {\n const ts = it.timestamp?.toISO();\n return {\n id,\n version: currentSchema.version,\n entity: stringifyEntityRef(it.entity),\n facts: JSON.stringify(it.facts),\n ...(ts && { timestamp: ts }),\n };\n });\n\n await this.db.transaction(async tx => {\n await tx.batchInsert<RawDbFactRow>('facts', factRows, this.CHUNK_SIZE);\n\n if (lifecycle && isTtl(lifecycle)) {\n const expiration = DateTime.now().minus(lifecycle.timeToLive);\n await this.deleteExpiredFactsByDate(tx, id, expiration);\n }\n if (lifecycle && isMaxItems(lifecycle)) {\n await this.deleteExpiredFactsByNumber(tx, id, lifecycle.maxItems);\n }\n });\n }\n\n async getLatestFactsByIds(\n ids: string[],\n entityTriplet: string,\n ): Promise<{ [factId: string]: FlatTechInsightFact }> {\n const results = await this.db<RawDbFactRow>('facts')\n .where({ entity: entityTriplet })\n .and.whereIn('id', ids)\n .join(\n this.db('facts')\n .max('timestamp as maxTimestamp')\n .column('id as subId')\n .where({ entity: entityTriplet })\n .and.whereIn('id', ids)\n .groupBy('id')\n .as('subQ'),\n {\n 'facts.id': 'subQ.subId',\n 'facts.timestamp': 'subQ.maxTimestamp',\n },\n );\n return this.dbFactRowsToTechInsightFacts(results);\n }\n\n async getEntities(): Promise<CompoundEntityRef[]> {\n const results = await this.db<RawDbFactRow>('facts').distinct('entity');\n return results.map(row => parseEntityRef(row.entity));\n }\n\n async getFactsBetweenTimestampsByIds(\n ids: string[],\n entityTriplet: string,\n startDateTime: DateTime,\n endDateTime: DateTime,\n ): Promise<{\n [factId: string]: FlatTechInsightFact[];\n }> {\n const results = await this.db<RawDbFactRow>('facts')\n .where({ entity: entityTriplet })\n .and.whereIn('id', ids)\n .and.whereBetween('timestamp', [\n startDateTime.toISO(),\n endDateTime.toISO(),\n ]);\n\n return groupBy(\n results.map(it => {\n const { namespace, kind, name } = parseEntityRef(it.entity);\n const timestamp =\n typeof it.timestamp === 'string'\n ? DateTime.fromISO(it.timestamp)\n : DateTime.fromJSDate(it.timestamp);\n return {\n id: it.id,\n entity: { namespace, kind, name },\n timestamp,\n version: it.version,\n facts: JSON.parse(it.facts),\n };\n }),\n 'id',\n );\n }\n\n private async getLatestSchema(id: string): Promise<RawDbFactSchemaRow> {\n const existingSchemas = await this.db<RawDbFactSchemaRow>('fact_schemas')\n .where({ id })\n .orderBy('id', 'desc')\n .select();\n if (existingSchemas.length < 1) {\n this.logger.warn(`No schema found for ${id}. `);\n throw new Error(`No schema found for ${id}. `);\n }\n const sorted = rsort(existingSchemas.map(it => it.version));\n return existingSchemas.find(it => it.version === sorted[0])!;\n }\n\n private async deleteExpiredFactsByDate(\n tx: Transaction,\n factRetrieverId: string,\n timestamp: DateTime,\n ) {\n await tx<RawDbFactRow>('facts')\n .where({ id: factRetrieverId })\n .and.where('timestamp', '<', timestamp.toISO())\n .delete();\n }\n\n private async deleteExpiredFactsByNumber(\n tx: Transaction,\n factRetrieverId: string,\n maxItems: number,\n ) {\n const deletionFilterQuery = (subTx: Knex.QueryBuilder<any, unknown[]>) =>\n subTx\n .select(['id', 'entity', 'timestamp'])\n .from('facts')\n .where({ id: factRetrieverId })\n .and.whereIn('entity', db =>\n db.distinct('entity').where({ id: factRetrieverId }),\n )\n .and.leftJoin(\n joinTable =>\n joinTable\n .select('*')\n .from(\n this.db('facts')\n .column(\n { fid: 'id' },\n { fentity: 'entity' },\n { ftimestamp: 'timestamp' },\n )\n .column(\n this.db.raw(\n 'row_number() over (partition by id, entity order by timestamp desc) as fact_rank',\n ),\n )\n .as('ranks'),\n )\n .where('fact_rank', '<=', maxItems)\n .as('filterjoin'),\n joinClause => {\n joinClause\n .on('filterjoin.fid', 'facts.id')\n .on('filterjoin.fentity', 'facts.entity')\n .on('filterjoin.ftimestamp', 'facts.timestamp');\n },\n )\n .whereNull('filterjoin.fid');\n await tx('facts')\n .whereIn(['id', 'entity', 'timestamp'], database =>\n deletionFilterQuery(database),\n )\n .delete();\n }\n\n private dbFactRowsToTechInsightFacts(rows: RawDbFactRow[]) {\n return rows.reduce((acc, it) => {\n const { namespace, kind, name } = parseEntityRef(it.entity);\n const timestamp =\n typeof it.timestamp === 'string'\n ? DateTime.fromISO(it.timestamp)\n : DateTime.fromJSDate(it.timestamp);\n return {\n ...acc,\n [it.id]: {\n id: it.id,\n entity: { namespace, kind, name },\n timestamp,\n version: it.version,\n facts: JSON.parse(it.facts),\n },\n };\n }, {});\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { TechInsightsDatabase } from './TechInsightsDatabase';\nimport { PersistenceContext } from '@backstage-community/plugin-tech-insights-node';\nimport {\n DatabaseService,\n LoggerService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage-community/plugin-tech-insights-backend',\n 'migrations',\n);\n\n/**\n * A Container for persistence context initialization options\n *\n * @public\n */\nexport type PersistenceContextOptions = {\n logger: LoggerService;\n};\n\n/**\n * A factory function to construct persistence context for running implementation.\n *\n * @public\n */\nexport const initializePersistenceContext = async (\n database: DatabaseService,\n options: PersistenceContextOptions,\n): Promise<PersistenceContext> => {\n const client = await database.getClient();\n\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return {\n techInsightsStore: new TechInsightsDatabase(client, options.logger),\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Config } from '@backstage/config';\nimport {\n FactChecker,\n PersistenceContext,\n TechInsightCheck,\n} from '@backstage-community/plugin-tech-insights-node';\n\nimport { CheckResult } from '@backstage-community/plugin-tech-insights-common';\nimport { DateTime } from 'luxon';\nimport {\n CompoundEntityRef,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { serializeError } from '@backstage/errors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport pLimit from 'p-limit';\n\n/**\n * @public\n *\n * RouterOptions to construct TechInsights endpoints\n * @typeParam CheckType - Type of the check for the fact checker this builder returns\n * @typeParam CheckResultType - Type of the check result for the fact checker this builder returns\n */\nexport interface RouterOptions<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n> {\n /**\n * Optional FactChecker implementation. If omitted, endpoints are not constructed\n */\n factChecker?: FactChecker<CheckType, CheckResultType>;\n\n /**\n * TechInsights PersistenceContext. Should contain an implementation of TechInsightsStore\n */\n persistenceContext: PersistenceContext;\n\n /**\n * Backstage config object\n */\n config: Config;\n\n /**\n * Implementation of Winston logger\n */\n logger: LoggerService;\n}\n\n/**\n * @public\n *\n * Constructs a tech-insights router.\n *\n * Exposes endpoints to handle facts\n * Exposes optional endpoints to handle checks if a FactChecker implementation is passed in\n *\n * @param options - RouterOptions object\n */\nexport async function createRouter<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n>(options: RouterOptions<CheckType, CheckResultType>): Promise<express.Router> {\n const router = Router();\n router.use(express.json());\n const { persistenceContext, factChecker, logger, config } = options;\n const { techInsightsStore } = persistenceContext;\n\n const factory = MiddlewareFactory.create({ logger, config });\n\n if (factChecker) {\n logger.info('Fact checker configured. Enabling fact checking endpoints.');\n router.get('/checks', async (_req, res) => {\n return res.json(await factChecker.getChecks());\n });\n\n router.post('/checks/run/:namespace/:kind/:name', async (req, res) => {\n const { namespace, kind, name } = req.params;\n const { checks }: { checks: string[] } = req.body;\n const entityTriplet = stringifyEntityRef({ namespace, kind, name });\n const checkResult = await factChecker.runChecks(entityTriplet, checks);\n return res.json(checkResult);\n });\n\n const checksRunConcurrency =\n config.getOptionalNumber('techInsights.checksRunConcurrency') || 100;\n router.post('/checks/run', async (req, res) => {\n const checks: string[] = req.body.checks;\n let entities: CompoundEntityRef[] = req.body.entities;\n if (entities.length === 0) {\n entities = await techInsightsStore.getEntities();\n }\n const limit = pLimit(checksRunConcurrency);\n const tasks = entities.map(async entity =>\n limit(async () => {\n const entityTriplet =\n typeof entity === 'string' ? entity : stringifyEntityRef(entity);\n try {\n const results = await factChecker.runChecks(entityTriplet, checks);\n return {\n entity: entityTriplet,\n results,\n };\n } catch (e: any) {\n const error = serializeError(e);\n logger.error(`${error.name}: ${error.message}`);\n return {\n entity: entityTriplet,\n error: error,\n results: [],\n };\n }\n }),\n );\n const results = await Promise.all(tasks);\n return res.json(results);\n });\n } else {\n logger.info(\n 'Starting tech insights module without fact checking endpoints.',\n );\n }\n\n router.get('/fact-schemas', async (req, res) => {\n const ids = req.query.ids as string[];\n return res.json(await techInsightsStore.getLatestSchemas(ids));\n });\n\n /**\n * /facts/latest?entity=component:default/mycomponent&ids[]=factRetrieverId1&ids[]=factRetrieverId2\n */\n router.get('/facts/latest', async (req, res) => {\n const { entity } = req.query;\n const { namespace, kind, name } = parseEntityRef(entity as string);\n\n if (!req.query.ids) {\n return res\n .status(422)\n .json({ error: 'Failed to parse ids from request' });\n }\n const ids = [req.query.ids].flat() as string[];\n return res.json(\n await techInsightsStore.getLatestFactsByIds(\n ids,\n stringifyEntityRef({ namespace, kind, name }),\n ),\n );\n });\n\n /**\n * /facts/range?entity=component:default/mycomponent&startDateTime=2021-12-24T01:23:45&endDateTime=2021-12-31T23:59:59&ids[]=factRetrieverId1&ids[]=factRetrieverId2\n */\n router.get('/facts/range', async (req, res) => {\n const { entity } = req.query;\n const { namespace, kind, name } = parseEntityRef(entity as string);\n\n if (!req.query.ids) {\n return res\n .status(422)\n .json({ error: 'Failed to parse ids from request' });\n }\n const ids = [req.query.ids].flat() as string[];\n const startDatetime = DateTime.fromISO(req.query.startDatetime as string);\n const endDatetime = DateTime.fromISO(req.query.endDatetime as string);\n if (!startDatetime.isValid || !endDatetime.isValid) {\n return res.status(422).json({\n message: 'Failed to parse datetime from request',\n field: !startDatetime.isValid ? 'startDateTime' : 'endDateTime',\n value: !startDatetime.isValid ? startDatetime : endDatetime,\n });\n }\n const entityTriplet = stringifyEntityRef({ namespace, kind, name });\n return res.json(\n await techInsightsStore.getFactsBetweenTimestampsByIds(\n ids,\n entityTriplet,\n startDatetime,\n endDatetime,\n ),\n );\n });\n\n router.use(factory.error());\n return router;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n FactLifecycle,\n FactRetriever,\n FactRetrieverContext,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n TechInsightFact,\n TechInsightsStore,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { Duration } from 'luxon';\nimport { LoggerService, SchedulerService } from '@backstage/backend-plugin-api';\n\nfunction randomDailyCron() {\n const rand = (min: number, max: number) =>\n Math.floor(Math.random() * (max - min + 1) + min);\n return `${rand(0, 59)} ${rand(0, 23)} * * *`;\n}\n\nfunction duration(startTimestamp: [number, number]): string {\n const delta = process.hrtime(startTimestamp);\n const seconds = delta[0] + delta[1] / 1e9;\n return `${seconds.toFixed(1)}s`;\n}\n\n/**\n * @public\n *\n * FactRetrieverEngine responsible scheduling and running fact retrieval tasks.\n */\nexport interface FactRetrieverEngine {\n /**\n * Schedules fact retriever run cycles based on configuration provided in the registration.\n *\n * Default implementation uses backend-tasks to handle scheduling. This function can be called multiple\n * times, where initial calls schedule the tasks and subsequent invocations update the schedules.\n */\n schedule(): Promise<void>;\n\n /**\n * Provides possibility to manually run a fact retriever job and construct fact data\n *\n * @param ref - Reference to the task name stored in the executor database. By convention this is the fact retriever id\n */\n triggerJob(ref: string): Promise<void>;\n\n /**\n * Exposes fact retriever job configuration information about previous and next runs and schedule\n *\n * @param ref - Reference to the task name stored in the executor database. By convention this is the fact retriever id\n */\n getJobRegistration(ref: string): Promise<FactRetrieverRegistration>;\n}\n\nexport class DefaultFactRetrieverEngine implements FactRetrieverEngine {\n private constructor(\n private readonly repository: TechInsightsStore,\n private readonly factRetrieverRegistry: FactRetrieverRegistry,\n private readonly factRetrieverContext: FactRetrieverContext,\n private readonly logger: LoggerService,\n private readonly scheduler: SchedulerService,\n private readonly defaultCadence?: string,\n private readonly defaultTimeout?: Duration,\n private readonly defaultInitialDelay?: Duration,\n ) {}\n\n static async create(options: {\n repository: TechInsightsStore;\n factRetrieverRegistry: FactRetrieverRegistry;\n factRetrieverContext: FactRetrieverContext;\n scheduler: SchedulerService;\n defaultCadence?: string;\n defaultTimeout?: Duration;\n defaultInitialDelay?: Duration;\n }) {\n const {\n repository,\n factRetrieverRegistry,\n factRetrieverContext,\n scheduler,\n defaultCadence,\n defaultTimeout,\n defaultInitialDelay,\n } = options;\n\n const retrievers = await factRetrieverRegistry.listRetrievers();\n await Promise.all(retrievers.map(it => repository.insertFactSchema(it)));\n\n return new DefaultFactRetrieverEngine(\n repository,\n factRetrieverRegistry,\n factRetrieverContext,\n factRetrieverContext.logger,\n scheduler,\n defaultCadence,\n defaultTimeout,\n defaultInitialDelay,\n );\n }\n\n async schedule() {\n const registrations = await this.factRetrieverRegistry.listRegistrations();\n const newRegs: string[] = [];\n\n await Promise.all(\n registrations.map(async registration => {\n const { factRetriever, cadence, lifecycle, timeout, initialDelay } =\n registration;\n const cronExpression =\n cadence || this.defaultCadence || randomDailyCron();\n const timeLimit =\n timeout || this.defaultTimeout || Duration.fromObject({ minutes: 5 });\n const initialDelaySetting =\n initialDelay ||\n this.defaultInitialDelay ||\n Duration.fromObject({ seconds: 5 });\n try {\n await this.scheduler.scheduleTask({\n id: factRetriever.id,\n frequency: { cron: cronExpression },\n fn: this.createFactRetrieverHandler(factRetriever, lifecycle),\n timeout: timeLimit,\n // We add a delay in order to prevent errors due to the\n // fact that the backend is not yet online in a cold-start scenario\n initialDelay: initialDelaySetting,\n });\n newRegs.push(factRetriever.id);\n } catch (e) {\n this.logger.warn(\n `Failed to schedule fact retriever ${factRetriever.id}, ${e}`,\n );\n }\n }),\n );\n\n this.logger.info(\n `Scheduled ${newRegs.length}/${registrations.length} fact retrievers into the tech-insights engine`,\n );\n }\n\n getJobRegistration(ref: string): Promise<FactRetrieverRegistration> {\n return this.factRetrieverRegistry.get(ref);\n }\n\n async triggerJob(ref: string): Promise<void> {\n await this.scheduler.triggerTask(ref);\n }\n\n private createFactRetrieverHandler(\n factRetriever: FactRetriever,\n lifecycle?: FactLifecycle,\n ) {\n return async () => {\n const startTimestamp = process.hrtime();\n this.logger.info(\n `Retrieving facts for fact retriever ${factRetriever.id}`,\n );\n\n let facts: TechInsightFact[] = [];\n try {\n facts = await factRetriever.handler({\n ...this.factRetrieverContext,\n logger: this.logger.child({ factRetrieverId: factRetriever.id }),\n entityFilter: factRetriever.entityFilter,\n });\n this.logger.debug(\n `Retrieved ${facts.length} facts for fact retriever ${\n factRetriever.id\n } in ${duration(startTimestamp)}`,\n );\n } catch (e) {\n this.logger.error(\n `Failed to retrieve facts for retriever ${factRetriever.id}`,\n e,\n );\n }\n\n try {\n await this.repository.insertFacts({\n id: factRetriever.id,\n facts,\n lifecycle,\n });\n this.logger.info(\n `Stored ${facts.length} facts for fact retriever ${\n factRetriever.id\n } in ${duration(startTimestamp)}`,\n );\n } catch (e) {\n this.logger.warn(\n `Failed to insert facts for fact retriever ${factRetriever.id}`,\n e,\n );\n }\n };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FactRetriever,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { FactSchema } from '@backstage-community/plugin-tech-insights-common';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\n\n/**\n * A basic in memory fact retriever registry.\n *\n * You can replace this with a persistence based version using the FactRetrieverRegistry interface.\n *\n */\nexport class DefaultFactRetrieverRegistry implements FactRetrieverRegistry {\n private readonly retrievers = new Map<string, FactRetrieverRegistration>();\n\n constructor(retrievers: FactRetrieverRegistration[]) {\n retrievers.forEach(r => {\n this.registerSync(r);\n });\n }\n\n registerSync(registration: FactRetrieverRegistration) {\n if (this.retrievers.has(registration.factRetriever.id)) {\n throw new ConflictError(\n `Tech insight fact retriever with identifier '${registration.factRetriever.id}' has already been registered`,\n );\n }\n this.retrievers.set(registration.factRetriever.id, registration);\n }\n\n async register(registration: FactRetrieverRegistration) {\n this.registerSync(registration);\n }\n\n async get(retrieverReference: string): Promise<FactRetrieverRegistration> {\n const registration = this.retrievers.get(retrieverReference);\n if (!registration) {\n throw new NotFoundError(\n `Tech insight fact retriever with identifier '${retrieverReference}' is not registered.`,\n );\n }\n return registration;\n }\n\n async listRetrievers(): Promise<FactRetriever[]> {\n return [...this.retrievers.values()].map(it => it.factRetriever);\n }\n\n async listRegistrations(): Promise<FactRetrieverRegistration[]> {\n return [...this.retrievers.values()];\n }\n\n async getSchemas(): Promise<FactSchema[]> {\n const retrievers = await this.listRetrievers();\n return retrievers.map(it => it.schema);\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DefaultFactRetrieverEngine,\n FactRetrieverEngine,\n} from './fact/FactRetrieverEngine';\nimport { DefaultFactRetrieverRegistry } from './fact/FactRetrieverRegistry';\nimport { Config } from '@backstage/config';\nimport {\n createLegacyAuthAdapters,\n TokenManager,\n} from '@backstage/backend-common';\nimport {\n FactChecker,\n FactCheckerFactory,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n PersistenceContext,\n TechInsightCheck,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { initializePersistenceContext } from './persistence';\nimport { CheckResult } from '@backstage-community/plugin-tech-insights-common';\nimport {\n AuthService,\n DatabaseService,\n DiscoveryService,\n LoggerService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * @public\n * @typeParam CheckType - Type of the check for the fact checker this builder returns\n * @typeParam CheckResultType - Type of the check result for the fact checker this builder returns\n *\n * Configuration options to initialize TechInsightsBuilder. Generic types params are needed if FactCheckerFactory\n * is included for FactChecker creation.\n */\nexport interface TechInsightsOptions<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n> {\n /**\n * Optional collection of FactRetrieverRegistrations (required if no factRetrieverRegistry passed in).\n * Used to register FactRetrievers and their schemas and schedule an execution loop for them.\n *\n * Not needed if passing in your own FactRetrieverRegistry implementation. Required otherwise.\n */\n factRetrievers?: FactRetrieverRegistration[];\n\n /**\n * Optional factory exposing a `construct` method to initialize a FactChecker implementation\n */\n factCheckerFactory?: FactCheckerFactory<CheckType, CheckResultType>;\n\n /**\n * Optional FactRetrieverRegistry implementation that replaces the default one.\n *\n * If passing this in you don't need to pass in factRetrievers also.\n */\n factRetrieverRegistry?: FactRetrieverRegistry;\n\n /**\n * Optional persistenceContext implementation that replaces the default one.\n * This can be used to replace underlying database with a more suitable implementation if needed\n */\n persistenceContext?: PersistenceContext;\n\n logger: LoggerService;\n config: Config;\n discovery: DiscoveryService;\n database: DatabaseService;\n scheduler: SchedulerService;\n tokenManager: TokenManager;\n auth?: AuthService;\n}\n\n/**\n * @public\n * @typeParam CheckType - Type of the check for the fact checker this builder returns\n * @typeParam CheckResultType - Type of the check result for the fact checker this builder returns\n *\n * A container for exported implementations related to TechInsights.\n * FactChecker is present if an optional FactCheckerFactory is included in the build stage.\n */\nexport type TechInsightsContext<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n> = {\n factChecker?: FactChecker<CheckType, CheckResultType>;\n persistenceContext: PersistenceContext;\n factRetrieverEngine: FactRetrieverEngine;\n};\n\n/**\n * @public\n *\n * Constructs needed persistence context, fact retriever engine\n * and optionally fact checker implementations to be used in the tech insights module.\n *\n * @param options - Needed options to construct TechInsightsContext\n * @returns TechInsightsContext with persistence implementations and optionally an implementation of a FactChecker\n */\nexport const buildTechInsightsContext = async <\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n>(\n options: TechInsightsOptions<CheckType, CheckResultType>,\n): Promise<TechInsightsContext<CheckType, CheckResultType>> => {\n const {\n factRetrievers,\n factCheckerFactory,\n config,\n discovery,\n database,\n logger,\n scheduler,\n tokenManager,\n } = options;\n\n const buildFactRetrieverRegistry = (): FactRetrieverRegistry => {\n if (!options.factRetrieverRegistry) {\n if (!factRetrievers) {\n throw new Error(\n 'Failed to build FactRetrieverRegistry because no factRetrievers found',\n );\n }\n return new DefaultFactRetrieverRegistry(factRetrievers);\n }\n return options.factRetrieverRegistry;\n };\n\n const factRetrieverRegistry = buildFactRetrieverRegistry();\n\n const persistenceContext =\n options.persistenceContext ??\n (await initializePersistenceContext(database, {\n logger,\n }));\n\n const { auth } = createLegacyAuthAdapters({\n auth: options.auth,\n tokenManager,\n discovery,\n });\n\n const factRetrieverEngine = await DefaultFactRetrieverEngine.create({\n scheduler,\n repository: persistenceContext.techInsightsStore,\n factRetrieverRegistry,\n factRetrieverContext: {\n config,\n discovery,\n logger,\n tokenManager,\n auth,\n },\n });\n\n await factRetrieverEngine.schedule();\n\n if (factCheckerFactory) {\n const factChecker = factCheckerFactory.construct(\n persistenceContext.techInsightsStore,\n );\n return {\n persistenceContext,\n factChecker,\n factRetrieverEngine,\n };\n }\n\n return {\n persistenceContext,\n factRetrieverEngine,\n };\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport {\n FactLifecycle,\n FactRetriever,\n FactRetrieverRegistration,\n} from '@backstage-community/plugin-tech-insights-node';\nimport {\n createFactRetrieverRegistration,\n FactRetrieverRegistrationOptions,\n} from '../service';\n\ntype FactRetrieverConfig = Omit<\n FactRetrieverRegistrationOptions,\n 'factRetriever'\n>;\n\nfunction readLifecycleConfig(\n config: Config | undefined,\n): FactLifecycle | undefined {\n if (!config) {\n return undefined;\n }\n\n if (config.has('maxItems')) {\n return {\n maxItems: config.getNumber('maxItems'),\n };\n }\n\n return {\n timeToLive: readDurationFromConfig(config.getConfig('timeToLive')),\n };\n}\n\nfunction readFactRetrieverConfig(\n config: Config,\n name: string,\n): FactRetrieverConfig | undefined {\n const factRetrieverConfig = config.getOptionalConfig(\n `techInsights.factRetrievers.${name}`,\n );\n if (!factRetrieverConfig) {\n return undefined;\n }\n\n const cadence = factRetrieverConfig.getString('cadence');\n const initialDelay = factRetrieverConfig.has('initialDelay')\n ? readDurationFromConfig(factRetrieverConfig.getConfig('initialDelay'))\n : undefined;\n const lifecycle = readLifecycleConfig(\n factRetrieverConfig.getOptionalConfig('lifecycle'),\n );\n const timeout = factRetrieverConfig.has('timeout')\n ? readDurationFromConfig(factRetrieverConfig.getConfig('timeout'))\n : undefined;\n\n return {\n cadence,\n initialDelay,\n lifecycle,\n timeout,\n };\n}\n\nexport function createFactRetrieverRegistrationFromConfig(\n config: Config,\n name: string,\n factRetriever: FactRetriever,\n): FactRetrieverRegistration | undefined {\n const factRetrieverConfig = readFactRetrieverConfig(config, name);\n\n return factRetrieverConfig\n ? createFactRetrieverRegistration({\n ...factRetrieverConfig,\n factRetriever,\n })\n : undefined;\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { CheckResult } from '@backstage-community/plugin-tech-insights-common';\nimport {\n FactCheckerFactory,\n FactRetriever,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n PersistenceContext,\n TechInsightCheck,\n techInsightsFactCheckerFactoryExtensionPoint,\n techInsightsFactRetrieverRegistryExtensionPoint,\n techInsightsFactRetrieversExtensionPoint,\n techInsightsPersistenceContextExtensionPoint,\n} from '@backstage-community/plugin-tech-insights-node';\nimport {\n buildTechInsightsContext,\n createRouter,\n entityMetadataFactRetriever,\n entityOwnershipFactRetriever,\n techdocsFactRetriever,\n} from '../service';\nimport { createFactRetrieverRegistrationFromConfig } from './config';\n\n/**\n * The tech-insights backend plugin.\n *\n * @public\n */\nexport const techInsightsPlugin = createBackendPlugin({\n pluginId: 'tech-insights',\n register(env) {\n let factCheckerFactory:\n | FactCheckerFactory<TechInsightCheck, CheckResult>\n | undefined = undefined;\n env.registerExtensionPoint(techInsightsFactCheckerFactoryExtensionPoint, {\n setFactCheckerFactory<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n >(factory: FactCheckerFactory<CheckType, CheckResultType>): void {\n factCheckerFactory = factory;\n },\n });\n\n let factRetrieverRegistry: FactRetrieverRegistry | undefined = undefined;\n env.registerExtensionPoint(\n techInsightsFactRetrieverRegistryExtensionPoint,\n {\n setFactRetrieverRegistry(registry: FactRetrieverRegistry): void {\n factRetrieverRegistry = registry;\n },\n },\n );\n\n // initialized with built-in fact retrievers\n // only added as registration if there is config for them\n const addedFactRetrievers: Record<string, FactRetriever> = {\n entityMetadataFactRetriever,\n entityOwnershipFactRetriever,\n techdocsFactRetriever,\n };\n env.registerExtensionPoint(techInsightsFactRetrieversExtensionPoint, {\n addFactRetrievers(factRetrievers: Record<string, FactRetriever>): void {\n Object.entries(factRetrievers).forEach(([key, value]) => {\n addedFactRetrievers[key] = value;\n });\n },\n });\n\n let persistenceContext: PersistenceContext | undefined = undefined;\n env.registerExtensionPoint(techInsightsPersistenceContextExtensionPoint, {\n setPersistenceContext(context: PersistenceContext): void {\n persistenceContext = context;\n },\n });\n\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n database: coreServices.database,\n discovery: coreServices.discovery,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n tokenManager: coreServices.tokenManager,\n auth: coreServices.auth,\n },\n async init({\n config,\n database,\n discovery,\n httpRouter,\n logger,\n scheduler,\n tokenManager,\n auth,\n }) {\n const factRetrievers: FactRetrieverRegistration[] = Object.entries(\n addedFactRetrievers,\n )\n .map(([name, factRetriever]) =>\n createFactRetrieverRegistrationFromConfig(\n config,\n name,\n factRetriever,\n ),\n )\n .filter(registration => registration) as FactRetrieverRegistration[];\n\n const context = await buildTechInsightsContext({\n config,\n database,\n discovery,\n factCheckerFactory,\n factRetrieverRegistry,\n factRetrievers,\n logger,\n persistenceContext,\n scheduler,\n tokenManager,\n auth,\n });\n\n httpRouter.use(\n await createRouter({\n ...context,\n config,\n logger,\n }),\n );\n },\n });\n },\n});\n"],"names":["catalogClient","CatalogClient","isEmpty","camelCase","get","groupBy","rsort","omit","stringifyEntityRef","DateTime","parseEntityRef","resolvePackagePath","Router","express","MiddlewareFactory","pLimit","results","serializeError","Duration","ConflictError","NotFoundError","createLegacyAuthAdapters","config","readDurationFromConfig","createBackendPlugin","techInsightsFactCheckerFactoryExtensionPoint","techInsightsFactRetrieverRegistryExtensionPoint","techInsightsFactRetrieversExtensionPoint","techInsightsPersistenceContextExtensionPoint","coreServices"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/service/fact/createFactRetriever.ts","../src/service/fact/factRetrievers/entityMetadataFactRetriever.ts","../src/service/fact/factRetrievers/entityOwnershipFactRetriever.ts","../src/service/fact/factRetrievers/utils.ts","../src/service/fact/factRetrievers/techdocsFactRetriever.ts","../src/service/persistence/TechInsightsDatabase.ts","../src/service/persistence/persistenceContext.ts","../src/service/router.ts","../src/service/fact/FactRetrieverEngine.ts","../src/service/fact/FactRetrieverRegistry.ts","../src/service/techInsightsContextBuilder.ts","../src/plugin/config.ts","../src/plugin/plugin.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { HumanDuration } from '@backstage/types';\nimport {\n FactLifecycle,\n FactRetriever,\n FactRetrieverRegistration,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { Duration } from 'luxon';\n\n/**\n * @public\n *\n * @param cadence - cron expression to indicate when the fact retriever should be triggered\n * @param factRetriever - Implementation of fact retriever consisting of at least id, version, schema and handler\n * @param lifecycle - Optional lifecycle definition indicating the cleanup logic of facts when this retriever is run\n * @param timeout - Optional duration to determine how long the fact retriever should be allowed to run, defaults to 5 minutes\n *\n */\nexport type FactRetrieverRegistrationOptions = {\n cadence: string;\n factRetriever: FactRetriever;\n lifecycle?: FactLifecycle;\n timeout?: Duration | HumanDuration;\n initialDelay?: Duration | HumanDuration;\n};\n\n/**\n * @public\n *\n * A helper function to construct fact retriever registrations.\n * @param cadence - Cron expression to indicate when the fact retriever should be triggered\n * @param factRetriever - Implementation of fact retriever consisting of at least id, version, schema and handler\n * @param lifecycle - Optional lifecycle definition indicating the cleanup logic of facts when this retriever is run\n * @param timeout - Optional duration to determine how long the fact retriever should be allowed to run, defaults to 5 minutes\n * @param initialDelay - Optional initial delay to determine how long the fact retriever should wait before the initial run, defaults to 5 seconds\n *\n *\n * @remarks\n *\n * Cron expressions help:\n * ┌────────────── second (optional)\n # │ ┌──────────── minute\n # │ │ ┌────────── hour\n # │ │ │ ┌──────── day of month\n # │ │ │ │ ┌────── month\n # │ │ │ │ │ ┌──── day of week\n # │ │ │ │ │ │\n # │ │ │ │ │ │\n # * * * * * *\n *\n * Valid lifecycle values:\n * \\{ ttl: \\{ weeks: 2 \\} \\} -- This fact retriever will remove items that are older than 2 weeks when it is run\n * \\{ maxItems: 7 \\} -- This fact retriever will leave 7 newest items in the database when it is run\n *\n */\nexport function createFactRetrieverRegistration(\n options: FactRetrieverRegistrationOptions,\n): FactRetrieverRegistration {\n const { cadence, factRetriever, lifecycle, timeout, initialDelay } = options;\n return {\n cadence,\n factRetriever,\n lifecycle,\n timeout,\n initialDelay,\n };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport isEmpty from 'lodash/isEmpty';\n\n/**\n * Generates facts which indicate the completeness of entity metadata.\n *\n * @public\n */\nexport const entityMetadataFactRetriever: FactRetriever = {\n id: 'entityMetadataFactRetriever',\n version: '0.0.1',\n title: 'Entity Metadata',\n description:\n 'Generates facts which indicate the completeness of entity metadata',\n schema: {\n hasTitle: {\n type: 'boolean',\n description: 'The entity has a title in metadata',\n },\n hasDescription: {\n type: 'boolean',\n description: 'The entity has a description in metadata',\n },\n hasTags: {\n type: 'boolean',\n description: 'The entity has tags in metadata',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n hasTitle: Boolean(entity.metadata?.title),\n hasDescription: Boolean(entity.metadata?.description),\n hasTags: !isEmpty(entity.metadata?.tags),\n },\n };\n });\n },\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\n\n/**\n * Generates facts which indicate the quality of data in the spec.owner field.\n *\n * @public\n */\nexport const entityOwnershipFactRetriever: FactRetriever = {\n id: 'entityOwnershipFactRetriever',\n version: '0.0.1',\n title: 'Entity Ownership',\n description:\n 'Generates facts which indicate the quality of data in the spec.owner field',\n entityFilter: [\n { kind: ['component', 'domain', 'system', 'api', 'resource', 'template'] },\n ],\n schema: {\n hasOwner: {\n type: 'boolean',\n description: 'The spec.owner field is set',\n },\n hasGroupOwner: {\n type: 'boolean',\n description: 'The spec.owner field is set and refers to a group',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n hasOwner: Boolean(entity.spec?.owner),\n hasGroupOwner: Boolean(\n entity.spec?.owner &&\n !(entity.spec?.owner as string).startsWith('user:'),\n ),\n },\n };\n });\n },\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport camelCase from 'lodash/camelCase';\nimport { Entity } from '@backstage/catalog-model';\nimport { get } from 'lodash';\nimport {\n FactLifecycle,\n MaxItems,\n TTL,\n} from '@backstage-community/plugin-tech-insights-node';\n\nexport const generateAnnotationFactName = (annotation: string) =>\n camelCase(`hasAnnotation-${annotation}`);\n\nexport const entityHasAnnotation = (entity: Entity, annotation: string) =>\n Boolean(get(entity, ['metadata', 'annotations', annotation]));\n\nexport const isTtl = (lifecycle: FactLifecycle): lifecycle is TTL => {\n return !!(lifecycle as TTL).timeToLive;\n};\n\nexport const isMaxItems = (lifecycle: FactLifecycle): lifecycle is MaxItems => {\n return !!(lifecycle as MaxItems).maxItems;\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FactRetriever,\n FactRetrieverContext,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { entityHasAnnotation, generateAnnotationFactName } from './utils';\n\nconst techdocsAnnotation = 'backstage.io/techdocs-ref';\nconst techdocsAnnotationFactName =\n generateAnnotationFactName(techdocsAnnotation);\n\n/**\n * Generates facts related to the completeness of techdocs configuration for entities.\n *\n * @public\n */\nexport const techdocsFactRetriever: FactRetriever = {\n id: 'techdocsFactRetriever',\n version: '0.0.1',\n title: 'Tech Docs',\n description:\n 'Generates facts related to the completeness of techdocs configuration for entities',\n schema: {\n [techdocsAnnotationFactName]: {\n type: 'boolean',\n description: 'The entity has a TechDocs reference annotation',\n },\n },\n handler: async ({ discovery, entityFilter, auth }: FactRetrieverContext) => {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const catalogClient = new CatalogClient({\n discoveryApi: discovery,\n });\n const entities = await catalogClient.getEntities(\n { filter: entityFilter },\n { token },\n );\n\n return entities.items.map((entity: Entity) => {\n return {\n entity: {\n namespace: entity.metadata.namespace!,\n kind: entity.kind,\n name: entity.metadata.name,\n },\n facts: {\n [techdocsAnnotationFactName]: entityHasAnnotation(\n entity,\n techdocsAnnotation,\n ),\n },\n };\n });\n },\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport {\n FactLifecycle,\n FactSchemaDefinition,\n FlatTechInsightFact,\n TechInsightFact,\n TechInsightsStore,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { FactSchema } from '@backstage-community/plugin-tech-insights-common';\nimport { rsort } from 'semver';\nimport { groupBy, omit } from 'lodash';\nimport { DateTime } from 'luxon';\nimport {\n CompoundEntityRef,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { isMaxItems, isTtl } from '../fact/factRetrievers/utils';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype Transaction = Knex.Transaction;\n\nexport type RawDbFactRow = {\n id: string;\n version: string;\n timestamp: Date | string;\n entity: string;\n facts: string;\n};\n\ntype RawDbFactSchemaRow = {\n id: string;\n version: string;\n schema: string;\n entityFilter?: string;\n};\n\n/**\n * Default TechInsightsDatabase implementation.\n *\n * @internal\n */\nexport class TechInsightsDatabase implements TechInsightsStore {\n private readonly CHUNK_SIZE = 50;\n\n constructor(\n private readonly db: Knex,\n private readonly logger: LoggerService,\n ) {}\n\n async getLatestSchemas(ids?: string[]): Promise<FactSchema[]> {\n const queryBuilder = this.db<RawDbFactSchemaRow>('fact_schemas');\n if (ids) {\n queryBuilder.whereIn('id', ids);\n }\n const existingSchemas = await queryBuilder.orderBy('id', 'desc').select();\n\n const groupedSchemas = groupBy(existingSchemas, 'id');\n return Object.values(groupedSchemas)\n .map(schemas => {\n const sorted = rsort(schemas.map(it => it.version));\n return schemas.find(it => it.version === sorted[0])!;\n })\n .map((it: RawDbFactSchemaRow) => ({\n ...omit(it, 'schema'),\n ...JSON.parse(it.schema),\n entityFilter: it.entityFilter ? JSON.parse(it.entityFilter) : null,\n }));\n }\n\n async insertFactSchema(schemaDefinition: FactSchemaDefinition) {\n const { id, version, schema, entityFilter } = schemaDefinition;\n const existingSchemas = await this.db<RawDbFactSchemaRow>('fact_schemas')\n .where({ id })\n .and.where({ version })\n .select();\n\n if (!existingSchemas || existingSchemas.length === 0) {\n await this.db<RawDbFactSchemaRow>('fact_schemas').insert({\n id,\n version,\n entityFilter: entityFilter ? JSON.stringify(entityFilter) : undefined,\n schema: JSON.stringify(schema),\n });\n }\n }\n\n async insertFacts({\n id,\n facts,\n lifecycle,\n }: {\n id: string;\n facts: TechInsightFact[];\n lifecycle?: FactLifecycle;\n }): Promise<void> {\n if (facts.length === 0) return;\n const currentSchema = await this.getLatestSchema(id);\n const factRows = facts.map(it => {\n const ts = it.timestamp?.toISO();\n return {\n id,\n version: currentSchema.version,\n entity: stringifyEntityRef(it.entity),\n facts: JSON.stringify(it.facts),\n ...(ts && { timestamp: ts }),\n };\n });\n\n await this.db.transaction(async tx => {\n await tx.batchInsert<RawDbFactRow>('facts', factRows, this.CHUNK_SIZE);\n\n if (lifecycle && isTtl(lifecycle)) {\n const expiration = DateTime.now().minus(lifecycle.timeToLive);\n await this.deleteExpiredFactsByDate(tx, id, expiration);\n }\n if (lifecycle && isMaxItems(lifecycle)) {\n await this.deleteExpiredFactsByNumber(tx, id, lifecycle.maxItems);\n }\n });\n }\n\n async getLatestFactsByIds(\n ids: string[],\n entityTriplet: string,\n ): Promise<{ [factId: string]: FlatTechInsightFact }> {\n const results = await this.db<RawDbFactRow>('facts')\n .where({ entity: entityTriplet })\n .and.whereIn('id', ids)\n .join(\n this.db('facts')\n .max('timestamp as maxTimestamp')\n .column('id as subId')\n .where({ entity: entityTriplet })\n .and.whereIn('id', ids)\n .groupBy('id')\n .as('subQ'),\n {\n 'facts.id': 'subQ.subId',\n 'facts.timestamp': 'subQ.maxTimestamp',\n },\n );\n return this.dbFactRowsToTechInsightFacts(results);\n }\n\n async getEntities(): Promise<CompoundEntityRef[]> {\n const results = await this.db<RawDbFactRow>('facts').distinct('entity');\n return results.map(row => parseEntityRef(row.entity));\n }\n\n async getFactsBetweenTimestampsByIds(\n ids: string[],\n entityTriplet: string,\n startDateTime: DateTime,\n endDateTime: DateTime,\n ): Promise<{\n [factId: string]: FlatTechInsightFact[];\n }> {\n const results = await this.db<RawDbFactRow>('facts')\n .where({ entity: entityTriplet })\n .and.whereIn('id', ids)\n .and.whereBetween('timestamp', [\n startDateTime.toISO(),\n endDateTime.toISO(),\n ]);\n\n return groupBy(\n results.map(it => {\n const { namespace, kind, name } = parseEntityRef(it.entity);\n const timestamp =\n typeof it.timestamp === 'string'\n ? DateTime.fromISO(it.timestamp)\n : DateTime.fromJSDate(it.timestamp);\n return {\n id: it.id,\n entity: { namespace, kind, name },\n timestamp,\n version: it.version,\n facts: JSON.parse(it.facts),\n };\n }),\n 'id',\n );\n }\n\n private async getLatestSchema(id: string): Promise<RawDbFactSchemaRow> {\n const existingSchemas = await this.db<RawDbFactSchemaRow>('fact_schemas')\n .where({ id })\n .orderBy('id', 'desc')\n .select();\n if (existingSchemas.length < 1) {\n this.logger.warn(`No schema found for ${id}. `);\n throw new Error(`No schema found for ${id}. `);\n }\n const sorted = rsort(existingSchemas.map(it => it.version));\n return existingSchemas.find(it => it.version === sorted[0])!;\n }\n\n private async deleteExpiredFactsByDate(\n tx: Transaction,\n factRetrieverId: string,\n timestamp: DateTime,\n ) {\n await tx<RawDbFactRow>('facts')\n .where({ id: factRetrieverId })\n .and.where('timestamp', '<', timestamp.toISO())\n .delete();\n }\n\n private async deleteExpiredFactsByNumber(\n tx: Transaction,\n factRetrieverId: string,\n maxItems: number,\n ) {\n const deletionFilterQuery = (subTx: Knex.QueryBuilder<any, unknown[]>) =>\n subTx\n .select(['id', 'entity', 'timestamp'])\n .from('facts')\n .where({ id: factRetrieverId })\n .and.whereIn('entity', db =>\n db.distinct('entity').where({ id: factRetrieverId }),\n )\n .and.leftJoin(\n joinTable =>\n joinTable\n .select('*')\n .from(\n this.db('facts')\n .column(\n { fid: 'id' },\n { fentity: 'entity' },\n { ftimestamp: 'timestamp' },\n )\n .column(\n this.db.raw(\n 'row_number() over (partition by id, entity order by timestamp desc) as fact_rank',\n ),\n )\n .as('ranks'),\n )\n .where('fact_rank', '<=', maxItems)\n .as('filterjoin'),\n joinClause => {\n joinClause\n .on('filterjoin.fid', 'facts.id')\n .on('filterjoin.fentity', 'facts.entity')\n .on('filterjoin.ftimestamp', 'facts.timestamp');\n },\n )\n .whereNull('filterjoin.fid');\n await tx('facts')\n .whereIn(['id', 'entity', 'timestamp'], database =>\n deletionFilterQuery(database),\n )\n .delete();\n }\n\n private dbFactRowsToTechInsightFacts(rows: RawDbFactRow[]) {\n return rows.reduce((acc, it) => {\n const { namespace, kind, name } = parseEntityRef(it.entity);\n const timestamp =\n typeof it.timestamp === 'string'\n ? DateTime.fromISO(it.timestamp)\n : DateTime.fromJSDate(it.timestamp);\n return {\n ...acc,\n [it.id]: {\n id: it.id,\n entity: { namespace, kind, name },\n timestamp,\n version: it.version,\n facts: JSON.parse(it.facts),\n },\n };\n }, {});\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { TechInsightsDatabase } from './TechInsightsDatabase';\nimport { PersistenceContext } from '@backstage-community/plugin-tech-insights-node';\nimport {\n DatabaseService,\n LoggerService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage-community/plugin-tech-insights-backend',\n 'migrations',\n);\n\n/**\n * A Container for persistence context initialization options\n *\n * @public\n */\nexport type PersistenceContextOptions = {\n logger: LoggerService;\n};\n\n/**\n * A factory function to construct persistence context for running implementation.\n *\n * @public\n */\nexport const initializePersistenceContext = async (\n database: DatabaseService,\n options: PersistenceContextOptions,\n): Promise<PersistenceContext> => {\n const client = await database.getClient();\n\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return {\n techInsightsStore: new TechInsightsDatabase(client, options.logger),\n };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Config } from '@backstage/config';\nimport {\n FactChecker,\n PersistenceContext,\n TechInsightCheck,\n} from '@backstage-community/plugin-tech-insights-node';\n\nimport { CheckResult } from '@backstage-community/plugin-tech-insights-common';\nimport { DateTime } from 'luxon';\nimport {\n CompoundEntityRef,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { serializeError } from '@backstage/errors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport pLimit from 'p-limit';\n\n/**\n * @public\n *\n * RouterOptions to construct TechInsights endpoints\n * @typeParam CheckType - Type of the check for the fact checker this builder returns\n * @typeParam CheckResultType - Type of the check result for the fact checker this builder returns\n */\nexport interface RouterOptions<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n> {\n /**\n * Optional FactChecker implementation. If omitted, endpoints are not constructed\n */\n factChecker?: FactChecker<CheckType, CheckResultType>;\n\n /**\n * TechInsights PersistenceContext. Should contain an implementation of TechInsightsStore\n */\n persistenceContext: PersistenceContext;\n\n /**\n * Backstage config object\n */\n config: Config;\n\n /**\n * Implementation of Winston logger\n */\n logger: LoggerService;\n}\n\n/**\n * @public\n *\n * Constructs a tech-insights router.\n *\n * Exposes endpoints to handle facts\n * Exposes optional endpoints to handle checks if a FactChecker implementation is passed in\n *\n * @param options - RouterOptions object\n */\nexport async function createRouter<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n>(options: RouterOptions<CheckType, CheckResultType>): Promise<express.Router> {\n const router = Router();\n router.use(express.json());\n const { persistenceContext, factChecker, logger, config } = options;\n const { techInsightsStore } = persistenceContext;\n\n const factory = MiddlewareFactory.create({ logger, config });\n\n if (factChecker) {\n logger.info('Fact checker configured. Enabling fact checking endpoints.');\n router.get('/checks', async (_req, res) => {\n return res.json(await factChecker.getChecks());\n });\n\n router.post('/checks/run/:namespace/:kind/:name', async (req, res) => {\n const { namespace, kind, name } = req.params;\n const { checks }: { checks: string[] } = req.body;\n const entityTriplet = stringifyEntityRef({ namespace, kind, name });\n const checkResult = await factChecker.runChecks(entityTriplet, checks);\n return res.json(checkResult);\n });\n\n const checksRunConcurrency =\n config.getOptionalNumber('techInsights.checksRunConcurrency') || 100;\n router.post('/checks/run', async (req, res) => {\n const checks: string[] = req.body.checks;\n let entities: CompoundEntityRef[] = req.body.entities;\n if (entities.length === 0) {\n entities = await techInsightsStore.getEntities();\n }\n const limit = pLimit(checksRunConcurrency);\n const tasks = entities.map(async entity =>\n limit(async () => {\n const entityTriplet =\n typeof entity === 'string' ? entity : stringifyEntityRef(entity);\n try {\n const results = await factChecker.runChecks(entityTriplet, checks);\n return {\n entity: entityTriplet,\n results,\n };\n } catch (e: any) {\n const error = serializeError(e);\n logger.error(`${error.name}: ${error.message}`);\n return {\n entity: entityTriplet,\n error: error,\n results: [],\n };\n }\n }),\n );\n const results = await Promise.all(tasks);\n return res.json(results);\n });\n } else {\n logger.info(\n 'Starting tech insights module without fact checking endpoints.',\n );\n }\n\n router.get('/fact-schemas', async (req, res) => {\n const ids = req.query.ids as string[];\n return res.json(await techInsightsStore.getLatestSchemas(ids));\n });\n\n /**\n * /facts/latest?entity=component:default/mycomponent&ids[]=factRetrieverId1&ids[]=factRetrieverId2\n */\n router.get('/facts/latest', async (req, res) => {\n const { entity } = req.query;\n const { namespace, kind, name } = parseEntityRef(entity as string);\n\n if (!req.query.ids) {\n return res\n .status(422)\n .json({ error: 'Failed to parse ids from request' });\n }\n const ids = [req.query.ids].flat() as string[];\n return res.json(\n await techInsightsStore.getLatestFactsByIds(\n ids,\n stringifyEntityRef({ namespace, kind, name }),\n ),\n );\n });\n\n /**\n * /facts/range?entity=component:default/mycomponent&startDateTime=2021-12-24T01:23:45&endDateTime=2021-12-31T23:59:59&ids[]=factRetrieverId1&ids[]=factRetrieverId2\n */\n router.get('/facts/range', async (req, res) => {\n const { entity } = req.query;\n const { namespace, kind, name } = parseEntityRef(entity as string);\n\n if (!req.query.ids) {\n return res\n .status(422)\n .json({ error: 'Failed to parse ids from request' });\n }\n const ids = [req.query.ids].flat() as string[];\n const startDatetime = DateTime.fromISO(req.query.startDatetime as string);\n const endDatetime = DateTime.fromISO(req.query.endDatetime as string);\n if (!startDatetime.isValid || !endDatetime.isValid) {\n return res.status(422).json({\n message: 'Failed to parse datetime from request',\n field: !startDatetime.isValid ? 'startDateTime' : 'endDateTime',\n value: !startDatetime.isValid ? startDatetime : endDatetime,\n });\n }\n const entityTriplet = stringifyEntityRef({ namespace, kind, name });\n return res.json(\n await techInsightsStore.getFactsBetweenTimestampsByIds(\n ids,\n entityTriplet,\n startDatetime,\n endDatetime,\n ),\n );\n });\n\n router.use(factory.error());\n return router;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n FactLifecycle,\n FactRetriever,\n FactRetrieverContext,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n TechInsightFact,\n TechInsightsStore,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { Duration } from 'luxon';\nimport { LoggerService, SchedulerService } from '@backstage/backend-plugin-api';\n\nfunction randomDailyCron() {\n const rand = (min: number, max: number) =>\n Math.floor(Math.random() * (max - min + 1) + min);\n return `${rand(0, 59)} ${rand(0, 23)} * * *`;\n}\n\nfunction duration(startTimestamp: [number, number]): string {\n const delta = process.hrtime(startTimestamp);\n const seconds = delta[0] + delta[1] / 1e9;\n return `${seconds.toFixed(1)}s`;\n}\n\n/**\n * @public\n *\n * FactRetrieverEngine responsible scheduling and running fact retrieval tasks.\n */\nexport interface FactRetrieverEngine {\n /**\n * Schedules fact retriever run cycles based on configuration provided in the registration.\n *\n * Default implementation uses backend-tasks to handle scheduling. This function can be called multiple\n * times, where initial calls schedule the tasks and subsequent invocations update the schedules.\n */\n schedule(): Promise<void>;\n\n /**\n * Provides possibility to manually run a fact retriever job and construct fact data\n *\n * @param ref - Reference to the task name stored in the executor database. By convention this is the fact retriever id\n */\n triggerJob(ref: string): Promise<void>;\n\n /**\n * Exposes fact retriever job configuration information about previous and next runs and schedule\n *\n * @param ref - Reference to the task name stored in the executor database. By convention this is the fact retriever id\n */\n getJobRegistration(ref: string): Promise<FactRetrieverRegistration>;\n}\n\nexport class DefaultFactRetrieverEngine implements FactRetrieverEngine {\n private constructor(\n private readonly repository: TechInsightsStore,\n private readonly factRetrieverRegistry: FactRetrieverRegistry,\n private readonly factRetrieverContext: FactRetrieverContext,\n private readonly logger: LoggerService,\n private readonly scheduler: SchedulerService,\n private readonly defaultCadence?: string,\n private readonly defaultTimeout?: Duration,\n private readonly defaultInitialDelay?: Duration,\n ) {}\n\n static async create(options: {\n repository: TechInsightsStore;\n factRetrieverRegistry: FactRetrieverRegistry;\n factRetrieverContext: FactRetrieverContext;\n scheduler: SchedulerService;\n defaultCadence?: string;\n defaultTimeout?: Duration;\n defaultInitialDelay?: Duration;\n }) {\n const {\n repository,\n factRetrieverRegistry,\n factRetrieverContext,\n scheduler,\n defaultCadence,\n defaultTimeout,\n defaultInitialDelay,\n } = options;\n\n const retrievers = await factRetrieverRegistry.listRetrievers();\n await Promise.all(retrievers.map(it => repository.insertFactSchema(it)));\n\n return new DefaultFactRetrieverEngine(\n repository,\n factRetrieverRegistry,\n factRetrieverContext,\n factRetrieverContext.logger,\n scheduler,\n defaultCadence,\n defaultTimeout,\n defaultInitialDelay,\n );\n }\n\n async schedule() {\n const registrations = await this.factRetrieverRegistry.listRegistrations();\n const newRegs: string[] = [];\n\n await Promise.all(\n registrations.map(async registration => {\n const { factRetriever, cadence, lifecycle, timeout, initialDelay } =\n registration;\n const cronExpression =\n cadence || this.defaultCadence || randomDailyCron();\n const timeLimit =\n timeout || this.defaultTimeout || Duration.fromObject({ minutes: 5 });\n const initialDelaySetting =\n initialDelay ||\n this.defaultInitialDelay ||\n Duration.fromObject({ seconds: 5 });\n try {\n await this.scheduler.scheduleTask({\n id: factRetriever.id,\n frequency: { cron: cronExpression },\n fn: this.createFactRetrieverHandler(factRetriever, lifecycle),\n timeout: timeLimit,\n // We add a delay in order to prevent errors due to the\n // fact that the backend is not yet online in a cold-start scenario\n initialDelay: initialDelaySetting,\n });\n newRegs.push(factRetriever.id);\n } catch (e) {\n this.logger.warn(\n `Failed to schedule fact retriever ${factRetriever.id}, ${e}`,\n );\n }\n }),\n );\n\n this.logger.info(\n `Scheduled ${newRegs.length}/${registrations.length} fact retrievers into the tech-insights engine`,\n );\n }\n\n getJobRegistration(ref: string): Promise<FactRetrieverRegistration> {\n return this.factRetrieverRegistry.get(ref);\n }\n\n async triggerJob(ref: string): Promise<void> {\n await this.scheduler.triggerTask(ref);\n }\n\n private createFactRetrieverHandler(\n factRetriever: FactRetriever,\n lifecycle?: FactLifecycle,\n ) {\n return async () => {\n const startTimestamp = process.hrtime();\n this.logger.info(\n `Retrieving facts for fact retriever ${factRetriever.id}`,\n );\n\n let facts: TechInsightFact[] = [];\n try {\n facts = await factRetriever.handler({\n ...this.factRetrieverContext,\n logger: this.logger.child({ factRetrieverId: factRetriever.id }),\n entityFilter: factRetriever.entityFilter,\n });\n this.logger.debug(\n `Retrieved ${facts.length} facts for fact retriever ${\n factRetriever.id\n } in ${duration(startTimestamp)}`,\n );\n } catch (e) {\n this.logger.error(\n `Failed to retrieve facts for retriever ${factRetriever.id}`,\n e,\n );\n }\n\n try {\n await this.repository.insertFacts({\n id: factRetriever.id,\n facts,\n lifecycle,\n });\n this.logger.info(\n `Stored ${facts.length} facts for fact retriever ${\n factRetriever.id\n } in ${duration(startTimestamp)}`,\n );\n } catch (e) {\n this.logger.warn(\n `Failed to insert facts for fact retriever ${factRetriever.id}`,\n e,\n );\n }\n };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FactRetriever,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { FactSchema } from '@backstage-community/plugin-tech-insights-common';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\n\n/**\n * A basic in memory fact retriever registry.\n *\n * You can replace this with a persistence based version using the FactRetrieverRegistry interface.\n *\n */\nexport class DefaultFactRetrieverRegistry implements FactRetrieverRegistry {\n private readonly retrievers = new Map<string, FactRetrieverRegistration>();\n\n constructor(retrievers: FactRetrieverRegistration[]) {\n retrievers.forEach(r => {\n this.registerSync(r);\n });\n }\n\n registerSync(registration: FactRetrieverRegistration) {\n if (this.retrievers.has(registration.factRetriever.id)) {\n throw new ConflictError(\n `Tech insight fact retriever with identifier '${registration.factRetriever.id}' has already been registered`,\n );\n }\n this.retrievers.set(registration.factRetriever.id, registration);\n }\n\n async register(registration: FactRetrieverRegistration) {\n this.registerSync(registration);\n }\n\n async get(retrieverReference: string): Promise<FactRetrieverRegistration> {\n const registration = this.retrievers.get(retrieverReference);\n if (!registration) {\n throw new NotFoundError(\n `Tech insight fact retriever with identifier '${retrieverReference}' is not registered.`,\n );\n }\n return registration;\n }\n\n async listRetrievers(): Promise<FactRetriever[]> {\n return [...this.retrievers.values()].map(it => it.factRetriever);\n }\n\n async listRegistrations(): Promise<FactRetrieverRegistration[]> {\n return [...this.retrievers.values()];\n }\n\n async getSchemas(): Promise<FactSchema[]> {\n const retrievers = await this.listRetrievers();\n return retrievers.map(it => it.schema);\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DefaultFactRetrieverEngine,\n FactRetrieverEngine,\n} from './fact/FactRetrieverEngine';\nimport { DefaultFactRetrieverRegistry } from './fact/FactRetrieverRegistry';\nimport { Config } from '@backstage/config';\nimport {\n FactChecker,\n FactCheckerFactory,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n PersistenceContext,\n TechInsightCheck,\n} from '@backstage-community/plugin-tech-insights-node';\nimport { initializePersistenceContext } from './persistence';\nimport { CheckResult } from '@backstage-community/plugin-tech-insights-common';\nimport {\n AuthService,\n DatabaseService,\n DiscoveryService,\n LoggerService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * @public\n * @typeParam CheckType - Type of the check for the fact checker this builder returns\n * @typeParam CheckResultType - Type of the check result for the fact checker this builder returns\n *\n * Configuration options to initialize TechInsightsBuilder. Generic types params are needed if FactCheckerFactory\n * is included for FactChecker creation.\n */\nexport interface TechInsightsOptions<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n> {\n /**\n * Optional collection of FactRetrieverRegistrations (required if no factRetrieverRegistry passed in).\n * Used to register FactRetrievers and their schemas and schedule an execution loop for them.\n *\n * Not needed if passing in your own FactRetrieverRegistry implementation. Required otherwise.\n */\n factRetrievers?: FactRetrieverRegistration[];\n\n /**\n * Optional factory exposing a `construct` method to initialize a FactChecker implementation\n */\n factCheckerFactory?: FactCheckerFactory<CheckType, CheckResultType>;\n\n /**\n * Optional FactRetrieverRegistry implementation that replaces the default one.\n *\n * If passing this in you don't need to pass in factRetrievers also.\n */\n factRetrieverRegistry?: FactRetrieverRegistry;\n\n /**\n * Optional persistenceContext implementation that replaces the default one.\n * This can be used to replace underlying database with a more suitable implementation if needed\n */\n persistenceContext?: PersistenceContext;\n\n logger: LoggerService;\n config: Config;\n discovery: DiscoveryService;\n database: DatabaseService;\n scheduler: SchedulerService;\n auth: AuthService;\n}\n\n/**\n * @public\n * @typeParam CheckType - Type of the check for the fact checker this builder returns\n * @typeParam CheckResultType - Type of the check result for the fact checker this builder returns\n *\n * A container for exported implementations related to TechInsights.\n * FactChecker is present if an optional FactCheckerFactory is included in the build stage.\n */\nexport type TechInsightsContext<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n> = {\n factChecker?: FactChecker<CheckType, CheckResultType>;\n persistenceContext: PersistenceContext;\n factRetrieverEngine: FactRetrieverEngine;\n};\n\n/**\n * @public\n *\n * Constructs needed persistence context, fact retriever engine\n * and optionally fact checker implementations to be used in the tech insights module.\n *\n * @param options - Needed options to construct TechInsightsContext\n * @returns TechInsightsContext with persistence implementations and optionally an implementation of a FactChecker\n */\nexport const buildTechInsightsContext = async <\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n>(\n options: TechInsightsOptions<CheckType, CheckResultType>,\n): Promise<TechInsightsContext<CheckType, CheckResultType>> => {\n const {\n factRetrievers,\n factCheckerFactory,\n config,\n discovery,\n database,\n logger,\n scheduler,\n auth,\n } = options;\n\n const buildFactRetrieverRegistry = (): FactRetrieverRegistry => {\n if (!options.factRetrieverRegistry) {\n if (!factRetrievers) {\n throw new Error(\n 'Failed to build FactRetrieverRegistry because no factRetrievers found',\n );\n }\n return new DefaultFactRetrieverRegistry(factRetrievers);\n }\n return options.factRetrieverRegistry;\n };\n\n const factRetrieverRegistry = buildFactRetrieverRegistry();\n\n const persistenceContext =\n options.persistenceContext ??\n (await initializePersistenceContext(database, {\n logger,\n }));\n\n const factRetrieverEngine = await DefaultFactRetrieverEngine.create({\n scheduler,\n repository: persistenceContext.techInsightsStore,\n factRetrieverRegistry,\n factRetrieverContext: {\n config,\n discovery,\n logger,\n auth,\n },\n });\n\n await factRetrieverEngine.schedule();\n\n if (factCheckerFactory) {\n const factChecker = factCheckerFactory.construct(\n persistenceContext.techInsightsStore,\n );\n return {\n persistenceContext,\n factChecker,\n factRetrieverEngine,\n };\n }\n\n return {\n persistenceContext,\n factRetrieverEngine,\n };\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport {\n FactLifecycle,\n FactRetriever,\n FactRetrieverRegistration,\n} from '@backstage-community/plugin-tech-insights-node';\nimport {\n createFactRetrieverRegistration,\n FactRetrieverRegistrationOptions,\n} from '../service';\n\ntype FactRetrieverConfig = Omit<\n FactRetrieverRegistrationOptions,\n 'factRetriever'\n>;\n\nfunction readLifecycleConfig(\n config: Config | undefined,\n): FactLifecycle | undefined {\n if (!config) {\n return undefined;\n }\n\n if (config.has('maxItems')) {\n return {\n maxItems: config.getNumber('maxItems'),\n };\n }\n\n return {\n timeToLive: readDurationFromConfig(config.getConfig('timeToLive')),\n };\n}\n\nfunction readFactRetrieverConfig(\n config: Config,\n name: string,\n): FactRetrieverConfig | undefined {\n const factRetrieverConfig = config.getOptionalConfig(\n `techInsights.factRetrievers.${name}`,\n );\n if (!factRetrieverConfig) {\n return undefined;\n }\n\n const cadence = factRetrieverConfig.getString('cadence');\n const initialDelay = factRetrieverConfig.has('initialDelay')\n ? readDurationFromConfig(factRetrieverConfig.getConfig('initialDelay'))\n : undefined;\n const lifecycle = readLifecycleConfig(\n factRetrieverConfig.getOptionalConfig('lifecycle'),\n );\n const timeout = factRetrieverConfig.has('timeout')\n ? readDurationFromConfig(factRetrieverConfig.getConfig('timeout'))\n : undefined;\n\n return {\n cadence,\n initialDelay,\n lifecycle,\n timeout,\n };\n}\n\nexport function createFactRetrieverRegistrationFromConfig(\n config: Config,\n name: string,\n factRetriever: FactRetriever,\n): FactRetrieverRegistration | undefined {\n const factRetrieverConfig = readFactRetrieverConfig(config, name);\n\n return factRetrieverConfig\n ? createFactRetrieverRegistration({\n ...factRetrieverConfig,\n factRetriever,\n })\n : undefined;\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { CheckResult } from '@backstage-community/plugin-tech-insights-common';\nimport {\n FactCheckerFactory,\n FactRetriever,\n FactRetrieverRegistration,\n FactRetrieverRegistry,\n PersistenceContext,\n TechInsightCheck,\n techInsightsFactCheckerFactoryExtensionPoint,\n techInsightsFactRetrieverRegistryExtensionPoint,\n techInsightsFactRetrieversExtensionPoint,\n techInsightsPersistenceContextExtensionPoint,\n} from '@backstage-community/plugin-tech-insights-node';\nimport {\n buildTechInsightsContext,\n createRouter,\n entityMetadataFactRetriever,\n entityOwnershipFactRetriever,\n techdocsFactRetriever,\n} from '../service';\nimport { createFactRetrieverRegistrationFromConfig } from './config';\n\n/**\n * The tech-insights backend plugin.\n *\n * @public\n */\nexport const techInsightsPlugin = createBackendPlugin({\n pluginId: 'tech-insights',\n register(env) {\n let factCheckerFactory:\n | FactCheckerFactory<TechInsightCheck, CheckResult>\n | undefined = undefined;\n env.registerExtensionPoint(techInsightsFactCheckerFactoryExtensionPoint, {\n setFactCheckerFactory<\n CheckType extends TechInsightCheck,\n CheckResultType extends CheckResult,\n >(factory: FactCheckerFactory<CheckType, CheckResultType>): void {\n factCheckerFactory = factory;\n },\n });\n\n let factRetrieverRegistry: FactRetrieverRegistry | undefined = undefined;\n env.registerExtensionPoint(\n techInsightsFactRetrieverRegistryExtensionPoint,\n {\n setFactRetrieverRegistry(registry: FactRetrieverRegistry): void {\n factRetrieverRegistry = registry;\n },\n },\n );\n\n // initialized with built-in fact retrievers\n // only added as registration if there is config for them\n const addedFactRetrievers: Record<string, FactRetriever> = {\n entityMetadataFactRetriever,\n entityOwnershipFactRetriever,\n techdocsFactRetriever,\n };\n env.registerExtensionPoint(techInsightsFactRetrieversExtensionPoint, {\n addFactRetrievers(factRetrievers: Record<string, FactRetriever>): void {\n Object.entries(factRetrievers).forEach(([key, value]) => {\n addedFactRetrievers[key] = value;\n });\n },\n });\n\n let persistenceContext: PersistenceContext | undefined = undefined;\n env.registerExtensionPoint(techInsightsPersistenceContextExtensionPoint, {\n setPersistenceContext(context: PersistenceContext): void {\n persistenceContext = context;\n },\n });\n\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n database: coreServices.database,\n discovery: coreServices.discovery,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n auth: coreServices.auth,\n },\n async init({\n config,\n database,\n discovery,\n httpRouter,\n logger,\n scheduler,\n auth,\n }) {\n const factRetrievers: FactRetrieverRegistration[] = Object.entries(\n addedFactRetrievers,\n )\n .map(([name, factRetriever]) =>\n createFactRetrieverRegistrationFromConfig(\n config,\n name,\n factRetriever,\n ),\n )\n .filter(registration => registration) as FactRetrieverRegistration[];\n\n const context = await buildTechInsightsContext({\n config,\n database,\n discovery,\n factCheckerFactory,\n factRetrieverRegistry,\n factRetrievers,\n logger,\n persistenceContext,\n scheduler,\n auth,\n });\n\n httpRouter.use(\n await createRouter({\n ...context,\n config,\n logger,\n }),\n );\n },\n });\n },\n});\n"],"names":["catalogClient","CatalogClient","isEmpty","camelCase","get","groupBy","rsort","omit","stringifyEntityRef","DateTime","parseEntityRef","resolvePackagePath","Router","express","MiddlewareFactory","pLimit","results","serializeError","Duration","ConflictError","NotFoundError","config","readDurationFromConfig","createBackendPlugin","techInsightsFactCheckerFactoryExtensionPoint","techInsightsFactRetrieverRegistryExtensionPoint","techInsightsFactRetrieversExtensionPoint","techInsightsPersistenceContextExtensionPoint","coreServices"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { Duration } from 'luxon';
|
|
|
6
6
|
import express from 'express';
|
|
7
7
|
import { Config } from '@backstage/config';
|
|
8
8
|
import { CheckResult } from '@backstage-community/plugin-tech-insights-common';
|
|
9
|
-
import { TokenManager } from '@backstage/backend-common';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* The tech-insights backend plugin.
|
|
@@ -209,8 +208,7 @@ interface TechInsightsOptions<CheckType extends TechInsightCheck, CheckResultTyp
|
|
|
209
208
|
discovery: DiscoveryService;
|
|
210
209
|
database: DatabaseService;
|
|
211
210
|
scheduler: SchedulerService;
|
|
212
|
-
|
|
213
|
-
auth?: AuthService;
|
|
211
|
+
auth: AuthService;
|
|
214
212
|
}
|
|
215
213
|
/**
|
|
216
214
|
* @public
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-tech-insights-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "backend-plugin",
|
|
6
6
|
"pluginId": "tech-insights",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"test": "backstage-cli package test"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@backstage-community/plugin-tech-insights-common": "^0.2.
|
|
49
|
-
"@backstage-community/plugin-tech-insights-node": "^0.
|
|
48
|
+
"@backstage-community/plugin-tech-insights-common": "^0.2.18",
|
|
49
|
+
"@backstage-community/plugin-tech-insights-node": "^1.0.0",
|
|
50
50
|
"@backstage/backend-common": "^0.24.0",
|
|
51
51
|
"@backstage/backend-defaults": "^0.4.3",
|
|
52
52
|
"@backstage/backend-plugin-api": "^0.8.0",
|