Merge branch 'master' into patch-2
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights-backend': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `buildTechInsightsContext` function now takes an additional
|
||||
field in its options argument: `tokenManager`. This is an instance of
|
||||
`TokenManager`, which can be found in your backend initialization code's
|
||||
`env`.
|
||||
|
||||
```diff
|
||||
const builder = buildTechInsightsContext({
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
scheduler: env.scheduler,
|
||||
+ tokenManager: env.tokenManager,
|
||||
factRetrievers: [ /* ... */ ],
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights-node': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The `FactRetrieverContext` type now contains an additional
|
||||
field: `tokenManager`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights-backend-module-jsonfc': patch
|
||||
---
|
||||
|
||||
Updated usages of `buildTechInsightsContext` in README.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-rollbar-backend': patch
|
||||
---
|
||||
|
||||
Updated README to include clearer installation instructions on how to install and configure.
|
||||
+4
-2
@@ -118,5 +118,7 @@ _If you're using Backstage in your organization, please try to add your company
|
||||
| [Pachama](https://pachama.com/) | [Aron Gates](https://github.com/agates4) | Internal Developer Portal, a catalog of all microservices, architecture documentation, and templates to generate developer resources. |
|
||||
| [SEEK](https://www.seek.com.au) | [Jahred Hope](https://github.com/jahredhope) | Developer portal for developer tooling and technical documentation. |
|
||||
| [Marks & Spencer](https://www.marksandspencer.com/) | [Kamal Cheriyath](https://github.com/kcheriyath) | Centralised discovery, adoption and devops automation hub for Engineering & Architecture. |
|
||||
| [McKesson](https://www.mckesson.com/) | [Agnel Antony](https://github.com/aantony2) | Internal Developer Platform for developer gated CI/CD templates, technical documentation, cloud automation service catalog, etc. |
|
||||
| [leboncoin](https://www.leboncoin.fr/) | [Andy Ladjadj](https://github.com/aladjadj) | Centralize our multiple UI in a single portal. Simplify onbording, new features and harmonize how people search information. Core features (catalog,api,docs,scafolder) are good to start the adoption. status: internal beta. |
|
||||
| [McKesson](https://www.mckesson.com/) | [Agnel Antony](https://github.com/aantony2) | Internal Developer Platform for developer gated CI/CD templates, technical documentation, cloud automation service catalog, etc. |
|
||||
| [World Fuel Services](https://www.wfscorp.com/) | [Anirudh Kurapathi](https://github.com/anirudhkurapati), [Alex Kwon](https://github.com/alexkwon), [Lester Hernandez](https://github.com/lhernandez-wfscorp), [Avi Boru](https://github.com/aviboru), [Vardhan Annapureddy](https://github.com/harshaaws) | Internal Developer Portal, service catalog product, API's, Software Templates, tech docs and more. |
|
||||
| [leboncoin](https://www.leboncoin.fr/) | [Andy Ladjadj](https://github.com/aladjadj) | Centralize our multiple UI in a single portal. Simplify onbording, new features and harmonize how people search information. Core features (catalog,api,docs,scafolder) are good to start the adoption. status: internal beta. |
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 297 KiB |
@@ -74,7 +74,7 @@ export class ProviderAAuthProvider implements OAuthProviderHandlers {
|
||||
clientID: options.clientId,
|
||||
clientSecret: options.clientSecret,
|
||||
callbackURL: options.callbackUrl,
|
||||
passReqToCallback: false as true,
|
||||
passReqToCallback: false,
|
||||
response_type: 'code',
|
||||
/// ... etc
|
||||
}
|
||||
|
||||
@@ -76,17 +76,19 @@ TechDocs packages:
|
||||
|
||||
TechDocs promoted to v1.0! To understand how this change affects the package, please check out our [versioning policy](https://backstage.io/docs/overview/versioning-policy).
|
||||
|
||||
**v1.2** 🚧
|
||||
|
||||
With the Backstage 1.2 release, we plan to introduce the [TechDocs Addon Framework](https://github.com/backstage/backstage/issues/9636) for augmenting the TechDocs experience at read-time.
|
||||
|
||||
In addition to the framework itself, we'll be open sourcing a `<ReportIssue />` addon, helping you to create a feedback loop that drives up documentation quality and fosters a documentation culture at your organization.
|
||||
|
||||
### **Future work 🔮**
|
||||
|
||||
Some of the following items are coming soon and some are potential ideas.
|
||||
|
||||
- [TechDocs Addon Framework](https://github.com/backstage/backstage/issues/9636)
|
||||
- Contribute to and deploy from a marketplace of TechDocs Addons
|
||||
- Addon: Highlight text and raise an Issue to create a feedback loop to drive up documentation quality
|
||||
- Addon: MDX (allows you to use JSX in your Markdown content)
|
||||
- Better integration with
|
||||
[Scaffolder V2](https://github.com/backstage/backstage/issues/2771) (e.g. easy to choose and plug documentation template with Software Templates)
|
||||
- Static site generator agnostic
|
||||
- Static site generator agnostic, including possible support for MDX (allowing you to use JSX in your Markdown content)
|
||||
- Possible to configure several aspects about TechDocs (e.g. URL, homepage,
|
||||
theme)
|
||||
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
---
|
||||
id: addons
|
||||
title: TechDocs Addons
|
||||
description: How to find, use, or create TechDocs Addons.
|
||||
---
|
||||
|
||||
> Note: This page contains documentation for features that have not yet been
|
||||
> released on a [main-line version](https://backstage.io/docs/overview/versioning-policy#main-release-line)
|
||||
> of Backstage and TechDocs. We plan to make Addons generally available in
|
||||
> Backstage v1.2.
|
||||
|
||||
## Concepts
|
||||
|
||||
TechDocs is a centralized platform for publishing, viewing, and discovering
|
||||
technical documentation across an entire organization. It's a solid foundation!
|
||||
But it doesn't solve higher-order documentation needs on its own: how do you
|
||||
create and reinforce a culture of documentation? How do you build trust in the
|
||||
quality of technical documentation?
|
||||
|
||||
TechDocs Addons are a mechanism by which you can customize the TechDocs
|
||||
experience in order to try and address some of these higher-order needs.
|
||||
|
||||
### Addons
|
||||
|
||||
An Addon is just a react component. Like any react component, it can retrieve
|
||||
and render data using normal Backstage or native hooks, APIs, and components.
|
||||
Props can be used to configure its behavior, where appropriate.
|
||||
|
||||
### Locations
|
||||
|
||||
Addons declare a `location` where they will be rendered. Most locations are
|
||||
representative of physical spaces in the TechDocs UI:
|
||||
|
||||
- `Header`: For Addons which fill up the header from the right, on the same
|
||||
line as the title.
|
||||
- `Subheader`: For Addons that sit below the header but above all content.
|
||||
This is a great location for tooling/configuration of TechDocs display.
|
||||
- `PrimarySidebar`: Left of the content, above of the navigation.
|
||||
- `SecondarySidebar`: Right of the content, above the table of contents.
|
||||
- `Content`: A special location intended for Addons which augment the
|
||||
statically generated content of the documentation itself.
|
||||
- `Component`: A [proposed-but-not-yet-implemented](https://github.com/backstage/backstage/issues/11109)
|
||||
virtual location, aimed at simplifying a common type of Addon.
|
||||
|
||||
<img data-zoomable src="../../assets/techdocs/addon-locations.png" alt="TechDocs Addon Location Guide" />
|
||||
|
||||
### Addon Registry
|
||||
|
||||
The installation and configuration of Addons happens within a Backstage app's
|
||||
frontend. Addons are imported from plugins and added underneath a registry
|
||||
component called `<TechDocsAddons>`. This registry can be configured for both
|
||||
the TechDocs Reader page as well as the Entity docs page.
|
||||
|
||||
Addons are rendered in the order in which they are registered.
|
||||
|
||||
## Installing and using Addons
|
||||
|
||||
Addons can be installed and configured in much the same way as extensions for
|
||||
other Backstage plugins: by adding them underneath an extension registry
|
||||
component (`<TechDocsAddons>`) under the route representing the TechDocs Reader
|
||||
page in your `App.tsx`:
|
||||
|
||||
```tsx
|
||||
// packages/app/src/App.tsx
|
||||
|
||||
import { TechDocsReaderPage } from '@backstage/plugin-techdocs';
|
||||
import { TechDocsAddons } from '@backstage/plugin-techdocs-react/alpha';
|
||||
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
|
||||
|
||||
// ...
|
||||
|
||||
<Route path="/docs/:namespace/:kind/:name/*" element={<TechDocsReaderPage />}>
|
||||
<TechDocsAddons>
|
||||
<ReportIssue />
|
||||
{/* Other addons can be added here. */}
|
||||
</TechDocsAddons>
|
||||
</Route>;
|
||||
```
|
||||
|
||||
The process for configuring Addons on the documentation tab on the entity page
|
||||
is very similar; instead of adding the `<TechDocsAddons>` registry under a
|
||||
`<Route>`, you'd add it as a child of `<EntityTechdocsContent />`:
|
||||
|
||||
```tsx
|
||||
// packages/app/src/components/catalog/EntityPage.tsx
|
||||
|
||||
import { EntityLayout } from '@backstage/plugin-catalog';
|
||||
import { EntityTechdocsContent } from '@backstage/plugin-techdocs';
|
||||
import { TechDocsAddons } from '@backstage/plugin-techdocs-react/alpha';
|
||||
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
|
||||
|
||||
// ...
|
||||
|
||||
<EntityLayout.Route path="/docs" title="Docs">
|
||||
<EntityTechdocsContent>
|
||||
<TechDocsAddons>
|
||||
<ReportIssue />
|
||||
{/* Other addons can be added here. */}
|
||||
</TechDocsAddons>
|
||||
</EntityTechdocsContent>
|
||||
</EntityLayout.Route>;
|
||||
```
|
||||
|
||||
Note that on the entity page, because the Catalog plugin is responsible for the
|
||||
page header, TechDocs Addons whose location is `Header` will not be rendered.
|
||||
|
||||
## Available Addons
|
||||
|
||||
Addons can, in principle, be provided by any plugin! To make it easier to
|
||||
discover available Addons, we've compiled a list of them here:
|
||||
|
||||
| Addon | Package/Plugin | Description |
|
||||
| ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`<ReportIssue />`](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.reportissue) | `@backstage/plugin-techdocs-module-addons-contrib` | Allows TechDocs users to select a portion of text on a TechDocs page and open an issue against the repository that contains the documentation, populating the issue description with the selected text according to a configurable template. |
|
||||
|
||||
Got an Addon to contribute? Feel free to add a row above!
|
||||
|
||||
## Creating an Addon
|
||||
|
||||
The simplest Addons are plain old react components that get rendered in
|
||||
specific locations within a TechDocs site. To package such a react component as
|
||||
an Addon, follow these steps:
|
||||
|
||||
1. Write the component in your plugin like any other component
|
||||
2. Create, provide, and export the component from your plugin
|
||||
|
||||
```ts
|
||||
// plugins/your-plugin/src/plugin.ts
|
||||
|
||||
import {
|
||||
createTechDocsAddonExtension,
|
||||
TechDocsAddonLocations,
|
||||
} from '@backstage/plugin-techdocs-react/alpha';
|
||||
import { CatGifComponent, CatGifComponentProps } from './addons';
|
||||
|
||||
// ...
|
||||
|
||||
// You must "provide" your Addon, just like any extension, via your plugin.
|
||||
export const CatGif = yourPlugin.provide(
|
||||
// This function "creates" the Addon given a component and location. If your
|
||||
// component can be configured via props, pass the prop type here too.
|
||||
createTechDocsAddonExtension<CatGifComponentProps>({
|
||||
name: 'CatGif',
|
||||
location: TechDocsAddonLocations.Header,
|
||||
component: CatGifComponent,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
### Addons in the Content location
|
||||
|
||||
Beyond the "render a component in a region" use-case, it's also possible for
|
||||
Addons to access and manipulate a TechDocs site's DOM; this could be used to,
|
||||
for example, load and instantiate client-side diagramming libraries, replace
|
||||
elements with dynamically loaded content, etc.
|
||||
|
||||
This type of Addon is still expressed as a react component, but instead of
|
||||
returning a react element to be rendered, it updates the DOM via side-effects
|
||||
(e.g. with `useEffect`). Access to the DOM is made available via utility hooks
|
||||
provided by the Addon framework.
|
||||
|
||||
```tsx
|
||||
// plugins/your-plugin/src/addons/MakeAllImagesCatGifs.tsx
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { useShadowRootElements } from '@backstage/plugin-techdocs-react/alpha';
|
||||
|
||||
// This is a normal react component; in order to make it an Addon, you would
|
||||
// still create and provide it via your plugin as described above. The only
|
||||
// difference is that you'd set `location` to `TechDocsAddonLocations.Content`.
|
||||
export const MakeAllImagesCatGifsAddon = () => {
|
||||
// This hook can be used to get references to specific elements. If you need
|
||||
// access to the whole shadow DOM, use the the underlying useShadowRoot()
|
||||
// hook instead.
|
||||
const images = useShadowRootElements<HTMLImageElement>(['img']);
|
||||
|
||||
useEffect(() => {
|
||||
images.forEach(img => {
|
||||
if (img.src !== 'https://example.com/cat.gif') {
|
||||
img.src = 'https://example.com/cat.gif';
|
||||
}
|
||||
});
|
||||
}, [images]);
|
||||
|
||||
// Nothing to render directly, so we can just return null.
|
||||
return null;
|
||||
};
|
||||
```
|
||||
|
||||
### Testing Addons
|
||||
|
||||
Install `@backstage/plugin-techdocs-addons-test-utils` as a `devDependency` in
|
||||
your plugin for access to utilities that make testing such Addons easier.
|
||||
|
||||
A test for the above Addon might look something like this:
|
||||
|
||||
```tsx
|
||||
// plugins/your-plugin/src/addons/MakeAllImagesCatGifs.test.tsx
|
||||
import { TechDocsAddonTester } from '@backstage/plugin-techdocs-addons-test-utils';
|
||||
|
||||
// Note: import your actual addon (the one provided by your plugin).
|
||||
import { MakeAllImagesCatGifs } from '../plugin.ts';
|
||||
|
||||
describe('MakeAllImagesCatGifs', () => {
|
||||
it('replaces img srcs with cat gif', async () => {
|
||||
const { getByTestId } = await TechDocsAddonTester.buildAddonsInTechDocs([
|
||||
<MakeAllImagesCatGifs />,
|
||||
])
|
||||
.withDom(<img data-testid="fixture" src="http://example.com/dog.jpg" />)
|
||||
.renderWithEffects();
|
||||
|
||||
expect(getByTestId('fixture')).toHaveAttribute(
|
||||
'src',
|
||||
'https://example.com/cat.gif',
|
||||
);
|
||||
});
|
||||
});
|
||||
```
|
||||
@@ -96,10 +96,6 @@ Documentation generated by TechDocs is generated as static HTML sites. The
|
||||
TechDocs Reader was therefore created to be able to integrate pre-generated HTML
|
||||
sites with the Backstage UI.
|
||||
|
||||
The TechDocs Reader purpose is also to open up the opportunity to integrate
|
||||
TechDocs widgets for a customized full-featured TechDocs experience.
|
||||
([coming soon V.3](./README.md#project-roadmap))
|
||||
|
||||
[TechDocs Reader](https://github.com/backstage/backstage/blob/master/plugins/techdocs/src/reader/README.md)
|
||||
|
||||
## Transformers
|
||||
@@ -110,3 +106,19 @@ transform the HTML content on pre and post render (e.g. rewrite docs links or
|
||||
modify css).
|
||||
|
||||
[Transformers API docs](https://github.com/backstage/backstage/blob/master/plugins/techdocs/src/reader/README.md)
|
||||
|
||||
## TechDocs Addons
|
||||
|
||||
Addons (introduced in Backstage v1.2) are client-side, React-based extensions
|
||||
that can be used to augment the TechDocs experience at read-time. They offer a
|
||||
mechanism for configuring the TechDocs Reader to better suit your
|
||||
organization's needs.
|
||||
|
||||
Addons can dynamically load and display information anywhere in the TechDocs
|
||||
Reader, including within the statically generated content itself.
|
||||
|
||||
Addons should not be confused with `mkdocs` plugins, which may be used to
|
||||
customize a TechDocs site's content at build-time. While it's possible to take
|
||||
advantage of some `mkdocs` plugins, not all such plugins play well with
|
||||
TechDocs (primarily, but not exclusively, for security reasons). Addons offer
|
||||
an alternative.
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
"features/techdocs/techdocs-overview",
|
||||
"features/techdocs/getting-started",
|
||||
"features/techdocs/concepts",
|
||||
"features/techdocs/addons",
|
||||
"features/techdocs/architecture",
|
||||
"features/techdocs/creating-and-publishing",
|
||||
"features/techdocs/configuration",
|
||||
|
||||
@@ -38,6 +38,7 @@ export default async function createPlugin(
|
||||
database: env.database,
|
||||
scheduler: env.scheduler,
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
factRetrievers: [
|
||||
createFactRetrieverRegistration({
|
||||
cadence: '1 1 1 * *', // Example cron, At 01:01 on day-of-month 1.
|
||||
|
||||
@@ -71,6 +71,8 @@ export class Auth0AuthProvider implements OAuthHandlers {
|
||||
clientSecret: options.clientSecret,
|
||||
callbackURL: options.callbackUrl,
|
||||
domain: options.domain,
|
||||
// We need passReqToCallback set to false to get params, but there's
|
||||
// no matching type signature for that, so instead behold this beauty
|
||||
passReqToCallback: false as true,
|
||||
},
|
||||
(
|
||||
|
||||
@@ -94,9 +94,7 @@ export class BitbucketAuthProvider implements OAuthHandlers {
|
||||
clientID: options.clientId,
|
||||
clientSecret: options.clientSecret,
|
||||
callbackURL: options.callbackUrl,
|
||||
// We need passReqToCallback set to false to get params, but there's
|
||||
// no matching type signature for that, so instead behold this beauty
|
||||
passReqToCallback: false as true,
|
||||
passReqToCallback: false,
|
||||
},
|
||||
(
|
||||
accessToken: any,
|
||||
|
||||
@@ -73,9 +73,7 @@ export class GoogleAuthProvider implements OAuthHandlers {
|
||||
clientID: options.clientId,
|
||||
clientSecret: options.clientSecret,
|
||||
callbackURL: options.callbackUrl,
|
||||
// We need passReqToCallback set to false to get params, but there's
|
||||
// no matching type signature for that, so instead behold this beauty
|
||||
passReqToCallback: false as true,
|
||||
passReqToCallback: false,
|
||||
},
|
||||
(
|
||||
accessToken: any,
|
||||
|
||||
@@ -83,7 +83,7 @@ export class MicrosoftAuthProvider implements OAuthHandlers {
|
||||
callbackURL: options.callbackUrl,
|
||||
authorizationURL: options.authorizationUrl,
|
||||
tokenURL: options.tokenUrl,
|
||||
passReqToCallback: false as true,
|
||||
passReqToCallback: false,
|
||||
},
|
||||
(
|
||||
accessToken: any,
|
||||
|
||||
@@ -76,7 +76,7 @@ export class OAuth2AuthProvider implements OAuthHandlers {
|
||||
callbackURL: options.callbackUrl,
|
||||
authorizationURL: options.authorizationUrl,
|
||||
tokenURL: options.tokenUrl,
|
||||
passReqToCallback: false as true,
|
||||
passReqToCallback: false,
|
||||
scope: options.scope,
|
||||
customHeaders: options.includeBasicAuth
|
||||
? {
|
||||
|
||||
@@ -146,7 +146,7 @@ export class OidcAuthProvider implements OAuthHandlers {
|
||||
const strategy = new OidcStrategy(
|
||||
{
|
||||
client,
|
||||
passReqToCallback: false as true,
|
||||
passReqToCallback: false,
|
||||
},
|
||||
(
|
||||
tokenset: TokenSet,
|
||||
|
||||
@@ -94,7 +94,7 @@ export class OktaAuthProvider implements OAuthHandlers {
|
||||
clientSecret: options.clientSecret,
|
||||
callbackURL: options.callbackUrl,
|
||||
audience: options.audience,
|
||||
passReqToCallback: false as true,
|
||||
passReqToCallback: false,
|
||||
store: this.store,
|
||||
response_type: 'code',
|
||||
},
|
||||
|
||||
@@ -71,7 +71,7 @@ export class OneLoginProvider implements OAuthHandlers {
|
||||
clientID: options.clientId,
|
||||
clientSecret: options.clientSecret,
|
||||
callbackURL: options.callbackUrl,
|
||||
passReqToCallback: false as true,
|
||||
passReqToCallback: false,
|
||||
},
|
||||
(
|
||||
accessToken: any,
|
||||
|
||||
@@ -4,6 +4,58 @@ Simple plugin that proxies requests to the [Rollbar](https://rollbar.com) API.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Install the plugin using:
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
yarn add --cwd packages/backend @backstage/plugin-rollbar-backend
|
||||
```
|
||||
|
||||
2. Create a `rollbar.ts` file inside `packages/backend/src/plugins/`:
|
||||
|
||||
```typescript
|
||||
import { createRouter } from '@backstage/plugin-rollbar-backend';
|
||||
import { Router } from 'express';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
return await createRouter({
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
3. Modify your `packages/backend/src/index.ts` to include:
|
||||
|
||||
```diff
|
||||
...
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import app from './plugins/app';
|
||||
+import rollbar from './plugins/rollbar';
|
||||
import scaffolder from './plugins/scaffolder';
|
||||
|
||||
...
|
||||
|
||||
async function main() {
|
||||
|
||||
...
|
||||
|
||||
const authEnv = useHotMemoize(module, () => createEnv('auth'));
|
||||
+ const rollbarEnv = useHotMemoize(module, () => createEnv('rollbar'));
|
||||
const proxyEnv = useHotMemoize(module, () => createEnv('proxy'));
|
||||
|
||||
...
|
||||
|
||||
const apiRouter = Router();
|
||||
apiRouter.use('/catalog', await catalog(catalogEnv));
|
||||
+ apiRouter.use('/rollbar', await rollbar(rollbarEnv));
|
||||
apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv));
|
||||
```
|
||||
|
||||
The following values are read from the configuration file.
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -28,6 +28,7 @@ and modify the `techInsights.ts` file to contain a reference to the FactCheckers
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
factRetrievers: [myFactRetrieverRegistration],
|
||||
+ factCheckerFactory: myFactCheckerFactory
|
||||
});
|
||||
|
||||
@@ -35,6 +35,7 @@ export default async function createPlugin(
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
scheduler: env.scheduler,
|
||||
tokenManager: env.tokenManager,
|
||||
factRetrievers: [], // Fact retrievers registrations you want tech insights to use
|
||||
});
|
||||
|
||||
@@ -104,6 +105,7 @@ const builder = buildTechInsightsContext({
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
- factRetrievers: [],
|
||||
+ factRetrievers: [myFactRetrieverRegistration],
|
||||
});
|
||||
@@ -119,6 +121,7 @@ const builder = buildTechInsightsContext({
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
- factRetrievers: [],
|
||||
+ factRetrievers: process.env.MAIN_FACT_RETRIEVER_INSTANCE ? [myFactRetrieverRegistration] : [],
|
||||
});
|
||||
@@ -158,9 +161,12 @@ const myFactRetriever: FactRetriever = {
|
||||
const catalogClient = new CatalogClient({
|
||||
discoveryApi: discovery,
|
||||
});
|
||||
const entities = await catalogClient.getEntities({
|
||||
filter: [{ kind: 'component' }],
|
||||
});
|
||||
const entities = await catalogClient.getEntities(
|
||||
{
|
||||
filter: [{ kind: 'component' }],
|
||||
},
|
||||
{ token },
|
||||
);
|
||||
/**
|
||||
* snip: Do complex logic to retrieve facts from external system or calculate fact values
|
||||
*/
|
||||
@@ -214,6 +220,7 @@ and modify the `techInsights.ts` file to contain a reference to the FactChecker
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
factRetrievers: [myFactRetrieverRegistration],
|
||||
+ factCheckerFactory: myFactCheckerFactory
|
||||
});
|
||||
@@ -273,6 +280,7 @@ export default async function createPlugin(
|
||||
config: env.config,
|
||||
database: env.database,
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
factRetrievers: [
|
||||
createFactRetrieverRegistration({
|
||||
cadence: '0 */6 * * *', // Run every 6 hours - https://crontab.guru/#0_*/6_*_*_*
|
||||
|
||||
@@ -17,6 +17,7 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import { PluginTaskScheduler } from '@backstage/backend-tasks';
|
||||
import { TechInsightCheck } from '@backstage/plugin-tech-insights-node';
|
||||
import { TechInsightsStore } from '@backstage/plugin-tech-insights-node';
|
||||
import { TokenManager } from '@backstage/backend-common';
|
||||
|
||||
// @public
|
||||
export const buildTechInsightsContext: <
|
||||
@@ -95,6 +96,8 @@ export interface TechInsightsOptions<
|
||||
logger: Logger;
|
||||
// (undocumented)
|
||||
scheduler: PluginTaskScheduler;
|
||||
// (undocumented)
|
||||
tokenManager: TokenManager;
|
||||
}
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
@@ -22,7 +22,11 @@ import {
|
||||
} from '@backstage/plugin-tech-insights-node';
|
||||
import { FactRetrieverRegistry } from './FactRetrieverRegistry';
|
||||
import { FactRetrieverEngine } from './FactRetrieverEngine';
|
||||
import { DatabaseManager, getVoidLogger } from '@backstage/backend-common';
|
||||
import {
|
||||
DatabaseManager,
|
||||
getVoidLogger,
|
||||
ServerTokenManager,
|
||||
} from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
|
||||
import { TaskScheduler } from '@backstage/backend-tasks';
|
||||
@@ -129,6 +133,7 @@ describe('FactRetrieverEngine', () => {
|
||||
factRetrieverContext: {
|
||||
logger: getVoidLogger(),
|
||||
config: ConfigReader.fromConfigs([]),
|
||||
tokenManager: ServerTokenManager.noop(),
|
||||
discovery: {
|
||||
getBaseUrl: (_: string) => Promise.resolve('http://mock.url'),
|
||||
getExternalBaseUrl: (_: string) => Promise.resolve('http://mock.url'),
|
||||
|
||||
+2
@@ -18,6 +18,7 @@ import { RELATION_OWNED_BY } from '@backstage/catalog-model';
|
||||
import {
|
||||
PluginEndpointDiscovery,
|
||||
getVoidLogger,
|
||||
ServerTokenManager,
|
||||
} from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { GetEntitiesResponse } from '@backstage/catalog-client';
|
||||
@@ -104,6 +105,7 @@ const handlerContext = {
|
||||
discovery,
|
||||
logger: getVoidLogger(),
|
||||
config: ConfigReader.fromConfigs([]),
|
||||
tokenManager: ServerTokenManager.noop(),
|
||||
};
|
||||
|
||||
const entityFactRetriever = entityMetadataFactRetriever;
|
||||
|
||||
+10
-2
@@ -44,11 +44,19 @@ export const entityMetadataFactRetriever: FactRetriever = {
|
||||
description: 'The entity has tags in metadata',
|
||||
},
|
||||
},
|
||||
handler: async ({ discovery, entityFilter }: FactRetrieverContext) => {
|
||||
handler: async ({
|
||||
discovery,
|
||||
entityFilter,
|
||||
tokenManager,
|
||||
}: FactRetrieverContext) => {
|
||||
const { token } = await tokenManager.getToken();
|
||||
const catalogClient = new CatalogClient({
|
||||
discoveryApi: discovery,
|
||||
});
|
||||
const entities = await catalogClient.getEntities({ filter: entityFilter });
|
||||
const entities = await catalogClient.getEntities(
|
||||
{ filter: entityFilter },
|
||||
{ token },
|
||||
);
|
||||
|
||||
return entities.items.map((entity: Entity) => {
|
||||
return {
|
||||
|
||||
+2
@@ -19,6 +19,7 @@ import { RELATION_OWNED_BY } from '@backstage/catalog-model';
|
||||
import {
|
||||
PluginEndpointDiscovery,
|
||||
getVoidLogger,
|
||||
ServerTokenManager,
|
||||
} from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { GetEntitiesResponse } from '@backstage/catalog-client';
|
||||
@@ -104,6 +105,7 @@ const handlerContext = {
|
||||
discovery,
|
||||
logger: getVoidLogger(),
|
||||
config: ConfigReader.fromConfigs([]),
|
||||
tokenManager: ServerTokenManager.noop(),
|
||||
};
|
||||
|
||||
const entityFactRetriever = entityOwnershipFactRetriever;
|
||||
|
||||
+10
-2
@@ -42,11 +42,19 @@ export const entityOwnershipFactRetriever: FactRetriever = {
|
||||
description: 'The spec.owner field is set and refers to a group',
|
||||
},
|
||||
},
|
||||
handler: async ({ discovery, entityFilter }: FactRetrieverContext) => {
|
||||
handler: async ({
|
||||
discovery,
|
||||
entityFilter,
|
||||
tokenManager,
|
||||
}: FactRetrieverContext) => {
|
||||
const { token } = await tokenManager.getToken();
|
||||
const catalogClient = new CatalogClient({
|
||||
discoveryApi: discovery,
|
||||
});
|
||||
const entities = await catalogClient.getEntities({ filter: entityFilter });
|
||||
const entities = await catalogClient.getEntities(
|
||||
{ filter: entityFilter },
|
||||
{ token },
|
||||
);
|
||||
|
||||
return entities.items.map((entity: Entity) => {
|
||||
return {
|
||||
|
||||
+2
@@ -19,6 +19,7 @@ import { RELATION_OWNED_BY } from '@backstage/catalog-model';
|
||||
import {
|
||||
PluginEndpointDiscovery,
|
||||
getVoidLogger,
|
||||
ServerTokenManager,
|
||||
} from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { GetEntitiesResponse } from '@backstage/catalog-client';
|
||||
@@ -104,6 +105,7 @@ const handlerContext = {
|
||||
discovery,
|
||||
logger: getVoidLogger(),
|
||||
config: ConfigReader.fromConfigs([]),
|
||||
tokenManager: ServerTokenManager.noop(),
|
||||
};
|
||||
|
||||
const entityFactRetriever = techdocsFactRetriever;
|
||||
|
||||
+10
-2
@@ -40,11 +40,19 @@ export const techdocsFactRetriever: FactRetriever = {
|
||||
description: 'The entity has a title in metadata',
|
||||
},
|
||||
},
|
||||
handler: async ({ discovery, entityFilter }: FactRetrieverContext) => {
|
||||
handler: async ({
|
||||
discovery,
|
||||
entityFilter,
|
||||
tokenManager,
|
||||
}: FactRetrieverContext) => {
|
||||
const { token } = await tokenManager.getToken();
|
||||
const catalogClient = new CatalogClient({
|
||||
discoveryApi: discovery,
|
||||
});
|
||||
const entities = await catalogClient.getEntities({ filter: entityFilter });
|
||||
const entities = await catalogClient.getEntities(
|
||||
{ filter: entityFilter },
|
||||
{ token },
|
||||
);
|
||||
|
||||
return entities.items.map((entity: Entity) => {
|
||||
return {
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
DatabaseManager,
|
||||
getVoidLogger,
|
||||
PluginDatabaseManager,
|
||||
ServerTokenManager,
|
||||
} from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import request from 'supertest';
|
||||
@@ -74,6 +75,7 @@ describe('Tech Insights router tests', () => {
|
||||
getBaseUrl: (_: string) => Promise.resolve('http://mock.url'),
|
||||
getExternalBaseUrl: (_: string) => Promise.resolve('http://mock.url'),
|
||||
},
|
||||
tokenManager: ServerTokenManager.noop(),
|
||||
});
|
||||
|
||||
const router = await createRouter({
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Config } from '@backstage/config';
|
||||
import {
|
||||
PluginDatabaseManager,
|
||||
PluginEndpointDiscovery,
|
||||
TokenManager,
|
||||
} from '@backstage/backend-common';
|
||||
import {
|
||||
FactChecker,
|
||||
@@ -63,6 +64,7 @@ export interface TechInsightsOptions<
|
||||
discovery: PluginEndpointDiscovery;
|
||||
database: PluginDatabaseManager;
|
||||
scheduler: PluginTaskScheduler;
|
||||
tokenManager: TokenManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +106,7 @@ export const buildTechInsightsContext = async <
|
||||
database,
|
||||
logger,
|
||||
scheduler,
|
||||
tokenManager,
|
||||
} = options;
|
||||
|
||||
const factRetrieverRegistry = new FactRetrieverRegistry(factRetrievers);
|
||||
@@ -121,6 +124,7 @@ export const buildTechInsightsContext = async <
|
||||
config,
|
||||
discovery,
|
||||
logger,
|
||||
tokenManager,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Duration } from 'luxon';
|
||||
import { DurationLike } from 'luxon';
|
||||
import { Logger } from 'winston';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import { TokenManager } from '@backstage/backend-common';
|
||||
|
||||
// @public
|
||||
export type CheckValidationResponse = {
|
||||
@@ -58,6 +59,7 @@ export type FactRetrieverContext = {
|
||||
config: Config;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
logger: Logger;
|
||||
tokenManager: TokenManager;
|
||||
entityFilter?:
|
||||
| Record<string, string | symbol | (string | symbol)[]>[]
|
||||
| Record<string, string | symbol | (string | symbol)[]>;
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
import { DateTime, Duration, DurationLike } from 'luxon';
|
||||
import { Config } from '@backstage/config';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import {
|
||||
PluginEndpointDiscovery,
|
||||
TokenManager,
|
||||
} from '@backstage/backend-common';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
/**
|
||||
@@ -135,6 +138,7 @@ export type FactRetrieverContext = {
|
||||
config: Config;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
logger: Logger;
|
||||
tokenManager: TokenManager;
|
||||
entityFilter?:
|
||||
| Record<string, string | symbol | (string | symbol)[]>[]
|
||||
| Record<string, string | symbol | (string | symbol)[]>;
|
||||
|
||||
@@ -5041,9 +5041,9 @@
|
||||
integrity sha512-6k/pU2jNlgYvKOy84vpCAZ8MGVwybvAdjzrh4UicCVOCPxz0LSBws1OE6O5TO4sPHaSw+yLfNzNK8RicGFc1Kw==
|
||||
|
||||
"@react-hookz/web@^13.0.0":
|
||||
version "13.2.1"
|
||||
resolved "https://registry.npmjs.org/@react-hookz/web/-/web-13.2.1.tgz#12b3bc30d2cced8b75690c6c3708f96cfdf58172"
|
||||
integrity sha512-ckHdvZ5rgblBscvHdPWAASH46FvfOGjnC+TG3ZtzkOEaYxFtXAzxgQyjjPS+veLuVEGLZ/9HdU6A2l24QBp+9w==
|
||||
version "13.3.0"
|
||||
resolved "https://registry.npmjs.org/@react-hookz/web/-/web-13.3.0.tgz#257e31049e92a121912fe1e67bdd01dbec5a203b"
|
||||
integrity sha512-KswgkmqBVVDo6UnBFfssrojmDisogxC4jGZmd976R8YHoS3zdQJxjqICpOBSRohbRyYhYS9Cprw7BuV/CZcMaw==
|
||||
dependencies:
|
||||
"@react-hookz/deep-equal" "^1.0.1"
|
||||
|
||||
@@ -10337,9 +10337,9 @@ cypress-plugin-snapshots@^1.4.4:
|
||||
unidiff "1.0.2"
|
||||
|
||||
cypress@^9.5.0:
|
||||
version "9.5.4"
|
||||
resolved "https://registry.npmjs.org/cypress/-/cypress-9.5.4.tgz#49d9272f62eba12f2314faf29c2a865610e87550"
|
||||
integrity sha512-6AyJAD8phe7IMvOL4oBsI9puRNOWxZjl8z1lgixJMcgJ85JJmyKeP6uqNA0dI1z14lmJ7Qklf2MOgP/xdAqJ/Q==
|
||||
version "9.6.0"
|
||||
resolved "https://registry.npmjs.org/cypress/-/cypress-9.6.0.tgz#84473b3362255fa8f5e627a596e58575c9e5320f"
|
||||
integrity sha512-nNwt9eBQmSENamwa8LxvggXksfyzpyYaQ7lNBLgks3XZ6dPE/6BCQFBzeAyAPt/bNXfH3tKPkAyhiAZPYkWoEg==
|
||||
dependencies:
|
||||
"@cypress/request" "^2.88.10"
|
||||
"@cypress/xvfb" "^1.2.4"
|
||||
@@ -14421,9 +14421,9 @@ inquirer@^7.3.3:
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^8.0.0, inquirer@^8.1.1, inquirer@^8.2.0:
|
||||
version "8.2.2"
|
||||
resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.2.tgz#1310517a87a0814d25336c78a20b44c3d9b7629d"
|
||||
integrity sha512-pG7I/si6K/0X7p1qU+rfWnpTE1UIkTONN1wxtzh0d+dHXtT/JG6qBgLxoyHVsQa8cFABxAPh0pD6uUUHiAoaow==
|
||||
version "8.2.3"
|
||||
resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.3.tgz#9c0b8a3fda91fdb00590557ec8530160e908c6e7"
|
||||
integrity sha512-jmoBlmWUChXgVi1wGDZsD7pWCaibJKmL+8+E2jaiWiRj8OlJLwQdQQS2CIjgvdg8UUHX+oyagQKicVVcqwxi9Q==
|
||||
dependencies:
|
||||
ansi-escapes "^4.2.1"
|
||||
chalk "^4.1.1"
|
||||
@@ -14439,6 +14439,7 @@ inquirer@^8.0.0, inquirer@^8.1.1, inquirer@^8.2.0:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
through "^2.3.6"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
internal-slot@^1.0.3:
|
||||
version "1.0.3"
|
||||
@@ -21288,9 +21289,9 @@ react-virtualized-auto-sizer@^1.0.6:
|
||||
integrity sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ==
|
||||
|
||||
react-window@^1.8.6:
|
||||
version "1.8.6"
|
||||
resolved "https://registry.npmjs.org/react-window/-/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112"
|
||||
integrity sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg==
|
||||
version "1.8.7"
|
||||
resolved "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz#5e9fd0d23f48f432d7022cdb327219353a15f0d4"
|
||||
integrity sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0"
|
||||
memoize-one ">=3.1.1 <6"
|
||||
|
||||
Reference in New Issue
Block a user