Merge branch 'master' of github.com:backstage/backstage into blam/isomorphic-git
* 'master' of github.com:backstage/backstage: (269 commits) address comments catalog-backend: flesh out and tweak the config schema Update chilled-pigs-destroy.md catalog-backend: start warning about usage of deprecated location types scripts: add script for migrating away from deprecated location types chore: fixing changeset prettyness Create good-hairs-sniff.md Update IconLinkVertical.tsx Update violet-sloths-reply.md Delete fuzzy-windows-cry.md Create violet-sloths-reply.md Added changeset build(deps): bump archiver from 5.0.2 to 5.1.0 build(deps): bump typescript-json-schema from 0.45.0 to 0.45.1 docs: Update lighthouse docs fix(app): listen to app.listen.host scaffolder-backend: clarify type detection error message docs: Update techdocs architecture features status scaffolder-backend: gitlab preparer uses integrations token core-api: ensure that routable extension components are discovered at boot ...
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-jenkins': patch
|
||||
---
|
||||
|
||||
Avoid loading data from Jenkins twice. Don't load data when navigating through the pages as all data from all pages is already loaded.
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
'@backstage/core-api': patch
|
||||
'@backstage/dev-utils': patch
|
||||
---
|
||||
|
||||
Update ApiFactory type to correctly infer API type and disallow mismatched implementations.
|
||||
|
||||
This fixes for example the following code:
|
||||
|
||||
```ts
|
||||
interface MyApi {
|
||||
myMethod(): void
|
||||
}
|
||||
|
||||
const myApiRef = createApiRef<MyApi>({...});
|
||||
|
||||
createApiFactory({
|
||||
api: myApiRef,
|
||||
deps: {},
|
||||
// This should've caused an error, since the empty object does not fully implement MyApi
|
||||
factory: () => ({}),
|
||||
})
|
||||
```
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-sentry': minor
|
||||
'@backstage/plugin-sentry-backend': minor
|
||||
---
|
||||
|
||||
The plugin uses the `proxy-backend` instead of a custom `sentry-backend`.
|
||||
It requires a proxy configuration:
|
||||
|
||||
`app-config.yaml`:
|
||||
|
||||
```yaml
|
||||
proxy:
|
||||
'/sentry/api':
|
||||
target: https://sentry.io/api/
|
||||
allowedMethods: ['GET']
|
||||
headers:
|
||||
Authorization:
|
||||
$env: SENTRY_TOKEN # export SENTRY_TOKEN="Bearer <your-sentry-token>"
|
||||
```
|
||||
|
||||
The `MockApiBackend` is no longer configured by the `NODE_ENV` variable.
|
||||
Instead, the mock backend can be used with an api-override:
|
||||
|
||||
`packages/app/src/apis.ts`:
|
||||
|
||||
```ts
|
||||
import { createApiFactory } from '@backstage/core';
|
||||
import { MockSentryApi, sentryApiRef } from '@backstage/plugin-sentry';
|
||||
|
||||
export const apis = [
|
||||
// ...
|
||||
|
||||
createApiFactory(sentryApiRef, new MockSentryApi()),
|
||||
];
|
||||
```
|
||||
|
||||
If you already use the Sentry backend, you must remove it from the backend:
|
||||
|
||||
Delete `packages/backend/src/plugins/sentry.ts`.
|
||||
|
||||
```diff
|
||||
# packages/backend/package.json
|
||||
|
||||
...
|
||||
"@backstage/plugin-scaffolder-backend": "^0.3.2",
|
||||
- "@backstage/plugin-sentry-backend": "^0.1.3",
|
||||
"@backstage/plugin-techdocs-backend": "^0.3.0",
|
||||
...
|
||||
```
|
||||
|
||||
```diff
|
||||
// packages/backend/src/index.html
|
||||
|
||||
const apiRouter = Router();
|
||||
apiRouter.use('/catalog', await catalog(catalogEnv));
|
||||
apiRouter.use('/rollbar', await rollbar(rollbarEnv));
|
||||
apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv));
|
||||
- apiRouter.use('/sentry', await sentry(sentryEnv));
|
||||
apiRouter.use('/auth', await auth(authEnv));
|
||||
apiRouter.use('/techdocs', await techdocs(techdocsEnv));
|
||||
apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv));
|
||||
apiRouter.use('/proxy', await proxy(proxyEnv));
|
||||
apiRouter.use('/graphql', await graphql(graphqlEnv));
|
||||
apiRouter.use(notFoundHandler());
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'example-backend': patch
|
||||
---
|
||||
|
||||
use node 14 for backend Dockerfile
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-cost-insights': minor
|
||||
---
|
||||
|
||||
Add support for multiple types of entity cost breakdown.
|
||||
|
||||
This change is backwards-incompatible with plugin-cost-insights 0.3.x; the `entities` field on Entity returned in product cost queries changed from `Entity[]` to `Record<string, Entity[]`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-cost-insights': minor
|
||||
---
|
||||
|
||||
Remove calendar MoM period option and fix quarter end date logic
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Update experimental backend bundle command to only output archives to `dist/` instead of a full workspace mirror in `dist-workspace/`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fixes a big in the bundling logic that caused `node_modules` inside local monorepo packages to be transformed.
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-circleci': patch
|
||||
'@backstage/plugin-jenkins': patch
|
||||
---
|
||||
|
||||
Refactor to support ADR004 module exporting.
|
||||
|
||||
For more information, see https://backstage.io/docs/architecture-decisions/adrs-adr004.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
refreshAllLocations uses a child logger of the HigherOrderOperation with a meta `component` : `catalog-all-locations-refresh`
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-cost-insights': patch
|
||||
---
|
||||
|
||||
fix react-hooks/exhaustive-deps error
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-api': patch
|
||||
---
|
||||
|
||||
Fix for GitHub and SAML auth not properly updating session state when already logged in.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
'@backstage/plugin-github-actions': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Added Github Actions for Create React App, and allow better imports of files inside a module when they're exposed using `files` in `package.json`
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': patch
|
||||
'@backstage/plugin-pagerduty': patch
|
||||
---
|
||||
|
||||
Added pagerduty plugin to example app
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
---
|
||||
|
||||
Align plugin ID and fix variable typo
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
---
|
||||
|
||||
Add register existing component instructions
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Add `"files": ["dist"]` to both app and backend packages. This ensures that packaged versions of these packages do not contain unnecessary files.
|
||||
|
||||
To apply this change to an existing app, add the following to `packages/app/package.json` and `packages/backend/package.json`:
|
||||
|
||||
```json
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
```
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/integration': patch
|
||||
---
|
||||
|
||||
Move the core url and auth logic to integration for the four major providers
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
GitLab preparer uses the right token (primarily the same one as the publisher, falling back to the integrations token)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/integration': patch
|
||||
---
|
||||
|
||||
Add the basics of cross-integration concerns
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': minor
|
||||
---
|
||||
|
||||
Add search plugin to default template for CLI created apps
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fix config schema for `.app.listen`
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
change default size for pageSize in search result view
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-jenkins': patch
|
||||
---
|
||||
|
||||
Improve loading speed of the CI/CD page.
|
||||
Only request the necessary fields from Jenkins to keep the request size low.
|
||||
In addition everything is loaded in a single request, instead of requesting
|
||||
each job and build individually. As this (and also the previous behavior) can
|
||||
lead to a big amount of data, this limits the amount of jobs to 50.
|
||||
For each job, only the latest build is loaded. Loading the full build history
|
||||
of a job can lead to excessive load on the Jenkins instance.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
'@backstage/test-utils': patch
|
||||
'@backstage/plugin-graphiql': patch
|
||||
---
|
||||
|
||||
Update to use new plugin extension API
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
---
|
||||
|
||||
Fix React warning of descendant paragraph tag
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': minor
|
||||
---
|
||||
|
||||
Removes the Prometheus integration from `backend-common`.
|
||||
|
||||
Rational behind this change is to keep the metrics integration of Backstage
|
||||
generic. Instead of directly relying on Prometheus, Backstage will expose
|
||||
metrics in a generic way. Integrators can then export the metrics in their
|
||||
desired format. For example using Prometheus.
|
||||
|
||||
To keep the existing behavior, you need to integrate Prometheus in your
|
||||
backend:
|
||||
|
||||
First, add a dependency on `express-prom-bundle` and `prom-client` to your backend.
|
||||
|
||||
```diff
|
||||
// packages/backend/package.json
|
||||
"dependencies": {
|
||||
+ "express-prom-bundle": "^6.1.0",
|
||||
+ "prom-client": "^12.0.0",
|
||||
```
|
||||
|
||||
Then, add a handler for metrics and a simple instrumentation for the endpoints.
|
||||
|
||||
```typescript
|
||||
// packages/backend/src/metrics.ts
|
||||
import { useHotCleanup } from '@backstage/backend-common';
|
||||
import { RequestHandler } from 'express';
|
||||
import promBundle from 'express-prom-bundle';
|
||||
import prom from 'prom-client';
|
||||
import * as url from 'url';
|
||||
|
||||
const rootRegEx = new RegExp('^/([^/]*)/.*');
|
||||
const apiRegEx = new RegExp('^/api/([^/]*)/.*');
|
||||
|
||||
export function normalizePath(req: any): string {
|
||||
const path = url.parse(req.originalUrl || req.url).pathname || '/';
|
||||
|
||||
// Capture /api/ and the plugin name
|
||||
if (apiRegEx.test(path)) {
|
||||
return path.replace(apiRegEx, '/api/$1');
|
||||
}
|
||||
|
||||
// Only the first path segment at root level
|
||||
return path.replace(rootRegEx, '/$1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a /metrics endpoint, register default runtime metrics and instrument the router.
|
||||
*/
|
||||
export function metricsHandler(): RequestHandler {
|
||||
// We can only initialize the metrics once and have to clean them up between hot reloads
|
||||
useHotCleanup(module, () => prom.register.clear());
|
||||
|
||||
return promBundle({
|
||||
includeMethod: true,
|
||||
includePath: true,
|
||||
// Using includePath alone is problematic, as it will include path labels with high
|
||||
// cardinality (e.g. path params). Instead we would have to template them. However, this
|
||||
// is difficult, as every backend plugin might use different routes. Instead we only take
|
||||
// the first directory of the path, to have at least an idea how each plugin performs:
|
||||
normalizePath,
|
||||
promClient: { collectDefaultMetrics: {} },
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Last, extend your router configuration with the `metricsHandler`:
|
||||
|
||||
```diff
|
||||
+import { metricsHandler } from './metrics';
|
||||
|
||||
...
|
||||
|
||||
const service = createServiceBuilder(module)
|
||||
.loadConfig(config)
|
||||
.addRouter('', await healthcheck(healthcheckEnv))
|
||||
+ .addRouter('', metricsHandler())
|
||||
.addRouter('/api', apiRouter);
|
||||
```
|
||||
|
||||
Your Prometheus metrics will be available at the `/metrics` endpoint.
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
'@backstage/core-api': patch
|
||||
---
|
||||
|
||||
Deprecated the `ConcreteRoute`, `MutableRouteRef`, `AbsoluteRouteRef` types and added a new `RouteRef` type as replacement.
|
||||
|
||||
Deprecated and disabled the `createSubRoute` method of `AbsoluteRouteRef`.
|
||||
|
||||
Add an as of yet unused `params` option to `createRouteRef`.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
'@backstage/plugin-pagerduty': patch
|
||||
---
|
||||
|
||||
Create AboutCard in core and use it in pagerduty and catalog plugin
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': minor
|
||||
---
|
||||
|
||||
Stop exposing a custom router from the `api-docs` plugin. Instead, use the
|
||||
widgets exported by the plugin to compose your custom entity pages.
|
||||
|
||||
Instead of displaying the API definitions directly in the API tab of the
|
||||
component, it now contains tables linking to the API entities. This also adds
|
||||
new widgets to display relationships (bot provides & consumes relationships)
|
||||
between components and APIs.
|
||||
|
||||
See the changelog of `create-app` for a migration guide.
|
||||
@@ -1,136 +0,0 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Adjust template to the latest changes in the `api-docs` plugin.
|
||||
|
||||
## Template Changes
|
||||
|
||||
While updating to the latest `api-docs` plugin, the following changes are
|
||||
necessary for the `create-app` template in your
|
||||
`app/src/components/catalog/EntityPage.tsx`. This adds:
|
||||
|
||||
- A custom entity page for API entities
|
||||
- Changes the API tab to include the new `ConsumedApisCard` and
|
||||
`ProvidedApisCard` that link to the API entity.
|
||||
|
||||
```diff
|
||||
import {
|
||||
+ ApiDefinitionCard,
|
||||
- Router as ApiDocsRouter,
|
||||
+ ConsumedApisCard,
|
||||
+ ProvidedApisCard,
|
||||
+ ConsumedApisCard,
|
||||
+ ConsumingComponentsCard,
|
||||
+ ProvidedApisCard,
|
||||
+ ProvidingComponentsCard
|
||||
} from '@backstage/plugin-api-docs';
|
||||
|
||||
...
|
||||
|
||||
+const ComponentApisContent = ({ entity }: { entity: Entity }) => (
|
||||
+ <Grid container spacing={3} alignItems="stretch">
|
||||
+ <Grid item md={6}>
|
||||
+ <ProvidedApisCard entity={entity} />
|
||||
+ </Grid>
|
||||
+ <Grid item md={6}>
|
||||
+ <ConsumedApisCard entity={entity} />
|
||||
+ </Grid>
|
||||
+ </Grid>
|
||||
+);
|
||||
|
||||
const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayout.Content
|
||||
path="/"
|
||||
title="Overview"
|
||||
element={<OverviewContent entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/ci-cd/*"
|
||||
title="CI/CD"
|
||||
element={<CICDSwitcher entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/api/*"
|
||||
title="API"
|
||||
- element={<ApiDocsRouter entity={entity} />}
|
||||
+ element={<ComponentApisContent entity={entity} />}
|
||||
/>
|
||||
...
|
||||
|
||||
-export const EntityPage = () => {
|
||||
- const { entity } = useEntity();
|
||||
- switch (entity?.spec?.type) {
|
||||
- case 'service':
|
||||
- return <ServiceEntityPage entity={entity} />;
|
||||
- case 'website':
|
||||
- return <WebsiteEntityPage entity={entity} />;
|
||||
- default:
|
||||
- return <DefaultEntityPage entity={entity} />;
|
||||
- }
|
||||
-};
|
||||
|
||||
+export const ComponentEntityPage = ({ entity }: { entity: Entity }) => {
|
||||
+ switch (entity?.spec?.type) {
|
||||
+ case 'service':
|
||||
+ return <ServiceEntityPage entity={entity} />;
|
||||
+ case 'website':
|
||||
+ return <WebsiteEntityPage entity={entity} />;
|
||||
+ default:
|
||||
+ return <DefaultEntityPage entity={entity} />;
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+const ApiOverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
+ <Grid container spacing={3}>
|
||||
+ <Grid item md={6}>
|
||||
+ <AboutCard entity={entity} />
|
||||
+ </Grid>
|
||||
+ <Grid container item md={12}>
|
||||
+ <Grid item md={6}>
|
||||
+ <ProvidingComponentsCard entity={entity} />
|
||||
+ </Grid>
|
||||
+ <Grid item md={6}>
|
||||
+ <ConsumingComponentsCard entity={entity} />
|
||||
+ </Grid>
|
||||
+ </Grid>
|
||||
+ </Grid>
|
||||
+);
|
||||
+
|
||||
+const ApiDefinitionContent = ({ entity }: { entity: ApiEntity }) => (
|
||||
+ <Grid container spacing={3}>
|
||||
+ <Grid item xs={12}>
|
||||
+ <ApiDefinitionCard apiEntity={entity} />
|
||||
+ </Grid>
|
||||
+ </Grid>
|
||||
+);
|
||||
+
|
||||
+const ApiEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
+ <EntityPageLayout>
|
||||
+ <EntityPageLayout.Content
|
||||
+ path="/*"
|
||||
+ title="Overview"
|
||||
+ element={<ApiOverviewContent entity={entity} />}
|
||||
+ />
|
||||
+ <EntityPageLayout.Content
|
||||
+ path="/definition/*"
|
||||
+ title="Definition"
|
||||
+ element={<ApiDefinitionContent entity={entity as ApiEntity} />}
|
||||
+ />
|
||||
+ </EntityPageLayout>
|
||||
+);
|
||||
+
|
||||
+export const EntityPage = () => {
|
||||
+ const { entity } = useEntity();
|
||||
+
|
||||
+ switch (entity?.kind?.toLowerCase()) {
|
||||
+ case 'component':
|
||||
+ return <ComponentEntityPage entity={entity} />;
|
||||
+ case 'api':
|
||||
+ return <ApiEntityPage entity={entity} />;
|
||||
+ default:
|
||||
+ return <DefaultEntityPage entity={entity} />;
|
||||
+ }
|
||||
+};
|
||||
```
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
'example-backend': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
'@backstage/plugin-techdocs-backend': patch
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Unify `dockerode` library and type dependency versions
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Start warning about usage of deprecated location types, such as `github`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-api': patch
|
||||
---
|
||||
|
||||
Introduce new plugin extension API
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
'@backstage/catalog-model': minor
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
Remove the deprecated fields `ancestors` and `descendants` from the `Group` entity.
|
||||
|
||||
See https://github.com/backstage/backstage/issues/3049 and the PRs linked from it for details.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': minor
|
||||
---
|
||||
|
||||
Removed modifyCss transformer and moved the css to injectCss transformer
|
||||
Fixed issue where some internal doc links would cause a reload of the page
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Added configuration schema for the commonly used properties
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/theme': patch
|
||||
---
|
||||
|
||||
Add a little more padding in dense tables
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
---
|
||||
|
||||
Export the `defaultConfigLoader` implementation
|
||||
@@ -2,4 +2,4 @@
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Batch the fetching of relations
|
||||
Updated the config schema
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
'@backstage/core': minor
|
||||
---
|
||||
|
||||
Introducing a new optional property within `app-config.yaml` called `auth.environment` to have configurable environment value for `auth.providers`
|
||||
|
||||
**Default Value:** 'development'
|
||||
|
||||
**Optional Values:** 'production' | 'development'
|
||||
|
||||
**Migration-steps:**
|
||||
|
||||
- To override the default value, one could simply introduce the new property `environment` within the `auth` section of the `config.yaml`
|
||||
- re-run the build to reflect the changed configs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fix for `app.listen.host` configuration not properly overriding listening host.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Clearer error message when preparer or publisher type can't be determined.
|
||||
+2
-1
@@ -8,7 +8,8 @@
|
||||
/docs/features/techdocs @backstage/techdocs-core
|
||||
/plugins/cost-insights @backstage/silver-lining
|
||||
/plugins/cloudbuild @trivago/ebarrios
|
||||
/plugins/techdocs @backstage/techdocs-core
|
||||
/plugins/search @backstage/techdocs-core
|
||||
/plugins/techdocs @backstage/techdocs-core
|
||||
/plugins/techdocs-backend @backstage/techdocs-core
|
||||
/packages/techdocs-common @backstage/techdocs-core
|
||||
/.changeset/cost-insights-* @backstage/silver-lining
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
abc
|
||||
adamdmharvey
|
||||
andrewthauer
|
||||
Apdex
|
||||
api
|
||||
@@ -23,6 +24,7 @@ changesets
|
||||
Changesets
|
||||
chanwit
|
||||
Chanwit
|
||||
ci
|
||||
cisphobia
|
||||
cissexist
|
||||
classname
|
||||
@@ -34,6 +36,7 @@ Codecov
|
||||
codehilite
|
||||
Codehilite
|
||||
codeowners
|
||||
composable
|
||||
config
|
||||
Config
|
||||
configmaps
|
||||
@@ -42,10 +45,12 @@ const
|
||||
cookiecutter
|
||||
css
|
||||
dariddler
|
||||
dataflow
|
||||
deadnaming
|
||||
destructured
|
||||
dev
|
||||
devs
|
||||
dhenneke
|
||||
discoverability
|
||||
Discoverability
|
||||
dls
|
||||
@@ -54,6 +59,8 @@ Dockerfile
|
||||
Dockerize
|
||||
dockerode
|
||||
Docusaurus
|
||||
Dominik
|
||||
dtuite
|
||||
dzolotusky
|
||||
eg
|
||||
Ek
|
||||
@@ -64,6 +71,7 @@ facto
|
||||
failover
|
||||
Figma
|
||||
Firekube
|
||||
Fiverr
|
||||
freben
|
||||
Fredrik
|
||||
github
|
||||
@@ -76,6 +84,7 @@ graphviz
|
||||
Gustavsson
|
||||
Hackathons
|
||||
haproxy
|
||||
Henneke
|
||||
heroku
|
||||
Heroku
|
||||
horizontalpodautoscalers
|
||||
@@ -137,14 +146,17 @@ Oldsberg
|
||||
onboarding
|
||||
Onboarding
|
||||
pagerduty
|
||||
parallelization
|
||||
Patrik
|
||||
Phoen
|
||||
plantuml
|
||||
Pomaceous
|
||||
postgres
|
||||
postpack
|
||||
pre
|
||||
prebaked
|
||||
preconfigured
|
||||
prepack
|
||||
Preprarer
|
||||
Prerequisities
|
||||
productional
|
||||
@@ -182,10 +194,12 @@ Serverless
|
||||
Sinon
|
||||
smartsymobls
|
||||
Snyk
|
||||
sourcemaps
|
||||
sparklines
|
||||
Spotifiers
|
||||
spotify
|
||||
Spotify
|
||||
sqlite
|
||||
squidfunk
|
||||
src
|
||||
stefanalund
|
||||
@@ -214,6 +228,9 @@ toolsets
|
||||
tooltip
|
||||
tooltips
|
||||
touchpoints
|
||||
transpiled
|
||||
transpilation
|
||||
Tuite
|
||||
ui
|
||||
untracked
|
||||
upvote
|
||||
|
||||
+18
-16
@@ -1,16 +1,18 @@
|
||||
| Organization | Contact | Description of Use |
|
||||
| -------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| [Spotify](https://www.spotify.com) | [@stefanalund](https://github.com/stefanalund) | Main interface towards all of Spotify's infrastructure and technical documentation. |
|
||||
| [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. |
|
||||
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
|
||||
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
|
||||
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
|
||||
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
|
||||
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
|
||||
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
|
||||
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
|
||||
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
|
||||
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
|
||||
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
|
||||
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
|
||||
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
|
||||
| Organization | Contact | Description of Use |
|
||||
| -------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
|
||||
| [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. |
|
||||
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
|
||||
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
|
||||
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
|
||||
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
|
||||
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
|
||||
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
|
||||
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
|
||||
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
|
||||
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
|
||||
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
|
||||
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
|
||||
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
|
||||
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
|
||||
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
|
||||
|
||||
@@ -22,3 +22,6 @@ People that have made significant contributions to the project and earned write
|
||||
|
||||
- Andrew Thauer - Wealthsimple (GitHub: [andrewthauer](https://github.com/andrewthauer))
|
||||
- Oliver Sand - SDA SE (GitHub: [Fox32](https://github.com/Fox32))
|
||||
- David Tuite - Roadie (GitHub: [dtuite](https://github.com/dtuite))
|
||||
- Adam Harvey - DXC Technology (GitHub: [adamdmharvey](https://github.com/adamdmharvey))
|
||||
- Dominik Henneke - SDA SE (GitHub: [dhenneke](https://github.com/dhenneke))
|
||||
|
||||
+7
-3
@@ -68,11 +68,15 @@ proxy:
|
||||
organization:
|
||||
name: My Company
|
||||
|
||||
# Reference documentation http://backstage.io/docs/features/techdocs/configuration
|
||||
techdocs:
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
requestUrl: http://localhost:7000/api/techdocs
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
builder: 'local' # Alternatives - 'external'
|
||||
generators:
|
||||
techdocs: 'docker'
|
||||
techdocs: 'docker' # Alternatives - 'local'
|
||||
publisher:
|
||||
type: 'local' # Alternatives - 'googleGcs'. Read documentation for using alternatives.
|
||||
|
||||
sentry:
|
||||
organization: my-company
|
||||
@@ -133,7 +137,7 @@ catalog:
|
||||
$env: GITHUB_TOKEN
|
||||
#### Example for how to add your GitHub Enterprise instance using the API:
|
||||
# - target: https://ghe.example.net
|
||||
# apiBaseUrl: https://ghe.example.net/api/v3
|
||||
# apiBaseUrl: https://ghe.example.net/api
|
||||
# token:
|
||||
# $env: GHE_TOKEN
|
||||
ldapOrg:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
ExampleComponent.tsx reference
|
||||
|
||||
```tsx
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { Typography, Grid } from '@material-ui/core';
|
||||
import {
|
||||
InfoCard,
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { useApi } from '@backstage/core-api';
|
||||
import ExampleFetchComponent from '../ExampleFetchComponent';
|
||||
|
||||
const ExampleComponent: FC<{}> = () => {
|
||||
const ExampleComponent = () => {
|
||||
const identityApi = useApi(identityApiRef);
|
||||
const userId = identityApi.getUserId();
|
||||
const profile = identityApi.getProfile();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
ExampleFetchComponent.tsx reference
|
||||
|
||||
```tsx
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import {
|
||||
@@ -57,7 +57,7 @@ type DenseTableProps = {
|
||||
viewer: Viewer;
|
||||
};
|
||||
|
||||
export const DenseTable: FC<DenseTableProps> = ({ viewer }) => {
|
||||
export const DenseTable = ({ viewer }: DenseTableProps) => {
|
||||
const columns: TableColumn[] = [
|
||||
{ title: 'Name', field: 'name' },
|
||||
{ title: 'Created', field: 'createdAt' },
|
||||
@@ -76,7 +76,7 @@ export const DenseTable: FC<DenseTableProps> = ({ viewer }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const ExampleFetchComponent: FC<{}> = () => {
|
||||
const ExampleFetchComponent = () => {
|
||||
const auth = useApi(githubAuthApiRef);
|
||||
|
||||
const { value, loading, error } = useAsync(async (): Promise<any> => {
|
||||
|
||||
+21
@@ -152,6 +152,27 @@ plugins to share dependencies between each other when possible. This contributes
|
||||
to Backstage being fast, which is an important part of the user and developer
|
||||
experience.
|
||||
|
||||
### Why are there no published Docker images or helm charts for Backstage?
|
||||
|
||||
As mentioned above, Backstage is not a packaged service that you can use out of
|
||||
the box. In order to get started with Backstage you need to use the
|
||||
`@backstage/create-app` package to create and customize your own Backstage app.
|
||||
|
||||
In order to build a Docker image from your own app, you can use the
|
||||
`yarn build-image` command which is included out of the box in the app template.
|
||||
By default this image will bundle up both the frontend and the backend into a
|
||||
single image that you can deploy using your favorite tooling.
|
||||
|
||||
There are also some examples that can help you deploy Backstage to kubernetes in
|
||||
the
|
||||
[contrib](https://github.com/backstage/backstage/tree/master/contrib/kubernetes)
|
||||
folder.
|
||||
|
||||
It is possible that example images will be provided in the future, which can be
|
||||
used to quickly try out a small subset of the functionality of Backstage, but
|
||||
these would not be able to provide much more functionality on top of what you
|
||||
can see on a demo site.
|
||||
|
||||
### Do I have to write plugins in TypeScript?
|
||||
|
||||
No, you can use JavaScript if you prefer. We want to keep the Backstage core
|
||||
|
||||
@@ -33,10 +33,10 @@ hook exported by `@backstage/core`, or the `withApis` HOC if you prefer class
|
||||
components. For example, the `ErrorApi` can be accessed like this:
|
||||
|
||||
```tsx
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { useApi, errorApiRef } from '@backstage/core';
|
||||
|
||||
export const MyComponent: FC<{}> = () => {
|
||||
export const MyComponent = () => {
|
||||
const errorApi = useApi(errorApiRef);
|
||||
|
||||
// Signal to the app that something went wrong, and display the error to the user.
|
||||
|
||||
@@ -0,0 +1,559 @@
|
||||
---
|
||||
id: commands
|
||||
title: Commands
|
||||
description: Descriptions of all commands available in the CLI.
|
||||
---
|
||||
|
||||
This page lists all commands provided by the Backstage CLI, what they're for,
|
||||
and where to use them.
|
||||
|
||||
The documentation for each command begins with specifying its scope, this
|
||||
indicates where the command should be used by selecting from the following list:
|
||||
|
||||
- `app` - A frontend app package, such as `packages/app`.
|
||||
- `backend` - A backend package, such as `packages/backend`.
|
||||
- `frontend-plugin` - A frontend plugin package.
|
||||
- `backend-plugin` - A backend plugin package.
|
||||
- `root` - The monorepo root.
|
||||
- `any` - Any kind of package, but not the repo root.
|
||||
|
||||
## help
|
||||
|
||||
This command displays a help summary or detailed help screens for each command.
|
||||
Below is a cleaned up output of `yarn backstage-cli --help`.
|
||||
|
||||
```text
|
||||
app:build Build an app for a production release
|
||||
app:diff Diff an existing app with the creation template
|
||||
app:serve Serve an app for local development
|
||||
|
||||
backend:build Build a backend plugin
|
||||
backend:build-image Bundles the package into a docker image
|
||||
backend:dev Start local development server with HMR for the backend
|
||||
|
||||
plugin:build Build a plugin
|
||||
plugin:diff Diff an existing plugin with the creation template
|
||||
plugin:serve Serves the dev/ folder of a plugin
|
||||
|
||||
build Build a package for publishing
|
||||
build-workspace Builds a temporary dist workspace from the provided packages
|
||||
lint Lint a package
|
||||
test Run tests, forwarding args to Jest, defaulting to watch mode
|
||||
clean Delete cache directories
|
||||
|
||||
create-plugin Creates a new plugin in the current repository
|
||||
remove-plugin Removes plugin in the current repository
|
||||
|
||||
config:print Print the app configuration for the current package
|
||||
config:check Validate that the given configuration loads and matches schema
|
||||
|
||||
versions:bump Bump Backstage packages to the latest versions
|
||||
versions:check Check Backstage package versioning
|
||||
|
||||
prepack Prepares a package for packaging before publishing
|
||||
postpack Restores the changes made by the prepack command
|
||||
|
||||
help [command] display help for command
|
||||
```
|
||||
|
||||
## app:build
|
||||
|
||||
Scope: `app`
|
||||
|
||||
Builds a bundle of static content from the app, which can then be served via any
|
||||
static web server such as `nginx`, or via the
|
||||
[`app-backend`](https://www.npmjs.com/package/@backstage/plugin-app-backend)
|
||||
plugin directly from a Backstage backend instance.
|
||||
|
||||
The command also reads and injects static configuration into the bundle. It is
|
||||
important to note that when deploying using your own static content hosting
|
||||
solution, this will be the final configuration used in the frontend unless you
|
||||
for example hook in configuration loading from the backend. When using the
|
||||
`nginx` based Dockerfile in this repo along with its included run script,
|
||||
`APP_CONFIG_` environment variables will be injected into the frontend, and when
|
||||
serving using the `app-backend` plugin, the configuration is completely injected
|
||||
from the backend and the configuration at the time of calling this command will
|
||||
not be used.
|
||||
|
||||
Note that even when injecting configuration at runtime, it is not possible to
|
||||
change the base path of the app. For example, if you at build time have
|
||||
`app.baseUrl` set to `http://dev-app.com/my-app`, you can change that to
|
||||
`https://prod-app.com/my-app`, but not to `https://prod-app.com`, as that would
|
||||
change the path.
|
||||
|
||||
During the build, the following variables are set:
|
||||
|
||||
```java
|
||||
process.env.NODE_ENV = 'production';
|
||||
process.env.BUILD_INFO = {
|
||||
cliVersion: '0.4.0', // The version of the CLI package
|
||||
gitVersion: 'v0.4.0-86-ge54815618', // output of `git describe --always`
|
||||
packageVersion: '1.0.5', // The version of the app package itself
|
||||
timestamp: 1678900000000, // Date.now() when the build started
|
||||
commit: 'e548156182a973ed4b459e18533afc22c85ffff8', // output of `git rev-parse HEAD`
|
||||
};
|
||||
```
|
||||
|
||||
Some CI environments do not properly report correct resource limits, potentially
|
||||
leading to errors such as `ENOMEM` during compilation. If you run into this
|
||||
issue you can limit the parallelization of the build process by setting the
|
||||
environment variable `BACKSTAGE_CLI_BUILD_PARALLEL`, which is forwarded to the
|
||||
[`terser-webpack-plugin`](https://github.com/webpack-contrib/terser-webpack-plugin#parallel).
|
||||
You can set it to `false` or `1` to completely disable parallelization, but
|
||||
usually a low value such as `2` is enough.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli app:build
|
||||
|
||||
Options:
|
||||
--stats Write bundle stats to output directory
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## app:diff
|
||||
|
||||
Scope: `app`
|
||||
|
||||
Diff an existing app with the template used in `@backstage/create-app`. This
|
||||
will verify that your app package has not diverged from the template, and can be
|
||||
useful to run after updating the version of `@backstage/cli` in your app.
|
||||
|
||||
This command is experimental and may be removed in the future.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli app:diff
|
||||
|
||||
Options:
|
||||
--check Fail if changes are required
|
||||
--yes Apply all changes
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## app:serve
|
||||
|
||||
Scope: `app`
|
||||
|
||||
Serve an app for local development. This starts up a local development server,
|
||||
using a bundling configuration that is quite similar to that of the `app:build`
|
||||
command, but with development features such as React Hot Module Replacement,
|
||||
faster sourcemaps, no minification, etc.
|
||||
|
||||
The static configuration is injected into the frontend, but it does not support
|
||||
watching, meaning that changes in for example `app-config.yaml` are not
|
||||
reflected until the serve process is restarted.
|
||||
|
||||
During the build, the following variables are set:
|
||||
|
||||
```java
|
||||
process.env.NODE_ENV = 'development';
|
||||
process.env.BUILD_INFO = { /* See app:build */ };
|
||||
```
|
||||
|
||||
The server listening configuration is controlled through the static
|
||||
configuration. The `app.baseUrl` determines the listening host and port, as well
|
||||
as whether HTTPS is used or not. It is also possible to override the listening
|
||||
host and port if needed by setting `app.listen.host` and `app.listen.port`.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli app:serve [options]
|
||||
|
||||
Options:
|
||||
--check Enable type checking and linting
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## backend:build
|
||||
|
||||
Scope: `backend`, `backend-plugin`
|
||||
|
||||
This builds a backend package for publishing and use in production. The build
|
||||
output is written to `dist/`. Be sure to list any additional file that the
|
||||
package depends on at runtime in the `"files"` field inside `package.json`, a
|
||||
common example being the `migrations` directory.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli backend:build [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## backend:build-image
|
||||
|
||||
Scope: `backend`
|
||||
|
||||
Builds a Docker image of the backend package, forwarding all unknown options to
|
||||
`docker image build`. For example:
|
||||
|
||||
```bash
|
||||
yarn backstage-cli backend:build-image --build --tag my-backend-image
|
||||
```
|
||||
|
||||
The image is built using the backend package along with all of its local package
|
||||
dependencies. It expects to find a `Dockerfile` at the root of the backend
|
||||
package, which will be used during the build.
|
||||
|
||||
The Dockerfile is **NOT** executed within the package or repo itself. Because
|
||||
the packages in the repo itself are configured for development instead of
|
||||
production use, the final Docker build happens in a separate temporary
|
||||
directory, to which the backend package and dependencies have been copied. Only
|
||||
files listed within the `"files"` field within each package's `package.json` are
|
||||
copied over, along with the root `package.json`, `yarn.lock`, and any
|
||||
`app-config.*.yaml` files.
|
||||
|
||||
During the build a `skeleton.tar` file is created and put at the repo root. This
|
||||
file contains the `package.json` of each included package, which together with
|
||||
the root `package.json` and `yarn.lock` can be used to run a cached
|
||||
`yarn install` before the full production builds of all the packages are copied
|
||||
over, providing a significant speedup if Docker build layer caching available.
|
||||
|
||||
This command is experimental and we hope to be able to replace it with one that
|
||||
is less integrated directly with Docker, and also supports multi-stage Docker
|
||||
builds. It is possible to replicate most of what this command does by manually
|
||||
building each package, and then use the `build-workspace` to create the
|
||||
temporary workspace, and finally copy over any additional files to the workspace
|
||||
and execute the Docker build within it.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli backend:build-image [options]
|
||||
|
||||
Options:
|
||||
--build Build packages before packing them into the image
|
||||
--backstage-cli-help display help for command
|
||||
```
|
||||
|
||||
## backend:dev
|
||||
|
||||
Scope: `backend`, `backend-plugin`
|
||||
|
||||
Starts a backend package in development mode, with watch mode enabled for all
|
||||
local dependencies.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli backend:dev [options]
|
||||
|
||||
Options:
|
||||
--check Enable type checking and linting
|
||||
--inspect Enable debugger
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## create-plugin
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Creates a new plugin within the repository. This command is typically wrapped up
|
||||
in the root `package.json` to be executed with `yarn create-plugin`, using
|
||||
options that are appropriate for the organization that owns the app repo. A
|
||||
recommended scope for internal packages is `@internal`.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli create-plugin [options]
|
||||
|
||||
Options:
|
||||
--backend Create plugin with the backend dependencies as default
|
||||
--scope <scope> npm scope
|
||||
--npm-registry <URL> npm registry URL
|
||||
--no-private Public npm package
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## remove-plugin
|
||||
|
||||
Scope: `root`
|
||||
|
||||
A utility to remove a plugin from a repo, essentially undoing everything that
|
||||
was done by `create-plugin`.
|
||||
|
||||
This is primarily intended as a utility for manual tests and end to end testing
|
||||
scripts.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli remove-plugin [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## plugin:build
|
||||
|
||||
Scope: `frontend-plugin`
|
||||
|
||||
Build a frontend plugin for publishing to a package registry. There is no need
|
||||
to run this command during development or even in CI unless the package is being
|
||||
published. The `app:bundle` command does not use the output for this command
|
||||
when bundling local package dependencies.
|
||||
|
||||
The output is written to a `dist/` folder. It also outputs type declarations for
|
||||
the plugin, and therefore requires `yarn tsc` to have been run first. The input
|
||||
type declarations are expected to be found within `dist-types/` at the root of
|
||||
the monorepo.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli plugin:build [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## plugin:serve
|
||||
|
||||
Scope: `frontend-plugin`
|
||||
|
||||
Serves a frontend plugin by itself for isolated development. The serve task
|
||||
itself is essentially identical to `app:serve`, but the entrypoint is instead
|
||||
set to the `dev/` folder within the plugin.
|
||||
|
||||
The `dev/` folder typically contains a small wrapper script that hooks up any
|
||||
necessary mock APIs or other things that are needed for the plugin to function.
|
||||
The `@backstage/dev-utils` package provides utilities to that end.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli plugin:serve [options]
|
||||
|
||||
Options:
|
||||
--check Enable type checking and linting
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## plugin:diff
|
||||
|
||||
Scope: `frontend-plugin`
|
||||
|
||||
Compares a frontend plugin to the `create-plugin` template, making sure that it
|
||||
hasn't diverged from the template and recommending updates when it has. A good
|
||||
practice is to run this command after updating the version of the CLI in a
|
||||
project.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli plugin:diff [options]
|
||||
|
||||
Options:
|
||||
--check Fail if changes are required
|
||||
--yes Apply all changes
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## build
|
||||
|
||||
Scope: `any`
|
||||
|
||||
Build a single package for publishing, just like the `plugin:build` and
|
||||
`backend:build` commands. This command is intended for standalone packages that
|
||||
aren't plugins, and for example support building of isomorphic packages for
|
||||
usage in both the frontend and backend.
|
||||
|
||||
For frontend packages you'll want to include `esm` output, and for backend
|
||||
packages `cjs`. Whether to include `types` depends on if you need type
|
||||
declarations for the package, and also requires `yarn tsc` to have been run
|
||||
first.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli build [options]
|
||||
|
||||
Options:
|
||||
--outputs <formats> List of formats to output [types,cjs,esm]
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## lint
|
||||
|
||||
Scope: `any`
|
||||
|
||||
Lint a package. In addition to the default `eslint` behavior, this command will
|
||||
include TypeScript files, treat warnings as errors, and default to linting the
|
||||
entire directory if no specific files are listed.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli lint [options]
|
||||
|
||||
Options:
|
||||
--format <format> Lint report output format (default: "eslint-formatter-friendly")
|
||||
--fix Attempt to automatically fix violations
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## test
|
||||
|
||||
Scope: `any`
|
||||
|
||||
Run tests, forwarding all unknown options to Jest, and defaulting to watch mode.
|
||||
When executing the tests, `process.env.NODE_ENV` will be set to `"test"`.
|
||||
|
||||
This command uses a default Jest configuration that is included in the CLI,
|
||||
which is set up with similar goals for speed, scale, and working within a
|
||||
monorepo. The configuration sets the `src` as the root directory, enforces the
|
||||
`.test.` infix for tests, and uses `src/setupTests.ts` as the test setup
|
||||
location.
|
||||
|
||||
If needed, the configuration can be extended using a `"jest"` field in
|
||||
`package.json`, both within the target package and the monorepo root, with
|
||||
configuration in the target package taking precedence. Refer to the
|
||||
[Jest configuration documentation](https://jestjs.io/docs/en/configuration) for
|
||||
a full list of configuration options.
|
||||
|
||||
In addition to the Jest configuration there's an optional `transformModules`
|
||||
option, which is an array of module names to include in transformations.
|
||||
Normally modules inside `node_modules` are not transformed, but there are cases
|
||||
were published packages are not transpiled far enough to be usable by Jest, in
|
||||
which case you need to enable transform of them.
|
||||
|
||||
Another way to override the Jest configuration is to place a `jest.config.js` or
|
||||
`jest.config.ts` file in the package root. As opposed to the `package.json` way
|
||||
of overriding config, this completely removes the base config, and so you need
|
||||
to set it up from scratch.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli test [options]
|
||||
|
||||
Options:
|
||||
--backstage-cli-help display help for command
|
||||
```
|
||||
|
||||
## config:print
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Print the static configuration, defaulting to reading `app-config.yaml` in the
|
||||
repo root, using schema collected from all local packages in the repo.
|
||||
|
||||
For example, to validate that a given configuration value is visible in the
|
||||
frontend when building the `my-app` package, you can use the following:
|
||||
|
||||
```bash
|
||||
yarn backstage-cli config:print --frontend --package my-app
|
||||
```
|
||||
|
||||
```text
|
||||
Usage: backstage-cli config:print [options]
|
||||
|
||||
Options:
|
||||
--package <name> Only load config schema that applies to the given package
|
||||
--frontend Print only the frontend configuration
|
||||
--with-secrets Include secrets in the printed configuration
|
||||
--format <format> Format to print the configuration in, either json or yaml [yaml]
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## config:check
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Validate that static configuration loads and matches schema, defaulting to
|
||||
reading `app-config.yaml` in the repo root and using schema collected from all
|
||||
local packages in the repo.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli config:check [options]
|
||||
|
||||
Options:
|
||||
--package <name> Only load config schema that applies to the given package
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## versions:bump
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Bump all `@backstage` packages to the latest versions. This checks for updates
|
||||
in the package registry, and will update entries both in `yarn.lock` and
|
||||
`package.json` files when necessary.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli versions:bump [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## versions:check
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Validate `@backstage` dependencies within the repo, making sure that there are
|
||||
no duplicates of packages that might lead to breakages. For example,
|
||||
`@backstage/core` must not be loaded in twice, so having two different versions
|
||||
of it installed will cause this command to exit with an error.
|
||||
|
||||
By supplying the `--fix` flag the command will attempt to fix any conflict that
|
||||
can be resolved by editing `yarn.lock`, but will not attempt to search for
|
||||
remote updates or modify any `package.json` files.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli versions:check [options]
|
||||
|
||||
Options:
|
||||
--fix Fix any auto-fixable versioning problems
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## prepack
|
||||
|
||||
Scope: `any`
|
||||
|
||||
This command should be added as `scripts.prepack` in all packages. It enables
|
||||
packaging- and publish-time overrides for fields inside `packages.json`.
|
||||
|
||||
The checked in version of all packages in a Backstage monorepo are tailored for
|
||||
local development, and as such `main` and similar fields inside `package.json`
|
||||
point to development source, i.e. `src/index.ts`. Using this when publishing
|
||||
would lead to a broken package, since `src/` is not included in the published
|
||||
package and we instead need to point to files in the `dist/` directory. This
|
||||
command allows for those fields to be rewritten when needed, and does so by
|
||||
copying all fields within `publishConfig` to the top-level of each
|
||||
`package.json`, skipping `access`, `registry`, and `tag`.
|
||||
|
||||
The need for this command may be removed in the future, as this exact method of
|
||||
overriding fields for publishing is already supported by some package managers.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli prepack [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## postpack
|
||||
|
||||
Scope: `any`
|
||||
|
||||
This should be added as `scripts.postpack` in all packages. It restores
|
||||
`package.json` to what it looked like before calling the `prepack` command.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli postpack [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## clean
|
||||
|
||||
Scope: `any`
|
||||
|
||||
Remove cache and output directories.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli clean [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## build-workspace
|
||||
|
||||
Scope: `any`, `root`
|
||||
|
||||
Builds a mirror of the workspace using the packaged production version of each
|
||||
package. This essentially calls `yarn pack` in each included package and unpacks
|
||||
the resulting archive in the target `workspace-dir`.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli build-workspace [options] <workspace-dir>
|
||||
```
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
id: index
|
||||
title: Overview
|
||||
description: Overview of the Backstage CLI
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Backstage provides an opinionated set of tooling for both frontend and backend
|
||||
development. It is delivered through the
|
||||
[`@backstage/cli`](https://www.npmjs.com/package/@backstage/cli) package and
|
||||
executed either directly through `yarn backstage-cli <command>` or within
|
||||
`package.json` scripts. When creating an app using
|
||||
[`@backstage/create-app`](https://www.npmjs.com/package/@backstage/create-app)
|
||||
it contains package scripts for executing the most common commands.
|
||||
|
||||
Under the hood the CLI uses [Webpack](https://webpack.js.org/) for bundling,
|
||||
[Rollup](https://rollupjs.org/) for building packages,
|
||||
[Jest](https://jestjs.io/) for testing, and [eslint](https://eslint.org/) for
|
||||
linting. It also includes custom tooling for working within Backstage apps, for
|
||||
example for keeping the app up to date and verifying static configuration.
|
||||
|
||||
For a full list of CLI commands, see the [commands](./commands.md) page.
|
||||
|
||||
## Introduction
|
||||
|
||||
A goal of Backstage is to provide a delightful developer experience in and
|
||||
around the project. Creating new apps and plugins should be simple, iteration
|
||||
speed should be fast, and the overhead of maintaining custom tooling should be
|
||||
minimal. As a part of accomplishing this goal, Backstage provides its own set of
|
||||
opinionated tooling, delivered primarily through the
|
||||
[`@backstage/cli`](https://www.npmjs.com/package/@backstage/cli) package.
|
||||
|
||||
The `@backstage/cli` package provides a single executable script,
|
||||
`backstage-cli`, which you can run directly with `yarn` or within a script in
|
||||
`package.json`. If you have a Backstage app set up, you can try out the
|
||||
following command to print the top-level help page of the CLI:
|
||||
|
||||
```text
|
||||
yarn backstage-cli --help
|
||||
```
|
||||
|
||||
If you are familiar with [`create-react-app`](https://create-react-app.dev/) you
|
||||
may recognize the pattern of bundling tooling up as a CLI, as it uses a package
|
||||
called [`react-scripts`](https://www.npmjs.com/package/react-scripts) to bring
|
||||
most of the functionality into the created project. The Backstage equivalent of
|
||||
`create-react-app` is
|
||||
[`@backstage/create-app`](https://www.npmjs.com/package/@backstage/create-app),
|
||||
and the equivalent of `react-scripts` is `@backstage/cli`. There are however a
|
||||
couple of key differences between the two. Most notably, Backstage apps are
|
||||
monorepos and the CLI is tailored for that environment. It provides tooling both
|
||||
for bundling and developing full end-user apps, but also for developing,
|
||||
building and publishing individual packages within the monorepo, as well as
|
||||
tooling that is more unique to Backstage, such as commands for working with
|
||||
static configuration.
|
||||
|
||||
## Opinionated Tooling
|
||||
|
||||
The Backstage CLI is highly opinionated in what tools are used and how they are
|
||||
configured. It is tailored for development in large TypeScript monorepos with
|
||||
hundreds of separate packages, but with the ability to have edits anywhere in
|
||||
the codebase reflected within a few seconds. The build output is also optimized
|
||||
for this setup, and aims to provide an excellent user experience with fast page
|
||||
load times in modern browsers, rather than a wide range of support.
|
||||
|
||||
While the Backstage tooling is opinionated in how to develop and build packages,
|
||||
it is also possible to use your own tooling either partially or fully. For
|
||||
example, the CLI provides a command for building a plugin package for
|
||||
publishing, but the output is a quite standard combination of transpiled
|
||||
JavaScript and TypeScript type declarations. The usage of the command from the
|
||||
CLI can therefore easily be replaced with other tools if necessary.
|
||||
|
||||
Just like `react-scripts`, the Backstage CLI does not provide many hooks for
|
||||
overriding or customizing the build process. This is to allow for evolution of
|
||||
the CLI without having to take a wide API surface into account. This allows us
|
||||
to quickly iterate and improve the tooling, as well as to more easily keep
|
||||
dependencies up to date.
|
||||
|
||||
## Opinions & Goals
|
||||
|
||||
In no particular order, this is a list of opinions and goals that guide the
|
||||
design and development of the Backstage CLI:
|
||||
|
||||
- All you need for development is `yarn start`, there should be no need to
|
||||
manually build packages or run other separate tasks.
|
||||
- Development experience comes first. The toolchain is optimized for keeping
|
||||
development smooth, rather than making it easy to for example build and
|
||||
publish packages.
|
||||
- Type checking and linting is left for text editors and Continuous Integration.
|
||||
Most text editors provide tooling for these checks, and running them a second
|
||||
time during compilation slows down iteration speed and consumes more system
|
||||
resources.
|
||||
- Backstage is run in modern browsers. We keep transpilation lightweight and
|
||||
rely on modern technologies such as HTTP/2 to optimize frontend speed.
|
||||
|
||||
## Glossary
|
||||
|
||||
- **Package** - A package in the Node.js ecosystem, often published to a package
|
||||
registry such as [NPM](https://www.npmjs.com/).
|
||||
- **Monorepo** - A project layout that consists of multiple packages within a
|
||||
single project, where packages are able to have local dependencies on each
|
||||
other. Often enabled through tooling such as [lerna](https://lerna.js.org/)
|
||||
and [yarn workspaces](https://classic.yarnpkg.com/en/docs/workspaces/)
|
||||
- **Local Package** - One of the packages within a monorepo. These package may
|
||||
or may not also be published to a package registry.
|
||||
- **Bundle** - A collection of the deployment artifacts. The output of the
|
||||
bundling process, which brings a collection of packages into a single
|
||||
collection of deployment artifacts.
|
||||
@@ -83,6 +83,12 @@ object will be available in the frontend. The full ancestry does not need to
|
||||
have correctly defined visibilities however, so it is enough to only for example
|
||||
declare the visibility of a leaf node of `type: "string"`.
|
||||
|
||||
| `visibility` | |
|
||||
| ------------ | ------------------------------------------------------------------ |
|
||||
| `frontend` | Visible in frontend and backend |
|
||||
| `backend` | (Default) Only in backend |
|
||||
| `secret` | Only in backend and may be excluded from logs for security reasons |
|
||||
|
||||
## Validation
|
||||
|
||||
Schemas can be validated using the `backstage-cli config:check` command. If you
|
||||
|
||||
@@ -444,21 +444,6 @@ Apart from being a string, the software catalog leaves the format of this field
|
||||
open to implementers to choose. Most commonly, it is set to the ID or email of a
|
||||
group of people in an organizational structure.
|
||||
|
||||
### `spec.implementsApis` [optional]
|
||||
|
||||
**NOTE**: This field was marked for deprecation on Nov 25nd, 2020. It will be
|
||||
removed entirely from the model on Dec 14th, 2020 in the repository and will not
|
||||
be present in released packages following the next release after that. Please
|
||||
update your code to not consume this field before the removal date.
|
||||
|
||||
Links APIs that are implemented by the component, e.g. `artist-api`. This field
|
||||
is optional.
|
||||
|
||||
The software catalog expects a list of one or more strings that references the
|
||||
names of other entities of the `kind` `API`.
|
||||
|
||||
This field has the same behavior as `spec.providesApis`.
|
||||
|
||||
### `spec.providesApis` [optional]
|
||||
|
||||
Links APIs that are provided by the component, e.g. `artist-api`. This field is
|
||||
@@ -723,6 +708,10 @@ metadata:
|
||||
description: The infra business unit
|
||||
spec:
|
||||
type: business-unit
|
||||
profile:
|
||||
displayName: Infrastructure
|
||||
email: infrastructure@example.com
|
||||
picture: https://example.com/groups/bu-infrastructure.jpeg
|
||||
parent: ops
|
||||
children: [backstage, other]
|
||||
```
|
||||
@@ -747,6 +736,14 @@ Some common values for this field could be:
|
||||
- `product-area`
|
||||
- `root` - as a common virtual root of the hierarchy, if desired
|
||||
|
||||
### `spec.profile` [optional]
|
||||
|
||||
Optional profile information about the group, mainly for display purposes. All
|
||||
fields of this structure are also optional. The email would be a group email of
|
||||
some form, that the group may wish to be used for contacting them. The picture
|
||||
is expected to be a URL pointing to an image that's representative of the group,
|
||||
and that a browser could fetch and render on a group page or similar.
|
||||
|
||||
### `spec.parent` [optional]
|
||||
|
||||
The immediate parent group in the hierarchy, if any. Not all groups must have a
|
||||
|
||||
@@ -96,26 +96,38 @@ Build a widget (plugin) framework so that contributors can easily contribute
|
||||
features to TechDocs - that others can use. And, also, so that we can easily
|
||||
migrate Spotify's existing TechDocs features to open source.
|
||||
|
||||
## Structure
|
||||
## Platforms Supported
|
||||
|
||||
- [Getting Started]
|
||||
- [Concepts]
|
||||
- [Creating and Publishing Documentation]
|
||||
- [FAQ]
|
||||
See [TechDocs Architecture](architecture.md) to get an overview of where these
|
||||
providers are used.
|
||||
|
||||
| Source Code Hosting Provider | Support Status |
|
||||
| ---------------------------- | -------------- |
|
||||
| GitHub | Yes ✅ |
|
||||
| GitHub Enterprise | Yes ✅ |
|
||||
| BitBucket | Yes ✅ |
|
||||
| Azure DevOps | Yes ✅ |
|
||||
| GitLab | Yes ✅ |
|
||||
| GitLab Enterprise | Yes ✅ |
|
||||
|
||||
| File Storage Provider | Support Status | Track status |
|
||||
| --------------------------------- | -------------- | ----------------------------------------------------------- |
|
||||
| Local Filesystem of Backstage app | Yes ✅ | |
|
||||
| Google Cloud Storage (GCS) | Yes ✅ | |
|
||||
| Amazon Web Services (AWS) S3 | No ❌ | [#3714](https://github.com/backstage/backstage/issues/3714) |
|
||||
| Azure Storage | No ❌ | |
|
||||
|
||||
[Reach out to us](#feedback) if you want to request more platforms.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
| Stack | Location |
|
||||
| ------------------------------------------- | -------------------------------------------------------- |
|
||||
| Frontend | [`@backstage/plugin-techdocs`][techdocs/frontend] |
|
||||
| Backend | [`@backstage/plugin-techdocs-backend`][techdocs/backend] |
|
||||
| Docker Container (for generating doc sites) | [`techdocs-container`][techdocs/container] |
|
||||
| CLI (for local development) | [`@techdocs/cli`][techdocs/cli] |
|
||||
| Stack | Location |
|
||||
| ----------------------------------------------- | -------------------------------------------------------- |
|
||||
| Frontend Plugin | [`@backstage/plugin-techdocs`][techdocs/frontend] |
|
||||
| Backend Plugin | [`@backstage/plugin-techdocs-backend`][techdocs/backend] |
|
||||
| CLI (for local development and generating docs) | [`@techdocs/cli`][techdocs/cli] |
|
||||
| Docker Container (for generating docs) | [`techdocs-container`][techdocs/container] |
|
||||
|
||||
[getting started]: getting-started.md
|
||||
[concepts]: concepts.md
|
||||
[creating and publishing documentation]: creating-and-publishing.md
|
||||
[faq]: FAQ.md 'Frequently asked questions'
|
||||
[techdocs/frontend]:
|
||||
https://github.com/backstage/backstage/blob/master/plugins/techdocs
|
||||
[techdocs/backend]:
|
||||
@@ -131,3 +143,6 @@ https://docs.google.com/forms/d/e/1FAIpQLSdn5Vn3MQhCdyYRuW8cMzZkMQF0bFxXYN168gZR
|
||||
This is to gather inputs from you (the Backstage community) which will help us
|
||||
best serve TechDocs adopters and existing users. Your inputs will shape our
|
||||
roadmap and we will share it in the open.
|
||||
|
||||
For any other general queries, reach out to us in the `#docs-like-code` channel
|
||||
of our [Discord chatroom](https://github.com/backstage/backstage#community).
|
||||
|
||||
@@ -50,8 +50,8 @@ built.
|
||||
|
||||
We assume each entity lives in a repository somewhere (GitHub, GitLab, etc.). We
|
||||
recommend using a CI/CD pipeline with the repository that has a dedicated
|
||||
step/job to build docs for TechDocs. The generated static files are then stored
|
||||
in a cloud storage solution of your choice.
|
||||
step/job to generate docs for TechDocs. The generated static files are then
|
||||
stored in a cloud storage solution of your choice.
|
||||
[Track progress here](https://github.com/backstage/backstage/issues/3096).
|
||||
|
||||
Similar to how it is done in the Basic setup, the TechDocs Reader requests
|
||||
@@ -60,10 +60,10 @@ your configured storage solution for the necessary files and returns them to
|
||||
TechDocs Reader.
|
||||
|
||||
We will provide instructions, scripts and/or templates (e.g. GitHub Actions) to
|
||||
build docs in your CI/CD system.
|
||||
generate docs in your CI/CD system.
|
||||
[Track progress here.](https://github.com/backstage/backstage/issues/3400) You
|
||||
will be able to use `techdocs-cli` to build docs and publish the generated docs
|
||||
site files to your cloud storage system.
|
||||
will be able to use `techdocs-cli` to generate docs and publish the generated
|
||||
docs site files to your cloud storage system.
|
||||
|
||||
Note about caching: We have noticed internally that some storage providers can
|
||||
be quite slow, which is why we are recommending a cache that sits between the
|
||||
@@ -120,8 +120,8 @@ docs site in real-time?**
|
||||
A: Generating the content from Markdown on the fly is not optimal (although that
|
||||
is how the basic out-of-the-box setup is implemented). Storage solutions act as
|
||||
a cache for the generated static content. TechDocs is also currently built on
|
||||
MkDocs which does not allow us to build docs per-page, so we would have to build
|
||||
all docs for a entity on every request.
|
||||
MkDocs which does not allow us to generate docs per-page, so we would have to
|
||||
build all docs for a entity on every request.
|
||||
|
||||
# Future work
|
||||
|
||||
@@ -141,13 +141,13 @@ Status of all the features mentioned above.
|
||||
**In place ✅**
|
||||
|
||||
- Basic setup with techdocs-backend file server as storage.
|
||||
- Basic setup with cloud storage solution.
|
||||
|
||||
**Work in progress 🚧**
|
||||
|
||||
- Basic setup with cloud storage solution.
|
||||
- `techdocs-cli` is able to generate docs in CI/CD environment.
|
||||
- `techdocs-cli` is able to publish docs site to any storage.
|
||||
|
||||
**Not implemented yet ❌**
|
||||
|
||||
- `techdocs-cli` is able to generate docs in CI/CD environment.
|
||||
- `techdocs-cli` is able to publish docs site to any storage.
|
||||
- `techdocs-backend` integration with Backstage access control management.
|
||||
|
||||
@@ -8,15 +8,45 @@ Spotify's docs-like-code solution in Backstage
|
||||
This page describes concepts that are introduced with Spotify's docs-like-code
|
||||
solution in Backstage.
|
||||
|
||||
### TechDocs Core Plugin
|
||||
## Generating TechDocs Steps
|
||||
|
||||
The TechDocs Core Plugin is an [MkDocs](https://www.mkdocs.org/) plugin created
|
||||
as a wrapper around multiple MkDocs plugins and Python Markdown extensions to
|
||||
standardize the configuration of MkDocs used for TechDocs.
|
||||
### TechDocs Preparer
|
||||
|
||||
[TechDocs Core](https://github.com/backstage/mkdocs-techdocs-core)
|
||||
Preparing is the first step of generating documentation for an entity. It
|
||||
fetches the source markdown files from the source code hosting provider (GitHub,
|
||||
GitLab, etc.) and passes the files to the generator for next steps.
|
||||
|
||||
### TechDocs container
|
||||
There are two kinds of preparers available -
|
||||
|
||||
1. Common Git Preparer - Uses `git clone` on any repository url.
|
||||
2. Url Reader - Uses source code hosting provider's API to download files.
|
||||
(Faster and recommended)
|
||||
|
||||
### TechDocs Generator
|
||||
|
||||
Generating is the second step after preparing the markdown source files. This
|
||||
step either runs the TechDocs container (defined below) or runs `mkdocs` CLI to
|
||||
generate static HTML files and its assets.
|
||||
|
||||
### TechDocs Publisher
|
||||
|
||||
Publishing is the third and final step after preparing and generating docs.
|
||||
TechDocs Publisher uploads the generated files to a storage.
|
||||
|
||||
The `techdocs-backend` plugin currently comes with two publishers - Google Cloud
|
||||
Storage and Local Filesystem. You can configure them in your Backstage app.
|
||||
[See here](./configuration.md).
|
||||
|
||||
A TechDocs publisher is responsible for two things (two-way communication
|
||||
between `techdocs-backend` and the storage)
|
||||
|
||||
1. Publish generated static files to a storage (Configured by
|
||||
`techdocs.builder`)
|
||||
2. Read files from the storage when users visit a TechDocs site
|
||||
|
||||
[TechDocs Backend](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend)
|
||||
|
||||
## TechDocs Container
|
||||
|
||||
The TechDocs container is a Docker container available at
|
||||
[DockerHub](https://hub.docker.com/r/spotify/techdocs). It builds static HTML
|
||||
@@ -25,16 +55,15 @@ MkDocs.
|
||||
|
||||
[TechDocs Container](https://github.com/backstage/techdocs-container)
|
||||
|
||||
### TechDocs publisher
|
||||
## TechDocs Core Plugin
|
||||
|
||||
The `techdocs-backend` plugin currently comes with one publisher -
|
||||
`LocalPublish`.
|
||||
The TechDocs Core Plugin is an [MkDocs](https://www.mkdocs.org/) plugin created
|
||||
as a wrapper around multiple MkDocs plugins and Python Markdown extensions to
|
||||
standardize the configuration of MkDocs used for TechDocs.
|
||||
|
||||
[TechDocs Backend](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend)
|
||||
[TechDocs Core](https://github.com/backstage/mkdocs-techdocs-core)
|
||||
|
||||
More standalone publishers will come in the near future...
|
||||
|
||||
### TechDocs CLI
|
||||
## TechDocs CLI
|
||||
|
||||
The TechDocs CLI was created to make it easy to write, generate and preview
|
||||
documentation for publishing. Currently it mostly acts as a wrapper around the
|
||||
@@ -43,7 +72,7 @@ container.
|
||||
|
||||
[TechDocs CLI](https://github.com/backstage/techdocs-cli)
|
||||
|
||||
### TechDocs Reader
|
||||
## TechDocs Reader
|
||||
|
||||
Documentation generated by TechDocs is generated as static HTML sites. The
|
||||
TechDocs Reader was therefore created to be able to integrate pre-generated HTML
|
||||
@@ -55,7 +84,7 @@ TechDocs widgets for a customized full-featured TechDocs experience.
|
||||
|
||||
[TechDocs Reader](https://github.com/backstage/backstage/blob/master/plugins/techdocs/src/reader/README.md)
|
||||
|
||||
### Transformers
|
||||
## Transformers
|
||||
|
||||
Transformers are different pieces of functionality used inside the TechDocs
|
||||
Reader. The reason why transformers were introduced was to provide a way to
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
id: configuration
|
||||
title: TechDocs Configuration Options
|
||||
description:
|
||||
Reference documentation for configuring TechDocs using app-config.yaml
|
||||
---
|
||||
|
||||
Using the `app-config.yaml` in the Backstage app, you can configure TechDocs
|
||||
using several options. This page serves as a reference to all the available
|
||||
configuration options for TechDocs.
|
||||
|
||||
```yaml
|
||||
# File: app-config.yaml
|
||||
|
||||
techdocs:
|
||||
|
||||
# TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc.
|
||||
|
||||
requestUrl: http://localhost:7000/api/techdocs
|
||||
|
||||
|
||||
# Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware
|
||||
# to serve files from either a local directory or an External storage provider.
|
||||
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
|
||||
|
||||
# generators.techdocs can have two values: 'docker' or 'local'. This is to determine how to run the generator - whether to
|
||||
# spin up the techdocs-container docker image or to run mkdocs locally (assuming all the dependencies are taken care of).
|
||||
# You want to change this to 'local' if you are running Backstage using your own custom Docker setup and want to avoid running
|
||||
# into Docker in Docker situation. Read more here
|
||||
# https://backstage.io/docs/features/techdocs/getting-started#disable-docker-in-docker-situation-optional
|
||||
|
||||
generators:
|
||||
techdocs: 'docker'
|
||||
|
||||
|
||||
# techdocs.builder can be either 'local' or 'external.
|
||||
# If builder is set to 'local' and you open a TechDocs page, techdocs-backend will try to generate the docs, publish to storage
|
||||
# and show the generated docs afterwords. This is the "Basic" setup of the TechDocs Architecture.
|
||||
# If builder is set to 'external', techdocs-backend will only fetch the docs and will NOT try to generate and publish. In this case of 'external',
|
||||
# we assume that docs are being built by an external process (e.g. in the CI/CD pipeline of the repository). This is the "Recommended" setup of
|
||||
# the architecture. Read more here https://backstage.io/docs/features/techdocs/architecture
|
||||
|
||||
builder: 'local'
|
||||
|
||||
|
||||
# techdocs.publisher is used to configure the Storage option, whether you want to use the local filesystem to store generated docs
|
||||
# or you want to use External storage providers like Google Cloud Storage, AWS S3, etc.
|
||||
|
||||
publisher:
|
||||
|
||||
# techdocs.publisher.type can be - 'local' or 'googleGcs' (awsS3, azureStorage, etc. to be available as well).
|
||||
# When set to 'local', techdocs-backend will create a 'static' directory at its root to store generated documentation files.
|
||||
# When set to 'googleGcs', techdocs-backend will use a Google Cloud Storage Bucket to store generated documentation files.
|
||||
|
||||
type: 'local'
|
||||
|
||||
|
||||
# Required when techdocs.publisher.type is set to 'googleGcs'. Skip otherwise.
|
||||
|
||||
googleGcs:
|
||||
# An API key is required to write to a storage bucket.
|
||||
credentials:
|
||||
$file: '/path/to/google_application_credentials.json',
|
||||
|
||||
# Your GCP Project ID where the Cloud Storage Bucket is hosted.
|
||||
projectId: 'gcp-project-id'
|
||||
|
||||
# Cloud Storage Bucket Name
|
||||
bucketName: 'techdocs-storage',
|
||||
|
||||
```
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: getting-started
|
||||
title: Getting Started
|
||||
description: Getting Started Guidelines
|
||||
description: Getting Started Documentation
|
||||
---
|
||||
|
||||
TechDocs functions as a plugin to Backstage, so you will need to use Backstage
|
||||
@@ -10,50 +10,156 @@ to use TechDocs.
|
||||
If you haven't setup Backstage already, start
|
||||
[here](../../getting-started/index.md).
|
||||
|
||||
## Installing TechDocs
|
||||
> If you used `npx @backstage/create-app`, TechDocs may already be present.
|
||||
>
|
||||
> You should skip to [`Setting the Configuration`](#setting-the-configuration)
|
||||
> below.
|
||||
|
||||
TechDocs is provided with the Backstage application by default. If you want to
|
||||
set up TechDocs manually, keep following the instructions below.
|
||||
|
||||
### Adding the package
|
||||
## Adding TechDocs frontend plugin
|
||||
|
||||
The first step is to add the TechDocs plugin to your Backstage application.
|
||||
Navigate to your new Backstage application folder:
|
||||
|
||||
```bash
|
||||
cd hello-world/
|
||||
```
|
||||
|
||||
Then navigate to your `packages/app` folder to install TechDocs:
|
||||
Navigate to your new Backstage application directory. And then to your
|
||||
`packages/app` directory, and install the `@backstage/plugin-techdocs` package.
|
||||
|
||||
```bash
|
||||
cd my-backstage-app/
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-techdocs
|
||||
```
|
||||
|
||||
After a short while, the TechDocs plugin should be successfully installed.
|
||||
Once the package has been installed, you need to import the plugin in your app.
|
||||
|
||||
Next, you need to set up some basic configuration. Enter the following command:
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
Add this to `packages/app/src/plugins.ts`:
|
||||
Add the following to `packages/app/src/plugins.ts`:
|
||||
|
||||
```typescript
|
||||
export { plugin as TechDocs } from '@backstage/plugin-techdocs';
|
||||
```
|
||||
|
||||
### Setting the configuration
|
||||
Now let us embed the TechDocs router in our main Backstage frontend router. In
|
||||
`packages/app/src/App.tsx`, import the TechDocs router and add the following to
|
||||
`AppRoutes`:
|
||||
|
||||
TechDocs allows for configuration of the docs storage URL through your
|
||||
`app-config.yaml` file. We provide two different values to be configured,
|
||||
`requestUrl` and `storageUrl`. The `requestUrl` is what the reader will request
|
||||
its data from, and `storageUrl` is where the backend can find the stored
|
||||
documentation.
|
||||
```tsx
|
||||
import { Router as DocsRouter } from '@backstage/plugin-techdocs';
|
||||
|
||||
The default storage and request URLs:
|
||||
// ...
|
||||
|
||||
const AppRoutes = () => {
|
||||
<Routes>
|
||||
// ... other plugin routes
|
||||
<Route path="/docs/*" element={<DocsRouter />} />
|
||||
</Routes>;
|
||||
};
|
||||
```
|
||||
|
||||
That's it! But now, we need the TechDocs Backend plugin for the frontend to
|
||||
work.
|
||||
|
||||
## Adding TechDocs Backend plugin
|
||||
|
||||
Navigate to `packages/backend` of your Backstage app, and install the
|
||||
`@backstage/plugin-techdocs-backend` package.
|
||||
|
||||
```bash
|
||||
cd my-backstage-app/
|
||||
cd packages/backend
|
||||
yarn add @backstage/plugin-techdocs-backend
|
||||
```
|
||||
|
||||
Create a file called `techdocs.ts` inside `packages/backend/src/plugins/` and
|
||||
add the following
|
||||
|
||||
```typescript
|
||||
import {
|
||||
createRouter,
|
||||
DirectoryPreparer,
|
||||
Preparers,
|
||||
Generators,
|
||||
TechdocsGenerator,
|
||||
CommonGitPreparer,
|
||||
UrlPreparer,
|
||||
Publisher,
|
||||
} from '@backstage/plugin-techdocs-backend';
|
||||
import { PluginEnvironment } from '../types';
|
||||
import Docker from 'dockerode';
|
||||
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
config,
|
||||
discovery,
|
||||
reader,
|
||||
}: PluginEnvironment) {
|
||||
// Preparers are responsible for fetching source files for documentation.
|
||||
const preparers = new Preparers();
|
||||
|
||||
const directoryPreparer = new DirectoryPreparer(logger);
|
||||
preparers.register('dir', directoryPreparer);
|
||||
|
||||
const commonGitPreparer = new CommonGitPreparer(logger);
|
||||
preparers.register('github', commonGitPreparer);
|
||||
preparers.register('gitlab', commonGitPreparer);
|
||||
preparers.register('azure/api', commonGitPreparer);
|
||||
|
||||
const urlPreparer = new UrlPreparer(reader, logger);
|
||||
preparers.register('url', urlPreparer);
|
||||
|
||||
// Generators are used for generating documentation sites.
|
||||
const generators = new Generators();
|
||||
const techdocsGenerator = new TechdocsGenerator(logger, config);
|
||||
generators.register('techdocs', techdocsGenerator);
|
||||
|
||||
// Publishers are used for
|
||||
// 1. Publishing generated files to storage
|
||||
// 2. Fetching files from storage and passing them to TechDocs frontend.
|
||||
const publisher = Publisher.fromConfig(config, logger, discovery);
|
||||
|
||||
// Docker client used by the generators.
|
||||
const dockerClient = new Docker();
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
generators,
|
||||
publisher,
|
||||
dockerClient,
|
||||
logger,
|
||||
config,
|
||||
discovery,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
You may need to install the `dockerode` package. But you may already have it in
|
||||
your backend since [Scaffolder plugin](../software-templates/index.md) also uses
|
||||
it.
|
||||
|
||||
See [Concepts](concepts.md) and [TechDocs Architecture](architecture.md) to
|
||||
learn more about how preparers, generators and publishers work.
|
||||
|
||||
Final step is to import the techdocs backend plugin in Backstage app backend.
|
||||
Add the following to your `packages/backend/src/index.ts`:
|
||||
|
||||
```typescript
|
||||
import techdocs from './plugins/techdocs';
|
||||
|
||||
// .... main should already be present.
|
||||
async function main() {
|
||||
// ... other backend plugin envs
|
||||
const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs'));
|
||||
|
||||
// ... other backend plugin routes
|
||||
apiRouter.use('/techdocs', await techdocs(techdocsEnv));
|
||||
}
|
||||
```
|
||||
|
||||
That's it! TechDocs frontend and backend have now been added to your Backstage
|
||||
app. Now let us tweak some configurations to suit your needs.
|
||||
|
||||
## Setting the configuration
|
||||
|
||||
**See [TechDocs Configuration Options](configuration.md) for complete
|
||||
configuration reference.**
|
||||
|
||||
### Setting TechDocs URLs
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
@@ -61,22 +167,59 @@ techdocs:
|
||||
requestUrl: http://localhost:7000/api/techdocs/
|
||||
```
|
||||
|
||||
If you want `techdocs-backend` to manage building and publishing, you want
|
||||
`requestUrl` to point to the default value (or wherever `techdocs-backend` is
|
||||
hosted). `storageUrl` should be where your publisher publishes your docs. Using
|
||||
the default `LocalPublish` that is the default value.
|
||||
`requestUrl` is used by TechDocs frontend plugin to discover techdocs-backend
|
||||
endpoints, and the `storageUrl` is another endpoint in `techdocs-backend` which
|
||||
acts as a middleware between TechDocs and the storage (where the static
|
||||
generated docs site are stored). These default values should mostly work for
|
||||
you. These options will soon be optional to set.
|
||||
|
||||
If you have a setup where you are not using `techdocs-backend` for managing
|
||||
building and publishing of your documentation, you want to change the
|
||||
`requestUrl` to point to your storage. In this case `storageUrl` is not
|
||||
required.
|
||||
### Should TechDocs Backend generate docs?
|
||||
|
||||
### Disable Docker in Docker situation (Optional)
|
||||
```yaml
|
||||
techdocs:
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
requestUrl: http://localhost:7000/api/techdocs/
|
||||
builder: 'local'
|
||||
```
|
||||
|
||||
The TechDocs backend plugin runs a docker container with mkdocs installed to
|
||||
Set `techdocs.builder` to `'local'` if you want your TechDocs Backend to be
|
||||
responsible for generating documentation sites. If set to `'external'`,
|
||||
Backstage will assume that the sites are being generated on each entity's CI/CD
|
||||
pipeline, and are being stored in a storage somewhere.
|
||||
|
||||
When `techdocs.builder` is set to `'external'`, TechDocs becomes more or less a
|
||||
read-only experience where it serves static files from a storage containing all
|
||||
the generated documentation. Read more in the "Basic" and "Recommended" setup of
|
||||
TechDocs [here](architecture.md)
|
||||
|
||||
### Choosing storage (publisher)
|
||||
|
||||
TechDocs needs to know where to store generated documentation sites and where to
|
||||
fetch the sites from. This is managed by a
|
||||
[Publisher](./concepts.md#techdocs-publisher). Examples: Google Cloud Storage,
|
||||
Amazon S3, or local filesystem of Backstage server.
|
||||
|
||||
It is okay to use the local filesystem in a "Basic" setup when you are trying
|
||||
out Backstage for the first time. Using Cloud Storage is documented
|
||||
[here](./using-cloud-storage.md).
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
requestUrl: http://localhost:7000/api/techdocs/
|
||||
builder: 'local'
|
||||
publisher:
|
||||
type: 'local'
|
||||
```
|
||||
|
||||
### Disabling Docker in Docker situation (Optional)
|
||||
|
||||
You can skip this if your `techdocs.builder` is set to `'external'`.
|
||||
|
||||
The TechDocs Backend plugin runs a docker container with mkdocs installed to
|
||||
generate the frontend of the docs from source files (Markdown). If you are
|
||||
deploying Backstage using Docker, this will mean that your Backstage Docker
|
||||
container will try to run another Docker container for TechDocs backend.
|
||||
container will try to run another Docker container for TechDocs Backend.
|
||||
|
||||
To avoid this problem, we have a configuration available. You can set a value in
|
||||
your `app-config.yaml` that tells the techdocs generator if it should run the
|
||||
@@ -108,23 +251,13 @@ the dependencies. For example, we want `Markdown` version to be
|
||||
You can also explicitly install `Markdown==3.2.2` after installing all other
|
||||
Python packages.
|
||||
|
||||
## Run Backstage locally
|
||||
## Running Backstage locally
|
||||
|
||||
Change folder to `<backstage-project-root>/packages/backend` and run the
|
||||
following command:
|
||||
Start the frontend and the backend app by
|
||||
[running backstage locally](../../getting-started/running-backstage-locally.md).
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
```
|
||||
|
||||
Open a new command line window. Change directory to your Backstage application
|
||||
root and run the following command:
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
```
|
||||
|
||||
Open your browser at [http://localhost:3000/docs/](http://localhost:3000/docs/).
|
||||
Open your browser at [http://localhost:3000/docs/](http://localhost:3000/docs/)
|
||||
to see all your documentation sites.
|
||||
|
||||
## Additional reading
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
id: using-cloud-storage
|
||||
title: Using Cloud Storage for TechDocs generated files
|
||||
description: Using Cloud Storage for TechDocs generated files
|
||||
---
|
||||
|
||||
In the [TechDocs architecture](./architecture.md) you have the option to choose
|
||||
where you want to store the Generated static files which TechDocs uses to render
|
||||
documentation. In both the "Basic" and "Recommended" setup, you can add cloud
|
||||
storage providers like Google GCS, Amazon AWS S3, etc. By default, TechDocs uses
|
||||
the local filesystem of the `techdocs-backend` plugin in the "Basic" setup. And
|
||||
in the recommended setup, having one of the cloud storage is a prerequisite.
|
||||
Read more on the TechDocs Architecture documentation page.
|
||||
|
||||
On this page you can read how to enable them.
|
||||
|
||||
## Configuring Google GCS Bucket with TechDocs
|
||||
|
||||
Follow the
|
||||
[official Google Cloud documentation](https://googleapis.dev/nodejs/storage/latest/index.html#quickstart)
|
||||
for the latest instructions on the following steps involving GCP.
|
||||
|
||||
**1. Set `techdocs.publisher.type` config in your `app-config.yaml`**
|
||||
|
||||
Set `techdocs.publisher.type` to `'googleGcs'`.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'googleGcs'
|
||||
```
|
||||
|
||||
**2. GCP (Google Cloud Platform) Project**
|
||||
|
||||
Create or choose a dedicated GCP project. Set
|
||||
`techdocs.publisher.googleGcs.projectId` to the project ID.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'googleGcs'
|
||||
googleGcs:
|
||||
projectId: 'gcp-project-id'
|
||||
```
|
||||
|
||||
**3. Service account API key**
|
||||
|
||||
Create a new Service Account and a key associated with it. In roles of the
|
||||
service account, use "Storage Admin".
|
||||
|
||||
If you want to create a custom role, make sure to include both `get` and
|
||||
`create` permissions for both "Objects" and "Buckets". See
|
||||
https://cloud.google.com/storage/docs/access-control/iam-permissions
|
||||
|
||||
A service account can have many keys. Open your newly created account's page (in
|
||||
IAM & Admin console), and create a new key. Use JSON format for the key.
|
||||
|
||||
A `<GCP-PROJECT-ID-random-uid>.json` file will be downloaded. This is the secret
|
||||
key TechDocs will use to make API calls. Make it available in your Backstage
|
||||
server and/or your local development server and set it in the app config
|
||||
`techdocs.publisher.googleGcs.credentials`.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'googleGcs'
|
||||
googleGcs:
|
||||
projectId: 'gcp-project-id'
|
||||
credentials:
|
||||
$file: '/path/to/google_application_credentials.json'
|
||||
```
|
||||
|
||||
**4. GCS Bucket**
|
||||
|
||||
Create a dedicated bucket for TechDocs sites. techdocs-backend will publish
|
||||
documentation to this bucket. TechDocs will fetch files from here to serve
|
||||
documentation in Backstage.
|
||||
|
||||
Set the name of the bucket to `techdocs.publisher.googleGcs.bucketName`.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
publisher:
|
||||
type: 'googleGcs'
|
||||
googleGcs:
|
||||
projectId: 'gcp-project-id'
|
||||
credentials:
|
||||
$file: '/path/to/google_application_credentials.json'
|
||||
bucketName: 'name-of-techdocs-storage-bucket'
|
||||
```
|
||||
|
||||
**5. That's it!**
|
||||
|
||||
Your Backstage app is now ready to use Google Cloud Storage for TechDocs, to
|
||||
store the static generated documentation files.
|
||||
+35
-39
@@ -47,55 +47,42 @@ guidelines to get started.
|
||||
|
||||
### Ongoing work 🚧
|
||||
|
||||
- **[Plugins for managing micro services end-2-end](https://github.com/backstage/backstage/milestone/14)**
|
||||
Out of the box Backstage will ship with a set of plugins (Overview, CI, API
|
||||
and Docs) that will demonstrate how a user can manage a micro service and
|
||||
follow a change all the way out in production. Completing this work will make
|
||||
it much easier to see how a plugin can be built that integrates with the
|
||||
Backstage Service Catalog.
|
||||
- **[Platform stabilization](https://github.com/backstage/backstage/milestone/19)** -
|
||||
Stabilize the core of Backstage, including its core features, so that the
|
||||
platform can be depended on for production use. After this, plugins will
|
||||
require little-to-no maintenance.
|
||||
|
||||
- **[Users and teams](https://github.com/backstage/backstage/issues/1807)**
|
||||
Ownership is a central concept in Backstage. It should be easy to import your
|
||||
existing organizational data, such as users and groups/teams, into Backstage.
|
||||
A user the logs into Backstage should see software components owned by the
|
||||
team(s) they are in.
|
||||
- **[Kubernetes plugin for service owners](https://github.com/backstage/backstage/issues/2857)** -
|
||||
Improve native support for Kubernetes, making it easier for service owners to
|
||||
see and manage their services running in K8s, regardless if that's locally, in
|
||||
AWS, GCS, Azure, or elsewhere.
|
||||
|
||||
- **[Backstage platform is stable](https://github.com/backstage/backstage/milestone/19)** -
|
||||
The platform APIs and features are stable and can be depended on for
|
||||
production use. After this plugins will require little to no maintenance.
|
||||
- **Global search** - Extend the basic search functionality currently available
|
||||
in the Backstage Service Catalog to become a global search experience.
|
||||
|
||||
* **[Improved Kubernetes plugin](https://github.com/backstage/backstage/issues/2857)** -
|
||||
Native support for Kubernetes, making it easier for developers to see and
|
||||
manage their services running in k8s.
|
||||
|
||||
- Further improvements to platform documentation. Examples include a Golden Path
|
||||
for plugin development.
|
||||
- **[Software Templates V2](https://github.com/backstage/backstage/issues/2771)** -
|
||||
Expand the templates to make the steps more composable by adding the ability
|
||||
to add more steps for custom logic, including webhooks and using authorization
|
||||
from integrations.
|
||||
|
||||
### Future work 🔮
|
||||
|
||||
- **Deploy a product demo at `demo.backstage.io`** - Deploy a typical Backstage
|
||||
deployment available publicly so that people can click around and get a feel
|
||||
for the product without having to install anything.
|
||||
- **Golden Path for Plugin Development** - Create an easy, standardized way for
|
||||
developers to build plugins that will encourage contributions and lead to a
|
||||
richer ecosystem for everyone.
|
||||
|
||||
- **[Global search](https://github.com/backstage/backstage/issues/1499)** -
|
||||
Extend the basic search available in the Backstage Service Catalog with a
|
||||
global search experience. Long term this search solution should be extensible,
|
||||
making it possible for you add custom search results.
|
||||
|
||||
- **[[TechDocs V.2] Stabilization release](https://github.com/backstage/backstage/milestone/17)** -
|
||||
Platform stability and compatibility improvements.
|
||||
|
||||
- **Additional auth providers** - Backstage should work for most (all!) auth
|
||||
solutions. Since Backstage can be used by companies regardless of what cloud
|
||||
(or on prem) you are using we are especially keen to get auth support for
|
||||
[AWS](https://github.com/backstage/backstage/issues/290),
|
||||
[Azure](https://github.com/backstage/backstage/issues/348) and others.
|
||||
|
||||
- **[Initial GraphQL API](https://github.com/backstage/backstage/milestone/13)** -
|
||||
A GraphQL API will open up the rich metadata provided by Backstage in a single
|
||||
- **[GraphQL API](https://github.com/backstage/backstage/milestone/13)** - A
|
||||
GraphQL API will open up the rich metadata provided by Backstage in a single
|
||||
query. Plugins can easily query this API as well as extend the model where
|
||||
needed.
|
||||
|
||||
- **Inter-Plugin Communication** - **[Under consideration]** Establish more
|
||||
clearly defined patterns for plugins to communicate.
|
||||
|
||||
- **Improved Access Control** - **[Under consideration]** Provide finer grained
|
||||
access controls and management for better control of the platform user
|
||||
experience.
|
||||
|
||||
### Plugins
|
||||
|
||||
Building and maintaining [plugins](https://backstage.io/plugins) is the work of
|
||||
@@ -110,8 +97,17 @@ Are you missing a plugin for your favorite tool? Please
|
||||
[suggest a new one](https://github.com/backstage/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME).
|
||||
Chances are that someone will jump in and help build it.
|
||||
|
||||
### Community Initiatives 🧑🤝🧑 (Coming soon)
|
||||
|
||||
- **Backstage Monthly Meetup** - A space for the community to come together to
|
||||
share and learn about the latest happenings in Backstage.
|
||||
|
||||
- **Backstage Hackathons** - Open to everyone in our Backstage community, a
|
||||
celebration of you, the project and building awesome things together
|
||||
|
||||
### Completed milestones ✅
|
||||
|
||||
- [Deploy a product demo at `demo.backstage.io`](https://demo.backstage.io)
|
||||
- [Kubernetes plugin - v1](https://github.com/backstage/backstage/tree/master/plugins/kubernetes)
|
||||
- [Helm charts](https://github.com/backstage/backstage/tree/master/contrib/chart/backstage)
|
||||
- [Backstage Design System 💅](https://backstage.io/blog/2020/09/30/backstage-design-system)
|
||||
|
||||
@@ -39,28 +39,28 @@ TL;DR:
|
||||
|
||||
## Packages
|
||||
|
||||
### [`example-app`](https://github.com/backstage/backstage/tree/master/packages/app/)
|
||||
### `example-app` [GitHub](https://github.com/backstage/backstage/tree/master/packages/app/)
|
||||
|
||||
This is the `packages/app` package, and it serves as an example as well as
|
||||
utility for local development in the main Backstage repo.
|
||||
|
||||
Stability: `N/A`
|
||||
|
||||
### [`example-backend`](https://github.com/backstage/backstage/tree/master/packages/backend/)
|
||||
### `example-backend` [GitHub](https://github.com/backstage/backstage/tree/master/packages/backend/)
|
||||
|
||||
This is the `packages/backend` package, and it serves as an example as well as
|
||||
utility for local development in the main Backstage repo.
|
||||
|
||||
Stability: `N/A`
|
||||
|
||||
### [`backend-common`](https://github.com/backstage/backstage/tree/master/packages/backend-common/)
|
||||
### `backend-common` [GitHub](https://github.com/backstage/backstage/tree/master/packages/backend-common/)
|
||||
|
||||
A collection of common helpers to be used by both backend plugins, and for
|
||||
constructing backend packages.
|
||||
|
||||
Stability: `1`
|
||||
|
||||
### [`catalog-client`](https://github.com/backstage/backstage/tree/master/packages/catalog-client/)
|
||||
### `catalog-client` [GitHub](https://github.com/backstage/backstage/tree/master/packages/catalog-client/)
|
||||
|
||||
An HTTP client for interacting with the catalog backend. Usable both in frontend
|
||||
and Backend.
|
||||
@@ -68,7 +68,7 @@ and Backend.
|
||||
Stability: `0`. This is a very new addition and we have some immediate changes
|
||||
planned.
|
||||
|
||||
### [`catalog-model`](https://github.com/backstage/backstage/tree/master/packages/catalog-model/)
|
||||
### `catalog-model` [GitHub](https://github.com/backstage/backstage/tree/master/packages/catalog-model/)
|
||||
|
||||
Contains the core catalog model, and utilities for working with entities. Usable
|
||||
both in frontend and Backend.
|
||||
@@ -77,7 +77,7 @@ Stability: `2`. The catalog model is evolving, but because of the broad usage we
|
||||
|
||||
want to ensure some stability.
|
||||
|
||||
### [`cli`](https://github.com/backstage/backstage/tree/master/packages/cli/)
|
||||
### `cli` [GitHub](https://github.com/backstage/backstage/tree/master/packages/cli/)
|
||||
|
||||
The main toolchain used for Backstage development. The various CLI commands and
|
||||
options passed to those commands, as well as the environment variables read by
|
||||
@@ -87,27 +87,27 @@ unless it is likely to affect external tooling.
|
||||
|
||||
Stability: `2`
|
||||
|
||||
### [`cli-common`](https://github.com/backstage/backstage/tree/master/packages/cli-common/)
|
||||
### `cli-common` [GitHub](https://github.com/backstage/backstage/tree/master/packages/cli-common/)
|
||||
|
||||
Lightweight utilities used by the various Backstage CLIs, not intended for
|
||||
external use.
|
||||
|
||||
Stability: `N/A`
|
||||
|
||||
### [`config`](https://github.com/backstage/backstage/tree/master/packages/config/)
|
||||
### `config` [GitHub](https://github.com/backstage/backstage/tree/master/packages/config/)
|
||||
|
||||
Provides the logic and interfaces for reading static configuration.
|
||||
|
||||
Stability: `2`
|
||||
|
||||
### [`config-loader`](https://github.com/backstage/backstage/tree/master/packages/config-loader/)
|
||||
### `config-loader` [GitHub](https://github.com/backstage/backstage/tree/master/packages/config-loader/)
|
||||
|
||||
Used to load in static configuration, mainly for use by the CLI and
|
||||
@backstage/backend-common.
|
||||
|
||||
Stability: `1`. Mainly intended for internal use.
|
||||
|
||||
### [`core`](https://github.com/backstage/backstage/tree/master/packages/core/)
|
||||
### `core` [GitHub](https://github.com/backstage/backstage/tree/master/packages/core/)
|
||||
|
||||
#### Section: React Components
|
||||
|
||||
@@ -147,51 +147,62 @@ ErrorApi, IdentityApi, the auth APIs, etc.
|
||||
Stability: `1`. Most changes to the core utility APIs will not lead to
|
||||
widespread breaking changes since most apps rely on the default implementations.
|
||||
|
||||
### [`core-api`](https://github.com/backstage/backstage/tree/master/packages/core-api/)
|
||||
### `core-api` [GitHub](https://github.com/backstage/backstage/tree/master/packages/core-api/)
|
||||
|
||||
The non-visual parts of @backstage/core. Everything in this packages is
|
||||
re-exported from @backstage/core, and this package should not be used directly.
|
||||
|
||||
Stability: See @backstage/core
|
||||
|
||||
### [`create-app`](https://github.com/backstage/backstage/tree/master/packages/create-app/)
|
||||
### `create-app` [GitHub](https://github.com/backstage/backstage/tree/master/packages/create-app/)
|
||||
|
||||
The CLI used to scaffold new Backstage projects.
|
||||
|
||||
Stability: `2`
|
||||
|
||||
### [`dev-utils`](https://github.com/backstage/backstage/tree/master/packages/dev-utils/)
|
||||
### `dev-utils` [GitHub](https://github.com/backstage/backstage/tree/master/packages/dev-utils/)
|
||||
|
||||
Provides utilities for developing plugins in isolation.
|
||||
|
||||
Stability: `0`. This package is largely broken and needs updates.
|
||||
|
||||
### [`docgen`](https://github.com/backstage/backstage/tree/master/packages/docgen/)
|
||||
### `docgen` [GitHub](https://github.com/backstage/backstage/tree/master/packages/docgen/)
|
||||
|
||||
Internal CLI utility for generating API Documentation.
|
||||
|
||||
Stability: `N/A`
|
||||
|
||||
### [`e2e-test`](https://github.com/backstage/backstage/tree/master/packages/e2e-test/)
|
||||
### `e2e-test` [GitHub](https://github.com/backstage/backstage/tree/master/packages/e2e-test/)
|
||||
|
||||
Internal CLI utility for running e2e tests.
|
||||
|
||||
Stability: `N/A`
|
||||
|
||||
### [`storybook`](https://github.com/backstage/backstage/tree/master/packages/storybook/)
|
||||
### `integration` [GitHub](https://github.com/backstage/backstage/tree/master/packages/integration/)
|
||||
|
||||
Provides shared utilities for managing integrations towards different types of
|
||||
third party systems. This package is currently internal and its functionality
|
||||
will likely be exposed via separate APIs in the future.
|
||||
|
||||
Some of the functionality in this package is not available elsewhere yes, so if
|
||||
it's necessary it can be used, but there will be breaking changes.
|
||||
|
||||
Stability: `0`
|
||||
|
||||
### `storybook` [GitHub](https://github.com/backstage/backstage/tree/master/packages/storybook/)
|
||||
|
||||
Internal storybook build for publishing stories to
|
||||
https://backstage.io/storybook
|
||||
|
||||
Stability: `N/A`
|
||||
|
||||
### [`test-utils`](https://github.com/backstage/backstage/tree/master/packages/test-utils/)
|
||||
### `test-utils` [GitHub](https://github.com/backstage/backstage/tree/master/packages/test-utils/)
|
||||
|
||||
Utilities for writing tests for Backstage plugins and apps.
|
||||
|
||||
Stability: `2`
|
||||
|
||||
### [`test-utils-core`](https://github.com/backstage/backstage/tree/master/packages/test-utils-core/)
|
||||
### `test-utils-core` [GitHub](https://github.com/backstage/backstage/tree/master/packages/test-utils-core/)
|
||||
|
||||
Internal testing utilities that are separated out for usage in
|
||||
@backstage/core-api. All exports are re-exported by @backstage/test-utils. This
|
||||
@@ -199,7 +210,7 @@ package should not be depended on directly.
|
||||
|
||||
Stability: See @backstage/test-utils
|
||||
|
||||
### [`theme`](https://github.com/backstage/backstage/tree/master/packages/theme/)
|
||||
### `theme` [GitHub](https://github.com/backstage/backstage/tree/master/packages/theme/)
|
||||
|
||||
The core Backstage MUI theme along with customization utilities.
|
||||
|
||||
@@ -229,21 +240,21 @@ Any plugin that is not listed below is untracked and can generally be considered
|
||||
unstable with a score of `0`. Open a Pull Request if you want your plugin to be
|
||||
added!
|
||||
|
||||
### [`api-docs`](https://github.com/backstage/backstage/tree/master/plugins/api-docs/)
|
||||
### `api-docs` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/api-docs/)
|
||||
|
||||
Components to discover and display API entities as an extension to the catalog
|
||||
plugin.
|
||||
|
||||
Stability: `0`
|
||||
|
||||
### [`app-backend`](https://github.com/backstage/backstage/tree/master/plugins/app-backend/)
|
||||
### `app-backend` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/app-backend/)
|
||||
|
||||
A backend plugin that can be used to serve the frontend app and inject
|
||||
configuration.
|
||||
|
||||
Stability: `2`
|
||||
|
||||
### [`auth-backend`](https://github.com/backstage/backstage/tree/master/plugins/auth-backend/)
|
||||
### `auth-backend` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/auth-backend/)
|
||||
|
||||
A backend plugin that implements the backend portion of the various
|
||||
authentication flows used in Backstage.
|
||||
@@ -256,7 +267,7 @@ Stability: `2`
|
||||
|
||||
Stability: `1`
|
||||
|
||||
### [`catalog`](https://github.com/backstage/backstage/tree/master/plugins/catalog/)
|
||||
### `catalog` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/catalog/)
|
||||
|
||||
The frontend plugin for the catalog, with the table and building blocks for the
|
||||
entity pages.
|
||||
@@ -264,7 +275,7 @@ entity pages.
|
||||
Stability: `1`. We're planning some work to overhaul how entity pages are
|
||||
constructed.
|
||||
|
||||
### [`catalog-backend`](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend/)
|
||||
### `catalog-backend` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend/)
|
||||
|
||||
The backend API for the catalog, also exposes the processing subsystem for
|
||||
customization of the catalog. Powers the @backstage/plugin-catalog frontend
|
||||
@@ -278,53 +289,53 @@ Stability: `1`. There are plans to remove and rework some endpoints.
|
||||
|
||||
Stability: `1`. There are plans to rework parts of the Processor interface.
|
||||
|
||||
### [`catalog-graphql`](https://github.com/backstage/backstage/tree/master/plugins/catalog-graphql/)
|
||||
### `catalog-graphql` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/catalog-graphql/)
|
||||
|
||||
Provides the catalog schema and resolvers for the graphql backend.
|
||||
|
||||
Stability: `0`. Under heavy development and subject to change.
|
||||
|
||||
### [`explore`](https://github.com/backstage/backstage/tree/master/plugins/explore/)
|
||||
### `explore` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/explore/)
|
||||
|
||||
A frontend plugin that introduces the concept of exploring internal and external
|
||||
tooling in an organization.
|
||||
|
||||
Stability: `0`. Only an example at the moment and not customizable.
|
||||
|
||||
### [`graphiql`](https://github.com/backstage/backstage/tree/master/plugins/graphiql/)
|
||||
### `graphiql` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/graphiql/)
|
||||
|
||||
Integrates GraphiQL as a tool to browse GraphQL API endpoints inside Backstage.
|
||||
|
||||
Stability: `1`
|
||||
|
||||
### [`graphql`](https://github.com/backstage/backstage/tree/master/plugins/graphql/)
|
||||
### `graphql` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/graphql/)
|
||||
|
||||
A backend plugin that provides
|
||||
|
||||
Stability: `0`. Under heavy development and subject to change.
|
||||
|
||||
### [`kubernetes`](https://github.com/backstage/backstage/tree/master/plugins/kubernetes/)
|
||||
### `kubernetes` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/kubernetes/)
|
||||
|
||||
The frontend component of the Kubernetes plugin, used to browse and visualize
|
||||
Kubernetes resources.
|
||||
|
||||
Stability: `1`.
|
||||
|
||||
### [`kubernetes-backend`](https://github.com/backstage/backstage/tree/master/plugins/kubernetes-backend/)
|
||||
### `kubernetes-backend` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/kubernetes-backend/)
|
||||
|
||||
The backend component of the Kubernetes plugin, used to fetch Kubernetes
|
||||
resources from clusters and associate them with entities in the Catalog.
|
||||
|
||||
Stability: `1`.
|
||||
|
||||
### [`proxy-backend`](https://github.com/backstage/backstage/tree/master/plugins/proxy-backend/)
|
||||
### `proxy-backend` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/proxy-backend/)
|
||||
|
||||
A backend plugin used to set up proxying to other endpoints based on static
|
||||
configuration.
|
||||
|
||||
Stability: `1`
|
||||
|
||||
### [`register-component`](https://github.com/backstage/backstage/tree/master/plugins/register-component/)
|
||||
### `register-component` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/register-component/)
|
||||
|
||||
A frontend plugin that allows the user to register entity locations in the
|
||||
catalog.
|
||||
@@ -332,14 +343,14 @@ catalog.
|
||||
Stability: `0`. This plugin is likely to be replaced by a generic entity import
|
||||
plugin instead.
|
||||
|
||||
### [`scaffolder`](https://github.com/backstage/backstage/tree/master/plugins/scaffolder/)
|
||||
### `scaffolder` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/scaffolder/)
|
||||
|
||||
The frontend scaffolder plugin where one can browse templates and initiate
|
||||
scaffolding jobs.
|
||||
|
||||
Stability: `1`
|
||||
|
||||
### [`scaffolder-backend`](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend/)
|
||||
### `scaffolder-backend` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend/)
|
||||
|
||||
The backend scaffolder plugin that provides an implementation for templates in
|
||||
the catalog.
|
||||
@@ -347,35 +358,35 @@ the catalog.
|
||||
Stability: `1`. There is planned work to rework the scaffolder in
|
||||
https://github.com/backstage/backstage/issues/2771.
|
||||
|
||||
### [`tech-radar`](https://github.com/backstage/backstage/tree/master/plugins/tech-radar/)
|
||||
### `tech-radar` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/tech-radar/)
|
||||
|
||||
Visualize the your company's official guidelines of different areas of software
|
||||
development.
|
||||
|
||||
Stability: `0`
|
||||
|
||||
### [`techdocs`](https://github.com/backstage/backstage/tree/master/plugins/techdocs/)
|
||||
### `techdocs` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/techdocs/)
|
||||
|
||||
The frontend component of the TechDocs plugin, used to browse technical
|
||||
documentation of entities.
|
||||
|
||||
Stability: `1`
|
||||
|
||||
### [`techdocs-backend`](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend/)
|
||||
### `techdocs-backend` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend/)
|
||||
|
||||
The backend component of the TechDocs plugin, used to transform and serve
|
||||
TechDocs.
|
||||
|
||||
Stability: `0`
|
||||
|
||||
### [`user-settings`](https://github.com/backstage/backstage/tree/master/plugins/user-settings/)
|
||||
### `user-settings` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/user-settings/)
|
||||
|
||||
A frontend plugin that provides a page where the user can tweak various
|
||||
settings.
|
||||
|
||||
Stability: `1`
|
||||
|
||||
### [`welcome`](https://github.com/backstage/backstage/tree/master/plugins/welcome/)
|
||||
### `welcome` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/welcome/)
|
||||
|
||||
A plugin that can be used to welcome the user to Backstage.
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ To inspect the state of a feature flag inside your plugin, you can use the
|
||||
`FeatureFlagsApi`, accessed via the `featureFlagsApiRef`. For example:
|
||||
|
||||
```tsx
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { Button } from '@material-ui/core';
|
||||
import { featureFlagsApiRef, useApi } from '@backstage/core';
|
||||
|
||||
|
||||
@@ -169,11 +169,19 @@ are separated out into their own folder, see further down.
|
||||
packages, publish them, created a new app, and the run it. CI uses this for
|
||||
e2e-tests.
|
||||
|
||||
- [`integration/`](https://github.com/backstage/backstage/tree/master/packages/integration) -
|
||||
Common functionalities of integrations like GitHub, GitLab, etc.
|
||||
|
||||
- [`storybook/`](https://github.com/backstage/backstage/tree/master/packages/storybook) -
|
||||
This folder contains only the storybook config. Stories are within the core
|
||||
package. The Backstage Storybook is found
|
||||
[here](https://backstage.io/storybook)
|
||||
|
||||
- [`techdocs-common/`](https://github.com/backstage/backstage/tree/master/packages/techdocs-common) -
|
||||
Common functionalities for TechDocs, to be shared between
|
||||
[techdocs-backend](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend)
|
||||
plugin and [techdocs-cli](https://github.com/backstage/techdocs-cli).
|
||||
|
||||
- [`test-utils-core/`](https://github.com/backstage/backstage/tree/master/packages/test-utils-core)
|
||||
|
||||
- [`test-utils/`](https://github.com/backstage/backstage/tree/master/packages/test-utils)
|
||||
|
||||
@@ -81,13 +81,13 @@ import { useApi } from '@backstage/core-api';
|
||||
_from inline:_
|
||||
|
||||
```tsx
|
||||
const ExampleComponent: FC<{}> = () => ( ... )
|
||||
const ExampleComponent = () => ( ... )
|
||||
```
|
||||
|
||||
_to block:_
|
||||
|
||||
```tsx
|
||||
const ExampleComponent: FC<{}> = () => {
|
||||
const ExampleComponent = () => {
|
||||
|
||||
return (
|
||||
...
|
||||
@@ -135,7 +135,7 @@ changes, let's start by wiping this component clean.
|
||||
1. Replace everything in the file with the following:
|
||||
|
||||
```tsx
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import {
|
||||
@@ -147,7 +147,7 @@ import {
|
||||
import { useApi } from '@backstage/core-api';
|
||||
import { graphql } from '@octokit/graphql';
|
||||
|
||||
const ExampleFetchComponent: FC<{}> = () => {
|
||||
const ExampleFetchComponent = () => {
|
||||
return <div>Nothing to see yet</div>;
|
||||
};
|
||||
|
||||
@@ -223,7 +223,7 @@ type DenseTableProps = {
|
||||
viewer: Viewer;
|
||||
};
|
||||
|
||||
export const DenseTable: FC<DenseTableProps> = ({ viewer }) => {
|
||||
export const DenseTable = ({ viewer }: DenseTableProps) => {
|
||||
const columns: TableColumn[] = [
|
||||
{ title: 'Name', field: 'name' },
|
||||
{ title: 'Created', field: 'createdAt' },
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
title: Kubernetes
|
||||
author: Spotify
|
||||
authorUrl: https://github.com/spotify
|
||||
category: Kubernetes
|
||||
description: Surfaces components in a Kubernetes container orchestration environment into the Backstage catalog.
|
||||
documentation: https://github.com/backstage/backstage/tree/master/plugins/kubernetes
|
||||
iconUrl: https://raw.githubusercontent.com/cncf/artwork/master/projects/kubernetes/icon/color/kubernetes-icon-color.png
|
||||
npmPackageName: '@backstage/plugin-kubernetes'
|
||||
tags:
|
||||
- kubernetes
|
||||
- k8s
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: PageDuty
|
||||
author: Spotify
|
||||
authorUrl: https://github.com/spotify
|
||||
category: Monitoring
|
||||
description: PagerDuty offers a simple way to identify any active incidents for an entity and the escalation policy.
|
||||
documentation: https://github.com/backstage/backstage/tree/master/plugins/pagerduty
|
||||
iconUrl: https://avatars2.githubusercontent.com/u/766800?s=200&v=4
|
||||
npmPackageName: '@backstage/plugin-pagerduty'
|
||||
tags:
|
||||
- monitoring
|
||||
- errors
|
||||
- alerting
|
||||
@@ -34,6 +34,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"CLI": ["cli/index", "cli/commands"],
|
||||
"Core Features": [
|
||||
{
|
||||
"type": "subcategory",
|
||||
@@ -74,6 +75,8 @@
|
||||
"features/techdocs/concepts",
|
||||
"features/techdocs/architecture",
|
||||
"features/techdocs/creating-and-publishing",
|
||||
"features/techdocs/configuration",
|
||||
"features/techdocs/using-cloud-storage",
|
||||
"features/techdocs/troubleshooting",
|
||||
"features/techdocs/faqs"
|
||||
]
|
||||
|
||||
@@ -48,6 +48,14 @@ h6 {
|
||||
color: $textColor;
|
||||
}
|
||||
|
||||
h2:hover .hash-link {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hash-link {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
/* body elements */
|
||||
p,
|
||||
ul,
|
||||
|
||||
@@ -54,6 +54,8 @@ nav:
|
||||
- Concepts: 'features/techdocs/concepts.md'
|
||||
- TechDocs Architecture: 'features/techdocs/architecture.md'
|
||||
- Creating and Publishing Documentation: 'features/techdocs/creating-and-publishing.md'
|
||||
- Configuration: 'features/techdocs/configuration.md'
|
||||
- Using Cloud Storage: 'features/techdocs/using-cloud-storage.md'
|
||||
- Troubleshooting: 'features/techdocs/troubleshooting.md'
|
||||
- FAQ: 'features/techdocs/FAQ.md'
|
||||
- Plugins:
|
||||
|
||||
+3
-2
@@ -24,7 +24,7 @@
|
||||
"docker-build": "yarn tsc && yarn workspace example-backend build-image",
|
||||
"create-plugin": "backstage-cli create-plugin --scope backstage --no-private",
|
||||
"remove-plugin": "backstage-cli remove-plugin",
|
||||
"release": "changeset version && yarn prettier --write '{packages,plugins}/*/{package.json,CHANGELOG.md}'",
|
||||
"release": "changeset version && yarn prettier --write '{packages,plugins}/*/{package.json,CHANGELOG.md}' && yarn install --frozen-lockfile",
|
||||
"prettier:check": "prettier --check .",
|
||||
"lerna": "lerna",
|
||||
"storybook": "yarn workspace storybook start",
|
||||
@@ -43,8 +43,9 @@
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.11.0",
|
||||
"@octokit/openapi-types": "^2.0.0",
|
||||
"@spotify/eslint-config-oss": "^1.0.1",
|
||||
"@spotify/prettier-config": "^8.0.0",
|
||||
"@spotify/prettier-config": "^9.0.0",
|
||||
"command-exists": "^1.2.9",
|
||||
"concurrently": "^5.2.0",
|
||||
"fs-extra": "^9.0.0",
|
||||
|
||||
@@ -1,5 +1,105 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c0fac6163]
|
||||
- Updated dependencies [48c305e69]
|
||||
- Updated dependencies [c911061b7]
|
||||
- Updated dependencies [ab805860a]
|
||||
- Updated dependencies [dae4f3983]
|
||||
- Updated dependencies [8ef71ed32]
|
||||
- Updated dependencies [0e6298f7e]
|
||||
- Updated dependencies [f3e75508d]
|
||||
- Updated dependencies [3b50f833d]
|
||||
- Updated dependencies [c36a01b4c]
|
||||
- Updated dependencies [c5297baeb]
|
||||
- Updated dependencies [ac3560b42]
|
||||
- Updated dependencies [962d1ad66]
|
||||
- @backstage/plugin-org@0.3.2
|
||||
- @backstage/plugin-cost-insights@0.5.2
|
||||
- @backstage/catalog-model@0.6.0
|
||||
- @backstage/plugin-techdocs@0.5.0
|
||||
- @backstage/core@0.4.1
|
||||
- @backstage/plugin-catalog-import@0.3.2
|
||||
- @backstage/plugin-pagerduty@0.2.3
|
||||
- @backstage/cli@0.4.2
|
||||
- @backstage/plugin-sentry@0.3.1
|
||||
- @backstage/plugin-api-docs@0.4.1
|
||||
- @backstage/plugin-catalog@0.2.7
|
||||
- @backstage/plugin-circleci@0.2.5
|
||||
- @backstage/plugin-cloudbuild@0.2.5
|
||||
- @backstage/plugin-github-actions@0.2.5
|
||||
- @backstage/plugin-jenkins@0.3.4
|
||||
- @backstage/plugin-kubernetes@0.3.3
|
||||
- @backstage/plugin-lighthouse@0.2.6
|
||||
- @backstage/plugin-register-component@0.2.5
|
||||
- @backstage/plugin-rollbar@0.2.7
|
||||
- @backstage/plugin-scaffolder@0.3.4
|
||||
- @backstage/plugin-search@0.2.4
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b2a07d2dc]
|
||||
- Updated dependencies [075d3dc5a]
|
||||
- Updated dependencies [e3071a0d4]
|
||||
- Updated dependencies [d6e8099ed]
|
||||
- Updated dependencies [88ef11b45]
|
||||
- Updated dependencies [06dbe707b]
|
||||
- Updated dependencies [2527628e1]
|
||||
- Updated dependencies [011708102]
|
||||
- Updated dependencies [04efbbdd2]
|
||||
- Updated dependencies [90458fed6]
|
||||
- Updated dependencies [6011b7d3e]
|
||||
- Updated dependencies [79418ddb6]
|
||||
- Updated dependencies [d2938af4c]
|
||||
- Updated dependencies [61897fb2c]
|
||||
- Updated dependencies [e1f4e24ef]
|
||||
- Updated dependencies [6a0d7a9fb]
|
||||
- Updated dependencies [0f8877168]
|
||||
- Updated dependencies [1c69d4716]
|
||||
- Updated dependencies [246799c7f]
|
||||
- Updated dependencies [83b6e0c1f]
|
||||
- Updated dependencies [87a33d2fe]
|
||||
- Updated dependencies [1665ae8bb]
|
||||
- Updated dependencies [04f26f88d]
|
||||
- Updated dependencies [ff243ce96]
|
||||
- Updated dependencies [2b71db211]
|
||||
- @backstage/plugin-jenkins@0.3.3
|
||||
- @backstage/plugin-sentry@0.3.0
|
||||
- @backstage/plugin-cost-insights@0.5.0
|
||||
- @backstage/cli@0.4.1
|
||||
- @backstage/core@0.4.0
|
||||
- @backstage/plugin-circleci@0.2.4
|
||||
- @backstage/plugin-catalog@0.2.6
|
||||
- @backstage/plugin-pagerduty@0.2.2
|
||||
- @backstage/plugin-catalog-import@0.3.1
|
||||
- @backstage/test-utils@0.1.5
|
||||
- @backstage/plugin-search@0.2.3
|
||||
- @backstage/plugin-api-docs@0.4.0
|
||||
- @backstage/catalog-model@0.5.0
|
||||
- @backstage/plugin-techdocs@0.4.0
|
||||
- @backstage/theme@0.2.2
|
||||
- @backstage/plugin-org@0.3.1
|
||||
- @backstage/plugin-cloudbuild@0.2.4
|
||||
- @backstage/plugin-explore@0.2.2
|
||||
- @backstage/plugin-gcp-projects@0.2.2
|
||||
- @backstage/plugin-github-actions@0.2.4
|
||||
- @backstage/plugin-gitops-profiles@0.2.2
|
||||
- @backstage/plugin-graphiql@0.2.2
|
||||
- @backstage/plugin-kubernetes@0.3.2
|
||||
- @backstage/plugin-lighthouse@0.2.5
|
||||
- @backstage/plugin-newrelic@0.2.2
|
||||
- @backstage/plugin-register-component@0.2.4
|
||||
- @backstage/plugin-rollbar@0.2.6
|
||||
- @backstage/plugin-scaffolder@0.3.3
|
||||
- @backstage/plugin-tech-radar@0.3.1
|
||||
- @backstage/plugin-user-settings@0.2.3
|
||||
- @backstage/plugin-welcome@0.2.3
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+32
-32
@@ -1,40 +1,40 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.7",
|
||||
"private": true,
|
||||
"bundled": true,
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.4.0",
|
||||
"@backstage/cli": "^0.4.0",
|
||||
"@backstage/core": "^0.3.2",
|
||||
"@backstage/plugin-api-docs": "^0.3.1",
|
||||
"@backstage/plugin-catalog": "^0.2.5",
|
||||
"@backstage/plugin-catalog-import": "^0.3.0",
|
||||
"@backstage/plugin-circleci": "^0.2.3",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.3",
|
||||
"@backstage/plugin-cost-insights": "^0.4.2",
|
||||
"@backstage/plugin-explore": "^0.2.1",
|
||||
"@backstage/plugin-gcp-projects": "^0.2.1",
|
||||
"@backstage/plugin-github-actions": "^0.2.3",
|
||||
"@backstage/plugin-gitops-profiles": "^0.2.1",
|
||||
"@backstage/plugin-graphiql": "^0.2.1",
|
||||
"@backstage/plugin-org": "^0.3.0",
|
||||
"@backstage/plugin-jenkins": "^0.3.2",
|
||||
"@backstage/plugin-kubernetes": "^0.3.1",
|
||||
"@backstage/plugin-lighthouse": "^0.2.4",
|
||||
"@backstage/plugin-newrelic": "^0.2.1",
|
||||
"@backstage/plugin-pagerduty": "0.2.1",
|
||||
"@backstage/plugin-register-component": "^0.2.3",
|
||||
"@backstage/plugin-rollbar": "^0.2.5",
|
||||
"@backstage/plugin-scaffolder": "^0.3.2",
|
||||
"@backstage/plugin-sentry": "^0.2.4",
|
||||
"@backstage/plugin-search": "^0.2.2",
|
||||
"@backstage/plugin-tech-radar": "^0.3.0",
|
||||
"@backstage/plugin-techdocs": "^0.3.1",
|
||||
"@backstage/plugin-user-settings": "^0.2.2",
|
||||
"@backstage/plugin-welcome": "^0.2.2",
|
||||
"@backstage/test-utils": "^0.1.4",
|
||||
"@backstage/theme": "^0.2.1",
|
||||
"@backstage/catalog-model": "^0.6.0",
|
||||
"@backstage/cli": "^0.4.2",
|
||||
"@backstage/core": "^0.4.1",
|
||||
"@backstage/plugin-api-docs": "^0.4.1",
|
||||
"@backstage/plugin-catalog": "^0.2.7",
|
||||
"@backstage/plugin-catalog-import": "^0.3.2",
|
||||
"@backstage/plugin-circleci": "^0.2.5",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.5",
|
||||
"@backstage/plugin-cost-insights": "^0.5.2",
|
||||
"@backstage/plugin-explore": "^0.2.2",
|
||||
"@backstage/plugin-gcp-projects": "^0.2.2",
|
||||
"@backstage/plugin-github-actions": "^0.2.5",
|
||||
"@backstage/plugin-gitops-profiles": "^0.2.2",
|
||||
"@backstage/plugin-graphiql": "^0.2.2",
|
||||
"@backstage/plugin-org": "^0.3.2",
|
||||
"@backstage/plugin-jenkins": "^0.3.4",
|
||||
"@backstage/plugin-kubernetes": "^0.3.3",
|
||||
"@backstage/plugin-lighthouse": "^0.2.6",
|
||||
"@backstage/plugin-newrelic": "^0.2.2",
|
||||
"@backstage/plugin-pagerduty": "0.2.3",
|
||||
"@backstage/plugin-register-component": "^0.2.5",
|
||||
"@backstage/plugin-rollbar": "^0.2.7",
|
||||
"@backstage/plugin-scaffolder": "^0.3.4",
|
||||
"@backstage/plugin-sentry": "^0.3.1",
|
||||
"@backstage/plugin-search": "^0.2.4",
|
||||
"@backstage/plugin-tech-radar": "^0.3.1",
|
||||
"@backstage/plugin-techdocs": "^0.5.0",
|
||||
"@backstage/plugin-user-settings": "^0.2.3",
|
||||
"@backstage/plugin-welcome": "^0.2.3",
|
||||
"@backstage/test-utils": "^0.1.5",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@octokit/rest": "^18.0.0",
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
SignInPage,
|
||||
createRouteRef,
|
||||
} from '@backstage/core';
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import Root from './components/Root';
|
||||
import * as plugins from './plugins';
|
||||
import { apis } from './apis';
|
||||
@@ -29,7 +29,7 @@ import { hot } from 'react-hot-loader/root';
|
||||
import { providers } from './identityProviders';
|
||||
import { Router as CatalogRouter } from '@backstage/plugin-catalog';
|
||||
import { Router as DocsRouter } from '@backstage/plugin-techdocs';
|
||||
import { Router as GraphiQLRouter } from '@backstage/plugin-graphiql';
|
||||
import { GraphiQLPage } from '@backstage/plugin-graphiql';
|
||||
import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar';
|
||||
import { Router as LighthouseRouter } from '@backstage/plugin-lighthouse';
|
||||
import { Router as RegisterComponentRouter } from '@backstage/plugin-register-component';
|
||||
@@ -81,7 +81,7 @@ const AppRoutes = () => (
|
||||
path="/tech-radar"
|
||||
element={<TechRadarRouter width={1500} height={800} />}
|
||||
/>
|
||||
<Route path="/graphiql" element={<GraphiQLRouter />} />
|
||||
<Route path="/graphiql" element={<GraphiQLPage />} />
|
||||
<Route path="/lighthouse/*" element={<LighthouseRouter />} />
|
||||
<Route
|
||||
path="/register-component"
|
||||
@@ -92,7 +92,7 @@ const AppRoutes = () => (
|
||||
</Routes>
|
||||
);
|
||||
|
||||
const App: FC<{}> = () => (
|
||||
const App = () => (
|
||||
<AppProvider>
|
||||
<AlertDisplay />
|
||||
<OAuthRequestDialog />
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
@@ -26,7 +26,7 @@ const useStyles = makeStyles({
|
||||
fill: '#7df3e1',
|
||||
},
|
||||
});
|
||||
const LogoFull: FC<{}> = () => {
|
||||
const LogoFull = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
@@ -27,7 +27,7 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
const LogoIcon: FC<{}> = () => {
|
||||
const LogoIcon = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { FC, useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useContext, PropsWithChildren } from 'react';
|
||||
import { Link, makeStyles } from '@material-ui/core';
|
||||
import HomeIcon from '@material-ui/icons/Home';
|
||||
import ExtensionIcon from '@material-ui/icons/Extension';
|
||||
@@ -55,7 +54,7 @@ const useSidebarLogoStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
const SidebarLogo: FC<{}> = () => {
|
||||
const SidebarLogo = () => {
|
||||
const classes = useSidebarLogoStyles();
|
||||
const { isOpen } = useContext(SidebarContext);
|
||||
|
||||
@@ -73,7 +72,7 @@ const SidebarLogo: FC<{}> = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const Root: FC<{}> = ({ children }) => (
|
||||
const Root = ({ children }: PropsWithChildren<{}>) => (
|
||||
<SidebarPage>
|
||||
<Sidebar>
|
||||
<SidebarLogo />
|
||||
@@ -102,8 +101,4 @@ const Root: FC<{}> = ({ children }) => (
|
||||
</SidebarPage>
|
||||
);
|
||||
|
||||
Root.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export default Root;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line monorepo/no-internal-import
|
||||
import '@backstage/cli/asset-types';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
@@ -1,5 +1,110 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1d1c2860f: Implement readTree on BitBucketUrlReader and getBitbucketDownloadUrl
|
||||
- 4eafdec4a: Introduce readTree method for GitLab URL Reader
|
||||
- Updated dependencies [1d1c2860f]
|
||||
- Updated dependencies [4eafdec4a]
|
||||
- Updated dependencies [178e09323]
|
||||
- @backstage/integration@0.1.4
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 12bbd748c: Removes the Prometheus integration from `backend-common`.
|
||||
|
||||
Rational behind this change is to keep the metrics integration of Backstage
|
||||
generic. Instead of directly relying on Prometheus, Backstage will expose
|
||||
metrics in a generic way. Integrators can then export the metrics in their
|
||||
desired format. For example using Prometheus.
|
||||
|
||||
To keep the existing behavior, you need to integrate Prometheus in your
|
||||
backend:
|
||||
|
||||
First, add a dependency on `express-prom-bundle` and `prom-client` to your backend.
|
||||
|
||||
```diff
|
||||
// packages/backend/package.json
|
||||
"dependencies": {
|
||||
+ "express-prom-bundle": "^6.1.0",
|
||||
+ "prom-client": "^12.0.0",
|
||||
```
|
||||
|
||||
Then, add a handler for metrics and a simple instrumentation for the endpoints.
|
||||
|
||||
```typescript
|
||||
// packages/backend/src/metrics.ts
|
||||
import { useHotCleanup } from '@backstage/backend-common';
|
||||
import { RequestHandler } from 'express';
|
||||
import promBundle from 'express-prom-bundle';
|
||||
import prom from 'prom-client';
|
||||
import * as url from 'url';
|
||||
|
||||
const rootRegEx = new RegExp('^/([^/]*)/.*');
|
||||
const apiRegEx = new RegExp('^/api/([^/]*)/.*');
|
||||
|
||||
export function normalizePath(req: any): string {
|
||||
const path = url.parse(req.originalUrl || req.url).pathname || '/';
|
||||
|
||||
// Capture /api/ and the plugin name
|
||||
if (apiRegEx.test(path)) {
|
||||
return path.replace(apiRegEx, '/api/$1');
|
||||
}
|
||||
|
||||
// Only the first path segment at root level
|
||||
return path.replace(rootRegEx, '/$1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a /metrics endpoint, register default runtime metrics and instrument the router.
|
||||
*/
|
||||
export function metricsHandler(): RequestHandler {
|
||||
// We can only initialize the metrics once and have to clean them up between hot reloads
|
||||
useHotCleanup(module, () => prom.register.clear());
|
||||
|
||||
return promBundle({
|
||||
includeMethod: true,
|
||||
includePath: true,
|
||||
// Using includePath alone is problematic, as it will include path labels with high
|
||||
// cardinality (e.g. path params). Instead we would have to template them. However, this
|
||||
// is difficult, as every backend plugin might use different routes. Instead we only take
|
||||
// the first directory of the path, to have at least an idea how each plugin performs:
|
||||
normalizePath,
|
||||
promClient: { collectDefaultMetrics: {} },
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Last, extend your router configuration with the `metricsHandler`:
|
||||
|
||||
```diff
|
||||
+import { metricsHandler } from './metrics';
|
||||
|
||||
...
|
||||
|
||||
const service = createServiceBuilder(module)
|
||||
.loadConfig(config)
|
||||
.addRouter('', await healthcheck(healthcheckEnv))
|
||||
+ .addRouter('', metricsHandler())
|
||||
.addRouter('/api', apiRouter);
|
||||
```
|
||||
|
||||
Your Prometheus metrics will be available at the `/metrics` endpoint.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 38e24db00: Move the core url and auth logic to integration for the four major providers
|
||||
- Updated dependencies [38e24db00]
|
||||
- Updated dependencies [b8ecf6f48]
|
||||
- Updated dependencies [e3bd9fc2f]
|
||||
- Updated dependencies [e3bd9fc2f]
|
||||
- @backstage/integration@0.1.3
|
||||
- @backstage/config@0.1.2
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.3.3",
|
||||
"version": "0.4.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -30,9 +30,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.1",
|
||||
"@backstage/config": "^0.1.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/config-loader": "^0.4.0",
|
||||
"@backstage/integration": "^0.1.2",
|
||||
"@backstage/integration": "^0.1.4",
|
||||
"@types/cors": "^2.8.6",
|
||||
"@types/express": "^4.17.6",
|
||||
"archiver": "^5.0.2",
|
||||
@@ -43,7 +43,7 @@
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
"fs-extra": "^9.0.1",
|
||||
"git-url-parse": "^11.4.0",
|
||||
"git-url-parse": "^11.4.3",
|
||||
"helmet": "^4.0.0",
|
||||
"isomorphic-git": "^1.8.0",
|
||||
"knex": "^0.21.6",
|
||||
@@ -66,8 +66,8 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.4.0",
|
||||
"@backstage/test-utils": "^0.1.4",
|
||||
"@backstage/cli": "^0.4.2",
|
||||
"@backstage/test-utils": "^0.1.5",
|
||||
"@types/archiver": "^3.1.1",
|
||||
"@types/compression": "^1.7.0",
|
||||
"@types/concat-stream": "^1.6.0",
|
||||
|
||||
@@ -21,14 +21,6 @@ import { SingleConnectionDatabaseManager } from './SingleConnection';
|
||||
jest.mock('./connection');
|
||||
|
||||
describe('SingleConnectionDatabaseManager', () => {
|
||||
const createConfig = (data: any) =>
|
||||
ConfigReader.fromConfigs([
|
||||
{
|
||||
context: '',
|
||||
data,
|
||||
},
|
||||
]);
|
||||
|
||||
const defaultConfigOptions = {
|
||||
backend: {
|
||||
database: {
|
||||
@@ -42,7 +34,7 @@ describe('SingleConnectionDatabaseManager', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const defaultConfig = () => createConfig(defaultConfigOptions);
|
||||
const defaultConfig = () => new ConfigReader(defaultConfigOptions);
|
||||
|
||||
// This is similar to the ts-jest `mocked` helper.
|
||||
const mocked = (f: Function) => f as jest.Mock;
|
||||
|
||||
@@ -18,19 +18,11 @@ import { ConfigReader } from '@backstage/config';
|
||||
import { createDatabaseClient } from './connection';
|
||||
|
||||
describe('database connection', () => {
|
||||
const createConfig = (data: any) =>
|
||||
ConfigReader.fromConfigs([
|
||||
{
|
||||
context: '',
|
||||
data,
|
||||
},
|
||||
]);
|
||||
|
||||
describe('createDatabaseClient', () => {
|
||||
it('returns a postgres connection', () => {
|
||||
expect(
|
||||
createDatabaseClient(
|
||||
createConfig({
|
||||
new ConfigReader({
|
||||
client: 'pg',
|
||||
connection: {
|
||||
host: 'acme',
|
||||
@@ -46,7 +38,7 @@ describe('database connection', () => {
|
||||
it('returns an sqlite connection', () => {
|
||||
expect(
|
||||
createDatabaseClient(
|
||||
createConfig({
|
||||
new ConfigReader({
|
||||
client: 'sqlite3',
|
||||
connection: ':memory:',
|
||||
}),
|
||||
@@ -57,7 +49,7 @@ describe('database connection', () => {
|
||||
it('tries to create a mysql connection as a passthrough', () => {
|
||||
expect(() =>
|
||||
createDatabaseClient(
|
||||
createConfig({
|
||||
new ConfigReader({
|
||||
client: 'mysql',
|
||||
connection: {
|
||||
host: '127.0.0.1',
|
||||
@@ -73,7 +65,7 @@ describe('database connection', () => {
|
||||
it('accepts overrides', () => {
|
||||
expect(
|
||||
createDatabaseClient(
|
||||
createConfig({
|
||||
new ConfigReader({
|
||||
client: 'pg',
|
||||
connection: {
|
||||
host: 'acme',
|
||||
@@ -94,7 +86,7 @@ describe('database connection', () => {
|
||||
it('throws an error without a client', () => {
|
||||
expect(() =>
|
||||
createDatabaseClient(
|
||||
createConfig({
|
||||
new ConfigReader({
|
||||
connection: '',
|
||||
}),
|
||||
),
|
||||
@@ -104,7 +96,7 @@ describe('database connection', () => {
|
||||
it('throws an error without a connection', () => {
|
||||
expect(() =>
|
||||
createDatabaseClient(
|
||||
createConfig({
|
||||
new ConfigReader({
|
||||
client: 'pg',
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -34,15 +34,7 @@ describe('postgres', () => {
|
||||
'postgresql://foo:bar@acme:5432/foodb';
|
||||
|
||||
const createConfig = (connection: any): Config =>
|
||||
ConfigReader.fromConfigs([
|
||||
{
|
||||
context: '',
|
||||
data: {
|
||||
client: 'pg',
|
||||
connection,
|
||||
},
|
||||
},
|
||||
]);
|
||||
new ConfigReader({ client: 'pg', connection });
|
||||
|
||||
describe('buildPgDatabaseConfig', () => {
|
||||
it('builds a postgres config', () => {
|
||||
|
||||
@@ -22,15 +22,7 @@ import {
|
||||
|
||||
describe('sqlite3', () => {
|
||||
const createConfig = (connection: any) =>
|
||||
ConfigReader.fromConfigs([
|
||||
{
|
||||
context: '',
|
||||
data: {
|
||||
client: 'sqlite3',
|
||||
connection,
|
||||
},
|
||||
},
|
||||
]);
|
||||
new ConfigReader({ client: 'sqlite3', connection });
|
||||
|
||||
describe('buildSqliteDatabaseConfig', () => {
|
||||
it('buidls a string connection', () => {
|
||||
|
||||
@@ -158,9 +158,7 @@ describe('AzureUrlReader', () => {
|
||||
|
||||
it('returns the wanted files from an archive', async () => {
|
||||
const processor = new AzureUrlReader(
|
||||
{
|
||||
host: 'dev.azure.com',
|
||||
},
|
||||
{ host: 'dev.azure.com' },
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
|
||||
@@ -14,15 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import fs from 'fs';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import path from 'path';
|
||||
import { BitbucketUrlReader } from './BitbucketUrlReader';
|
||||
import { ReadTreeResponseFactory } from './tree';
|
||||
|
||||
const treeResponseFactory = ReadTreeResponseFactory.create({
|
||||
config: new ConfigReader({}),
|
||||
});
|
||||
|
||||
describe('BitbucketUrlReader', () => {
|
||||
describe('implementation', () => {
|
||||
it('rejects unknown targets', async () => {
|
||||
const processor = new BitbucketUrlReader({
|
||||
host: 'bitbucket.org',
|
||||
apiBaseUrl: 'https://api.bitbucket.org/2.0',
|
||||
});
|
||||
const processor = new BitbucketUrlReader(
|
||||
{ host: 'bitbucket.org', apiBaseUrl: 'https://api.bitbucket.org/2.0' },
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
await expect(
|
||||
processor.read('https://not.bitbucket.com/apa'),
|
||||
).rejects.toThrow(
|
||||
@@ -30,4 +41,141 @@ describe('BitbucketUrlReader', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readTree', () => {
|
||||
const worker = setupServer();
|
||||
msw.setupDefaultHandlers(worker);
|
||||
|
||||
const repoBuffer = fs.readFileSync(
|
||||
path.resolve(
|
||||
'src',
|
||||
'reading',
|
||||
'__fixtures__',
|
||||
'bitbucket-repo-with-commit-hash.zip',
|
||||
),
|
||||
);
|
||||
|
||||
it('returns the wanted files from an archive', async () => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://bitbucket.org/backstage/mock/get/master.zip',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('Content-Type', 'application/zip'),
|
||||
ctx.body(repoBuffer),
|
||||
),
|
||||
),
|
||||
rest.get(
|
||||
'https://api.bitbucket.org/2.0/repositories/backstage/mock/commits/master',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
values: [{ hash: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }],
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const processor = new BitbucketUrlReader(
|
||||
{ host: 'bitbucket.org', apiBaseUrl: 'https://api.bitbucket.org/2.0' },
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
const response = await processor.readTree(
|
||||
'https://bitbucket.org/backstage/mock/src/master',
|
||||
);
|
||||
|
||||
const files = await response.files();
|
||||
|
||||
expect(files.length).toBe(2);
|
||||
const indexMarkdownFile = await files[0].content();
|
||||
const mkDocsFile = await files[1].content();
|
||||
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
expect(mkDocsFile.toString()).toBe('site_name: Test\n');
|
||||
});
|
||||
|
||||
it('uses private bitbucket host', async () => {
|
||||
const privateBitbucketRepoBuffer = fs.readFileSync(
|
||||
path.resolve(
|
||||
'src',
|
||||
'reading',
|
||||
'__fixtures__',
|
||||
'bitbucket-server-repo.zip',
|
||||
),
|
||||
);
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/archive?format=zip&prefix=mock&path=docs',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('Content-Type', 'application/zip'),
|
||||
ctx.body(privateBitbucketRepoBuffer),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const processor = new BitbucketUrlReader(
|
||||
{
|
||||
host: 'bitbucket.mycompany.net',
|
||||
apiBaseUrl: 'https://api.bitbucket.mycompany.net/rest/api/1.0',
|
||||
},
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
const response = await processor.readTree(
|
||||
'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/docs?at=some-branch',
|
||||
);
|
||||
|
||||
const files = await response.files();
|
||||
|
||||
expect(files.length).toBe(1);
|
||||
const indexMarkdownFile = await files[0].content();
|
||||
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
});
|
||||
|
||||
it('returns the wanted files from an archive with a subpath', async () => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://bitbucket.org/backstage/mock/get/master.zip',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('Content-Type', 'application/zip'),
|
||||
ctx.body(repoBuffer),
|
||||
),
|
||||
),
|
||||
rest.get(
|
||||
'https://api.bitbucket.org/2.0/repositories/backstage/mock/commits/master',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
values: [{ hash: '12ab34cd56ef78gh90ij12kl34mn56op78qr90st' }],
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const processor = new BitbucketUrlReader(
|
||||
{ host: 'bitbucket.org', apiBaseUrl: 'https://api.bitbucket.org/2.0' },
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
const response = await processor.readTree(
|
||||
'https://bitbucket.org/backstage/mock/src/master/docs',
|
||||
);
|
||||
|
||||
const files = await response.files();
|
||||
|
||||
expect(files.length).toBe(1);
|
||||
const indexMarkdownFile = await files[0].content();
|
||||
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,13 +16,23 @@
|
||||
|
||||
import {
|
||||
BitbucketIntegrationConfig,
|
||||
getBitbucketDefaultBranch,
|
||||
getBitbucketDownloadUrl,
|
||||
getBitbucketFileFetchUrl,
|
||||
getBitbucketRequestOptions,
|
||||
readBitbucketIntegrationConfigs,
|
||||
} from '@backstage/integration';
|
||||
import fetch from 'cross-fetch';
|
||||
import parseGitUri from 'git-url-parse';
|
||||
import { Readable } from 'stream';
|
||||
import { NotFoundError } from '../errors';
|
||||
import { ReaderFactory, ReadTreeResponse, UrlReader } from './types';
|
||||
import { ReadTreeResponseFactory } from './tree';
|
||||
import {
|
||||
ReaderFactory,
|
||||
ReadTreeOptions,
|
||||
ReadTreeResponse,
|
||||
UrlReader,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* A processor that adds the ability to read files from Bitbucket v1 and v2 APIs, such as
|
||||
@@ -30,19 +40,23 @@ import { ReaderFactory, ReadTreeResponse, UrlReader } from './types';
|
||||
*/
|
||||
export class BitbucketUrlReader implements UrlReader {
|
||||
private readonly config: BitbucketIntegrationConfig;
|
||||
private readonly treeResponseFactory: ReadTreeResponseFactory;
|
||||
|
||||
static factory: ReaderFactory = ({ config }) => {
|
||||
static factory: ReaderFactory = ({ config, treeResponseFactory }) => {
|
||||
const configs = readBitbucketIntegrationConfigs(
|
||||
config.getOptionalConfigArray('integrations.bitbucket') ?? [],
|
||||
);
|
||||
return configs.map(provider => {
|
||||
const reader = new BitbucketUrlReader(provider);
|
||||
const reader = new BitbucketUrlReader(provider, { treeResponseFactory });
|
||||
const predicate = (url: URL) => url.host === provider.host;
|
||||
return { reader, predicate };
|
||||
});
|
||||
};
|
||||
|
||||
constructor(config: BitbucketIntegrationConfig) {
|
||||
constructor(
|
||||
config: BitbucketIntegrationConfig,
|
||||
deps: { treeResponseFactory: ReadTreeResponseFactory },
|
||||
) {
|
||||
const { host, apiBaseUrl, token, username, appPassword } = config;
|
||||
|
||||
if (!apiBaseUrl) {
|
||||
@@ -58,6 +72,7 @@ export class BitbucketUrlReader implements UrlReader {
|
||||
}
|
||||
|
||||
this.config = config;
|
||||
this.treeResponseFactory = deps.treeResponseFactory;
|
||||
}
|
||||
|
||||
async read(url: string): Promise<Buffer> {
|
||||
@@ -82,8 +97,39 @@ export class BitbucketUrlReader implements UrlReader {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
readTree(): Promise<ReadTreeResponse> {
|
||||
throw new Error('BitbucketUrlReader does not implement readTree');
|
||||
async readTree(
|
||||
url: string,
|
||||
options?: ReadTreeOptions,
|
||||
): Promise<ReadTreeResponse> {
|
||||
const gitUrl: parseGitUri.GitUrl = parseGitUri(url);
|
||||
const { name: repoName, owner: project, resource, filepath } = gitUrl;
|
||||
|
||||
const isHosted = resource === 'bitbucket.org';
|
||||
|
||||
const downloadUrl = await getBitbucketDownloadUrl(url, this.config);
|
||||
const response = await fetch(
|
||||
downloadUrl,
|
||||
getBitbucketRequestOptions(this.config),
|
||||
);
|
||||
if (!response.ok) {
|
||||
const message = `Failed to read tree from ${url}, ${response.status} ${response.statusText}`;
|
||||
if (response.status === 404) {
|
||||
throw new NotFoundError(message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
let folderPath = `${project}-${repoName}`;
|
||||
if (isHosted) {
|
||||
const lastCommitShortHash = await this.getLastCommitShortHash(url);
|
||||
folderPath = `${project}-${repoName}-${lastCommitShortHash}`;
|
||||
}
|
||||
|
||||
return this.treeResponseFactory.fromZipArchive({
|
||||
stream: (response.body as unknown) as Readable,
|
||||
path: `${folderPath}/${filepath}`,
|
||||
filter: options?.filter,
|
||||
});
|
||||
}
|
||||
|
||||
toString() {
|
||||
@@ -94,4 +140,37 @@ export class BitbucketUrlReader implements UrlReader {
|
||||
}
|
||||
return `bitbucket{host=${host},authed=${authed}}`;
|
||||
}
|
||||
|
||||
private async getLastCommitShortHash(url: string): Promise<String> {
|
||||
const { name: repoName, owner: project, ref } = parseGitUri(url);
|
||||
|
||||
let branch = ref;
|
||||
if (!branch) {
|
||||
branch = await getBitbucketDefaultBranch(url, this.config);
|
||||
}
|
||||
const commitsApiUrl = `${this.config.apiBaseUrl}/repositories/${project}/${repoName}/commits/${branch}`;
|
||||
|
||||
const commitsResponse = await fetch(
|
||||
commitsApiUrl,
|
||||
getBitbucketRequestOptions(this.config),
|
||||
);
|
||||
if (!commitsResponse.ok) {
|
||||
const message = `Failed to retrieve commits from ${commitsApiUrl}, ${commitsResponse.status} ${commitsResponse.statusText}`;
|
||||
if (commitsResponse.status === 404) {
|
||||
throw new NotFoundError(message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
const commits = await commitsResponse.json();
|
||||
if (
|
||||
commits &&
|
||||
commits.values &&
|
||||
commits.values.length > 0 &&
|
||||
commits.values[0].hash
|
||||
) {
|
||||
return commits.values[0].hash.substring(0, 12);
|
||||
}
|
||||
throw new Error(`Failed to read response from ${commitsApiUrl}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import fs from 'fs';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import path from 'path';
|
||||
import { getVoidLogger } from '../logging';
|
||||
import { GitlabUrlReader } from './GitlabUrlReader';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import { ReadTreeResponseFactory } from './tree';
|
||||
|
||||
const logger = getVoidLogger();
|
||||
@@ -30,105 +32,207 @@ const treeResponseFactory = ReadTreeResponseFactory.create({
|
||||
|
||||
describe('GitlabUrlReader', () => {
|
||||
const worker = setupServer();
|
||||
|
||||
msw.setupDefaultHandlers(worker);
|
||||
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get('*/api/v4/projects/:name', (_, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json({ id: 12345 })),
|
||||
),
|
||||
rest.get('*', (req, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
url: req.url.toString(),
|
||||
headers: req.headers.getAllHeaders(),
|
||||
}),
|
||||
describe('implementation', () => {
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get('*/api/v4/projects/:name', (_, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json({ id: 12345 })),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
const createConfig = (token?: string) =>
|
||||
new ConfigReader(
|
||||
{
|
||||
integrations: { gitlab: [{ host: 'gitlab.com', token }] },
|
||||
},
|
||||
'test-config',
|
||||
);
|
||||
|
||||
it.each([
|
||||
// Project URLs
|
||||
{
|
||||
url:
|
||||
'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml',
|
||||
config: createConfig(),
|
||||
response: expect.objectContaining({
|
||||
url:
|
||||
'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch',
|
||||
headers: expect.objectContaining({
|
||||
'private-token': '',
|
||||
}),
|
||||
}),
|
||||
},
|
||||
{
|
||||
url:
|
||||
'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml',
|
||||
config: createConfig('0123456789'),
|
||||
response: expect.objectContaining({
|
||||
url:
|
||||
'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch',
|
||||
headers: expect.objectContaining({
|
||||
'private-token': '0123456789',
|
||||
}),
|
||||
}),
|
||||
},
|
||||
{
|
||||
url:
|
||||
'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path/to/file.yaml', // Repo not in subgroup
|
||||
config: createConfig(),
|
||||
response: expect.objectContaining({
|
||||
url:
|
||||
'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch',
|
||||
}),
|
||||
},
|
||||
|
||||
// Raw URLs
|
||||
{
|
||||
url: 'https://gitlab.example.com/a/b/blob/master/c.yaml',
|
||||
config: createConfig(),
|
||||
response: expect.objectContaining({
|
||||
url: 'https://gitlab.example.com/a/b/raw/master/c.yaml',
|
||||
}),
|
||||
},
|
||||
])('should handle happy path %#', async ({ url, config, response }) => {
|
||||
const [{ reader }] = GitlabUrlReader.factory({
|
||||
config,
|
||||
logger,
|
||||
treeResponseFactory,
|
||||
rest.get('*', (req, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
url: req.url.toString(),
|
||||
headers: req.headers.getAllHeaders(),
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
const data = await reader.read(url);
|
||||
const res = await JSON.parse(data.toString('utf-8'));
|
||||
expect(res).toEqual(response);
|
||||
});
|
||||
const createConfig = (token?: string) =>
|
||||
new ConfigReader(
|
||||
{
|
||||
integrations: { gitlab: [{ host: 'gitlab.com', token }] },
|
||||
},
|
||||
'test-config',
|
||||
);
|
||||
|
||||
it.each([
|
||||
{
|
||||
url: '',
|
||||
config: createConfig(''),
|
||||
error:
|
||||
"Invalid type in config for key 'integrations.gitlab[0].token' in 'test-config', got empty-string, wanted string",
|
||||
},
|
||||
])('should handle error path %#', async ({ url, config, error }) => {
|
||||
await expect(async () => {
|
||||
it.each([
|
||||
// Project URLs
|
||||
{
|
||||
url:
|
||||
'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml',
|
||||
config: createConfig(),
|
||||
response: expect.objectContaining({
|
||||
url:
|
||||
'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch',
|
||||
headers: expect.objectContaining({
|
||||
'private-token': '',
|
||||
}),
|
||||
}),
|
||||
},
|
||||
{
|
||||
url:
|
||||
'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml',
|
||||
config: createConfig('0123456789'),
|
||||
response: expect.objectContaining({
|
||||
url:
|
||||
'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch',
|
||||
headers: expect.objectContaining({
|
||||
'private-token': '0123456789',
|
||||
}),
|
||||
}),
|
||||
},
|
||||
{
|
||||
url:
|
||||
'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path/to/file.yaml', // Repo not in subgroup
|
||||
config: createConfig(),
|
||||
response: expect.objectContaining({
|
||||
url:
|
||||
'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch',
|
||||
}),
|
||||
},
|
||||
|
||||
// Raw URLs
|
||||
{
|
||||
url: 'https://gitlab.example.com/a/b/blob/master/c.yaml',
|
||||
config: createConfig(),
|
||||
response: expect.objectContaining({
|
||||
url: 'https://gitlab.example.com/a/b/raw/master/c.yaml',
|
||||
}),
|
||||
},
|
||||
])('should handle happy path %#', async ({ url, config, response }) => {
|
||||
const [{ reader }] = GitlabUrlReader.factory({
|
||||
config,
|
||||
logger,
|
||||
treeResponseFactory,
|
||||
});
|
||||
await reader.read(url);
|
||||
}).rejects.toThrow(error);
|
||||
|
||||
const data = await reader.read(url);
|
||||
const res = await JSON.parse(data.toString('utf-8'));
|
||||
expect(res).toEqual(response);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
url: '',
|
||||
config: createConfig(''),
|
||||
error:
|
||||
"Invalid type in config for key 'integrations.gitlab[0].token' in 'test-config', got empty-string, wanted string",
|
||||
},
|
||||
])('should handle error path %#', async ({ url, config, error }) => {
|
||||
await expect(async () => {
|
||||
const [{ reader }] = GitlabUrlReader.factory({
|
||||
config,
|
||||
logger,
|
||||
treeResponseFactory,
|
||||
});
|
||||
await reader.read(url);
|
||||
}).rejects.toThrow(error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readTree', () => {
|
||||
const repoBuffer = fs.readFileSync(
|
||||
path.resolve('src', 'reading', '__fixtures__', 'repo.zip'),
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://gitlab.com/backstage/mock/-/archive/repo/mock-repo.zip',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('Content-Type', 'application/zip'),
|
||||
ctx.body(repoBuffer),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the wanted files from an archive', async () => {
|
||||
const processor = new GitlabUrlReader(
|
||||
{ host: 'gitlab.com' },
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
const response = await processor.readTree(
|
||||
'https://gitlab.com/backstage/mock/tree/repo',
|
||||
);
|
||||
|
||||
const files = await response.files();
|
||||
expect(files.length).toBe(2);
|
||||
|
||||
const indexMarkdownFile = await files[0].content();
|
||||
const mkDocsFile = await files[1].content();
|
||||
|
||||
expect(mkDocsFile.toString()).toBe('site_name: Test\n');
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
});
|
||||
|
||||
it('returns the wanted files from hosted gitlab', async () => {
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://git.mycompany.com/backstage/mock/-/archive/repo/mock-repo.zip',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('Content-Type', 'application/zip'),
|
||||
ctx.body(repoBuffer),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const processor = new GitlabUrlReader(
|
||||
{ host: 'git.mycompany.com' },
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
const response = await processor.readTree(
|
||||
'https://git.mycompany.com/backstage/mock/tree/repo/docs',
|
||||
);
|
||||
|
||||
const files = await response.files();
|
||||
|
||||
expect(files.length).toBe(1);
|
||||
const indexMarkdownFile = await files[0].content();
|
||||
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
});
|
||||
|
||||
it('throws an error when branch is not specified', async () => {
|
||||
const processor = new GitlabUrlReader(
|
||||
{ host: 'gitlab.com' },
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
await expect(
|
||||
processor.readTree('https://gitlab.com/backstage/mock'),
|
||||
).rejects.toThrow(
|
||||
'GitLab URL must contain a branch to be able to fetch its tree',
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the wanted files from an archive with a subpath', async () => {
|
||||
const processor = new GitlabUrlReader(
|
||||
{ host: 'gitlab.com' },
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
const response = await processor.readTree(
|
||||
'https://gitlab.com/backstage/mock/tree/repo/docs',
|
||||
);
|
||||
|
||||
const files = await response.files();
|
||||
|
||||
expect(files.length).toBe(1);
|
||||
const indexMarkdownFile = await files[0].content();
|
||||
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,22 +21,37 @@ import {
|
||||
readGitLabIntegrationConfigs,
|
||||
} from '@backstage/integration';
|
||||
import fetch from 'cross-fetch';
|
||||
import { NotFoundError } from '../errors';
|
||||
import { ReaderFactory, ReadTreeResponse, UrlReader } from './types';
|
||||
import { InputError, NotFoundError } from '../errors';
|
||||
import { ReadTreeResponseFactory } from './tree';
|
||||
import {
|
||||
ReaderFactory,
|
||||
ReadTreeOptions,
|
||||
ReadTreeResponse,
|
||||
UrlReader,
|
||||
} from './types';
|
||||
import parseGitUri from 'git-url-parse';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
export class GitlabUrlReader implements UrlReader {
|
||||
static factory: ReaderFactory = ({ config }) => {
|
||||
private readonly treeResponseFactory: ReadTreeResponseFactory;
|
||||
|
||||
static factory: ReaderFactory = ({ config, treeResponseFactory }) => {
|
||||
const configs = readGitLabIntegrationConfigs(
|
||||
config.getOptionalConfigArray('integrations.gitlab') ?? [],
|
||||
);
|
||||
return configs.map(options => {
|
||||
const reader = new GitlabUrlReader(options);
|
||||
const reader = new GitlabUrlReader(options, { treeResponseFactory });
|
||||
const predicate = (url: URL) => url.host === options.host;
|
||||
return { reader, predicate };
|
||||
});
|
||||
};
|
||||
|
||||
constructor(private readonly options: GitLabIntegrationConfig) {}
|
||||
constructor(
|
||||
private readonly options: GitLabIntegrationConfig,
|
||||
deps: { treeResponseFactory: ReadTreeResponseFactory },
|
||||
) {
|
||||
this.treeResponseFactory = deps.treeResponseFactory;
|
||||
}
|
||||
|
||||
async read(url: string): Promise<Buffer> {
|
||||
const builtUrl = await getGitLabFileFetchUrl(url, this.options);
|
||||
@@ -59,8 +74,45 @@ export class GitlabUrlReader implements UrlReader {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
readTree(): Promise<ReadTreeResponse> {
|
||||
throw new Error('GitlabUrlReader does not implement readTree');
|
||||
async readTree(
|
||||
url: string,
|
||||
options?: ReadTreeOptions,
|
||||
): Promise<ReadTreeResponse> {
|
||||
const {
|
||||
name: repoName,
|
||||
ref,
|
||||
protocol,
|
||||
resource,
|
||||
full_name,
|
||||
filepath,
|
||||
} = parseGitUri(url);
|
||||
|
||||
if (!ref) {
|
||||
throw new InputError(
|
||||
'GitLab URL must contain a branch to be able to fetch its tree',
|
||||
);
|
||||
}
|
||||
|
||||
const archive = `${protocol}://${resource}/${full_name}/-/archive/${ref}/${repoName}-${ref}.zip`;
|
||||
const response = await fetch(
|
||||
archive,
|
||||
getGitLabRequestOptions(this.options),
|
||||
);
|
||||
if (!response.ok) {
|
||||
const msg = `Failed to read tree from ${url}, ${response.status} ${response.statusText}`;
|
||||
if (response.status === 404) {
|
||||
throw new NotFoundError(msg);
|
||||
}
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
const path = filepath ? `${repoName}-${ref}/${filepath}/` : '';
|
||||
|
||||
return this.treeResponseFactory.fromZipArchive({
|
||||
stream: (response.body as unknown) as Readable,
|
||||
path,
|
||||
filter: options?.filter,
|
||||
});
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -52,7 +52,7 @@ const DEFAULT_CSP = {
|
||||
'frame-ancestors': ["'self'"],
|
||||
'img-src': ["'self'", 'data:'],
|
||||
'object-src': ["'none'"],
|
||||
'script-src': ["'self'"],
|
||||
'script-src': ["'self'", "'unsafe-eval'"],
|
||||
'script-src-attr': ["'none'"],
|
||||
'style-src': ["'self'", 'https:', "'unsafe-inline'"],
|
||||
'upgrade-insecure-requests': [] as string[],
|
||||
|
||||
@@ -20,9 +20,7 @@ import { readCspOptions } from './config';
|
||||
describe('config', () => {
|
||||
describe('readCspOptions', () => {
|
||||
it('reads valid values', () => {
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{ context: '', data: { csp: { key: ['value'] } } },
|
||||
]);
|
||||
const config = new ConfigReader({ csp: { key: ['value'] } });
|
||||
expect(readCspOptions(config)).toEqual(
|
||||
expect.objectContaining({
|
||||
key: ['value'],
|
||||
@@ -31,9 +29,7 @@ describe('config', () => {
|
||||
});
|
||||
|
||||
it('accepts false', () => {
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{ context: '', data: { csp: { key: false } } },
|
||||
]);
|
||||
const config = new ConfigReader({ csp: { key: false } });
|
||||
expect(readCspOptions(config)).toEqual(
|
||||
expect.objectContaining({
|
||||
key: false,
|
||||
@@ -42,9 +38,7 @@ describe('config', () => {
|
||||
});
|
||||
|
||||
it('rejects invalid value types', () => {
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{ context: '', data: { csp: { key: [4] } } },
|
||||
]);
|
||||
const config = new ConfigReader({ csp: { key: [4] } });
|
||||
expect(() => readCspOptions(config)).toThrow(/wanted string-array/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,64 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c6eeefa35]
|
||||
- Updated dependencies [fb386b760]
|
||||
- Updated dependencies [c911061b7]
|
||||
- Updated dependencies [7c3ffc0cd]
|
||||
- Updated dependencies [dae4f3983]
|
||||
- Updated dependencies [7b15cc271]
|
||||
- Updated dependencies [e7496dc3e]
|
||||
- Updated dependencies [1d1c2860f]
|
||||
- Updated dependencies [0e6298f7e]
|
||||
- Updated dependencies [8dd0a906d]
|
||||
- Updated dependencies [4eafdec4a]
|
||||
- Updated dependencies [6b37c95bf]
|
||||
- Updated dependencies [8c31c681c]
|
||||
- Updated dependencies [7b98e7fee]
|
||||
- Updated dependencies [ac3560b42]
|
||||
- Updated dependencies [94c65a9d4]
|
||||
- Updated dependencies [0097057ed]
|
||||
- @backstage/plugin-catalog-backend@0.5.0
|
||||
- @backstage/catalog-model@0.6.0
|
||||
- @backstage/plugin-techdocs-backend@0.4.0
|
||||
- @backstage/plugin-auth-backend@0.2.7
|
||||
- @backstage/backend-common@0.4.1
|
||||
- @backstage/plugin-scaffolder-backend@0.3.5
|
||||
- example-app@0.2.7
|
||||
- @backstage/plugin-kubernetes-backend@0.2.3
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1e22f8e0b: Unify `dockerode` library and type dependency versions
|
||||
- Updated dependencies [6e8bb3ac0]
|
||||
- Updated dependencies [e708679d7]
|
||||
- Updated dependencies [047c018c9]
|
||||
- Updated dependencies [38e24db00]
|
||||
- Updated dependencies [e3bd9fc2f]
|
||||
- Updated dependencies [12bbd748c]
|
||||
- Updated dependencies [38d63fbe1]
|
||||
- Updated dependencies [1e22f8e0b]
|
||||
- Updated dependencies [83b6e0c1f]
|
||||
- Updated dependencies [e3bd9fc2f]
|
||||
- @backstage/plugin-catalog-backend@0.4.0
|
||||
- @backstage/backend-common@0.4.0
|
||||
- @backstage/config@0.1.2
|
||||
- @backstage/plugin-scaffolder-backend@0.3.4
|
||||
- @backstage/plugin-techdocs-backend@0.3.2
|
||||
- @backstage/catalog-model@0.5.0
|
||||
- example-app@0.2.6
|
||||
- @backstage/plugin-app-backend@0.3.3
|
||||
- @backstage/plugin-auth-backend@0.2.6
|
||||
- @backstage/plugin-graphql-backend@0.1.4
|
||||
- @backstage/plugin-kubernetes-backend@0.2.2
|
||||
- @backstage/plugin-proxy-backend@0.2.3
|
||||
- @backstage/plugin-rollbar-backend@0.1.5
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:12-buster
|
||||
FROM node:14-buster
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.7",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -27,23 +27,23 @@
|
||||
"migrate:create": "knex migrate:make -x ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.3.3",
|
||||
"@backstage/catalog-model": "^0.4.0",
|
||||
"@backstage/config": "^0.1.1",
|
||||
"@backstage/plugin-app-backend": "^0.3.2",
|
||||
"@backstage/plugin-auth-backend": "^0.2.5",
|
||||
"@backstage/plugin-catalog-backend": "^0.3.0",
|
||||
"@backstage/plugin-graphql-backend": "^0.1.3",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.2.1",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.2",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.4",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.3.3",
|
||||
"@backstage/plugin-techdocs-backend": "^0.3.1",
|
||||
"@backstage/backend-common": "^0.4.1",
|
||||
"@backstage/catalog-model": "^0.6.0",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/plugin-app-backend": "^0.3.3",
|
||||
"@backstage/plugin-auth-backend": "^0.2.7",
|
||||
"@backstage/plugin-catalog-backend": "^0.5.0",
|
||||
"@backstage/plugin-graphql-backend": "^0.1.4",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.2.3",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.3",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.5",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.3.5",
|
||||
"@backstage/plugin-techdocs-backend": "^0.4.0",
|
||||
"@gitbeaker/node": "^25.2.0",
|
||||
"@octokit/rest": "^18.0.0",
|
||||
"azure-devops-node-api": "^10.1.1",
|
||||
"dockerode": "^3.2.1",
|
||||
"example-app": "^0.2.5",
|
||||
"example-app": "^0.2.7",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
"knex": "^0.21.6",
|
||||
@@ -53,7 +53,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.4.0",
|
||||
"@backstage/cli": "^0.4.2",
|
||||
"@types/dockerode": "^3.2.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/express-serve-static-core": "^4.17.5",
|
||||
|
||||
@@ -13,16 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
createRouter,
|
||||
DirectoryPreparer,
|
||||
Preparers,
|
||||
Generators,
|
||||
LocalPublish,
|
||||
TechdocsGenerator,
|
||||
CommonGitPreparer,
|
||||
UrlPreparer,
|
||||
Publisher,
|
||||
} from '@backstage/plugin-techdocs-backend';
|
||||
import { PluginEnvironment } from '../types';
|
||||
import Docker from 'dockerode';
|
||||
@@ -33,10 +32,7 @@ export default async function createPlugin({
|
||||
discovery,
|
||||
reader,
|
||||
}: PluginEnvironment) {
|
||||
const generators = new Generators();
|
||||
const techdocsGenerator = new TechdocsGenerator(logger, config);
|
||||
generators.register('techdocs', techdocsGenerator);
|
||||
|
||||
// Preparers are responsible for fetching source files for documentation.
|
||||
const preparers = new Preparers();
|
||||
|
||||
const directoryPreparer = new DirectoryPreparer(logger);
|
||||
@@ -50,8 +46,17 @@ export default async function createPlugin({
|
||||
const urlPreparer = new UrlPreparer(reader, logger);
|
||||
preparers.register('url', urlPreparer);
|
||||
|
||||
const publisher = new LocalPublish(logger, discovery);
|
||||
// Generators are used for generating documentation sites.
|
||||
const generators = new Generators();
|
||||
const techdocsGenerator = new TechdocsGenerator(logger, config);
|
||||
generators.register('techdocs', techdocsGenerator);
|
||||
|
||||
// Publishers are used for
|
||||
// 1. Publishing generated files to storage
|
||||
// 2. Fetching files from storage and passing them to TechDocs frontend.
|
||||
const publisher = Publisher.fromConfig(config, logger, discovery);
|
||||
|
||||
// Docker client used by the generators.
|
||||
const dockerClient = new Docker();
|
||||
|
||||
return await createRouter({
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/catalog-client
|
||||
|
||||
## 0.3.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c911061b7]
|
||||
- Updated dependencies [0e6298f7e]
|
||||
- Updated dependencies [ac3560b42]
|
||||
- @backstage/catalog-model@0.6.0
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e3bd9fc2f]
|
||||
- Updated dependencies [83b6e0c1f]
|
||||
- Updated dependencies [e3bd9fc2f]
|
||||
- @backstage/config@0.1.2
|
||||
- @backstage/catalog-model@0.5.0
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user