Merge branch 'master' into eide/shortcut-plugin
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-cost-insights': minor
|
||||
---
|
||||
|
||||
make change ratio optional
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-tech-radar': patch
|
||||
---
|
||||
|
||||
Update README for composability
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-proxy-backend': patch
|
||||
---
|
||||
|
||||
Prefix proxy routes with `/` if not present in configuration
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
'@backstage/catalog-model': patch
|
||||
'@backstage/cli': patch
|
||||
'@backstage/config-loader': patch
|
||||
'@backstage/config': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Bump `json-schema` dependency from `0.2.5` to `0.3.0`.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
---
|
||||
|
||||
Adding optional config to enable S3-like API for tech-docs using s3ForcePathStyle option.
|
||||
This allows providers like LocalStack, Minio and Wasabi (+possibly others) to be used to host tech docs.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/catalog-client': patch
|
||||
---
|
||||
|
||||
Allow `filter` parameter to be specified multiple times
|
||||
@@ -111,6 +111,7 @@ Usage: backstage-cli app:build
|
||||
|
||||
Options:
|
||||
--stats Write bundle stats to output directory
|
||||
--lax Do not require environment variables to be set
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
@@ -486,6 +487,7 @@ Usage: backstage-cli config:print [options]
|
||||
|
||||
Options:
|
||||
--package <name> Only load config schema that applies to the given package
|
||||
--lax Do not require environment variables to be set
|
||||
--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]
|
||||
@@ -506,6 +508,7 @@ Usage: backstage-cli config:check [options]
|
||||
|
||||
Options:
|
||||
--package <name> Only load config schema that applies to the given package
|
||||
--lax Do not require environment variables to be set
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
@@ -8,44 +8,36 @@ The Kubernetes feature is a plugin to Backstage, and it is exposed as a tab when
|
||||
viewing entities in the software catalog.
|
||||
|
||||
If you haven't setup Backstage already, read the
|
||||
[Getting Started](../../getting-started/index.md).
|
||||
[Getting Started](../../getting-started/index.md) guide.
|
||||
|
||||
## Adding the Kubernetes frontend plugin
|
||||
|
||||
The first step is to add the frontend Kubernetes plugin to your Backstage
|
||||
application. Navigate to your new Backstage application directory. And then to
|
||||
The first step is to add the Kubernetes frontend plugin to your Backstage
|
||||
application. Navigate to your new Backstage application directory, and then to
|
||||
your `packages/app` directory, and install the `@backstage/plugin-kubernetes`
|
||||
package.
|
||||
|
||||
```bash
|
||||
cd my-backstage-app/
|
||||
# From your Backstage root directory
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-kubernetes
|
||||
```
|
||||
|
||||
Once the package has been installed, you need to import the plugin in your app
|
||||
by adding the "Kubernetes" tab to the catalog entity page. In
|
||||
`packages/app/src/components/catalog/EntityPage.tsx`, you'll add a router to get
|
||||
to the tab, and add the tab itself.
|
||||
|
||||
`EntityPage.tsx`:
|
||||
by adding the "Kubernetes" tab to the respective catalog pages.
|
||||
|
||||
```tsx
|
||||
import { Router as KubernetesRouter } from '@backstage/plugin-kubernetes';
|
||||
// In packages/app/src/components/catalog/EntityPage.tsx
|
||||
import { EntityKubernetesContent } from '@backstage/plugin-kubernetes';
|
||||
|
||||
// ...
|
||||
|
||||
const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
// ...
|
||||
<EntityPageLayout.Content
|
||||
path="/kubernetes/*"
|
||||
title="Kubernetes"
|
||||
element={<KubernetesRouter entity={entity} />}
|
||||
/>
|
||||
// ...
|
||||
</EntityPageLayout>
|
||||
);
|
||||
// You can add the tab to any number of pages, the service page is shown as an
|
||||
// example here
|
||||
const serviceEntityPage = (
|
||||
<EntityLayout>
|
||||
{/* other tabs... */}
|
||||
<EntityLayout.Route path="/kubernetes" title="Kubernetes">
|
||||
<EntityKubernetesContent />
|
||||
</EntityLayout.Route>
|
||||
```
|
||||
|
||||
That's it! But now, we need the Kubernetes Backend plugin for the frontend to
|
||||
@@ -57,17 +49,16 @@ Navigate to `packages/backend` of your Backstage app, and install the
|
||||
`@backstage/plugin-kubernetes-backend` package.
|
||||
|
||||
```bash
|
||||
cd my-backstage-app/
|
||||
# From your Backstage root directory
|
||||
cd packages/backend
|
||||
yarn add @backstage/plugin-kubernetes-backend
|
||||
```
|
||||
|
||||
Create a file called `kubernetes.ts` inside `packages/backend/src/plugins/` and
|
||||
add the following
|
||||
|
||||
`kubernetes.ts`:
|
||||
add the following:
|
||||
|
||||
```typescript
|
||||
// In packages/backend/src/plugins/kubernetes.ts
|
||||
import { createRouter } from '@backstage/plugin-kubernetes-backend';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
@@ -83,18 +74,15 @@ And import the plugin to `packages/backend/src/index.ts`. There are three lines
|
||||
of code you'll need to add, and they should be added near similar code in your
|
||||
existing Backstage backend.
|
||||
|
||||
`index.ts`:
|
||||
|
||||
```typescript
|
||||
// In packages/backend/src/index.ts
|
||||
import kubernetes from './plugins/kubernetes';
|
||||
|
||||
// ...
|
||||
|
||||
const kubernetesEnv = useHotMemoize(module, () => createEnv('kubernetes'));
|
||||
|
||||
// ...
|
||||
|
||||
apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv));
|
||||
async function main() {
|
||||
// ...
|
||||
const kubernetesEnv = useHotMemoize(module, () => createEnv('kubernetes'));
|
||||
// ...
|
||||
apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv));
|
||||
```
|
||||
|
||||
That's it! The Kubernetes frontend and backend have now been added to your
|
||||
|
||||
@@ -37,6 +37,13 @@ The locations added through static configuration cannot be removed through the
|
||||
catalog locations API. To remove these locations, you must remove them from the
|
||||
configuration.
|
||||
|
||||
Syntax errors or other types of errors present in `catalog-info.yaml` files will
|
||||
be logged for investigation. Errors do not cause processing to abort.
|
||||
|
||||
When multiple `catalog-info.yaml` files with the same `metadata.name` property
|
||||
are discovered, one will be processed and all others will be skipped. This
|
||||
action is logged for further investigation.
|
||||
|
||||
### Integration Processors
|
||||
|
||||
Integrations may simply provide a mechanism to handle `url` location type for an
|
||||
@@ -111,8 +118,7 @@ catalog:
|
||||
> deleting entities will not work in this mode.**
|
||||
|
||||
A common use case for this configuration is when organizations have a remote
|
||||
source that should be mirrored into backstage. If we want backstage to be a
|
||||
mirror of this remote source we cannot allow users to also register entities
|
||||
with e.g.
|
||||
source that should be mirrored into Backstage. To make Backstage a mirror of
|
||||
this remote source, users cannot also register new entities with e.g. the
|
||||
[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import)
|
||||
plugin.
|
||||
|
||||
@@ -18,6 +18,7 @@ The catalog frontend plugin should be installed in your `app` package, which is
|
||||
created as a part of `@backstage/create-app`. To install the package, run:
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-catalog
|
||||
```
|
||||
@@ -103,6 +104,7 @@ The catalog backend should be installed in your `backend` package, which is
|
||||
created as a part of `@backstage/create-app`. To install the package, run:
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
cd packages/backend
|
||||
yarn add @backstage/plugin-catalog-backend
|
||||
```
|
||||
|
||||
@@ -20,6 +20,7 @@ The scaffolder frontend plugin should be installed in your `app` package, which
|
||||
is created as a part of `@backstage/create-app`. To install the package, run:
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-scaffolder
|
||||
```
|
||||
@@ -57,6 +58,7 @@ The scaffolder backend should be installed in your `backend` package, which is
|
||||
created as a part of `@backstage/create-app`. To install the package, run:
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
cd packages/backend
|
||||
yarn add @backstage/plugin-scaffolder-backend
|
||||
```
|
||||
@@ -68,6 +70,10 @@ creating a file called `packages/backend/src/plugins/scaffolder.ts` with the
|
||||
following contents to get you up and running quickly.
|
||||
|
||||
```ts
|
||||
import {
|
||||
DockerContainerRunner,
|
||||
SingleHostDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
import {
|
||||
CookieCutter,
|
||||
createRouter,
|
||||
@@ -76,7 +82,6 @@ import {
|
||||
CreateReactAppTemplater,
|
||||
Templaters,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
import { SingleHostDiscovery } from '@backstage/backend-common';
|
||||
import type { PluginEnvironment } from '../types';
|
||||
import Docker from 'dockerode';
|
||||
import { CatalogClient } from '@backstage/catalog-client';
|
||||
@@ -87,8 +92,11 @@ export default async function createPlugin({
|
||||
database,
|
||||
reader,
|
||||
}: PluginEnvironment) {
|
||||
const cookiecutterTemplater = new CookieCutter();
|
||||
const craTemplater = new CreateReactAppTemplater();
|
||||
const dockerClient = new Docker();
|
||||
const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
const cookiecutterTemplater = new CookieCutter({ containerRunner });
|
||||
const craTemplater = new CreateReactAppTemplater({ containerRunner });
|
||||
const templaters = new Templaters();
|
||||
|
||||
templaters.register('cookiecutter', cookiecutterTemplater);
|
||||
@@ -97,8 +105,6 @@ export default async function createPlugin({
|
||||
const preparers = await Preparers.fromConfig(config, { logger });
|
||||
const publishers = await Publishers.fromConfig(config, { logger });
|
||||
|
||||
const dockerClient = new Docker();
|
||||
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const catalogClient = new CatalogClient({ discoveryApi: discovery });
|
||||
|
||||
@@ -108,7 +114,6 @@ export default async function createPlugin({
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
database,
|
||||
catalogClient,
|
||||
reader,
|
||||
@@ -262,6 +267,6 @@ library. By default it will use the
|
||||
[spotify/backstage-cookiecutter](https://github.com/backstage/backstage/blob/37e35b910afc7d1270855aed0ec4718aba366c91/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile)
|
||||
docker image.
|
||||
|
||||
If you are running backstage from a Docker container and you want to avoid
|
||||
If you are running Backstage from a Docker container and you want to avoid
|
||||
calling a container inside a container, you can set up Cookiecutter in your own
|
||||
image, this will use the local installation instead.
|
||||
|
||||
@@ -106,7 +106,6 @@ return await createRouter({
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
database,
|
||||
catalogClient,
|
||||
reader,
|
||||
@@ -124,7 +123,6 @@ return await createRouter({
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
database,
|
||||
catalogClient,
|
||||
reader,
|
||||
@@ -136,11 +134,9 @@ return await createRouter({
|
||||
want to have those as well as your new one, you'll need to do the following:
|
||||
|
||||
```ts
|
||||
|
||||
import { createBuiltinActions } from '@backstage/plugin-scaffolder-backend`;
|
||||
import { createBuiltinActions } from '@backstage/plugin-scaffolder-backend';
|
||||
|
||||
const builtInActions = createBuiltinActions({
|
||||
dockerClient,
|
||||
integrations,
|
||||
catalogClient,
|
||||
templaters,
|
||||
@@ -155,7 +151,6 @@ return await createRouter({
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
database,
|
||||
catalogClient,
|
||||
reader,
|
||||
|
||||
@@ -148,6 +148,23 @@ jobs:
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-python@v2
|
||||
|
||||
# the 2 steps below can be removed if you aren't using plantuml in your documentation
|
||||
- name: setup java
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: '11'
|
||||
- name: download, validate, install plantuml and its dependencies
|
||||
run: |
|
||||
curl -o plantuml.jar -L http://sourceforge.net/projects/plantuml/files/plantuml.1.2021.4.jar/download
|
||||
echo "be498123d20eaea95a94b174d770ef94adfdca18 plantuml.jar" | sha1sum -c -
|
||||
mv plantuml.jar /opt/plantuml.jar
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
echo $'#!/bin/sh\n\njava -jar '/opt/plantuml.jar' ${@}' >> "$HOME/.local/bin/plantuml"
|
||||
chmod +x "$HOME/.local/bin/plantuml"
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
sudo apt-get install -y graphviz
|
||||
|
||||
- name: Install techdocs-cli
|
||||
run: sudo npm install -g @techdocs/cli
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ 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/
|
||||
# From your Backstage root directory
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-techdocs
|
||||
```
|
||||
@@ -54,7 +54,7 @@ Navigate to `packages/backend` of your Backstage app, and install the
|
||||
`@backstage/plugin-techdocs-backend` package.
|
||||
|
||||
```bash
|
||||
cd my-backstage-app/
|
||||
# From your Backstage root directory
|
||||
cd packages/backend
|
||||
yarn add @backstage/plugin-techdocs-backend
|
||||
```
|
||||
@@ -63,6 +63,7 @@ Create a file called `techdocs.ts` inside `packages/backend/src/plugins/` and
|
||||
add the following
|
||||
|
||||
```typescript
|
||||
import { DockerContainerRunner } from '@backstage/backend-common';
|
||||
import {
|
||||
createRouter,
|
||||
Generators,
|
||||
@@ -84,9 +85,14 @@ export default async function createPlugin({
|
||||
reader,
|
||||
});
|
||||
|
||||
// Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
const dockerClient = new Docker();
|
||||
const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
// Generators are used for generating documentation sites.
|
||||
const generators = await Generators.fromConfig(config, {
|
||||
logger,
|
||||
containerRunner,
|
||||
});
|
||||
|
||||
// Publisher is used for
|
||||
@@ -97,14 +103,13 @@ export default async function createPlugin({
|
||||
discovery,
|
||||
});
|
||||
|
||||
// Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
const dockerClient = new Docker();
|
||||
// checks if the publisher is working and logs the result
|
||||
await publisher.getReadiness();
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
generators,
|
||||
publisher,
|
||||
dockerClient,
|
||||
logger,
|
||||
config,
|
||||
discovery,
|
||||
|
||||
@@ -135,3 +135,31 @@ const themeOptions = createThemeOptions({
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Custom Logo
|
||||
|
||||
In addition to a custom theme, you can also customize the logo displayed at the
|
||||
far top left of the site.
|
||||
|
||||
In your frontend app, locate `src/components/Root/` folder. You'll find two
|
||||
components:
|
||||
|
||||
- `LogoFull.tsx` - A larger logo used when the Sidebar navigation is opened.
|
||||
- `LogoIcon.tsx` - A smaller logo used when the sidebar navigation is closed.
|
||||
|
||||
To replace the images, you can simply replace the relevant code in those
|
||||
components with raw SVG definitions.
|
||||
|
||||
You can also use another web image format such as PNG by importing it. To do
|
||||
this, place your new image into a new subdirectory such as
|
||||
`src/components/Root/logo/my-company-logo.png`, and then add this code:
|
||||
|
||||
```jsx
|
||||
import MyCustomLogoFull from './logo/my-company-logo.png';
|
||||
|
||||
//...
|
||||
|
||||
const LogoFull = () => {
|
||||
return <img src={MyCustomLogoFull} />;
|
||||
};
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: integrating-plugin-into-service-catalog
|
||||
title: Integrate into the Service Catalog
|
||||
description: Documentation on How to integrate plugin into service catalog
|
||||
description: How to integrate a plugin into service catalog
|
||||
---
|
||||
|
||||
> This is an advanced use case and currently is an experimental feature. Expect
|
||||
|
||||
@@ -17,11 +17,11 @@ switch between database backends.
|
||||
|
||||
## Install PostgreSQL
|
||||
|
||||
First, swap out SQLite for PostgreSQL in your `backend` package:
|
||||
First, add PostgreSQL to your `backend` package:
|
||||
|
||||
```shell
|
||||
# From your Backstage root directory
|
||||
cd packages/backend
|
||||
yarn remove sqlite3
|
||||
yarn add pg
|
||||
```
|
||||
|
||||
@@ -46,7 +46,6 @@ backend:
|
||||
+ #ssl: require # see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
|
||||
+ #ca: # if you have a CA file and want to verify it you can uncomment this section
|
||||
+ #$file: <file-path>/ca/server.crt
|
||||
|
||||
```
|
||||
|
||||
If you have an `app-config.local.yaml` for local development, a similar update
|
||||
|
||||
+20
-12
@@ -1,3 +1,9 @@
|
||||
# Backstage Documentation
|
||||
|
||||
This folder holds the service and configuration that runs Backstage's documentation hosted at https://backstage.io.
|
||||
|
||||
It pulls content in from the [root `/docs`](../docs/) folder and builds it into the resulting HTML web site.
|
||||
|
||||
This website was created with [Docusaurus](https://docusaurus.io/).
|
||||
|
||||
# What's In This Document
|
||||
@@ -10,6 +16,8 @@ This website was created with [Docusaurus](https://docusaurus.io/).
|
||||
|
||||
# Getting Started
|
||||
|
||||
Testing the web site locally is a great way to see what final website will look like after publishing, and is ideal for testing more complex changes, large updates to navigation, or complex page designs that may include special alignment, which may not otherwise be validated through continuous integration.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
@@ -22,7 +30,7 @@ $ yarn install
|
||||
$ yarn start
|
||||
```
|
||||
|
||||
This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.
|
||||
This command starts a local development server and opens up a browser window. Most content changes made to the `docs/` root folder are reflected live without having to restart the server.
|
||||
|
||||
## Build
|
||||
|
||||
@@ -57,9 +65,9 @@ my-docusaurus/
|
||||
siteConfig.js
|
||||
```
|
||||
|
||||
# Editing Content
|
||||
## Editing Content
|
||||
|
||||
## Editing an existing docs page
|
||||
### Editing an existing docs page
|
||||
|
||||
Edit docs by navigating to `docs/` and editing the corresponding document:
|
||||
|
||||
@@ -76,7 +84,7 @@ Edit me...
|
||||
|
||||
For more information about docs, click [here](https://docusaurus.io/docs/en/navigation)
|
||||
|
||||
## Editing an existing blog post
|
||||
### Editing an existing blog post
|
||||
|
||||
Edit blog posts by navigating to `website/blog` and editing the corresponding post:
|
||||
|
||||
@@ -93,9 +101,9 @@ Edit me...
|
||||
|
||||
For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog)
|
||||
|
||||
# Adding Content
|
||||
## Adding Content
|
||||
|
||||
## Adding a new docs page to an existing sidebar
|
||||
### Adding a new docs page to an existing sidebar
|
||||
|
||||
1. Create the doc as a new markdown file in `/docs`, example `docs/newly-created-doc.md`:
|
||||
|
||||
@@ -126,7 +134,7 @@ My new content here..
|
||||
|
||||
For more information about adding new docs, click [here](https://docusaurus.io/docs/en/navigation)
|
||||
|
||||
## Adding a new blog post
|
||||
### Adding a new blog post
|
||||
|
||||
1. Make sure there is a header link to your blog in `website/siteConfig.js`:
|
||||
|
||||
@@ -157,7 +165,7 @@ Lorem Ipsum...
|
||||
|
||||
For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog)
|
||||
|
||||
## Adding items to your site's top navigation bar
|
||||
### Adding items to your site's top navigation bar
|
||||
|
||||
1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`:
|
||||
|
||||
@@ -181,7 +189,7 @@ For more information about blog posts, click [here](https://docusaurus.io/docs/e
|
||||
|
||||
For more information about the navigation bar, click [here](https://docusaurus.io/docs/en/navigation)
|
||||
|
||||
## Adding custom pages
|
||||
### Adding custom pages
|
||||
|
||||
1. Docusaurus uses React components to build pages. The components are saved as .js files in `website/pages/en`:
|
||||
1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element:
|
||||
@@ -199,11 +207,11 @@ For more information about the navigation bar, click [here](https://docusaurus.i
|
||||
}
|
||||
```
|
||||
|
||||
For more information about custom pages, click [here](https://docusaurus.io/docs/en/custom-pages).
|
||||
Learn more about [Docusaurus custom pages](https://docusaurus.io/docs/en/custom-pages).
|
||||
|
||||
# Full Documentation
|
||||
## Full Documentation
|
||||
|
||||
Full documentation can be found on the [website](https://docusaurus.io/).
|
||||
Full documentation can be found on the [Docusaurus website](https://docusaurus.io/).
|
||||
|
||||
## Additional notes
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ The only thing you need to do is to start the app:
|
||||
|
||||
```bash
|
||||
cd my-app
|
||||
yarn start
|
||||
yarn dev
|
||||
```
|
||||
|
||||
And you are good to go! 👍
|
||||
@@ -101,18 +101,12 @@ We provide a collection of public Backstage plugins (look for packages with the
|
||||
Install in your app’s package folder (`<root>/packages/app`) with:
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-<plugin-name>
|
||||
```
|
||||
|
||||
Then add it to your app's `plugin.ts` file to import and register it:
|
||||
|
||||
`<root>/packages/app/src/plugin.ts`:
|
||||
|
||||
```js
|
||||
export { plugin as PluginName } from '@backstage/plugin-<plugin-name>';
|
||||
```
|
||||
|
||||
A plugin registers its own `route` in the app — read the documentation for the specific plugin you are installing for more information on that.
|
||||
After that, you inject the plugin into the application where you want it to be exposed. Please read the documentation for the specific plugin you are installing for more information.
|
||||
|
||||
### Creating an internal plugin
|
||||
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6f1b82b14]
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [f65adcde7]
|
||||
- Updated dependencies [81c54d1f2]
|
||||
- Updated dependencies [80888659b]
|
||||
- Updated dependencies [7b8272fb7]
|
||||
- Updated dependencies [8aedbb4af]
|
||||
- Updated dependencies [fc79a6dd3]
|
||||
- Updated dependencies [f53fba29f]
|
||||
- Updated dependencies [b2e2ec753]
|
||||
- Updated dependencies [9314a8592]
|
||||
- Updated dependencies [2e05277e0]
|
||||
- Updated dependencies [4075c6367]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/plugin-cost-insights@0.9.0
|
||||
- @backstage/plugin-catalog-import@0.5.5
|
||||
- @backstage/plugin-github-actions@0.4.5
|
||||
- @backstage/cli@0.6.10
|
||||
- @backstage/core@0.7.8
|
||||
- @backstage/plugin-catalog-react@0.1.5
|
||||
- @backstage/theme@0.2.7
|
||||
- @backstage/plugin-kubernetes@0.4.3
|
||||
- @backstage/plugin-tech-radar@0.3.10
|
||||
- @backstage/plugin-scaffolder@0.9.3
|
||||
- @backstage/plugin-techdocs@0.9.1
|
||||
- @backstage/catalog-model@0.7.8
|
||||
|
||||
## 0.2.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+14
-14
@@ -1,46 +1,46 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.26",
|
||||
"version": "0.2.27",
|
||||
"private": true,
|
||||
"bundled": true,
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.7",
|
||||
"@backstage/cli": "^0.6.9",
|
||||
"@backstage/core": "^0.7.7",
|
||||
"@backstage/catalog-model": "^0.7.8",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@backstage/core": "^0.7.8",
|
||||
"@backstage/integration-react": "^0.1.1",
|
||||
"@backstage/plugin-api-docs": "^0.4.12",
|
||||
"@backstage/plugin-badges": "^0.2.0",
|
||||
"@backstage/plugin-catalog": "^0.5.6",
|
||||
"@backstage/plugin-catalog-import": "^0.5.4",
|
||||
"@backstage/plugin-catalog-react": "^0.1.3",
|
||||
"@backstage/plugin-catalog-import": "^0.5.5",
|
||||
"@backstage/plugin-catalog-react": "^0.1.5",
|
||||
"@backstage/plugin-circleci": "^0.2.13",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.13",
|
||||
"@backstage/plugin-code-coverage": "^0.1.2",
|
||||
"@backstage/plugin-cost-insights": "^0.8.5",
|
||||
"@backstage/plugin-cost-insights": "^0.9.0",
|
||||
"@backstage/plugin-explore": "^0.3.4",
|
||||
"@backstage/plugin-gcp-projects": "^0.2.5",
|
||||
"@backstage/plugin-github-actions": "^0.4.4",
|
||||
"@backstage/plugin-github-actions": "^0.4.5",
|
||||
"@backstage/plugin-graphiql": "^0.2.10",
|
||||
"@backstage/plugin-jenkins": "^0.4.2",
|
||||
"@backstage/plugin-kafka": "^0.2.6",
|
||||
"@backstage/plugin-kubernetes": "^0.4.2",
|
||||
"@backstage/plugin-kubernetes": "^0.4.3",
|
||||
"@backstage/plugin-lighthouse": "^0.2.15",
|
||||
"@backstage/plugin-newrelic": "^0.2.6",
|
||||
"@backstage/plugin-org": "^0.3.12",
|
||||
"@backstage/plugin-pagerduty": "0.3.3",
|
||||
"@backstage/plugin-rollbar": "^0.3.4",
|
||||
"@backstage/plugin-scaffolder": "^0.9.2",
|
||||
"@backstage/plugin-scaffolder": "^0.9.3",
|
||||
"@backstage/plugin-search": "^0.3.5",
|
||||
"@backstage/plugin-sentry": "^0.3.9",
|
||||
"@backstage/plugin-shortcuts": "^0.1.1",
|
||||
"@backstage/plugin-tech-radar": "^0.3.9",
|
||||
"@backstage/plugin-techdocs": "^0.9.0",
|
||||
"@backstage/plugin-tech-radar": "^0.3.10",
|
||||
"@backstage/plugin-techdocs": "^0.9.1",
|
||||
"@backstage/plugin-todo": "^0.1.0",
|
||||
"@backstage/plugin-user-settings": "^0.2.8",
|
||||
"@backstage/theme": "^0.2.6",
|
||||
"@backstage/theme": "^0.2.7",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@octokit/rest": "^18.0.12",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"@roadiehq/backstage-plugin-buildkite": "^1.0.0",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^1.0.0",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^1.0.0",
|
||||
|
||||
@@ -1,5 +1,73 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- e0bfd3d44: Refactor the `runDockerContainer(…)` function to an interface-based api.
|
||||
This gives the option to replace the docker runtime in the future.
|
||||
|
||||
Packages and plugins that previously used the `dockerode` as argument should be migrated to use the new `ContainerRunner` interface instead.
|
||||
|
||||
```diff
|
||||
import {
|
||||
- runDockerContainer,
|
||||
+ ContainerRunner,
|
||||
PluginEndpointDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
- import Docker from 'dockerode';
|
||||
|
||||
type RouterOptions = {
|
||||
// ...
|
||||
- dockerClient: Docker,
|
||||
+ containerRunner: ContainerRunner;
|
||||
};
|
||||
|
||||
export async function createRouter({
|
||||
// ...
|
||||
- dockerClient,
|
||||
+ containerRunner,
|
||||
}: RouterOptions): Promise<express.Router> {
|
||||
// ...
|
||||
|
||||
+ await containerRunner.runContainer({
|
||||
- await runDockerContainer({
|
||||
image: 'docker',
|
||||
// ...
|
||||
- dockerClient,
|
||||
});
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
To keep the `dockerode` based runtime, use the `DockerContainerRunner` implementation:
|
||||
|
||||
```diff
|
||||
+ import {
|
||||
+ ContainerRunner,
|
||||
+ DockerContainerRunner
|
||||
+ } from '@backstage/backend-common';
|
||||
- import { runDockerContainer } from '@backstage/backend-common';
|
||||
|
||||
+ const containerRunner: ContainerRunner = new DockerContainerRunner({dockerClient});
|
||||
+ await containerRunner.runContainer({
|
||||
- await runDockerContainer({
|
||||
image: 'docker',
|
||||
// ...
|
||||
- dockerClient,
|
||||
});
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 38ca05168: The default `@octokit/rest` dependency was bumped to `"^18.5.3"`.
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/integration@0.5.2
|
||||
- @backstage/config-loader@0.6.1
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.6.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -8,6 +8,8 @@ error handling and similar.
|
||||
Add the library to your backend package:
|
||||
|
||||
```sh
|
||||
# From your Backstage root directory
|
||||
cd packages/backend
|
||||
yarn add @backstage/backend-common
|
||||
```
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import cors from 'cors';
|
||||
import Docker from 'dockerode';
|
||||
import { ErrorRequestHandler } from 'express';
|
||||
import express from 'express';
|
||||
import { Format } from 'logform';
|
||||
import { GithubCredentialsProvider } from '@backstage/integration';
|
||||
import { GitHubIntegration } from '@backstage/integration';
|
||||
import { GitLabIntegration } from '@backstage/integration';
|
||||
@@ -64,7 +63,13 @@ export class BitbucketUrlReader implements UrlReader {
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export const coloredFormat: Format;
|
||||
export const coloredFormat: winston.Logform.Format;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ContainerRunner {
|
||||
// (undocumented)
|
||||
runContainer(opts: RunContainerOptions): Promise<void>;
|
||||
}
|
||||
|
||||
// @public @deprecated
|
||||
export const createDatabase: typeof createDatabaseClient;
|
||||
@@ -81,6 +86,15 @@ export function createServiceBuilder(_module: NodeModule): ServiceBuilderImpl;
|
||||
// @public (undocumented)
|
||||
export function createStatusCheckRouter(options: StatusCheckRouterOptions): Promise<express.Router>;
|
||||
|
||||
// @public (undocumented)
|
||||
export class DockerContainerRunner implements ContainerRunner {
|
||||
constructor({ dockerClient }: {
|
||||
dockerClient: Docker;
|
||||
});
|
||||
// (undocumented)
|
||||
runContainer({ imageName, command, args, logStream, mountDirs, workingDir, envVars, }: RunContainerOptions): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export function ensureDatabaseExists(dbConfig: Config, ...databases: Array<string>): Promise<void>;
|
||||
|
||||
@@ -256,10 +270,15 @@ export function requestLoggingHandler(logger?: Logger): RequestHandler;
|
||||
export function resolvePackagePath(name: string, ...paths: string[]): string;
|
||||
|
||||
// @public (undocumented)
|
||||
export const runDockerContainer: ({ imageName, args, logStream, dockerClient, mountDirs, workingDir, envVars, createOptions, }: RunDockerContainerOptions) => Promise<{
|
||||
error: any;
|
||||
statusCode: any;
|
||||
}>;
|
||||
export type RunContainerOptions = {
|
||||
imageName: string;
|
||||
command?: string | string[];
|
||||
args: string[];
|
||||
logStream?: Writable;
|
||||
mountDirs?: Record<string, string>;
|
||||
workingDir?: string;
|
||||
envVars?: Record<string, string>;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SearchResponse = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.6.3",
|
||||
"version": "0.7.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -30,12 +30,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.1",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/config-loader": "^0.6.0",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/config-loader": "^0.6.1",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@backstage/integration": "^0.5.1",
|
||||
"@backstage/integration": "^0.5.2",
|
||||
"@google-cloud/storage": "^5.8.0",
|
||||
"@octokit/rest": "^18.0.12",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"@types/cors": "^2.8.6",
|
||||
"@types/dockerode": "^3.2.1",
|
||||
"@types/express": "^4.17.6",
|
||||
@@ -73,7 +73,7 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.9",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@backstage/test-utils": "^0.1.10",
|
||||
"@types/archiver": "^5.1.0",
|
||||
"@types/compression": "^1.7.0",
|
||||
|
||||
+13
-24
@@ -14,29 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ClusterLocatorMethod,
|
||||
CustomResource,
|
||||
} from '@backstage/plugin-kubernetes-backend';
|
||||
import { Writable } from 'stream';
|
||||
|
||||
export interface Config {
|
||||
kubernetes?: {
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
serviceLocatorMethod: {
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
type: 'multiTenant';
|
||||
};
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
clusterLocatorMethods: ClusterLocatorMethod[];
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
customResources?: CustomResource[];
|
||||
};
|
||||
export type RunContainerOptions = {
|
||||
imageName: string;
|
||||
command?: string | string[];
|
||||
args: string[];
|
||||
logStream?: Writable;
|
||||
mountDirs?: Record<string, string>;
|
||||
workingDir?: string;
|
||||
envVars?: Record<string, string>;
|
||||
};
|
||||
|
||||
export interface ContainerRunner {
|
||||
runContainer(opts: RunContainerOptions): Promise<void>;
|
||||
}
|
||||
+15
-16
@@ -13,17 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Docker from 'dockerode';
|
||||
import mockFs from 'mock-fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import Stream, { PassThrough } from 'stream';
|
||||
import { runDockerContainer, UserOptions } from './docker';
|
||||
import { ContainerRunner } from './ContainerRunner';
|
||||
import { DockerContainerRunner, UserOptions } from './DockerContainerRunner';
|
||||
|
||||
const mockDocker = new Docker() as jest.Mocked<Docker>;
|
||||
const rootDir = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir';
|
||||
|
||||
describe('runDockerContainer', () => {
|
||||
describe('DockerContainerRunner', () => {
|
||||
let containerTaskApi: ContainerRunner;
|
||||
|
||||
beforeEach(() => {
|
||||
mockFs({
|
||||
[rootDir]: {
|
||||
@@ -49,6 +53,8 @@ describe('runDockerContainer', () => {
|
||||
jest
|
||||
.spyOn(mockDocker, 'ping')
|
||||
.mockResolvedValue(Buffer.from('OK', 'utf-8'));
|
||||
|
||||
containerTaskApi = new DockerContainerRunner({ dockerClient: mockDocker });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -66,10 +72,9 @@ describe('runDockerContainer', () => {
|
||||
const envVarsArray = ['HOME=/tmp', 'LOG_LEVEL=debug'];
|
||||
|
||||
it('should pull the docker container', async () => {
|
||||
await runDockerContainer({
|
||||
await containerTaskApi.runContainer({
|
||||
imageName,
|
||||
args,
|
||||
dockerClient: mockDocker,
|
||||
});
|
||||
|
||||
expect(mockDocker.pull).toHaveBeenCalledWith(
|
||||
@@ -82,13 +87,12 @@ describe('runDockerContainer', () => {
|
||||
});
|
||||
|
||||
it('should call the dockerClient run command with the correct arguments passed through', async () => {
|
||||
await runDockerContainer({
|
||||
await containerTaskApi.runContainer({
|
||||
imageName,
|
||||
args,
|
||||
mountDirs,
|
||||
envVars,
|
||||
workingDir,
|
||||
dockerClient: mockDocker,
|
||||
});
|
||||
|
||||
expect(mockDocker.run).toHaveBeenCalledWith(
|
||||
@@ -113,20 +117,18 @@ describe('runDockerContainer', () => {
|
||||
});
|
||||
|
||||
it('should ping docker to test availability', async () => {
|
||||
await runDockerContainer({
|
||||
await containerTaskApi.runContainer({
|
||||
imageName,
|
||||
args,
|
||||
dockerClient: mockDocker,
|
||||
});
|
||||
|
||||
expect(mockDocker.ping).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass through the user and group id from the host machine and set the home dir', async () => {
|
||||
await runDockerContainer({
|
||||
await containerTaskApi.runContainer({
|
||||
imageName,
|
||||
args,
|
||||
dockerClient: mockDocker,
|
||||
});
|
||||
|
||||
const userOptions: UserOptions = {};
|
||||
@@ -153,10 +155,9 @@ describe('runDockerContainer', () => {
|
||||
]);
|
||||
|
||||
await expect(
|
||||
runDockerContainer({
|
||||
containerTaskApi.runContainer({
|
||||
imageName,
|
||||
args,
|
||||
dockerClient: mockDocker,
|
||||
}),
|
||||
).rejects.toThrow(/Something went wrong with docker/);
|
||||
});
|
||||
@@ -172,10 +173,9 @@ describe('runDockerContainer', () => {
|
||||
|
||||
it('should throw with a descriptive error message including the docker error message', async () => {
|
||||
await expect(
|
||||
runDockerContainer({
|
||||
containerTaskApi.runContainer({
|
||||
imageName,
|
||||
args,
|
||||
dockerClient: mockDocker,
|
||||
}),
|
||||
).rejects.toThrow(new RegExp(`.+: ${dockerError}`));
|
||||
});
|
||||
@@ -183,11 +183,10 @@ describe('runDockerContainer', () => {
|
||||
|
||||
it('should pass through the log stream to the docker client', async () => {
|
||||
const logStream = new PassThrough();
|
||||
await runDockerContainer({
|
||||
await containerTaskApi.runContainer({
|
||||
imageName,
|
||||
args,
|
||||
logStream,
|
||||
dockerClient: mockDocker,
|
||||
});
|
||||
|
||||
expect(mockDocker.run).toHaveBeenCalledWith(
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Docker from 'dockerode';
|
||||
import fs from 'fs-extra';
|
||||
import { PassThrough } from 'stream';
|
||||
import { ContainerRunner, RunContainerOptions } from './ContainerRunner';
|
||||
|
||||
export type UserOptions = {
|
||||
User?: string;
|
||||
};
|
||||
|
||||
export class DockerContainerRunner implements ContainerRunner {
|
||||
private readonly dockerClient: Docker;
|
||||
|
||||
constructor({ dockerClient }: { dockerClient: Docker }) {
|
||||
this.dockerClient = dockerClient;
|
||||
}
|
||||
|
||||
async runContainer({
|
||||
imageName,
|
||||
command,
|
||||
args,
|
||||
logStream = new PassThrough(),
|
||||
mountDirs = {},
|
||||
workingDir,
|
||||
envVars = {},
|
||||
}: RunContainerOptions) {
|
||||
// Show a better error message when Docker is unavailable.
|
||||
try {
|
||||
await this.dockerClient.ping();
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`This operation requires Docker. Docker does not appear to be available. Docker.ping() failed with: ${e.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
this.dockerClient.pull(imageName, {}, (err, stream) => {
|
||||
if (err) return reject(err);
|
||||
stream.pipe(logStream, { end: false });
|
||||
stream.on('end', () => resolve());
|
||||
stream.on('error', (error: Error) => reject(error));
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
|
||||
const userOptions: UserOptions = {};
|
||||
if (process.getuid && process.getgid) {
|
||||
// Files that are created inside the Docker container will be owned by
|
||||
// root on the host system on non Mac systems, because of reasons. Mainly the fact that
|
||||
// volume sharing is done using NFS on Mac and actual mounts in Linux world.
|
||||
// So we set the user in the container as the same user and group id as the host.
|
||||
// On Windows we don't have process.getuid nor process.getgid
|
||||
userOptions.User = `${process.getuid()}:${process.getgid()}`;
|
||||
}
|
||||
|
||||
// Initialize volumes to mount based on mountDirs map
|
||||
const Volumes: { [T: string]: object } = {};
|
||||
for (const containerDir of Object.values(mountDirs)) {
|
||||
Volumes[containerDir] = {};
|
||||
}
|
||||
|
||||
// Create bind volumes
|
||||
const Binds: string[] = [];
|
||||
for (const [hostDir, containerDir] of Object.entries(mountDirs)) {
|
||||
// Need to use realpath here as Docker mounting does not like
|
||||
// symlinks for binding volumes
|
||||
const realHostDir = await fs.realpath(hostDir);
|
||||
Binds.push(`${realHostDir}:${containerDir}`);
|
||||
}
|
||||
|
||||
// Create docker environment variables array
|
||||
const Env = [];
|
||||
for (const [key, value] of Object.entries(envVars)) {
|
||||
Env.push(`${key}=${value}`);
|
||||
}
|
||||
|
||||
const [
|
||||
{ Error: error, StatusCode: statusCode },
|
||||
] = await this.dockerClient.run(imageName, args, logStream, {
|
||||
Volumes,
|
||||
HostConfig: {
|
||||
Binds,
|
||||
},
|
||||
...(workingDir ? { WorkingDir: workingDir } : {}),
|
||||
Entrypoint: command,
|
||||
Env,
|
||||
...userOptions,
|
||||
} as Docker.ContainerCreateOptions);
|
||||
|
||||
if (error) {
|
||||
throw new Error(
|
||||
`Docker failed to run with the following error message: ${error}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (statusCode !== 0) {
|
||||
throw new Error(
|
||||
`Docker container returned a non-zero exit code (${statusCode})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Docker from 'dockerode';
|
||||
import fs from 'fs-extra';
|
||||
import { PassThrough, Writable } from 'stream';
|
||||
|
||||
export type UserOptions = {
|
||||
User?: string;
|
||||
};
|
||||
|
||||
export type RunDockerContainerOptions = {
|
||||
imageName: string;
|
||||
args: string[];
|
||||
logStream?: Writable;
|
||||
dockerClient: Docker;
|
||||
mountDirs?: Record<string, string>;
|
||||
workingDir?: string;
|
||||
envVars?: Record<string, string>;
|
||||
createOptions?: Docker.ContainerCreateOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param options the options object
|
||||
* @param options.imageName the image to run
|
||||
* @param options.args the arguments to pass the container
|
||||
* @param options.logStream the log streamer to capture log messages
|
||||
* @param options.dockerClient the dockerClient to use
|
||||
* @param options.mountDirs A map of host directories to mount on the container.
|
||||
* Object Key: Path on host machine, Value: Path on Docker container
|
||||
* @param options.workingDir Working dir in the container
|
||||
* @param options.envVars Environment variables to set in the container. e.g. {'HOME': '/tmp'}
|
||||
*/
|
||||
export const runDockerContainer = async ({
|
||||
imageName,
|
||||
args,
|
||||
logStream = new PassThrough(),
|
||||
dockerClient,
|
||||
mountDirs = {},
|
||||
workingDir,
|
||||
envVars = {},
|
||||
createOptions = {},
|
||||
}: RunDockerContainerOptions) => {
|
||||
// Show a better error message when Docker is unavailable.
|
||||
try {
|
||||
await dockerClient.ping();
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`This operation requires Docker. Docker does not appear to be available. Docker.ping() failed with: ${e.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
dockerClient.pull(imageName, {}, (err, stream) => {
|
||||
if (err) return reject(err);
|
||||
stream.pipe(logStream, { end: false });
|
||||
stream.on('end', () => resolve());
|
||||
stream.on('error', (error: Error) => reject(error));
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
|
||||
const userOptions: UserOptions = {};
|
||||
if (process.getuid && process.getgid) {
|
||||
// Files that are created inside the Docker container will be owned by
|
||||
// root on the host system on non Mac systems, because of reasons. Mainly the fact that
|
||||
// volume sharing is done using NFS on Mac and actual mounts in Linux world.
|
||||
// So we set the user in the container as the same user and group id as the host.
|
||||
// On Windows we don't have process.getuid nor process.getgid
|
||||
userOptions.User = `${process.getuid()}:${process.getgid()}`;
|
||||
}
|
||||
|
||||
// Initialize volumes to mount based on mountDirs map
|
||||
const Volumes: { [T: string]: object } = {};
|
||||
for (const containerDir of Object.values(mountDirs)) {
|
||||
Volumes[containerDir] = {};
|
||||
}
|
||||
|
||||
// Create bind volumes
|
||||
const Binds: string[] = [];
|
||||
for (const [hostDir, containerDir] of Object.entries(mountDirs)) {
|
||||
// Need to use realpath here as Docker mounting does not like
|
||||
// symlinks for binding volumes
|
||||
const realHostDir = await fs.realpath(hostDir);
|
||||
Binds.push(`${realHostDir}:${containerDir}`);
|
||||
}
|
||||
|
||||
// Create docker environment variables array
|
||||
const Env = [];
|
||||
for (const [key, value] of Object.entries(envVars)) {
|
||||
Env.push(`${key}=${value}`);
|
||||
}
|
||||
|
||||
const [{ Error: error, StatusCode: statusCode }] = await dockerClient.run(
|
||||
imageName,
|
||||
args,
|
||||
logStream,
|
||||
{
|
||||
Volumes,
|
||||
HostConfig: {
|
||||
Binds,
|
||||
},
|
||||
...(workingDir ? { WorkingDir: workingDir } : {}),
|
||||
Env,
|
||||
...userOptions,
|
||||
...createOptions,
|
||||
},
|
||||
);
|
||||
|
||||
if (error) {
|
||||
throw new Error(
|
||||
`Docker failed to run with the following error message: ${error}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (statusCode !== 0) {
|
||||
throw new Error(
|
||||
`Docker container returned a non-zero exit code (${statusCode})`,
|
||||
);
|
||||
}
|
||||
|
||||
return { error, statusCode };
|
||||
};
|
||||
@@ -14,4 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { runDockerContainer } from './docker';
|
||||
export type { ContainerRunner, RunContainerOptions } from './ContainerRunner';
|
||||
export { DockerContainerRunner } from './DockerContainerRunner';
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [b219821a0]
|
||||
- Updated dependencies [69eefb5ae]
|
||||
- Updated dependencies [f53fba29f]
|
||||
- Updated dependencies [75c8cec39]
|
||||
- Updated dependencies [227439a72]
|
||||
- Updated dependencies [cdb3426e5]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- Updated dependencies [d1b1306d9]
|
||||
- @backstage/plugin-scaffolder-backend@0.11.0
|
||||
- @backstage/backend-common@0.7.0
|
||||
- @backstage/plugin-techdocs-backend@0.8.0
|
||||
- @backstage/plugin-catalog-backend@0.8.2
|
||||
- @backstage/plugin-kubernetes-backend@0.3.6
|
||||
- @backstage/plugin-proxy-backend@0.2.7
|
||||
- @backstage/catalog-model@0.7.8
|
||||
- @backstage/config@0.1.5
|
||||
- @backstage/catalog-client@0.3.11
|
||||
- example-app@0.2.27
|
||||
- @backstage/plugin-app-backend@0.3.12
|
||||
- @backstage/plugin-auth-backend@0.3.9
|
||||
- @backstage/plugin-badges-backend@0.1.3
|
||||
- @backstage/plugin-code-coverage-backend@0.1.4
|
||||
- @backstage/plugin-graphql-backend@0.1.7
|
||||
- @backstage/plugin-kafka-backend@0.2.4
|
||||
- @backstage/plugin-rollbar-backend@0.1.10
|
||||
- @backstage/plugin-search-backend@0.1.4
|
||||
- @backstage/plugin-todo-backend@0.1.4
|
||||
|
||||
## 0.2.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.25",
|
||||
"version": "0.2.27",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -27,30 +27,30 @@
|
||||
"migrate:create": "knex migrate:make -x ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.6.3",
|
||||
"@backstage/catalog-client": "^0.3.9",
|
||||
"@backstage/catalog-model": "^0.7.5",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/plugin-app-backend": "^0.3.10",
|
||||
"@backstage/plugin-auth-backend": "^0.3.7",
|
||||
"@backstage/plugin-badges-backend": "^0.1.1",
|
||||
"@backstage/plugin-catalog-backend": "^0.8.0",
|
||||
"@backstage/plugin-code-coverage-backend": "^0.1.2",
|
||||
"@backstage/plugin-graphql-backend": "^0.1.6",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.3.5",
|
||||
"@backstage/plugin-kafka-backend": "^0.2.3",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.6",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.9",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.10.0",
|
||||
"@backstage/plugin-search-backend": "^0.1.3",
|
||||
"@backstage/backend-common": "^0.7.0",
|
||||
"@backstage/catalog-client": "^0.3.11",
|
||||
"@backstage/catalog-model": "^0.7.8",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/plugin-app-backend": "^0.3.12",
|
||||
"@backstage/plugin-auth-backend": "^0.3.9",
|
||||
"@backstage/plugin-badges-backend": "^0.1.3",
|
||||
"@backstage/plugin-catalog-backend": "^0.8.2",
|
||||
"@backstage/plugin-code-coverage-backend": "^0.1.4",
|
||||
"@backstage/plugin-graphql-backend": "^0.1.7",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.3.6",
|
||||
"@backstage/plugin-kafka-backend": "^0.2.4",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.7",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.10",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.11.0",
|
||||
"@backstage/plugin-search-backend": "^0.1.4",
|
||||
"@backstage/plugin-search-backend-node": "^0.1.3",
|
||||
"@backstage/plugin-techdocs-backend": "^0.7.0",
|
||||
"@backstage/plugin-todo-backend": "^0.1.3",
|
||||
"@backstage/plugin-techdocs-backend": "^0.8.0",
|
||||
"@backstage/plugin-todo-backend": "^0.1.4",
|
||||
"@gitbeaker/node": "^28.0.2",
|
||||
"@octokit/rest": "^18.0.12",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"azure-devops-node-api": "^10.1.1",
|
||||
"dockerode": "^3.2.1",
|
||||
"example-app": "^0.2.25",
|
||||
"example-app": "^0.2.27",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"knex": "^0.95.1",
|
||||
@@ -60,7 +60,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.9",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@types/dockerode": "^3.2.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/express-serve-static-core": "^4.17.5"
|
||||
|
||||
@@ -42,7 +42,7 @@ export default async function createPlugin(
|
||||
} = await builder.build();
|
||||
|
||||
// TODO(jhaals): run and manage in background.
|
||||
processingEngine.start();
|
||||
await processingEngine.start();
|
||||
|
||||
return await createRouter({
|
||||
entitiesCatalog,
|
||||
|
||||
@@ -15,12 +15,11 @@
|
||||
*/
|
||||
|
||||
import { createRouter } from '@backstage/plugin-kubernetes-backend';
|
||||
import { Router } from 'express';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
config,
|
||||
}: PluginEnvironment): Promise<Router> {
|
||||
}: PluginEnvironment) {
|
||||
return await createRouter({ logger, config });
|
||||
}
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { SingleHostDiscovery } from '@backstage/backend-common';
|
||||
import {
|
||||
DockerContainerRunner,
|
||||
SingleHostDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
import { CatalogClient } from '@backstage/catalog-client';
|
||||
import {
|
||||
CookieCutter,
|
||||
@@ -34,8 +37,11 @@ export default async function createPlugin({
|
||||
database,
|
||||
reader,
|
||||
}: PluginEnvironment): Promise<Router> {
|
||||
const cookiecutterTemplater = new CookieCutter();
|
||||
const craTemplater = new CreateReactAppTemplater();
|
||||
const dockerClient = new Docker();
|
||||
const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
const cookiecutterTemplater = new CookieCutter({ containerRunner });
|
||||
const craTemplater = new CreateReactAppTemplater({ containerRunner });
|
||||
const templaters = new Templaters();
|
||||
|
||||
templaters.register('cookiecutter', cookiecutterTemplater);
|
||||
@@ -44,8 +50,6 @@ export default async function createPlugin({
|
||||
const preparers = await Preparers.fromConfig(config, { logger });
|
||||
const publishers = await Publishers.fromConfig(config, { logger });
|
||||
|
||||
const dockerClient = new Docker();
|
||||
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const catalogClient = new CatalogClient({ discoveryApi: discovery });
|
||||
|
||||
@@ -55,7 +59,6 @@ export default async function createPlugin({
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
database,
|
||||
catalogClient,
|
||||
reader,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { DockerContainerRunner } from '@backstage/backend-common';
|
||||
import {
|
||||
createRouter,
|
||||
Generators,
|
||||
@@ -35,9 +36,14 @@ export default async function createPlugin({
|
||||
reader,
|
||||
});
|
||||
|
||||
// Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
const dockerClient = new Docker();
|
||||
const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
// Generators are used for generating documentation sites.
|
||||
const generators = await Generators.fromConfig(config, {
|
||||
logger,
|
||||
containerRunner,
|
||||
});
|
||||
|
||||
// Publisher is used for
|
||||
@@ -51,14 +57,10 @@ export default async function createPlugin({
|
||||
// checks if the publisher is working and logs the result
|
||||
await publisher.getReadiness();
|
||||
|
||||
// Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
const dockerClient = new Docker();
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
generators,
|
||||
publisher,
|
||||
dockerClient,
|
||||
logger,
|
||||
config,
|
||||
discovery,
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/catalog-client
|
||||
|
||||
## 0.3.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d1b1306d9: Allow `filter` parameter to be specified multiple times
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/catalog-model@0.7.8
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.3.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/catalog-client",
|
||||
"version": "0.3.10",
|
||||
"version": "0.3.11",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,13 +29,13 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.7",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/catalog-model": "^0.7.8",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"cross-fetch": "^3.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.8",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@types/jest": "^26.0.7",
|
||||
"msw": "^0.21.2"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/catalog-model
|
||||
|
||||
## 0.7.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d8b81fd28: Bump `json-schema` dependency from `0.2.5` to `0.3.0`.
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.7.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/catalog-model",
|
||||
"version": "0.7.7",
|
||||
"version": "0.7.8",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,7 +29,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@types/json-schema": "^7.0.5",
|
||||
"@types/yup": "^0.29.8",
|
||||
"ajv": "^7.0.3",
|
||||
@@ -39,7 +39,7 @@
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.8",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/lodash": "^4.14.151",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.6.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- f65adcde7: Fix some transitive dependency warnings in yarn
|
||||
- fc79a6dd3: Added lax option to backstage-cli app:build command
|
||||
- d8b81fd28: Bump `json-schema` dependency from `0.2.5` to `0.3.0`.
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/config-loader@0.6.1
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.6.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -7,13 +7,13 @@ This package provides a CLI for developing Backstage plugins and apps.
|
||||
Install the package via npm or Yarn:
|
||||
|
||||
```sh
|
||||
$ npm install --save @backstage/cli
|
||||
npm install --save @backstage/cli
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
$ yarn add @backstage/cli
|
||||
yarn add @backstage/cli
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"version": "0.6.9",
|
||||
"version": "0.6.10",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -31,8 +31,8 @@
|
||||
"@babel/core": "^7.4.4",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.4.4",
|
||||
"@backstage/cli-common": "^0.1.1",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/config-loader": "^0.6.0",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/config-loader": "^0.6.1",
|
||||
"@hot-loader/react-dom": "^16.13.0",
|
||||
"@lerna/package-graph": "^4.0.0",
|
||||
"@lerna/project": "^4.0.0",
|
||||
@@ -86,6 +86,7 @@
|
||||
"lodash": "^4.17.19",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"ora": "^5.3.0",
|
||||
"postcss": "^8.1.0",
|
||||
"raw-loader": "^4.0.1",
|
||||
"react": "^16.0.0",
|
||||
"react-dev-utils": "^11.0.4",
|
||||
@@ -116,12 +117,12 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "^0.6.3",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/core": "^0.7.6",
|
||||
"@backstage/backend-common": "^0.7.0",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/core": "^0.7.8",
|
||||
"@backstage/dev-utils": "^0.1.13",
|
||||
"@backstage/test-utils": "^0.1.10",
|
||||
"@backstage/theme": "^0.2.6",
|
||||
"@backstage/theme": "^0.2.7",
|
||||
"@types/diff": "^5.0.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
|
||||
@@ -30,6 +30,7 @@ export default async (cmd: Command) => {
|
||||
...(await loadCliConfig({
|
||||
args: cmd.config,
|
||||
fromPackage: name,
|
||||
mockEnv: cmd.lax,
|
||||
})),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ export function registerCommands(program: CommanderStatic) {
|
||||
.command('app:build')
|
||||
.description('Build an app for a production release')
|
||||
.option('--stats', 'Write bundle stats to output directory')
|
||||
.option('--lax', 'Do not require environment variables to be set')
|
||||
.option(...configOption)
|
||||
.action(lazy(() => import('./app/build').then(m => m.default)));
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/config-loader
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d8b81fd28: Bump `json-schema` dependency from `0.2.5` to `0.3.0`.
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/config-loader",
|
||||
"description": "Config loading functionality used by Backstage backend, and CLI",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.1",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -31,7 +31,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.1",
|
||||
"@backstage/config": "^0.1.1",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@types/json-schema": "^7.0.6",
|
||||
"ajv": "^7.0.3",
|
||||
"fs-extra": "^9.0.0",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/config
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d8b81fd28: Bump `json-schema` dependency from `0.2.5` to `0.3.0`.
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/config",
|
||||
"description": "Config API used by Backstage core, backend, and CLI",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
@@ -7,13 +7,13 @@ This package provides the core API used by Backstage plugins and apps.
|
||||
Do not install this package directly, it is reexported by `@backstage/core`. Install that instead:
|
||||
|
||||
```sh
|
||||
$ npm install --save @backstage/core
|
||||
npm install --save @backstage/core
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
$ yarn add @backstage/core
|
||||
yarn add @backstage/core
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/core
|
||||
|
||||
## 0.7.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- f65adcde7: Fix some transitive dependency warnings in yarn
|
||||
- 80888659b: Bump react-hook-form version to be the same for the entire project.
|
||||
- Updated dependencies [7b8272fb7]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/theme@0.2.7
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.7.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -7,13 +7,13 @@ This package provides the core API used by Backstage plugins and apps.
|
||||
Install the package via npm or Yarn:
|
||||
|
||||
```sh
|
||||
$ npm install --save @backstage/core
|
||||
npm install --save @backstage/core
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
$ yarn add @backstage/core
|
||||
yarn add @backstage/core
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/core",
|
||||
"description": "Core API used by Backstage plugins and apps",
|
||||
"version": "0.7.7",
|
||||
"version": "0.7.8",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -29,10 +29,10 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/core-api": "^0.2.17",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@backstage/theme": "^0.2.6",
|
||||
"@backstage/theme": "^0.2.7",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.45",
|
||||
@@ -48,6 +48,7 @@
|
||||
"d3-shape": "^2.0.0",
|
||||
"d3-zoom": "^2.0.0",
|
||||
"dagre": "^0.8.5",
|
||||
"history": "^5.0.0",
|
||||
"immer": "^9.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
"material-table": "^1.69.1",
|
||||
@@ -57,7 +58,7 @@
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-helmet": "6.1.0",
|
||||
"react-hook-form": "^6.6.0",
|
||||
"react-hook-form": "^6.15.4",
|
||||
"react-markdown": "^5.0.2",
|
||||
"react-router": "6.0.0-beta.0",
|
||||
"react-router-dom": "6.0.0-beta.0",
|
||||
@@ -69,7 +70,7 @@
|
||||
"zen-observable": "^0.8.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.9",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@backstage/test-utils": "^0.1.10",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -1,5 +1,162 @@
|
||||
# @backstage/create-app
|
||||
|
||||
## 0.3.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 38ca05168: The default `@octokit/rest` dependency was bumped to `"^18.5.3"`.
|
||||
- e0bfd3d44: The `scaffolder-backend` and `techdocs-backend` plugins have been updated.
|
||||
In order to update, you need to apply the following changes to your existing backend application:
|
||||
|
||||
`@backstage/plugin-techdocs-backend`:
|
||||
|
||||
```diff
|
||||
// packages/backend/src/plugin/techdocs.ts
|
||||
|
||||
+ import { DockerContainerRunner } from '@backstage/backend-common';
|
||||
|
||||
// ...
|
||||
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
config,
|
||||
discovery,
|
||||
reader,
|
||||
}: PluginEnvironment): Promise<Router> {
|
||||
// Preparers are responsible for fetching source files for documentation.
|
||||
const preparers = await Preparers.fromConfig(config, {
|
||||
logger,
|
||||
reader,
|
||||
});
|
||||
|
||||
+ // Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
+ const dockerClient = new Docker();
|
||||
+ const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
// Generators are used for generating documentation sites.
|
||||
const generators = await Generators.fromConfig(config, {
|
||||
logger,
|
||||
+ containerRunner,
|
||||
});
|
||||
|
||||
// Publisher is used for
|
||||
// 1. Publishing generated files to storage
|
||||
// 2. Fetching files from storage and passing them to TechDocs frontend.
|
||||
const publisher = await Publisher.fromConfig(config, {
|
||||
logger,
|
||||
discovery,
|
||||
});
|
||||
|
||||
// checks if the publisher is working and logs the result
|
||||
await publisher.getReadiness();
|
||||
|
||||
- // Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
- const dockerClient = new Docker();
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
generators,
|
||||
publisher,
|
||||
- dockerClient,
|
||||
logger,
|
||||
config,
|
||||
discovery,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
`@backstage/plugin-scaffolder-backend`:
|
||||
|
||||
```diff
|
||||
// packages/backend/src/plugin/scaffolder.ts
|
||||
|
||||
- import { SingleHostDiscovery } from '@backstage/backend-common';
|
||||
+ import {
|
||||
+ DockerContainerRunner,
|
||||
+ SingleHostDiscovery,
|
||||
+ } from '@backstage/backend-common';
|
||||
|
||||
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
config,
|
||||
database,
|
||||
reader,
|
||||
}: PluginEnvironment): Promise<Router> {
|
||||
+ const dockerClient = new Docker();
|
||||
+ const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
+ const cookiecutterTemplater = new CookieCutter({ containerRunner });
|
||||
- const cookiecutterTemplater = new CookieCutter();
|
||||
+ const craTemplater = new CreateReactAppTemplater({ containerRunner });
|
||||
- const craTemplater = new CreateReactAppTemplater();
|
||||
const templaters = new Templaters();
|
||||
|
||||
templaters.register('cookiecutter', cookiecutterTemplater);
|
||||
templaters.register('cra', craTemplater);
|
||||
|
||||
const preparers = await Preparers.fromConfig(config, { logger });
|
||||
const publishers = await Publishers.fromConfig(config, { logger });
|
||||
|
||||
- const dockerClient = new Docker();
|
||||
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const catalogClient = new CatalogClient({ discoveryApi: discovery });
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
templaters,
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
- dockerClient,
|
||||
database,
|
||||
catalogClient,
|
||||
reader,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [f65adcde7]
|
||||
- Updated dependencies [80888659b]
|
||||
- Updated dependencies [b219821a0]
|
||||
- Updated dependencies [7b8272fb7]
|
||||
- Updated dependencies [8aedbb4af]
|
||||
- Updated dependencies [fc79a6dd3]
|
||||
- Updated dependencies [69eefb5ae]
|
||||
- Updated dependencies [75c8cec39]
|
||||
- Updated dependencies [b2e2ec753]
|
||||
- Updated dependencies [227439a72]
|
||||
- Updated dependencies [9314a8592]
|
||||
- Updated dependencies [2e05277e0]
|
||||
- Updated dependencies [4075c6367]
|
||||
- Updated dependencies [cdb3426e5]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- Updated dependencies [d1b1306d9]
|
||||
- @backstage/plugin-scaffolder-backend@0.11.0
|
||||
- @backstage/backend-common@0.7.0
|
||||
- @backstage/plugin-techdocs-backend@0.8.0
|
||||
- @backstage/plugin-catalog-import@0.5.5
|
||||
- @backstage/plugin-github-actions@0.4.5
|
||||
- @backstage/cli@0.6.10
|
||||
- @backstage/core@0.7.8
|
||||
- @backstage/plugin-catalog-backend@0.8.2
|
||||
- @backstage/theme@0.2.7
|
||||
- @backstage/plugin-tech-radar@0.3.10
|
||||
- @backstage/plugin-scaffolder@0.9.3
|
||||
- @backstage/plugin-techdocs@0.9.1
|
||||
- @backstage/plugin-proxy-backend@0.2.7
|
||||
- @backstage/catalog-model@0.7.8
|
||||
- @backstage/config@0.1.5
|
||||
- @backstage/catalog-client@0.3.11
|
||||
- @backstage/plugin-app-backend@0.3.12
|
||||
- @backstage/plugin-auth-backend@0.3.9
|
||||
- @backstage/plugin-rollbar-backend@0.1.10
|
||||
|
||||
## 0.3.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/create-app",
|
||||
"description": "Create app package for Backstage",
|
||||
"version": "0.3.20",
|
||||
"version": "0.3.21",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"@backstage/plugin-scaffolder-backend": "^{{version '@backstage/plugin-scaffolder-backend'}}",
|
||||
"@backstage/plugin-techdocs-backend": "^{{version '@backstage/plugin-techdocs-backend'}}",
|
||||
"@gitbeaker/node": "^28.0.2",
|
||||
"@octokit/rest": "^18.0.12",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"dockerode": "^3.2.1",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
|
||||
+11
-8
@@ -1,4 +1,7 @@
|
||||
import { SingleHostDiscovery } from '@backstage/backend-common';
|
||||
import {
|
||||
DockerContainerRunner,
|
||||
SingleHostDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
import { CatalogClient } from '@backstage/catalog-client';
|
||||
import {
|
||||
CookieCutter,
|
||||
@@ -6,7 +9,7 @@ import {
|
||||
createRouter,
|
||||
Preparers,
|
||||
Publishers,
|
||||
Templaters
|
||||
Templaters,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
import Docker from 'dockerode';
|
||||
import { Router } from 'express';
|
||||
@@ -18,8 +21,11 @@ export default async function createPlugin({
|
||||
database,
|
||||
reader,
|
||||
}: PluginEnvironment): Promise<Router> {
|
||||
const cookiecutterTemplater = new CookieCutter();
|
||||
const craTemplater = new CreateReactAppTemplater();
|
||||
const dockerClient = new Docker();
|
||||
const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
const cookiecutterTemplater = new CookieCutter({ containerRunner });
|
||||
const craTemplater = new CreateReactAppTemplater({ containerRunner });
|
||||
const templaters = new Templaters();
|
||||
|
||||
templaters.register('cookiecutter', cookiecutterTemplater);
|
||||
@@ -28,8 +34,6 @@ export default async function createPlugin({
|
||||
const preparers = await Preparers.fromConfig(config, { logger });
|
||||
const publishers = await Publishers.fromConfig(config, { logger });
|
||||
|
||||
const dockerClient = new Docker();
|
||||
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const catalogClient = new CatalogClient({ discoveryApi: discovery });
|
||||
|
||||
@@ -39,9 +43,8 @@ export default async function createPlugin({
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
database,
|
||||
catalogClient,
|
||||
reader
|
||||
reader,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { DockerContainerRunner } from '@backstage/backend-common';
|
||||
import {
|
||||
createRouter,
|
||||
|
||||
Generators, Preparers,
|
||||
|
||||
Publisher
|
||||
Generators,
|
||||
Preparers,
|
||||
Publisher,
|
||||
} from '@backstage/plugin-techdocs-backend';
|
||||
import Docker from 'dockerode';
|
||||
import { Router } from 'express';
|
||||
@@ -21,9 +21,14 @@ export default async function createPlugin({
|
||||
reader,
|
||||
});
|
||||
|
||||
// Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
const dockerClient = new Docker();
|
||||
const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
// Generators are used for generating documentation sites.
|
||||
const generators = await Generators.fromConfig(config, {
|
||||
logger,
|
||||
containerRunner,
|
||||
});
|
||||
|
||||
// Publisher is used for
|
||||
@@ -37,14 +42,10 @@ export default async function createPlugin({
|
||||
// checks if the publisher is working and logs the result
|
||||
await publisher.getReadiness();
|
||||
|
||||
// Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
const dockerClient = new Docker();
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
generators,
|
||||
publisher,
|
||||
dockerClient,
|
||||
logger,
|
||||
config,
|
||||
discovery,
|
||||
|
||||
@@ -9,13 +9,13 @@ This package provides utilities that help in developing plugins for Backstage, l
|
||||
Install the package via npm or Yarn:
|
||||
|
||||
```sh
|
||||
$ npm install --save-dev @backstage/dev-utils
|
||||
npm install --save-dev @backstage/dev-utils
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
$ yarn add -D @backstage/dev-utils
|
||||
yarn add -D @backstage/dev-utils
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/integration
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 38ca05168: The default `@octokit/rest` dependency was bumped to `"^18.5.3"`.
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/integration",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,16 +29,16 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"cross-fetch": "^3.0.6",
|
||||
"git-url-parse": "^11.4.4",
|
||||
"@octokit/rest": "^18.0.12",
|
||||
"@octokit/auth-app": "^2.10.5",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"@octokit/auth-app": "^3.4.0",
|
||||
"luxon": "^1.25.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.7",
|
||||
"@backstage/config-loader": "^0.6.0",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@backstage/config-loader": "^0.6.1",
|
||||
"@backstage/test-utils": "^0.1.10",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/luxon": "^1.25.0",
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/theme": "^0.2.0"
|
||||
"@backstage/theme": "^0.2.0",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-actions": "^6.1.11",
|
||||
|
||||
@@ -1,5 +1,45 @@
|
||||
# @backstage/techdocs-common
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- e0bfd3d44: Migrate the package to use the `ContainerRunner` interface instead of `runDockerContainer(…)`.
|
||||
It also no longer provides the `ContainerRunner` as an input to the `GeneratorBase#run(…)` function, but expects it as a constructor parameter instead.
|
||||
|
||||
If you use the `TechdocsGenerator` you need to update the usage:
|
||||
|
||||
```diff
|
||||
+ const containerRunner = new DockerContainerRunner({ dockerClient });
|
||||
|
||||
- const generator = new TechdocsGenerator(logger, config);
|
||||
+ const techdocsGenerator = new TechdocsGenerator({
|
||||
+ logger,
|
||||
+ containerRunner,
|
||||
+ config,
|
||||
+ });
|
||||
|
||||
await this.generator.run({
|
||||
inputDir: preparedDir,
|
||||
outputDir,
|
||||
- dockerClient: this.dockerClient,
|
||||
parsedLocationAnnotation,
|
||||
etag: newEtag,
|
||||
});
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e9e56b01a: Adding optional config to enable S3-like API for tech-docs using s3ForcePathStyle option.
|
||||
This allows providers like LocalStack, Minio and Wasabi (+possibly others) to be used to host tech docs.
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/backend-common@0.7.0
|
||||
- @backstage/integration@0.5.2
|
||||
- @backstage/catalog-model@0.7.8
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { AzureIntegrationConfig } from '@backstage/integration';
|
||||
import { Config } from '@backstage/config';
|
||||
import Docker from 'dockerode';
|
||||
import { ContainerRunner } from '@backstage/backend-common';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { EntityName } from '@backstage/catalog-model';
|
||||
import express from 'express';
|
||||
@@ -50,8 +50,9 @@ export type GeneratorBuilder = {
|
||||
// @public (undocumented)
|
||||
export class Generators implements GeneratorBuilder {
|
||||
// (undocumented)
|
||||
static fromConfig(config: Config, { logger }: {
|
||||
static fromConfig(config: Config, { logger, containerRunner, }: {
|
||||
logger: Logger;
|
||||
containerRunner: ContainerRunner;
|
||||
}): Promise<GeneratorBuilder>;
|
||||
// (undocumented)
|
||||
get(entity: Entity): GeneratorBase;
|
||||
@@ -151,9 +152,13 @@ export type RemoteProtocol = 'url' | 'dir' | 'github' | 'gitlab' | 'file' | 'azu
|
||||
|
||||
// @public (undocumented)
|
||||
export class TechdocsGenerator implements GeneratorBase {
|
||||
constructor(logger: Logger, config: Config);
|
||||
constructor({ logger, containerRunner, config, }: {
|
||||
logger: Logger;
|
||||
containerRunner: ContainerRunner;
|
||||
config: Config;
|
||||
});
|
||||
// (undocumented)
|
||||
run({ inputDir, outputDir, dockerClient, parsedLocationAnnotation, etag, }: GeneratorRunOptions): Promise<void>;
|
||||
run({ inputDir, outputDir, parsedLocationAnnotation, etag, }: GeneratorRunOptions): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/techdocs-common",
|
||||
"description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli",
|
||||
"version": "0.5.1",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -38,17 +38,15 @@
|
||||
"dependencies": {
|
||||
"@azure/identity": "^1.2.2",
|
||||
"@azure/storage-blob": "^12.4.0",
|
||||
"@backstage/backend-common": "^0.6.0",
|
||||
"@backstage/catalog-model": "^0.7.7",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/backend-common": "^0.7.0",
|
||||
"@backstage/catalog-model": "^0.7.8",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@backstage/integration": "^0.5.1",
|
||||
"@backstage/integration": "^0.5.2",
|
||||
"@google-cloud/storage": "^5.6.0",
|
||||
"@types/dockerode": "^3.2.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"aws-sdk": "^2.840.0",
|
||||
"cross-fetch": "^3.0.6",
|
||||
"dockerode": "^3.2.1",
|
||||
"express": "^4.17.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"git-url-parse": "^11.4.4",
|
||||
@@ -62,7 +60,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.8",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@types/fs-extra": "^9.0.5",
|
||||
"@types/git-url-parse": "^9.0.0",
|
||||
"@types/js-yaml": "^4.0.0",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { ContainerRunner, getVoidLogger } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { Generators } from './generators';
|
||||
import { TechdocsGenerator } from './techdocs';
|
||||
@@ -30,6 +30,10 @@ const mockEntity = {
|
||||
};
|
||||
|
||||
describe('generators', () => {
|
||||
const containerRunner: jest.Mocked<ContainerRunner> = {
|
||||
runContainer: jest.fn(),
|
||||
};
|
||||
|
||||
it('should return error if no generator is registered', async () => {
|
||||
const generators = new Generators();
|
||||
|
||||
@@ -40,7 +44,11 @@ describe('generators', () => {
|
||||
|
||||
it('should return correct registered generator', async () => {
|
||||
const generators = new Generators();
|
||||
const techdocs = new TechdocsGenerator(logger, new ConfigReader({}));
|
||||
const techdocs = new TechdocsGenerator({
|
||||
logger,
|
||||
containerRunner,
|
||||
config: new ConfigReader({}),
|
||||
});
|
||||
|
||||
generators.register('techdocs', techdocs);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ContainerRunner } from '@backstage/backend-common';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { Config } from '@backstage/config';
|
||||
import { Logger } from 'winston';
|
||||
@@ -30,11 +31,18 @@ export class Generators implements GeneratorBuilder {
|
||||
|
||||
static async fromConfig(
|
||||
config: Config,
|
||||
{ logger }: { logger: Logger },
|
||||
{
|
||||
logger,
|
||||
containerRunner,
|
||||
}: { logger: Logger; containerRunner: ContainerRunner },
|
||||
): Promise<GeneratorBuilder> {
|
||||
const generators = new Generators();
|
||||
|
||||
const techdocsGenerator = new TechdocsGenerator(logger, config);
|
||||
const techdocsGenerator = new TechdocsGenerator({
|
||||
logger,
|
||||
containerRunner,
|
||||
config,
|
||||
});
|
||||
generators.register('techdocs', techdocsGenerator);
|
||||
|
||||
return generators;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { runDockerContainer } from '@backstage/backend-common';
|
||||
import { ContainerRunner } from '@backstage/backend-common';
|
||||
import { Config } from '@backstage/config';
|
||||
import path from 'path';
|
||||
import { PassThrough } from 'stream';
|
||||
@@ -48,20 +48,29 @@ const createStream = (): [string[], PassThrough] => {
|
||||
|
||||
export class TechdocsGenerator implements GeneratorBase {
|
||||
private readonly logger: Logger;
|
||||
private readonly containerRunner: ContainerRunner;
|
||||
private readonly options: TechdocsGeneratorOptions;
|
||||
|
||||
constructor(logger: Logger, config: Config) {
|
||||
constructor({
|
||||
logger,
|
||||
containerRunner,
|
||||
config,
|
||||
}: {
|
||||
logger: Logger;
|
||||
containerRunner: ContainerRunner;
|
||||
config: Config;
|
||||
}) {
|
||||
this.logger = logger;
|
||||
this.options = {
|
||||
runGeneratorIn:
|
||||
config.getOptionalString('techdocs.generators.techdocs') ?? 'docker',
|
||||
};
|
||||
this.containerRunner = containerRunner;
|
||||
}
|
||||
|
||||
public async run({
|
||||
inputDir,
|
||||
outputDir,
|
||||
dockerClient,
|
||||
parsedLocationAnnotation,
|
||||
etag,
|
||||
}: GeneratorRunOptions): Promise<void> {
|
||||
@@ -100,7 +109,7 @@ export class TechdocsGenerator implements GeneratorBase {
|
||||
);
|
||||
break;
|
||||
case 'docker':
|
||||
await runDockerContainer({
|
||||
await this.containerRunner.runContainer({
|
||||
imageName: 'spotify/techdocs',
|
||||
args: ['build', '-d', '/output'],
|
||||
logStream,
|
||||
@@ -109,7 +118,6 @@ export class TechdocsGenerator implements GeneratorBase {
|
||||
// Set the home directory inside the container as something that applications can
|
||||
// write to, otherwise they will just fail trying to write to /
|
||||
envVars: { HOME: '/tmp' },
|
||||
dockerClient,
|
||||
});
|
||||
this.logger.info(
|
||||
`Successfully generated docs from ${inputDir} into ${outputDir} using techdocs-container`,
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import Docker from 'dockerode';
|
||||
import { Writable } from 'stream';
|
||||
import { ParsedLocationAnnotation } from '../../helpers';
|
||||
|
||||
@@ -23,7 +22,6 @@ import { ParsedLocationAnnotation } from '../../helpers';
|
||||
*
|
||||
* @param {string} inputDir The directory of the uncompiled documentation, with the values from the frontend
|
||||
* @param {string} outputDir Directory to store generated docs in. Usually - a newly created temporary directory.
|
||||
* @param {Docker} dockerClient A docker client to run any generator on top of your directory
|
||||
* @param {ParsedLocationAnnotation} parsedLocationAnnotation backstage.io/techdocs-ref annotation of an entity
|
||||
* @param {string} etag A unique identifier for the prepared tree e.g. commit SHA. If provided it will be stored in techdocs_metadata.json.
|
||||
* @param {Writable} [logStream] A dedicated log stream
|
||||
@@ -31,7 +29,6 @@ import { ParsedLocationAnnotation } from '../../helpers';
|
||||
export type GeneratorRunOptions = {
|
||||
inputDir: string;
|
||||
outputDir: string;
|
||||
dockerClient: Docker;
|
||||
parsedLocationAnnotation?: ParsedLocationAnnotation;
|
||||
etag?: string;
|
||||
logStream?: Writable;
|
||||
|
||||
@@ -7,13 +7,13 @@ This package provides utilities that can be used to test plugins and apps for Ba
|
||||
Install the package via npm or Yarn:
|
||||
|
||||
```sh
|
||||
$ npm install --save-dev @backstage/test-utils
|
||||
npm install --save-dev @backstage/test-utils
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
$ yarn add -D @backstage/test-utils
|
||||
yarn add -D @backstage/test-utils
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/theme
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7b8272fb7: Remove extra bottom padding in InfoCard content
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -7,13 +7,13 @@ This package provides the extended Material UI Theme(s) that power Backstage.
|
||||
Install the package via npm or Yarn:
|
||||
|
||||
```sh
|
||||
$ npm install --save @backstage/theme
|
||||
npm install --save @backstage/theme
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
$ yarn add @backstage/theme
|
||||
yarn add @backstage/theme
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/theme",
|
||||
"description": "material-ui theme for use with Backstage.",
|
||||
"version": "0.2.6",
|
||||
"version": "0.2.7",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -31,7 +31,7 @@
|
||||
"@material-ui/core": "^4.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.9"
|
||||
"@backstage/cli": "^0.6.10"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -257,6 +257,9 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides {
|
||||
// etc) end up at the bottom of the card instead of just below the body
|
||||
// contents.
|
||||
flexGrow: 1,
|
||||
'&:last-child': {
|
||||
paddingBottom: undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardActions: {
|
||||
|
||||
@@ -28,15 +28,15 @@ To link that a component provides or consumes an API, see the [`providesApis`](h
|
||||
1. Install the API docs plugin
|
||||
|
||||
```bash
|
||||
# packages/app
|
||||
|
||||
# From your Backstage root directory
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-api-docs
|
||||
```
|
||||
|
||||
2. Add the `ApiExplorerPage` extension to the app:
|
||||
|
||||
```tsx
|
||||
// packages/app/src/App.tsx
|
||||
// In packages/app/src/App.tsx
|
||||
|
||||
import { ApiExplorerPage } from '@backstage/plugin-api-docs';
|
||||
|
||||
@@ -56,7 +56,7 @@ import {
|
||||
} from '@backstage/plugin-api-docs';
|
||||
|
||||
const apiPage = (
|
||||
<EntityLayoutWrapper>
|
||||
<EntityLayout>
|
||||
<EntityLayout.Route path="/" title="Overview">
|
||||
<Grid container spacing={3}>
|
||||
<Grid item md={6}>
|
||||
@@ -80,7 +80,7 @@ const apiPage = (
|
||||
</Grid>
|
||||
</Grid>
|
||||
</EntityLayout.Route>
|
||||
</EntityLayoutWrapper>
|
||||
</EntityLayout>
|
||||
);
|
||||
|
||||
// ...
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
"dependencies": {
|
||||
"@asyncapi/react-component": "^0.23.0",
|
||||
"@backstage/catalog-model": "^0.7.7",
|
||||
"@backstage/core": "^0.7.7",
|
||||
"@backstage/core": "^0.7.8",
|
||||
"@backstage/plugin-catalog-react": "^0.1.4",
|
||||
"@backstage/theme": "^0.2.6",
|
||||
"@backstage/theme": "^0.2.7",
|
||||
"@material-icons/font": "^1.0.2",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -49,7 +49,7 @@
|
||||
"swagger-ui-react": "^3.37.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.9",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@backstage/dev-utils": "^0.1.13",
|
||||
"@backstage/test-utils": "^0.1.10",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
|
||||
@@ -96,14 +96,18 @@ describe('<ConsumedApisCard />', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
catalogApi.getEntityByName.mockResolvedValue({
|
||||
apiVersion: 'v1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
catalogApi.getEntities.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { getByText } = await renderInTestApp(
|
||||
|
||||
@@ -96,14 +96,18 @@ describe('<HasApisCard />', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
catalogApi.getEntityByName.mockResolvedValue({
|
||||
apiVersion: 'v1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
catalogApi.getEntities.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { getByText } = await renderInTestApp(
|
||||
|
||||
@@ -96,14 +96,18 @@ describe('<ProvidedApisCard />', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
catalogApi.getEntityByName.mockResolvedValue({
|
||||
apiVersion: 'v1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
catalogApi.getEntities.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'API',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { getByText } = await renderInTestApp(
|
||||
|
||||
@@ -101,14 +101,18 @@ describe('<ConsumingComponentsCard />', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
catalogApi.getEntityByName.mockResolvedValue({
|
||||
apiVersion: 'v1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
catalogApi.getEntities.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { getByText } = await renderInTestApp(
|
||||
|
||||
@@ -101,14 +101,18 @@ describe('<ProvidingComponentsCard />', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
catalogApi.getEntityByName.mockResolvedValue({
|
||||
apiVersion: 'v1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
catalogApi.getEntities.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'target-name',
|
||||
namespace: 'my-namespace',
|
||||
},
|
||||
spec: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { getByText } = await renderInTestApp(
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/plugin-app-backend
|
||||
|
||||
## 0.3.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/backend-common@0.7.0
|
||||
- @backstage/config-loader@0.6.1
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.3.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -7,7 +7,9 @@ This backend plugin can be installed to serve static content of a Backstage app.
|
||||
Add both this package and your local frontend app package as dependencies to your backend, for example
|
||||
|
||||
```bash
|
||||
yarn add @backstage/plugin-app-backend example-app
|
||||
# From your Backstage root directory
|
||||
cd packages/backend
|
||||
yarn add @backstage/plugin-app-backend app
|
||||
```
|
||||
|
||||
By adding the app package as a dependency we ensure that it is built as part of the backend, and that it can be resolved at runtime.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-app-backend",
|
||||
"version": "0.3.11",
|
||||
"version": "0.3.12",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,9 +29,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.6.2",
|
||||
"@backstage/config-loader": "^0.6.0",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/backend-common": "^0.7.0",
|
||||
"@backstage/config-loader": "^0.6.1",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@types/express": "^4.17.6",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
@@ -40,7 +40,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.7",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"msw": "^0.20.5",
|
||||
"supertest": "^6.1.3"
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @backstage/plugin-auth-backend
|
||||
|
||||
## 0.3.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- Updated dependencies [d1b1306d9]
|
||||
- @backstage/backend-common@0.7.0
|
||||
- @backstage/catalog-model@0.7.8
|
||||
- @backstage/config@0.1.5
|
||||
- @backstage/catalog-client@0.3.11
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-auth-backend",
|
||||
"version": "0.3.8",
|
||||
"version": "0.3.9",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,10 +29,10 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.6.2",
|
||||
"@backstage/catalog-client": "^0.3.9",
|
||||
"@backstage/catalog-model": "^0.7.6",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/backend-common": "^0.7.0",
|
||||
"@backstage/catalog-client": "^0.3.11",
|
||||
"@backstage/catalog-model": "^0.7.8",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@backstage/test-utils": "^0.1.10",
|
||||
"@types/express": "^4.17.6",
|
||||
@@ -68,7 +68,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.7",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@types/body-parser": "^1.19.0",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express-session": "^1.17.2",
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @backstage/plugin-badges-backend
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- Updated dependencies [d1b1306d9]
|
||||
- @backstage/backend-common@0.7.0
|
||||
- @backstage/catalog-model@0.7.8
|
||||
- @backstage/config@0.1.5
|
||||
- @backstage/catalog-client@0.3.11
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-badges-backend",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,10 +30,10 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.6.2",
|
||||
"@backstage/catalog-client": "^0.3.6",
|
||||
"@backstage/catalog-model": "^0.7.6",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/backend-common": "^0.7.0",
|
||||
"@backstage/catalog-client": "^0.3.11",
|
||||
"@backstage/catalog-model": "^0.7.8",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"badge-maker": "^3.3.0",
|
||||
@@ -45,7 +45,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.7",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"supertest": "^6.1.3"
|
||||
},
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.6",
|
||||
"@backstage/core": "^0.7.7",
|
||||
"@backstage/core": "^0.7.8",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@backstage/plugin-catalog-react": "^0.1.3",
|
||||
"@backstage/theme": "^0.2.6",
|
||||
"@backstage/theme": "^0.2.7",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.45",
|
||||
@@ -34,7 +34,7 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.9",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@backstage/dev-utils": "^0.1.13",
|
||||
"@backstage/test-utils": "^0.1.10",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
|
||||
@@ -8,9 +8,9 @@ Welcome to the Bitrise plugin!
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
# The plugin must be added in the app package
|
||||
$ cd packages/app
|
||||
$ yarn add @backstage/plugin-bitrise
|
||||
# From your Backstage root directory
|
||||
cd packages/app
|
||||
yarn add @backstage/plugin-bitrise
|
||||
```
|
||||
|
||||
Bitrise Plugin exposes an entity tab component named `EntityBitriseContent`. You can include it in the
|
||||
@@ -22,7 +22,7 @@ import { EntityBitriseContent } from '@backstage/plugin-bitrise';
|
||||
|
||||
// Farther down at the website declaration
|
||||
const websiteEntityPage = (
|
||||
<EntityLayoutWrapper>
|
||||
<EntityLayout>
|
||||
{/* Place the following section where you want the tab to appear */}
|
||||
<EntityLayout.Route path="/bitrise" title="Bitrise">
|
||||
<EntityBitriseContent />
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.7.7",
|
||||
"@backstage/core": "^0.7.8",
|
||||
"@backstage/plugin-catalog-react": "^0.1.2",
|
||||
"@backstage/theme": "^0.2.6",
|
||||
"@backstage/theme": "^0.2.7",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.45",
|
||||
@@ -37,7 +37,7 @@
|
||||
"recharts": "^1.8.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.9",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@backstage/dev-utils": "^0.1.13",
|
||||
"@backstage/test-utils": "^0.1.10",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @backstage/plugin-catalog-backend
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b219821a0: Expose `BitbucketRepositoryParser` introduced in [#5295](https://github.com/backstage/backstage/pull/5295)
|
||||
- 227439a72: Add support for non-organization accounts in GitHub Discovery
|
||||
- Updated dependencies [e0bfd3d44]
|
||||
- Updated dependencies [38ca05168]
|
||||
- Updated dependencies [d8b81fd28]
|
||||
- @backstage/backend-common@0.7.0
|
||||
- @backstage/integration@0.5.2
|
||||
- @backstage/catalog-model@0.7.8
|
||||
- @backstage/config@0.1.5
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-backend",
|
||||
"version": "0.8.1",
|
||||
"version": "0.8.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,11 +30,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/msal-node": "^1.0.0-beta.3",
|
||||
"@backstage/backend-common": "^0.6.3",
|
||||
"@backstage/catalog-model": "^0.7.7",
|
||||
"@backstage/config": "^0.1.4",
|
||||
"@backstage/backend-common": "^0.7.0",
|
||||
"@backstage/catalog-model": "^0.7.8",
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@backstage/integration": "^0.5.1",
|
||||
"@backstage/integration": "^0.5.2",
|
||||
"@backstage/plugin-search-backend-node": "^0.1.4",
|
||||
"@backstage/search-common": "^0.1.1",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
@@ -63,7 +63,7 @@
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.9",
|
||||
"@backstage/cli": "^0.6.10",
|
||||
"@backstage/test-utils": "^0.1.9",
|
||||
"@types/core-js": "^2.5.4",
|
||||
"@types/git-url-parse": "^9.0.0",
|
||||
@@ -73,7 +73,8 @@
|
||||
"@types/yup": "^0.29.8",
|
||||
"msw": "^0.21.2",
|
||||
"sqlite3": "^5.0.0",
|
||||
"supertest": "^6.1.3"
|
||||
"supertest": "^6.1.3",
|
||||
"wait-for-expect": "^3.0.2"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
+88
-123
@@ -17,21 +17,73 @@ import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { BitbucketDiscoveryProcessor } from './BitbucketDiscoveryProcessor';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { LocationSpec } from '@backstage/catalog-model';
|
||||
import {
|
||||
BitbucketClient,
|
||||
BitbucketRepositoryParser,
|
||||
PagedResponse,
|
||||
} from './bitbucket';
|
||||
import { BitbucketRepositoryParser, PagedResponse } from './bitbucket';
|
||||
import { results } from './index';
|
||||
import { RequestHandler, rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
|
||||
function pagedResponse(values: any): PagedResponse<any> {
|
||||
return {
|
||||
values: values,
|
||||
isLastPage: true,
|
||||
} as PagedResponse<any>;
|
||||
const server = setupServer();
|
||||
|
||||
function setupStubs(projects: any[]) {
|
||||
function pagedResponse(values: any): PagedResponse<any> {
|
||||
return {
|
||||
values: values,
|
||||
isLastPage: true,
|
||||
} as PagedResponse<any>;
|
||||
}
|
||||
|
||||
function stubbedProject(
|
||||
project: string,
|
||||
repos: string[],
|
||||
): RequestHandler<any, any> {
|
||||
return rest.get(
|
||||
`https://bitbucket.mycompany.com/api/rest/1.0/projects/${project}/repos`,
|
||||
(_, res, ctx) => {
|
||||
const response = [];
|
||||
for (const repo of repos) {
|
||||
response.push({
|
||||
slug: repo,
|
||||
links: {
|
||||
self: [
|
||||
{
|
||||
href: `https://bitbucket.mycompany.com/projects/${project}/repos/${repo}/browse`,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
return res(ctx.json(pagedResponse(response)));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
server.use(
|
||||
rest.get(
|
||||
`https://bitbucket.mycompany.com/api/rest/1.0/projects`,
|
||||
(_, res, ctx) => {
|
||||
return res(
|
||||
ctx.json(
|
||||
pagedResponse(
|
||||
projects.map(p => {
|
||||
return { key: p.key };
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
for (const project of projects) {
|
||||
server.use(stubbedProject(project.key, project.repos));
|
||||
}
|
||||
}
|
||||
|
||||
describe('BitbucketDiscoveryProcessor', () => {
|
||||
beforeAll(() => server.listen());
|
||||
afterEach(() => server.resetHandlers());
|
||||
afterAll(() => server.close());
|
||||
|
||||
afterEach(() => jest.resetAllMocks());
|
||||
|
||||
describe('reject unrelated entries', () => {
|
||||
@@ -81,58 +133,29 @@ describe('BitbucketDiscoveryProcessor', () => {
|
||||
const processor = BitbucketDiscoveryProcessor.fromConfig(
|
||||
new ConfigReader({
|
||||
integrations: {
|
||||
bitbucket: [{ host: 'bitbucket.mycompany.com', token: 'blob' }],
|
||||
bitbucket: [
|
||||
{
|
||||
host: 'bitbucket.mycompany.com',
|
||||
token: 'blob',
|
||||
apiBaseUrl: 'https://bitbucket.mycompany.com/api/rest/1.0',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
{ logger: getVoidLogger() },
|
||||
);
|
||||
|
||||
it('output all repositories', async () => {
|
||||
setupStubs([
|
||||
{ key: 'backstage', repos: ['backstage'] },
|
||||
{ key: 'demo', repos: ['demo'] },
|
||||
]);
|
||||
const location: LocationSpec = {
|
||||
type: 'bitbucket-discovery',
|
||||
target:
|
||||
'https://bitbucket.mycompany.com/projects/*/repos/*/catalog.yaml',
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listProjects')
|
||||
.mockResolvedValue(
|
||||
pagedResponse([{ key: 'backstage' }, { key: 'demo' }]),
|
||||
);
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listRepositories')
|
||||
.mockResolvedValueOnce(
|
||||
pagedResponse([
|
||||
{
|
||||
slug: 'backstage',
|
||||
links: {
|
||||
self: [
|
||||
{
|
||||
href:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/backstage/browse',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listRepositories')
|
||||
.mockResolvedValueOnce(
|
||||
pagedResponse([
|
||||
{
|
||||
slug: 'demo',
|
||||
links: {
|
||||
self: [
|
||||
{
|
||||
href:
|
||||
'https://bitbucket.mycompany.com/projects/demo/repos/demo/browse',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
const emitter = jest.fn();
|
||||
|
||||
await processor.readLocation(location, false, emitter);
|
||||
@@ -158,44 +181,16 @@ describe('BitbucketDiscoveryProcessor', () => {
|
||||
});
|
||||
|
||||
it('output repositories with wildcards', async () => {
|
||||
setupStubs([
|
||||
{ key: 'backstage', repos: ['backstage', 'techdocs-cli'] },
|
||||
{ key: 'demo', repos: ['demo'] },
|
||||
]);
|
||||
const location: LocationSpec = {
|
||||
type: 'bitbucket-discovery',
|
||||
target:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/techdocs-*/catalog.yaml',
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listProjects')
|
||||
.mockResolvedValue(pagedResponse([{ key: 'backstage' }]));
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listRepositories')
|
||||
.mockResolvedValueOnce(
|
||||
pagedResponse([
|
||||
{ slug: 'backstage' },
|
||||
{
|
||||
slug: 'techdocs-cli',
|
||||
links: {
|
||||
self: [
|
||||
{
|
||||
href:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/techdocs-cli/browse',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'techdocs-container',
|
||||
links: {
|
||||
self: [
|
||||
{
|
||||
href:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/techdocs-container/browse',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
const emitter = jest.fn();
|
||||
await processor.readLocation(location, false, emitter);
|
||||
|
||||
@@ -208,46 +203,15 @@ describe('BitbucketDiscoveryProcessor', () => {
|
||||
},
|
||||
optional: true,
|
||||
});
|
||||
expect(emitter).toHaveBeenCalledWith({
|
||||
type: 'location',
|
||||
location: {
|
||||
type: 'url',
|
||||
target:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/techdocs-container/browse/catalog.yaml',
|
||||
},
|
||||
optional: true,
|
||||
});
|
||||
});
|
||||
it('filter unrelated repositories', async () => {
|
||||
setupStubs([{ key: 'backstage', repos: ['test', 'abctest', 'testxyz'] }]);
|
||||
const location: LocationSpec = {
|
||||
type: 'bitbucket-discovery',
|
||||
target:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/test/catalog.yaml',
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listProjects')
|
||||
.mockResolvedValue(pagedResponse([{ key: 'backstage' }]));
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listRepositories')
|
||||
.mockResolvedValue(
|
||||
pagedResponse([
|
||||
{ slug: 'abstest' },
|
||||
{ slug: 'testxyz' },
|
||||
{
|
||||
slug: 'test',
|
||||
links: {
|
||||
self: [
|
||||
{
|
||||
href:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/test',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
const emitter = jest.fn();
|
||||
await processor.readLocation(location, false, emitter);
|
||||
|
||||
@@ -256,7 +220,7 @@ describe('BitbucketDiscoveryProcessor', () => {
|
||||
location: {
|
||||
type: 'url',
|
||||
target:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/test/catalog.yaml',
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/test/browse/catalog.yaml',
|
||||
},
|
||||
optional: true,
|
||||
});
|
||||
@@ -277,26 +241,27 @@ describe('BitbucketDiscoveryProcessor', () => {
|
||||
const processor = BitbucketDiscoveryProcessor.fromConfig(
|
||||
new ConfigReader({
|
||||
integrations: {
|
||||
bitbucket: [{ host: 'bitbucket.mycompany.com', token: 'blob' }],
|
||||
bitbucket: [
|
||||
{
|
||||
host: 'bitbucket.mycompany.com',
|
||||
token: 'blob',
|
||||
apiBaseUrl: 'https://bitbucket.mycompany.com/api/rest/1.0',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
{ parser: customRepositoryParser, logger: getVoidLogger() },
|
||||
);
|
||||
|
||||
it('use custom repository parser', async () => {
|
||||
setupStubs([{ key: 'backstage', repos: ['test'] }]);
|
||||
|
||||
const location: LocationSpec = {
|
||||
type: 'bitbucket-discovery',
|
||||
target:
|
||||
'https://bitbucket.mycompany.com/projects/backstage/repos/test/catalog.yaml',
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listProjects')
|
||||
.mockResolvedValue(pagedResponse([{ key: 'backstage' }]));
|
||||
jest
|
||||
.spyOn(BitbucketClient.prototype, 'listRepositories')
|
||||
.mockResolvedValue(pagedResponse([{ slug: 'test' }]));
|
||||
|
||||
const emitter = jest.fn();
|
||||
await processor.readLocation(location, false, emitter);
|
||||
|
||||
|
||||
@@ -22,11 +22,11 @@ import {
|
||||
} from '@backstage/integration';
|
||||
import { LocationSpec } from '@backstage/catalog-model';
|
||||
import {
|
||||
Repository,
|
||||
BitbucketRepositoryParser,
|
||||
BitbucketClient,
|
||||
defaultRepositoryParser,
|
||||
paginated,
|
||||
BitbucketRepository,
|
||||
} from './bitbucket';
|
||||
import { CatalogProcessor, CatalogProcessorEmit } from './types';
|
||||
|
||||
@@ -66,20 +66,19 @@ export class BitbucketDiscoveryProcessor implements CatalogProcessor {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bitbucketConfig = this.integrations.bitbucket.byUrl(location.target)
|
||||
?.config;
|
||||
if (!bitbucketConfig) {
|
||||
const integration = this.integrations.bitbucket.byUrl(location.target);
|
||||
if (!integration) {
|
||||
throw new Error(
|
||||
`There is no Bitbucket integration that matches ${location.target}. Please add a configuration entry for it under integrations.bitbucket`,
|
||||
);
|
||||
} else if (bitbucketConfig.host === 'bitbucket.org') {
|
||||
} else if (integration.config.host === 'bitbucket.org') {
|
||||
throw new Error(
|
||||
`Component discovery for Bitbucket Cloud is not yet supported`,
|
||||
);
|
||||
}
|
||||
|
||||
const client = new BitbucketClient({
|
||||
config: bitbucketConfig,
|
||||
config: integration.config,
|
||||
});
|
||||
const startTimestamp = Date.now();
|
||||
this.logger.info(`Reading Bitbucket repositories from ${location.target}`);
|
||||
@@ -90,9 +89,9 @@ export class BitbucketDiscoveryProcessor implements CatalogProcessor {
|
||||
|
||||
for (const repository of result.matches) {
|
||||
for await (const entity of this.parser({
|
||||
client: client,
|
||||
repository: repository,
|
||||
path: catalogPath,
|
||||
integration: integration,
|
||||
target: `${repository.links.self[0].href}${catalogPath}`,
|
||||
logger: this.logger,
|
||||
})) {
|
||||
emit(entity);
|
||||
}
|
||||
@@ -159,5 +158,5 @@ function escapeRegExp(str: string): RegExp {
|
||||
|
||||
type Result = {
|
||||
scanned: number;
|
||||
matches: Repository[];
|
||||
matches: BitbucketRepository[];
|
||||
};
|
||||
|
||||
+5
-11
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defaultRepositoryParser } from './BitbucketRepositoryParser';
|
||||
import { Project, Repository } from './types';
|
||||
import { BitbucketClient } from './client';
|
||||
import { results } from '../index';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { BitbucketIntegration } from '@backstage/integration';
|
||||
|
||||
describe('BitbucketRepositoryParser', () => {
|
||||
describe('defaultRepositoryParser', () => {
|
||||
@@ -34,15 +34,9 @@ describe('BitbucketRepositoryParser', () => {
|
||||
),
|
||||
];
|
||||
const actual = await defaultRepositoryParser({
|
||||
client: {} as BitbucketClient,
|
||||
repository: {
|
||||
project: {} as Project,
|
||||
slug: 'repo-slug',
|
||||
links: {
|
||||
self: [{ href: browseUrl }],
|
||||
},
|
||||
} as Repository,
|
||||
path: path,
|
||||
integration: {} as BitbucketIntegration,
|
||||
target: `${browseUrl}${path}`,
|
||||
logger: getVoidLogger(),
|
||||
});
|
||||
|
||||
let i = 0;
|
||||
|
||||
+7
-8
@@ -13,25 +13,24 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Repository } from './types';
|
||||
import { CatalogProcessorResult } from '../types';
|
||||
import { results } from '../index';
|
||||
import { BitbucketClient } from './client';
|
||||
import { Logger } from 'winston';
|
||||
import { BitbucketIntegration } from '@backstage/integration';
|
||||
|
||||
export type BitbucketRepositoryParser = (options: {
|
||||
client: BitbucketClient;
|
||||
repository: Repository;
|
||||
path: string;
|
||||
integration: BitbucketIntegration;
|
||||
target: string;
|
||||
logger: Logger;
|
||||
}) => AsyncIterable<CatalogProcessorResult>;
|
||||
|
||||
export const defaultRepositoryParser: BitbucketRepositoryParser = async function* defaultRepositoryParser({
|
||||
repository,
|
||||
path,
|
||||
target,
|
||||
}) {
|
||||
yield results.location(
|
||||
{
|
||||
type: 'url',
|
||||
target: `${repository.links.self[0].href}${path}`,
|
||||
target: target,
|
||||
},
|
||||
// Not all locations may actually exist, since the user defined them as a wildcard pattern.
|
||||
// Thus, we emit them as optional and let the downstream processor find them while not outputting
|
||||
|
||||
@@ -41,15 +41,6 @@ export class BitbucketClient {
|
||||
);
|
||||
}
|
||||
|
||||
async getRaw(
|
||||
projectKey: string,
|
||||
repo: string,
|
||||
path: string,
|
||||
): Promise<Response> {
|
||||
const request = `${this.config.apiBaseUrl}/projects/${projectKey}/repos/${repo}/raw/${path}`;
|
||||
return fetch(request, getBitbucketRequestOptions(this.config));
|
||||
}
|
||||
|
||||
private async pagedRequest(
|
||||
endpoint: string,
|
||||
options?: ListOptions,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { BitbucketClient, paginated } from './client';
|
||||
export type { PagedResponse } from './client';
|
||||
export * from './types';
|
||||
export type { BitbucketRepositoryParser } from './BitbucketRepositoryParser';
|
||||
export { defaultRepositoryParser } from './BitbucketRepositoryParser';
|
||||
export type { PagedResponse } from './client';
|
||||
export type { BitbucketRepository } from './types';
|
||||
export type { BitbucketRepositoryParser } from './BitbucketRepositoryParser';
|
||||
|
||||
@@ -13,16 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export type Project = {
|
||||
key: string;
|
||||
};
|
||||
|
||||
export type Repository = {
|
||||
project: Project;
|
||||
export type BitbucketRepository = {
|
||||
project: {
|
||||
key: string;
|
||||
};
|
||||
slug: string;
|
||||
links: Record<string, Link[]>;
|
||||
};
|
||||
|
||||
export type Link = {
|
||||
href: string;
|
||||
links: Record<
|
||||
string,
|
||||
{
|
||||
href: string;
|
||||
}[]
|
||||
>;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user