Merge branch 'master' of https://github.com/backstage/backstage into marley/7678-pull-request-dashboard
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Switched to dynamically determining the packages that are unsafe to repack when executing the CLI within the Backstage main repo.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
'@backstage/theme': patch
|
||||
---
|
||||
|
||||
Added a warning variant to `DismissableBanner` component. If you are using a
|
||||
custom theme, you will need to add the optional `palette.banner.warning` color,
|
||||
otherwise this variant will fall back to the `palette.banner.error` color.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
AWSS3UrlReader now throws a `NotModifiedError` (exported from @backstage/backend-common) when s3 returns a 304 response.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kafka': patch
|
||||
---
|
||||
|
||||
Use IdentityApi to provide Auth Token for KafkaBackendClient Api calls
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/test-utils': patch
|
||||
---
|
||||
|
||||
Update Keyboard deprecation with a link to the recommended successor
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Expose some classes and interfaces public so TaskWorkers can run externally from the scaffolder API.
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Adds a new endpoint for consuming logs from the Scaffolder that uses long polling instead of Server Sent Events.
|
||||
|
||||
This is useful if Backstage is accessed from an environment that doesn't support SSE correctly, which happens in combination with certain enterprise HTTP Proxy servers.
|
||||
|
||||
It is intended to switch the endpoint globally for the whole instance.
|
||||
If you want to use it, you can provide a reconfigured API to the `scaffolderApiRef`:
|
||||
|
||||
```tsx
|
||||
// packages/app/src/apis.ts
|
||||
|
||||
// ...
|
||||
import {
|
||||
scaffolderApiRef,
|
||||
ScaffolderClient,
|
||||
} from '@backstage/plugin-scaffolder';
|
||||
|
||||
export const apis: AnyApiFactory[] = [
|
||||
// ...
|
||||
|
||||
createApiFactory({
|
||||
api: scaffolderApiRef,
|
||||
deps: {
|
||||
discoveryApi: discoveryApiRef,
|
||||
identityApi: identityApiRef,
|
||||
scmIntegrationsApi: scmIntegrationsApiRef,
|
||||
},
|
||||
factory: ({ discoveryApi, identityApi, scmIntegrationsApi }) =>
|
||||
new ScaffolderClient({
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
scmIntegrationsApi,
|
||||
// use long polling instead of an eventsource
|
||||
useLongPollingLogs: true,
|
||||
}),
|
||||
}),
|
||||
];
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
---
|
||||
|
||||
I have added default icons for the catalog, scaffolder, techdocs, and search.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
---
|
||||
|
||||
Default TechDocs container used at docs generation-time is now [v0.3.5](https://github.com/backstage/techdocs-container/releases/tag/v0.3.5).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
---
|
||||
|
||||
Updated to properly join URL segments under any OS for both AWS S3 and GCP
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/errors': patch
|
||||
---
|
||||
|
||||
Add `stringifyError` that is useful for logging e.g. `Something went wrong, ${stringifyError(e)}`
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
paths:
|
||||
- '.github/workflows/e2e-win.yml'
|
||||
- 'packages/cli/**'
|
||||
- 'packages/e2e/**'
|
||||
- 'packages/e2e-test/**'
|
||||
- 'packages/create-app/**'
|
||||
|
||||
jobs:
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
env:
|
||||
CI: true
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
|
||||
name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -40,6 +40,8 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
- name: setup chrome
|
||||
uses: browser-actions/setup-chrome@latest
|
||||
- name: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
@@ -48,3 +50,5 @@ jobs:
|
||||
run: yarn build --ignore example-app --ignore example-backend --ignore @techdocs/cli
|
||||
- name: run E2E test
|
||||
run: yarn e2e-test run
|
||||
env:
|
||||
DEBUG: zombie
|
||||
|
||||
@@ -53,6 +53,8 @@ jobs:
|
||||
id: yarn-cache
|
||||
if: steps.cache-modules.outputs.cache-hit != 'true'
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
- name: setup chrome
|
||||
uses: browser-actions/setup-chrome@latest
|
||||
- name: cache global yarn cache
|
||||
uses: actions/cache@v2
|
||||
if: steps.cache-modules.outputs.cache-hit != 'true'
|
||||
@@ -72,8 +74,3 @@ jobs:
|
||||
run: |
|
||||
sudo sysctl fs.inotify.max_user_watches=524288
|
||||
yarn e2e-test run
|
||||
env:
|
||||
POSTGRES_HOST: localhost
|
||||
POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }}
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
|
||||
@@ -59,3 +59,7 @@
|
||||
| [Box](https://www.box.com) | [@kielosz](https://github.com/kielosz), [@jluk-box](https://github.com/jluk-box), [@ptychu](https://github.com/ptychu), [@alexrybch](https://github.com/alexrybch), [@szubster](https://github.com/szubster) | Developer portal for service catalog, integration with internal systems, new service onboarding. |
|
||||
| [Bazaarvoice](https://www.bazaarvoice.com) | [@niallmccullagh](https://github.com/niallmccullagh) | Developer portal for service catalog and scaffolds, publishing Github docs and API documentation, visualising our internal tech radar and our product engineering org structure. |
|
||||
| [Krateo PlatformOps](https://www.krateo.io) | [@projectkerberus](https://github.com/projectkerberus) | A multi-cloud control plane to create, manage and deploy any kind of resource easily and centrally via a Developer Portal that centralizes via a self-service catalog the templating and ownership of services, the available documentation, the overview of the components that compose an entire domain and all the data of the service lifecycle. |
|
||||
| [Adevinta](https://www.adevinta.com) | [Ray Sinnema](https://github.com/RemonSinnema) | Showcase shared services to our internal customers. |
|
||||
| [Splunk](https://www.splunk.com) | [@tonytamsf](https://github.com/tonytamsf) | Developer portal as a centralized place to find people, services, documentation, escalation policies and give bravos. This portal is also being used as a centralized search engine for engineering specific documentation.|
|
||||
| [SoundCloud](https://www.soundcloud.com) | [Julio Zynger](https://github.com/julioz) | Developer portal as a [humane registry](https://martinfowler.com/bliki/HumaneRegistry.html) for the organization: catalog of people, services, documentation, feature toggles, escalation policies, etc.|
|
||||
| [Volvofinans Bank](https://www.volvofinans.se) | [Johan Hammar](https://github.com/johanhammar) | Developer portal enabling engineers to manage and explore software and documentation. |
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
# [Backstage](https://backstage.io)
|
||||
|
||||
> 🏖 All of the maintainers will be taking a wellness break Nov. 1–5. The repo and Discord may be quieter than usual, but not to worry. We’ll have coverage plans in place and be back in full force, rested and restored, on Nov. 8. 🏖
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://www.cncf.io/projects)
|
||||
[](https://github.com/backstage/backstage/actions?query=workflow%3A%22Main+Master+Build%22)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 131 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -502,6 +502,8 @@ spec:
|
||||
lifecycle: production
|
||||
owner: artist-relations-team
|
||||
system: artist-engagement-portal
|
||||
dependsOn:
|
||||
- resource:default/artists-db
|
||||
providesApis:
|
||||
- artist-api
|
||||
```
|
||||
|
||||
@@ -156,4 +156,16 @@ return await createRouter({
|
||||
});
|
||||
```
|
||||
|
||||
### List of custom action packages
|
||||
|
||||
Here is a list of Open Source custom actions that you can add to your Backstage
|
||||
scaffolder backend:
|
||||
|
||||
| Name | Package | Owner |
|
||||
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
|
||||
| Yeoman | [plugin-scaffolder-backend-module-yeoman](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-yeoman) | [Backstage](https://backstage.io) |
|
||||
| Cookiecutter | [plugin-scaffolder-backend-module-cookiecutter](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-cookiecutter) | [Backstage](https://backstage.io) |
|
||||
| Rails | [plugin-scaffolder-backend-module-rails](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-rails) | [Backstage](https://backstage.io) |
|
||||
| HTTP requests | [scaffolder-backend-module-http-request](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-http-request) | [Roadie](https://roadie.io) |
|
||||
|
||||
Have fun! 🚀
|
||||
|
||||
@@ -27,20 +27,27 @@ You can create your own Field Extension by using the
|
||||
|
||||
```tsx
|
||||
//packages/app/scaffolder/MyCustomExtension/MyCustomExtension.tsx
|
||||
import React from 'react';
|
||||
import { FieldProps, FieldValidation } from '@rjsf/core';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import { KubernetesValidatorFunctions } from '@backstage/catalog-model';
|
||||
/*
|
||||
This is the actual component that will get rendered in the form
|
||||
*/
|
||||
export const MyCustomExtension = ({ onChange, required }: FieldProps<string>) => {
|
||||
export const MyCustomExtension = ({
|
||||
onChange,
|
||||
rawErrors,
|
||||
required,
|
||||
formData,
|
||||
}: FieldProps<string>) => {
|
||||
return (
|
||||
<FormControl
|
||||
<FormControl
|
||||
margin="normal"
|
||||
required={required}
|
||||
error={rawErrors?.length > 0 && !formData}
|
||||
onChange={onChange}
|
||||
>
|
||||
)
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -63,10 +70,10 @@ export const myCustomValidation = (
|
||||
```tsx
|
||||
// packages/app/scaffolder/MyCustomExtension/extensions.ts
|
||||
|
||||
/*
|
||||
/*
|
||||
This is where the magic happens and creates the custom field extension.
|
||||
|
||||
Note that if you're writing extensions part of a separate plugin,
|
||||
Note that if you're writing extensions part of a separate plugin,
|
||||
then please use `plugin.provide` from there instead and export it part of your `plugin.ts` rather than re-using the `scaffolder.plugin`.
|
||||
*/
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ techdocs:
|
||||
# (Required) Cloud Storage Bucket Name
|
||||
bucketName: 'techdocs-storage'
|
||||
|
||||
# (Optional) Location in storage bucket to save files
|
||||
# If not set, the default location will be the root of the storage bucket
|
||||
bucketRootPath: '/'
|
||||
|
||||
# (Optional) An API key is required to write to a storage bucket.
|
||||
# If missing, GOOGLE_APPLICATION_CREDENTIALS environment variable will be used.
|
||||
# https://cloud.google.com/docs/authentication/production
|
||||
@@ -75,6 +79,10 @@ techdocs:
|
||||
# (Required) AWS S3 Bucket Name
|
||||
bucketName: 'techdocs-storage'
|
||||
|
||||
# (Optional) Location in storage bucket to save files
|
||||
# If not set, the default location will be the root of the storage bucket
|
||||
bucketRootPath: '/'
|
||||
|
||||
# (Optional) An API key is required to write to a storage bucket.
|
||||
# If not set, environment variables or aws config file will be used to authenticate.
|
||||
# https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html
|
||||
|
||||
@@ -4,49 +4,99 @@ title: Getting Started
|
||||
description: Documentation on How to get started with Backstage
|
||||
---
|
||||
|
||||
There are two different ways to get started with Backstage:
|
||||
For most Backstage installations, installing the standalone app will bring you
|
||||
the best and most streamlined experience. In this guide you will:
|
||||
|
||||
- **Recommended:** Create a standalone app
|
||||
- **Contributors:** Clone the Backstage repository
|
||||
- Deploy Backstage Standalone with npm packages
|
||||
- Run Backstage Standalone with a SQLite in-memory database and demo content
|
||||
|
||||
Creating a standalone app makes it simpler to customize the application for your
|
||||
needs and stay up to date with the project. You will depend on `@backstage`
|
||||
packages from npm, making your app much smaller. This is the recommended
|
||||
approach for most installations.
|
||||
This guide assumes a basic understanding of working on a Linux based operating
|
||||
system using tools like apt-get, npm, yarn, curl. Docker knowledge is also
|
||||
helpful for making the best use of your Backstage installation.
|
||||
|
||||
If you want to contribute plugins or to the project in general, it's easier to
|
||||
fork and clone the repository. The `@backstage` packages will be included in the
|
||||
clone. That will let you stay up to date with the latest changes, and give you
|
||||
an easier path to make Pull Requests.
|
||||
If you are planning to contribute plugins or the project in general, we advise
|
||||
you to use the
|
||||
[Getting Started for Contributors](https://backstage.io/docs/getting-started/running-backstage-locally)
|
||||
guide to do a repository-based installation.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Access to a Linux-based operating system, such as Linux, MacOS or
|
||||
[Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/)
|
||||
- An account with elevated rights
|
||||
- `curl` or `wget` installed
|
||||
- Node.js Active LTS Release installed (currently v14) using one of these
|
||||
methods:
|
||||
- Using `nvm` (recommended)
|
||||
- [Installing nvm](https://github.com/nvm-sh/nvm#install--update-script)
|
||||
- [Install and change Node version with nvm](https://nodejs.org/en/download/package-manager/#nvm)
|
||||
- [Binary Download](https://nodejs.org/en/download/)
|
||||
- [Package manager](https://nodejs.org/en/download/package-manager/)
|
||||
- [Using NodeSource packages](https://github.com/nodesource/distributions/blob/master/README.md)
|
||||
- `yarn` [Installation](https://classic.yarnpkg.com/en/docs/install)
|
||||
- `docker` [installation](https://docs.docker.com/engine/install/)
|
||||
- `git` [installation](https://github.com/git-guides/install-git)
|
||||
- If the system is not directly accessible over your network, the following
|
||||
ports need to be opened: 3000, 7000
|
||||
|
||||
### Create your Backstage App
|
||||
|
||||
Backstage provides the `@backstage/create-app` package to scaffold standalone
|
||||
instances of Backstage. You will need to have
|
||||
[Node.js](https://nodejs.org/en/download/) Active LTS Release installed
|
||||
(currently v14) and [Yarn](https://classic.yarnpkg.com/en/docs/install). You
|
||||
will also need to have [Docker](https://docs.docker.com/engine/install/)
|
||||
installed to use some features like Software Templates and TechDocs.
|
||||
|
||||
Using `npx` you can then run the following to create an app in a chosen
|
||||
subdirectory of your current working directory:
|
||||
To install the Backstage Standalone app, we make use of `npx`, a tool to run
|
||||
Node executables straight from the registry. Running the command below will
|
||||
install Backstage. The wizard will create a subdirectory inside your current
|
||||
working directory.
|
||||
|
||||
```bash
|
||||
npx @backstage/create-app
|
||||
```
|
||||
|
||||
You will be taken through a wizard to create your app. You can read more about
|
||||
this process in [Create an app](./create-an-app.md).
|
||||
The wizard will ask you
|
||||
|
||||
### Contributing to Backstage
|
||||
- The name of the app, which will also be the name of the directory
|
||||
- The database type to use for the backend. For this guide, you'll be using the
|
||||
SQLite option.
|
||||
|
||||
If you intend to make changes to the core project's packages, certain plugins,
|
||||
or project documentation, then you can fork and clone
|
||||
[https://github.com/backstage/backstage](https://github.com/backstage/backstage).
|
||||
<p align='center'>
|
||||
<img src='../assets/getting-started/wizard.png' alt='Screenshot of the wizard asking for a name for the app, and a selection menu for the database.'>
|
||||
</p>
|
||||
|
||||
This will let you run the latest code off of the `master` branch, fix bugs or
|
||||
contribute new features, run test suites, etc.
|
||||
### Run the Backstage app
|
||||
|
||||
You can read more in our
|
||||
[CONTRIBUTING](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md)
|
||||
guide, which can help you get setup with a Backstage development environment.
|
||||
When the installation is complete you can go to the application directory and
|
||||
start the app. The `yarn dev` command will run both the frontend and backend as
|
||||
separate processes (named `[0]` and `[1]`) in the same window.
|
||||
|
||||
```bash
|
||||
cd my-backstage-app
|
||||
yarn dev
|
||||
```
|
||||
|
||||
<p align='center'>
|
||||
<img src='../assets/getting-started/startup.png' alt='Screenshot of the command output, with the message web pack compiled successfully.'>
|
||||
</p>
|
||||
|
||||
It might take a little while, but as soon as the message
|
||||
`[0] webpack compiled successfully` appears, you can open a browser and directly
|
||||
navigate to your freshly installed Backstage portal at `http://localhost:3000`.
|
||||
You can start exploring the demo immediately.
|
||||
|
||||
<p align='center'>
|
||||
<img src='../assets/getting-started/portal.png' alt='Screenshot of the Backstage portal.'>
|
||||
</p>
|
||||
|
||||
Congratulations! That should be it. Let us know how it went:
|
||||
[on discord](https://discord.gg/EBHEGzX), file issues for any
|
||||
[feature](https://github.com/backstage/backstage/issues/new?labels=help+wanted&template=feature_template.md)
|
||||
or
|
||||
[plugin suggestions](https://github.com/backstage/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME),
|
||||
or
|
||||
[bugs](https://github.com/backstage/backstage/issues/new?labels=bug&template=bug_template.md)
|
||||
you have, and feel free to
|
||||
[contribute](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md)!
|
||||
|
||||
The most common next steps are to configure Backstage, add a plugin and moving
|
||||
to a more persistent database:
|
||||
|
||||
- [Setting up Authentication](https://backstage.io/docs/auth/)
|
||||
- [Switching from SQLite to PostgresQL](https://backstage.io/docs/tutorials/switching-sqlite-postgres)
|
||||
- [Adding a plugin](https://backstage.io/docs/getting-started/configure-app-with-plugins)
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"**/@graphql-codegen/cli/**/ws": "^7.4.6",
|
||||
"**/@roadiehq/**/@backstage/core": "*",
|
||||
"**/@roadiehq/**/@backstage/plugin-catalog": "*",
|
||||
"**/@roadiehq/**/@backstage/catalog-model": "*",
|
||||
"graphql-language-service-interface": "2.8.2",
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
window,
|
||||
document,
|
||||
'script',
|
||||
'https://www.datadoghq-browser-agent.com/datadog-rum.js',
|
||||
'https://www.datadoghq-browser-agent.com/datadog-rum-v3.js',
|
||||
'DD_RUM',
|
||||
);
|
||||
DD_RUM.onReady(function () {
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.9.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 96cfa561eb: Adjusted some API exports
|
||||
- 10615525f3: Switch to use the json and observable types from `@backstage/types`
|
||||
- 1be8d2abdb: Any set configurations which have been tagged with a visibility 'secret', are now redacted from log lines.
|
||||
- Updated dependencies
|
||||
- @backstage/config@0.1.11
|
||||
- @backstage/cli-common@0.1.5
|
||||
- @backstage/errors@0.1.4
|
||||
- @backstage/integration@0.6.9
|
||||
- @backstage/config-loader@0.7.1
|
||||
|
||||
## 0.9.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -18,7 +18,7 @@ import { GithubCredentialsProvider } from '@backstage/integration';
|
||||
import { GitHubIntegration } from '@backstage/integration';
|
||||
import { GitLabIntegration } from '@backstage/integration';
|
||||
import { isChildPath } from '@backstage/cli-common';
|
||||
import { JsonValue } from '@backstage/config';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { Knex } from 'knex';
|
||||
import { Logger as Logger_2 } from 'winston';
|
||||
import { MergeResult } from 'isomorphic-git';
|
||||
@@ -211,6 +211,12 @@ export type ErrorHandlerOptions = {
|
||||
logClientErrors?: boolean;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type FromReadableArrayOptions = Array<{
|
||||
data: Readable;
|
||||
path: string;
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
export function getRootLogger(): winston.Logger;
|
||||
|
||||
@@ -419,15 +425,13 @@ export type ReadTreeResponse = {
|
||||
etag: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type ReadTreeResponseDirOptions = {
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ReadTreeResponseFactory {
|
||||
// Warning: (ae-forgotten-export) The symbol "FromReadableArrayOptions" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
fromReadableArray(
|
||||
options: FromReadableArrayOptions,
|
||||
@@ -442,7 +446,7 @@ export interface ReadTreeResponseFactory {
|
||||
): Promise<ReadTreeResponse>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type ReadTreeResponseFactoryOptions = {
|
||||
stream: Readable;
|
||||
subpath?: string;
|
||||
@@ -580,7 +584,7 @@ export type UrlReader = {
|
||||
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type UrlReaderPredicateTuple = {
|
||||
predicate: (url: URL) => boolean;
|
||||
reader: UrlReader;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.9.7",
|
||||
"version": "0.9.8",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -29,12 +29,14 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.4",
|
||||
"@backstage/config": "^0.1.10",
|
||||
"@backstage/config-loader": "^0.7.0",
|
||||
"@backstage/errors": "^0.1.3",
|
||||
"@backstage/integration": "^0.6.7",
|
||||
"@backstage/cli-common": "^0.1.5",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/config-loader": "^0.7.1",
|
||||
"@backstage/errors": "^0.1.4",
|
||||
"@backstage/integration": "^0.6.9",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@google-cloud/storage": "^5.8.0",
|
||||
"@lerna/project": "^4.0.0",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"@types/cors": "^2.8.6",
|
||||
"@types/dockerode": "^3.2.1",
|
||||
@@ -77,8 +79,8 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.8.0",
|
||||
"@backstage/test-utils": "^0.1.18",
|
||||
"@backstage/cli": "^0.8.1",
|
||||
"@backstage/test-utils": "^0.1.20",
|
||||
"@types/archiver": "^5.1.0",
|
||||
"@types/compression": "^1.7.0",
|
||||
"@types/concat-stream": "^1.6.0",
|
||||
@@ -98,7 +100,7 @@
|
||||
"http-errors": "^1.7.3",
|
||||
"jest": "^26.0.1",
|
||||
"mock-fs": "^5.1.0",
|
||||
"msw": "^0.29.0",
|
||||
"msw": "^0.35.0",
|
||||
"mysql2": "^2.2.5",
|
||||
"recursive-readdir": "^2.2.2",
|
||||
"supertest": "^6.1.3"
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonValue } from '@backstage/config';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { createHash } from 'crypto';
|
||||
import Keyv from 'keyv';
|
||||
|
||||
|
||||
@@ -18,8 +18,38 @@ import { resolve as resolvePath } from 'path';
|
||||
import parseArgs from 'minimist';
|
||||
import { Logger } from 'winston';
|
||||
import { findPaths } from '@backstage/cli-common';
|
||||
import { Config, ConfigReader, JsonValue } from '@backstage/config';
|
||||
import { loadConfig } from '@backstage/config-loader';
|
||||
import {
|
||||
loadConfigSchema,
|
||||
loadConfig,
|
||||
ConfigSchema,
|
||||
} from '@backstage/config-loader';
|
||||
import { AppConfig, Config, ConfigReader } from '@backstage/config';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
|
||||
import { setRootLoggerRedactionList } from './logging/rootLogger';
|
||||
|
||||
// Fetch the schema and get all the secrets to pass to the rootLogger for redaction
|
||||
const updateRedactionList = (
|
||||
schema: ConfigSchema,
|
||||
configs: AppConfig[],
|
||||
logger: Logger,
|
||||
) => {
|
||||
const secretAppConfigs = schema.process(configs, { visibility: ['secret'] });
|
||||
const secretConfig = ConfigReader.fromConfigs(secretAppConfigs);
|
||||
const values = new Set<string>();
|
||||
const data = secretConfig.get();
|
||||
|
||||
JSON.parse(
|
||||
JSON.stringify(data),
|
||||
(_, v) => typeof v === 'string' && values.add(v),
|
||||
);
|
||||
|
||||
logger.info(
|
||||
`${values.size} secrets found in the config which will be redacted`,
|
||||
);
|
||||
|
||||
setRootLoggerRedactionList(Array.from(values));
|
||||
};
|
||||
|
||||
export class ObservableConfigProxy implements Config {
|
||||
private config: Config = new ConfigReader({});
|
||||
@@ -150,11 +180,20 @@ export async function loadBackendConfig(options: {
|
||||
const args = parseArgs(options.argv);
|
||||
const configPaths: string[] = [args.config ?? []].flat();
|
||||
|
||||
const config = new ObservableConfigProxy(options.logger);
|
||||
|
||||
/* eslint-disable-next-line no-restricted-syntax */
|
||||
const paths = findPaths(__dirname);
|
||||
|
||||
// TODO(hhogg): This is fetching _all_ of the packages of the monorepo
|
||||
// in order to find the secrets for redactions, however we only care about
|
||||
// the backend ones, we need to find a way to exclude the frontend packages.
|
||||
const { Project } = require('@lerna/project');
|
||||
const project = new Project(paths.targetDir);
|
||||
const packages = await project.getPackages();
|
||||
const schema = await loadConfigSchema({
|
||||
dependencies: packages.map((p: any) => p.name),
|
||||
});
|
||||
|
||||
const config = new ObservableConfigProxy(options.logger);
|
||||
const configs = await loadConfig({
|
||||
configRoot: paths.targetRoot,
|
||||
configPaths: configPaths.map(opt => resolvePath(opt)),
|
||||
@@ -186,5 +225,9 @@ export async function loadBackendConfig(options: {
|
||||
|
||||
config.setConfig(ConfigReader.fromConfigs(configs));
|
||||
|
||||
// Subscribe to config changes and update the redaction list for logging
|
||||
updateRedactionList(schema, configs, options.logger);
|
||||
config.subscribe(() => updateRedactionList(schema, configs, options.logger));
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
import { Knex } from 'knex';
|
||||
import { omit } from 'lodash';
|
||||
import { Config, ConfigReader, JsonObject } from '@backstage/config';
|
||||
import { Config, ConfigReader } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import {
|
||||
createDatabaseClient,
|
||||
ensureDatabaseExists,
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Config, JsonObject } from '@backstage/config';
|
||||
import { Config } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import knexFactory, { Knex } from 'knex';
|
||||
import { mergeDatabaseConfig } from './config';
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
*/
|
||||
|
||||
export * from './formats';
|
||||
export * from './rootLogger';
|
||||
export { createRootLogger, getRootLogger, setRootLogger } from './rootLogger';
|
||||
export * from './voidLogger';
|
||||
|
||||
@@ -15,7 +15,12 @@
|
||||
*/
|
||||
|
||||
import * as winston from 'winston';
|
||||
import { createRootLogger, getRootLogger, setRootLogger } from './rootLogger';
|
||||
import {
|
||||
createRootLogger,
|
||||
getRootLogger,
|
||||
setRootLogger,
|
||||
setRootLoggerRedactionList,
|
||||
} from './rootLogger';
|
||||
|
||||
describe('rootLogger', () => {
|
||||
it('can replace the default logger', () => {
|
||||
@@ -30,7 +35,20 @@ describe('rootLogger', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('createRootLoger', () => {
|
||||
it('redacts given secrets', () => {
|
||||
const logger = createRootLogger();
|
||||
jest.spyOn(logger, 'write');
|
||||
setRootLoggerRedactionList(['SECRET-1', 'SECRET_2', 'SECRET.3']);
|
||||
logger.info('Logging SECRET-1 and SECRET_2 and SECRET.3');
|
||||
|
||||
expect(logger.write).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
message: 'Logging [REDACTED] and [REDACTED] and [REDACTED]',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
describe('createRootLogger', () => {
|
||||
it('creates a new logger', () => {
|
||||
const oldLogger = getRootLogger();
|
||||
const newLogger = createRootLogger();
|
||||
|
||||
@@ -18,8 +18,10 @@ import { merge } from 'lodash';
|
||||
import * as winston from 'winston';
|
||||
import { LoggerOptions } from 'winston';
|
||||
import { coloredFormat } from './formats';
|
||||
import { escapeRegExp } from '../util/escapeRegExp';
|
||||
|
||||
let rootLogger: winston.Logger;
|
||||
let redactionRegExp: RegExp;
|
||||
|
||||
/** @public */
|
||||
export function getRootLogger(): winston.Logger {
|
||||
@@ -31,6 +33,30 @@ export function setRootLogger(newLogger: winston.Logger) {
|
||||
rootLogger = newLogger;
|
||||
}
|
||||
|
||||
export function setRootLoggerRedactionList(redactionList: string[]) {
|
||||
if (redactionList.length) {
|
||||
redactionRegExp = new RegExp(
|
||||
`(${redactionList.map(escapeRegExp).join('|')})`,
|
||||
'g',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A winston formatting function that finds occurrences of filteredKeys
|
||||
* and replaces them with the corresponding identifier.
|
||||
*/
|
||||
function redactLogLine(info: winston.Logform.TransformableInfo) {
|
||||
// TODO(hhogg): The logger is created before the config is loaded,
|
||||
// because the logger is needed in the config loader. There is a risk of
|
||||
// a secret being logged out during the config loading stage.
|
||||
if (redactionRegExp) {
|
||||
info.message = info.message.replace(redactionRegExp, '[REDACTED]');
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function createRootLogger(
|
||||
options: winston.LoggerOptions = {},
|
||||
@@ -41,6 +67,7 @@ export function createRootLogger(
|
||||
{
|
||||
level: env.LOG_LEVEL || 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format(redactLogLine)(),
|
||||
env.NODE_ENV === 'production' ? winston.format.json() : coloredFormat,
|
||||
),
|
||||
defaultMeta: {
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ConfigReader, JsonObject } from '@backstage/config';
|
||||
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { getVoidLogger } from '../logging';
|
||||
import { DefaultReadTreeResponseFactory } from './tree';
|
||||
import { AwsS3UrlReader } from './AwsS3UrlReader';
|
||||
@@ -25,6 +27,7 @@ import { UrlReaderPredicateTuple } from './types';
|
||||
import AWSMock from 'aws-sdk-mock';
|
||||
import aws from 'aws-sdk';
|
||||
import path from 'path';
|
||||
import { NotModifiedError } from '@backstage/errors';
|
||||
|
||||
const treeResponseFactory = DefaultReadTreeResponseFactory.create({
|
||||
config: new ConfigReader({}),
|
||||
@@ -129,29 +132,37 @@ describe('AwsS3UrlReader', () => {
|
||||
});
|
||||
|
||||
describe('read', () => {
|
||||
AWSMock.setSDKInstance(aws);
|
||||
AWSMock.mock(
|
||||
'S3',
|
||||
'getObject',
|
||||
Buffer.from(
|
||||
require('fs').readFileSync(
|
||||
path.resolve(__dirname, '__fixtures__/awsS3/awsS3-mock-object.yaml'),
|
||||
let awsS3UrlReader: AwsS3UrlReader;
|
||||
|
||||
beforeAll(() => {
|
||||
AWSMock.setSDKInstance(aws);
|
||||
AWSMock.mock(
|
||||
'S3',
|
||||
'getObject',
|
||||
Buffer.from(
|
||||
require('fs').readFileSync(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'__fixtures__/awsS3/awsS3-mock-object.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
const s3 = new aws.S3();
|
||||
const awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: 'amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
);
|
||||
|
||||
const s3 = new aws.S3();
|
||||
awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: 'amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
{ s3, treeResponseFactory },
|
||||
);
|
||||
{ s3, treeResponseFactory },
|
||||
);
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket', async () => {
|
||||
const response = await awsS3UrlReader.read(
|
||||
@@ -174,32 +185,39 @@ describe('AwsS3UrlReader', () => {
|
||||
});
|
||||
|
||||
describe('readUrl', () => {
|
||||
AWSMock.setSDKInstance(aws);
|
||||
let awsS3UrlReader: AwsS3UrlReader;
|
||||
|
||||
AWSMock.mock(
|
||||
'S3',
|
||||
'getObject',
|
||||
Buffer.from(
|
||||
require('fs').readFileSync(
|
||||
path.resolve(__dirname, '__fixtures__/awsS3/awsS3-mock-object.yaml'),
|
||||
beforeAll(() => {
|
||||
AWSMock.setSDKInstance(aws);
|
||||
|
||||
AWSMock.mock(
|
||||
'S3',
|
||||
'getObject',
|
||||
Buffer.from(
|
||||
require('fs').readFileSync(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'__fixtures__/awsS3/awsS3-mock-object.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
|
||||
const s3 = new aws.S3();
|
||||
const s3 = new aws.S3();
|
||||
|
||||
const awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: 'amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: 'amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
{ s3, treeResponseFactory },
|
||||
);
|
||||
{ s3, treeResponseFactory },
|
||||
);
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket', async () => {
|
||||
const response = await awsS3UrlReader.readUrl(
|
||||
@@ -221,40 +239,89 @@ describe('AwsS3UrlReader', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readUrl with etag', () => {
|
||||
let awsS3UrlReader: AwsS3UrlReader;
|
||||
|
||||
beforeAll(() => {
|
||||
AWSMock.setSDKInstance(aws);
|
||||
|
||||
AWSMock.mock('S3', 'getObject', (_, callback) => {
|
||||
callback({ statusCode: 304 }, null);
|
||||
});
|
||||
|
||||
const s3 = new aws.S3();
|
||||
|
||||
awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: 'amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
),
|
||||
),
|
||||
{ s3, treeResponseFactory },
|
||||
);
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket', async () => {
|
||||
await expect(
|
||||
awsS3UrlReader.readUrl(
|
||||
'https://test-bucket.s3.us-east-2.amazonaws.com/awsS3-mock-object.yaml',
|
||||
{
|
||||
etag: 'abc123',
|
||||
},
|
||||
),
|
||||
).rejects.toThrow(NotModifiedError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readTree', () => {
|
||||
const object: aws.S3.Types.Object = {
|
||||
Key: 'awsS3-mock-object.yaml',
|
||||
};
|
||||
const objectList: aws.S3.ObjectList = [object];
|
||||
const output: aws.S3.Types.ListObjectsV2Output = {
|
||||
Contents: objectList,
|
||||
};
|
||||
AWSMock.setSDKInstance(aws);
|
||||
AWSMock.mock('S3', 'listObjectsV2', output);
|
||||
let awsS3UrlReader: AwsS3UrlReader;
|
||||
|
||||
AWSMock.mock(
|
||||
'S3',
|
||||
'getObject',
|
||||
Buffer.from(
|
||||
require('fs').readFileSync(
|
||||
path.resolve(__dirname, '__fixtures__/awsS3/awsS3-mock-object.yaml'),
|
||||
),
|
||||
),
|
||||
);
|
||||
beforeAll(() => {
|
||||
const object: aws.S3.Types.Object = {
|
||||
Key: 'awsS3-mock-object.yaml',
|
||||
};
|
||||
|
||||
const s3 = new aws.S3();
|
||||
const awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: '.amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
const objectList: aws.S3.ObjectList = [object];
|
||||
const output: aws.S3.Types.ListObjectsV2Output = {
|
||||
Contents: objectList,
|
||||
};
|
||||
|
||||
AWSMock.setSDKInstance(aws);
|
||||
AWSMock.mock('S3', 'listObjectsV2', output);
|
||||
|
||||
AWSMock.mock(
|
||||
'S3',
|
||||
'getObject',
|
||||
Buffer.from(
|
||||
require('fs').readFileSync(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
'__fixtures__/awsS3/awsS3-mock-object.yaml',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
{ s3, treeResponseFactory },
|
||||
);
|
||||
);
|
||||
|
||||
const s3 = new aws.S3();
|
||||
awsS3UrlReader = new AwsS3UrlReader(
|
||||
new AwsS3Integration(
|
||||
readAwsS3IntegrationConfig(
|
||||
new ConfigReader({
|
||||
host: '.amazonaws.com',
|
||||
accessKeyId: 'fake-access-key',
|
||||
secretAccessKey: 'fake-secret-key',
|
||||
}),
|
||||
),
|
||||
),
|
||||
{ s3, treeResponseFactory },
|
||||
);
|
||||
});
|
||||
|
||||
it('returns contents of an object in a bucket', async () => {
|
||||
const response = await awsS3UrlReader.readTree(
|
||||
'https://test.s3.us-east-2.amazonaws.com',
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
} from './types';
|
||||
import getRawBody from 'raw-body';
|
||||
import { AwsS3Integration, ScmIntegrations } from '@backstage/integration';
|
||||
import { ForwardedError } from '@backstage/errors';
|
||||
import { ForwardedError, NotModifiedError } from '@backstage/errors';
|
||||
import { ListObjectsV2Output, ObjectList } from 'aws-sdk/clients/s3';
|
||||
|
||||
const parseURL = (
|
||||
@@ -163,6 +163,10 @@ export class AwsS3UrlReader implements UrlReader {
|
||||
etag: etag,
|
||||
};
|
||||
} catch (e) {
|
||||
if (e.statusCode === 304) {
|
||||
throw new NotModifiedError();
|
||||
}
|
||||
|
||||
throw new ForwardedError('Could not retrieve file from S3', e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
AzureIntegration,
|
||||
readAzureIntegrationConfig,
|
||||
} from '@backstage/integration';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
import fs from 'fs-extra';
|
||||
import mockFs from 'mock-fs';
|
||||
import { rest } from 'msw';
|
||||
@@ -51,7 +51,7 @@ describe('AzureUrlReader', () => {
|
||||
});
|
||||
|
||||
const worker = setupServer();
|
||||
msw.setupDefaultHandlers(worker);
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
describe('read', () => {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
BitbucketIntegration,
|
||||
readBitbucketIntegrationConfig,
|
||||
} from '@backstage/integration';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
import fs from 'fs-extra';
|
||||
import mockFs from 'mock-fs';
|
||||
import { rest } from 'msw';
|
||||
@@ -72,7 +72,7 @@ describe('BitbucketUrlReader', () => {
|
||||
});
|
||||
|
||||
const worker = setupServer();
|
||||
msw.setupDefaultHandlers(worker);
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
describe('readUrl', () => {
|
||||
worker.use(
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { NotFoundError, NotModifiedError } from '@backstage/errors';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { getVoidLogger } from '../logging';
|
||||
@@ -28,7 +28,7 @@ const fetchUrlReader = new FetchUrlReader();
|
||||
describe('FetchUrlReader', () => {
|
||||
const worker = setupServer();
|
||||
|
||||
msw.setupDefaultHandlers(worker);
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
GitHubIntegration,
|
||||
readGitHubIntegrationConfig,
|
||||
} from '@backstage/integration';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
import fs from 'fs-extra';
|
||||
import mockFs from 'mock-fs';
|
||||
import { rest } from 'msw';
|
||||
@@ -73,7 +73,7 @@ const tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp';
|
||||
|
||||
describe('GithubUrlReader', () => {
|
||||
const worker = setupServer();
|
||||
msw.setupDefaultHandlers(worker);
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
beforeEach(() => {
|
||||
mockFs({
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
import fs from 'fs-extra';
|
||||
import mockFs from 'mock-fs';
|
||||
import { rest } from 'msw';
|
||||
@@ -77,7 +77,7 @@ describe('GitlabUrlReader', () => {
|
||||
});
|
||||
|
||||
const worker = setupServer();
|
||||
msw.setupDefaultHandlers(worker);
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
describe('read', () => {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ConfigReader, JsonObject } from '@backstage/config';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { getVoidLogger } from '../logging';
|
||||
import { DefaultReadTreeResponseFactory } from './tree';
|
||||
import { GoogleGcsUrlReader } from './GoogleGcsUrlReader';
|
||||
|
||||
@@ -20,6 +20,7 @@ export { GithubUrlReader } from './GithubUrlReader';
|
||||
export { GitlabUrlReader } from './GitlabUrlReader';
|
||||
export { AwsS3UrlReader } from './AwsS3UrlReader';
|
||||
export type {
|
||||
FromReadableArrayOptions,
|
||||
ReaderFactory,
|
||||
ReadTreeOptions,
|
||||
ReadTreeResponse,
|
||||
|
||||
@@ -24,24 +24,41 @@ import { Config } from '@backstage/config';
|
||||
* @public
|
||||
*/
|
||||
export type UrlReader = {
|
||||
/* Used to read a single file and return its content. */
|
||||
/**
|
||||
* Reads a single file and return its content.
|
||||
*/
|
||||
read(url: string): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* A replacement for the read method that supports options and complex responses.
|
||||
* Reads a single file and return its content.
|
||||
*
|
||||
* Use this whenever it is available, as the read method will be deprecated and
|
||||
* eventually removed in the future.
|
||||
* @remarks
|
||||
*
|
||||
* This is a replacement for the read method that supports options and
|
||||
* complex responses.
|
||||
*
|
||||
* Use this whenever it is available, as the read method will be
|
||||
* deprecated and eventually removed in a future release.
|
||||
*/
|
||||
readUrl?(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
|
||||
|
||||
/* Used to read a file tree and download as a directory. */
|
||||
/**
|
||||
* Reads a full or partial file tree.
|
||||
*/
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
/* Used to search a file in a tree using a glob pattern. */
|
||||
|
||||
/**
|
||||
* Searches for a file in a tree using a glob pattern.
|
||||
*/
|
||||
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A predicate that decides whether a specific {@link UrlReader} can handle a
|
||||
* given URL.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UrlReaderPredicateTuple = {
|
||||
predicate: (url: URL) => boolean;
|
||||
reader: UrlReader;
|
||||
@@ -49,7 +66,7 @@ export type UrlReaderPredicateTuple = {
|
||||
|
||||
/**
|
||||
* A factory function that can read config to construct zero or more
|
||||
* UrlReaders along with a predicate for when it should be used.
|
||||
* {@link UrlReader}s along with a predicate for when it should be used.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -66,21 +83,28 @@ export type ReaderFactory = (options: {
|
||||
*/
|
||||
export type ReadUrlOptions = {
|
||||
/**
|
||||
* An etag can be provided to check whether readUrl's response has changed from a previous execution.
|
||||
* An ETag which can be provided to check whether a
|
||||
* {@link UrlReader.readUrl} response has changed from a previous execution.
|
||||
*
|
||||
* In the readUrl() response, an etag is returned along with the data. The etag is a unique identifer
|
||||
* of the data, usually the commit SHA or etag from the target.
|
||||
* @remarks
|
||||
*
|
||||
* When an etag is given in ReadUrlOptions, readUrl will first compare the etag against the etag
|
||||
* on the target. If they match, readUrl will throw a NotModifiedError indicating that the readUrl
|
||||
* response will not differ from the previous response which included this particular etag. If they
|
||||
* do not match, readUrl will return the rest of ReadUrlResponse along with a new etag.
|
||||
* In the {@link UrlReader.readUrl} response, an ETag is returned along with
|
||||
* the data. The ETag is a unique identifier of the data, usually the commit
|
||||
* SHA or ETag from the target.
|
||||
*
|
||||
* When an ETag is given in ReadUrlOptions, {@link UrlReader.readUrl} will
|
||||
* first compare the ETag against the ETag of the target. If they match,
|
||||
* {@link UrlReader.readUrl} will throw a
|
||||
* {@link @backstage/errors#NotModifiedError} indicating that the response
|
||||
* will not differ from the previous response which included this particular
|
||||
* ETag. If they do not match, {@link UrlReader.readUrl} will return the rest
|
||||
* of the response along with a new ETag.
|
||||
*/
|
||||
etag?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A response object for readUrl operations.
|
||||
* A response object for {@link UrlReader.readUrl} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -92,13 +116,16 @@ export type ReadUrlResponse = {
|
||||
|
||||
/**
|
||||
* Etag returned by content provider.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Can be used to compare and cache responses when doing subsequent calls.
|
||||
*/
|
||||
etag?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* An options object for readTree operations.
|
||||
* An options object for {@link UrlReader.readTree} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -106,6 +133,8 @@ export type ReadTreeOptions = {
|
||||
/**
|
||||
* A filter that can be used to select which files should be included.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The path passed to the filter function is the relative path from the URL
|
||||
* that the file tree is fetched from, without any leading '/'.
|
||||
*
|
||||
@@ -113,56 +142,82 @@ export type ReadTreeOptions = {
|
||||
* at https://github.com/my/repo/blob/master/my-dir/my-subdir/my-file.txt will
|
||||
* be represented as my-subdir/my-file.txt
|
||||
*
|
||||
* If no filter is provided all files are extracted.
|
||||
* If no filter is provided, all files are extracted.
|
||||
*/
|
||||
filter?(path: string, info?: { size: number }): boolean;
|
||||
|
||||
/**
|
||||
* An etag can be provided to check whether readTree's response has changed from a previous execution.
|
||||
* An ETag which can be provided to check whether a
|
||||
* {@link UrlReader.readTree} response has changed from a previous execution.
|
||||
*
|
||||
* In the readTree() response, an etag is returned along with the tree blob. The etag is a unique identifer
|
||||
* of the tree blob, usually the commit SHA or etag from the target.
|
||||
* @remarks
|
||||
*
|
||||
* When an etag is given in ReadTreeOptions, readTree will first compare the etag against the etag
|
||||
* on the target branch. If they match, readTree will throw a NotModifiedError indicating that the readTree
|
||||
* response will not differ from the previous response which included this particular etag. If they
|
||||
* do not match, readTree will return the rest of ReadTreeResponse along with a new etag.
|
||||
* In the {@link UrlReader.readTree} response, an ETag is returned along with
|
||||
* the tree blob. The ETag is a unique identifier of the tree blob, usually
|
||||
* the commit SHA or ETag from the target.
|
||||
*
|
||||
* When an ETag is given as a request option, {@link UrlReader.readTree} will
|
||||
* first compare the ETag against the ETag on the target branch. If they
|
||||
* match, {@link UrlReader.readTree} will throw a
|
||||
* {@link @backstage/errors#NotModifiedError} indicating that the response
|
||||
* will not differ from the previous response which included this particular
|
||||
* ETag. If they do not match, {@link UrlReader.readTree} will return the
|
||||
* rest of the response along with a new ETag.
|
||||
*/
|
||||
etag?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options that control {@link ReadTreeResponse.dir} execution.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponseDirOptions = {
|
||||
/** The directory to write files to. Defaults to the OS tmpdir or `backend.workingDirectory` if set in config */
|
||||
/**
|
||||
* The directory to write files to.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Defaults to the OS tmpdir, or `backend.workingDirectory` if set in config.
|
||||
*/
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A response object for readTree operations.
|
||||
* A response object for {@link UrlReader.readTree} operations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponse = {
|
||||
/**
|
||||
* files() returns an array of all the files inside the tree and corresponding functions to read their content.
|
||||
* Returns an array of all the files inside the tree, and corresponding
|
||||
* functions to read their content.
|
||||
*/
|
||||
files(): Promise<ReadTreeResponseFile[]>;
|
||||
|
||||
/**
|
||||
* Returns the tree contents as a binary archive, using a stream.
|
||||
*/
|
||||
archive(): Promise<NodeJS.ReadableStream>;
|
||||
|
||||
/**
|
||||
* dir() extracts the tree response into a directory and returns the path of the directory.
|
||||
* Extracts the tree response into a directory and returns the path of the
|
||||
* directory.
|
||||
*/
|
||||
dir(options?: ReadTreeResponseDirOptions): Promise<string>;
|
||||
|
||||
/**
|
||||
* Etag returned by content provider.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Can be used to compare and cache responses when doing subsequent calls.
|
||||
*/
|
||||
etag: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a single file in a readTree response.
|
||||
* Represents a single file in a {@link UrlReader.readTree} response.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -171,7 +226,11 @@ export type ReadTreeResponseFile = {
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options that control execution of {@link ReadTreeResponseFactory} methods.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ReadTreeResponseFactoryOptions = {
|
||||
// A binary stream of a tar archive.
|
||||
stream: Readable;
|
||||
@@ -183,11 +242,21 @@ export type ReadTreeResponseFactoryOptions = {
|
||||
// Filter passed on from the ReadTreeOptions
|
||||
filter?: (path: string, info?: { size: number }) => boolean;
|
||||
};
|
||||
/** @public */
|
||||
|
||||
/**
|
||||
* Options that control {@link ReadTreeResponseFactory.fromReadableArray}
|
||||
* execution.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type FromReadableArrayOptions = Array<{
|
||||
// Data in the form of a readable
|
||||
/**
|
||||
* The raw data itself.
|
||||
*/
|
||||
data: Readable;
|
||||
// A string containing the filepath of the data
|
||||
/**
|
||||
* The filepath of the data.
|
||||
*/
|
||||
path: string;
|
||||
}>;
|
||||
|
||||
@@ -213,7 +282,7 @@ export type SearchOptions = {
|
||||
/**
|
||||
* An etag can be provided to check whether the search response has changed from a previous execution.
|
||||
*
|
||||
* In the search() response, an etag is returned along with the files. The etag is a unique identifer
|
||||
* In the search() response, an etag is returned along with the files. The etag is a unique identifier
|
||||
* of the current tree, usually the commit SHA or etag from the target.
|
||||
*
|
||||
* When an etag is given in SearchOptions, search will first compare the etag against the etag
|
||||
@@ -236,7 +305,7 @@ export type SearchResponse = {
|
||||
files: SearchResponseFile[];
|
||||
|
||||
/**
|
||||
* A unique identifer of the current remote tree, usually the commit SHA or etag from the target.
|
||||
* A unique identifier of the current remote tree, usually the commit SHA or etag from the target.
|
||||
*/
|
||||
etag: string;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* 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 { escapeRegExp } from './escapeRegExp';
|
||||
|
||||
describe('escapeRegExp', () => {
|
||||
test('does not escape non-regex characters', () => {
|
||||
expect(escapeRegExp('Backstage Backstage')).toBe('Backstage Backstage');
|
||||
});
|
||||
|
||||
test('all the characters', () => {
|
||||
expect(escapeRegExp('^$\\.*+?()[]{}|')).toBe(
|
||||
'\\^\\$\\\\\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|',
|
||||
);
|
||||
});
|
||||
|
||||
test('character: ^', () => {
|
||||
expect(escapeRegExp('^')).toBe('\\^');
|
||||
});
|
||||
|
||||
test('character: $', () => {
|
||||
expect(escapeRegExp('$')).toBe('\\$');
|
||||
});
|
||||
|
||||
test('character: \\', () => {
|
||||
expect(escapeRegExp('\\')).toBe('\\\\');
|
||||
});
|
||||
|
||||
test('character: .', () => {
|
||||
expect(escapeRegExp('.')).toBe('\\.');
|
||||
});
|
||||
|
||||
test('character: *', () => {
|
||||
expect(escapeRegExp('*')).toBe('\\*');
|
||||
});
|
||||
|
||||
test('character: +', () => {
|
||||
expect(escapeRegExp('+')).toBe('\\+');
|
||||
});
|
||||
|
||||
test('character: ?', () => {
|
||||
expect(escapeRegExp('?')).toBe('\\?');
|
||||
});
|
||||
|
||||
test('character: (', () => {
|
||||
expect(escapeRegExp('(')).toBe('\\(');
|
||||
});
|
||||
|
||||
test('character: )', () => {
|
||||
expect(escapeRegExp(')')).toBe('\\)');
|
||||
});
|
||||
|
||||
test('character: [', () => {
|
||||
expect(escapeRegExp('[')).toBe('\\[');
|
||||
});
|
||||
|
||||
test('character: ]', () => {
|
||||
expect(escapeRegExp(']')).toBe('\\]');
|
||||
});
|
||||
|
||||
test('character: {', () => {
|
||||
expect(escapeRegExp('{')).toBe('\\{');
|
||||
});
|
||||
|
||||
test('character: }', () => {
|
||||
expect(escapeRegExp('}')).toBe('\\}');
|
||||
});
|
||||
|
||||
test('character: |', () => {
|
||||
expect(escapeRegExp('|')).toBe('\\|');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Escapes a given string to be used inside a RegExp.
|
||||
*
|
||||
* Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
||||
*/
|
||||
export const escapeRegExp = (text: string) => {
|
||||
return text.replace(/[.*+?^${}(\)|[\]\\]/g, '\\$&');
|
||||
};
|
||||
@@ -48,6 +48,9 @@
|
||||
"@backstage/plugin-search-backend-module-elasticsearch": "^0.0.4",
|
||||
"@backstage/plugin-search-backend-module-pg": "^0.2.1",
|
||||
"@backstage/plugin-techdocs-backend": "^0.10.5",
|
||||
"@backstage/plugin-tech-insights-backend": "^0.1.0",
|
||||
"@backstage/plugin-tech-insights-node": "^0.1.0",
|
||||
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.0",
|
||||
"@backstage/plugin-todo-backend": "^0.1.13",
|
||||
"@gitbeaker/node": "^30.2.0",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
|
||||
@@ -53,6 +53,7 @@ import graphql from './plugins/graphql';
|
||||
import app from './plugins/app';
|
||||
import badges from './plugins/badges';
|
||||
import jenkins from './plugins/jenkins';
|
||||
import techInsights from './plugins/techInsights';
|
||||
import { PluginEnvironment } from './types';
|
||||
|
||||
function makeCreateEnv(config: Config) {
|
||||
@@ -107,12 +108,16 @@ async function main() {
|
||||
const appEnv = useHotMemoize(module, () => createEnv('app'));
|
||||
const badgesEnv = useHotMemoize(module, () => createEnv('badges'));
|
||||
const jenkinsEnv = useHotMemoize(module, () => createEnv('jenkins'));
|
||||
const techInsightsEnv = useHotMemoize(module, () =>
|
||||
createEnv('tech-insights'),
|
||||
);
|
||||
|
||||
const apiRouter = Router();
|
||||
apiRouter.use('/catalog', await catalog(catalogEnv));
|
||||
apiRouter.use('/code-coverage', await codeCoverage(codeCoverageEnv));
|
||||
apiRouter.use('/rollbar', await rollbar(rollbarEnv));
|
||||
apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv));
|
||||
apiRouter.use('/tech-insights', await techInsights(techInsightsEnv));
|
||||
apiRouter.use('/auth', await auth(authEnv));
|
||||
apiRouter.use('/azure-devops', await azureDevOps(azureDevOpsEnv));
|
||||
apiRouter.use('/search', await search(searchEnv));
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* 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 {
|
||||
createRouter,
|
||||
buildTechInsightsContext,
|
||||
createFactRetrieverRegistration,
|
||||
} from '@backstage/plugin-tech-insights-backend';
|
||||
import { Router } from 'express';
|
||||
import { PluginEnvironment } from '../types';
|
||||
import { CatalogClient } from '@backstage/catalog-client';
|
||||
import {
|
||||
JsonRulesEngineFactCheckerFactory,
|
||||
JSON_RULE_ENGINE_CHECK_TYPE,
|
||||
} from '@backstage/plugin-tech-insights-backend-module-jsonfc';
|
||||
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
config,
|
||||
discovery,
|
||||
database,
|
||||
}: PluginEnvironment): Promise<Router> {
|
||||
const techInsightsContext = await buildTechInsightsContext({
|
||||
logger,
|
||||
config,
|
||||
database,
|
||||
discovery,
|
||||
factRetrievers: [
|
||||
createFactRetrieverRegistration('5 4 * * 6', {
|
||||
// Example cron, At 04:05 on Saturday.
|
||||
id: 'testRetriever',
|
||||
version: '1.1.2',
|
||||
entityFilter: [{ kind: 'component' }], // EntityFilter to be used in the future (creating checks, graphs etc.) to figure out which entities this fact retrieves data for.
|
||||
schema: {
|
||||
examplenumberfact: {
|
||||
type: 'integer',
|
||||
description: 'Example fact returning a number',
|
||||
},
|
||||
},
|
||||
handler: async _ctx => {
|
||||
const catalogClient = new CatalogClient({
|
||||
discoveryApi: discovery,
|
||||
});
|
||||
const entities = await catalogClient.getEntities({
|
||||
filter: [{ kind: 'component' }],
|
||||
});
|
||||
|
||||
return Promise.resolve(
|
||||
entities.items.map(it => {
|
||||
return {
|
||||
entity: {
|
||||
namespace: it.metadata.namespace!!,
|
||||
kind: it.kind,
|
||||
name: it.metadata.name,
|
||||
},
|
||||
facts: {
|
||||
examplenumberfact: 2,
|
||||
},
|
||||
};
|
||||
}),
|
||||
);
|
||||
},
|
||||
}),
|
||||
],
|
||||
factCheckerFactory: new JsonRulesEngineFactCheckerFactory({
|
||||
checks: [
|
||||
{
|
||||
id: 'simpleTestCheck',
|
||||
type: JSON_RULE_ENGINE_CHECK_TYPE,
|
||||
name: 'simpleTestCheck',
|
||||
description: 'Simple Check For Testing',
|
||||
factIds: ['testRetriever'],
|
||||
rule: {
|
||||
conditions: {
|
||||
all: [
|
||||
{
|
||||
fact: 'examplenumberfact',
|
||||
operator: 'lessThan',
|
||||
value: 5,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
logger,
|
||||
}),
|
||||
});
|
||||
|
||||
return await createRouter({
|
||||
...techInsightsContext,
|
||||
logger,
|
||||
config,
|
||||
});
|
||||
}
|
||||
@@ -37,7 +37,7 @@
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.8.0",
|
||||
"@types/jest": "^26.0.7",
|
||||
"msw": "^0.29.0"
|
||||
"msw": "^0.35.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/catalog-model
|
||||
|
||||
## 0.9.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10615525f3: Switch to use the json and observable types from `@backstage/types`
|
||||
- Updated dependencies
|
||||
- @backstage/config@0.1.11
|
||||
- @backstage/errors@0.1.4
|
||||
|
||||
## 0.9.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { JsonValue } from '@backstage/config';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { SerializedError } from '@backstage/errors';
|
||||
import * as yup from 'yup';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/catalog-model",
|
||||
"description": "Types and validators that help describe the model of a Backstage Catalog",
|
||||
"version": "0.9.5",
|
||||
"version": "0.9.6",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,8 +30,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.10",
|
||||
"@backstage/errors": "^0.1.3",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/errors": "^0.1.4",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@types/json-schema": "^7.0.5",
|
||||
"@types/yup": "^0.29.13",
|
||||
"ajv": "^7.0.3",
|
||||
@@ -41,7 +42,7 @@
|
||||
"yup": "^0.32.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.8.0",
|
||||
"@backstage/cli": "^0.8.1",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/lodash": "^4.14.151",
|
||||
"yaml": "^1.9.2"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { EntityName } from '../types';
|
||||
import { UNSTABLE_EntityStatus } from './EntityStatus';
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import type { Entity } from '../entity/Entity';
|
||||
import schema from '../schema/kinds/Template.v1beta2.schema.json';
|
||||
import { ajvCompiledJsonSchemaValidator } from './util';
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonValue } from '@backstage/config';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/cli-common
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c2d50a0073: Add docs to the last export of cli-common
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -21,6 +21,6 @@ export type Paths = {
|
||||
resolveTargetRoot: ResolveFunc;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type ResolveFunc = (...paths: string[]) => string;
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli-common",
|
||||
"description": "Common functionality used by cli, backend, and create-app",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"private": false,
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
|
||||
@@ -17,7 +17,12 @@
|
||||
import fs from 'fs';
|
||||
import { dirname, resolve as resolvePath } from 'path';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A function that takes a set of path fragments and resolves them into a
|
||||
* single complete path, relative to some root.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ResolveFunc = (...paths: string[]) => string;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- f1e96dc5b1: Update usage of msw in default plugin template
|
||||
- b0dc1fd241: bump `@spotify/eslint-config-base` from 9.0.2 to 12.0.0
|
||||
- c5bb1df55d: Bump `msw` to `v0.35.0` to resolve [CVE-2021-32796](https://github.com/advisories/GHSA-5fg8-2547-mr8q).
|
||||
- 10615525f3: Switch to use the json and observable types from `@backstage/types`
|
||||
- Updated dependencies
|
||||
- @backstage/config@0.1.11
|
||||
- @backstage/cli-common@0.1.5
|
||||
- @backstage/errors@0.1.4
|
||||
- @backstage/config-loader@0.7.1
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
+15
-14
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.1",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -28,10 +28,11 @@
|
||||
"backstage-cli": "bin/backstage-cli"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.4",
|
||||
"@backstage/config": "^0.1.10",
|
||||
"@backstage/config-loader": "^0.7.0",
|
||||
"@backstage/errors": "^0.1.3",
|
||||
"@backstage/cli-common": "^0.1.5",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/config-loader": "^0.7.1",
|
||||
"@backstage/errors": "^0.1.4",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@hot-loader/react-dom": "^16.13.0",
|
||||
"@lerna/package-graph": "^4.0.0",
|
||||
"@lerna/project": "^4.0.0",
|
||||
@@ -40,7 +41,7 @@
|
||||
"@rollup/plugin-json": "^4.0.2",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@rollup/plugin-yaml": "^3.0.0",
|
||||
"@spotify/eslint-config-base": "^9.0.0",
|
||||
"@spotify/eslint-config-base": "^12.0.0",
|
||||
"@spotify/eslint-config-react": "^10.0.0",
|
||||
"@spotify/eslint-config-typescript": "^10.0.0",
|
||||
"@sucrase/jest-plugin": "^2.1.1",
|
||||
@@ -109,21 +110,21 @@
|
||||
"typescript": "^4.0.3",
|
||||
"util": "^0.12.3",
|
||||
"webpack": "^5.48.0",
|
||||
"webpack-dev-server": "4.0.0-rc.0",
|
||||
"webpack-dev-server": "4.3.1",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"yaml": "^1.10.0",
|
||||
"yml-loader": "^2.1.0",
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "^0.9.7",
|
||||
"@backstage/config": "^0.1.10",
|
||||
"@backstage/core-components": "^0.7.1",
|
||||
"@backstage/core-plugin-api": "^0.1.11",
|
||||
"@backstage/core-app-api": "^0.1.18",
|
||||
"@backstage/backend-common": "^0.9.8",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/core-components": "^0.7.2",
|
||||
"@backstage/core-plugin-api": "^0.1.12",
|
||||
"@backstage/core-app-api": "^0.1.19",
|
||||
"@backstage/dev-utils": "^0.2.12",
|
||||
"@backstage/test-utils": "^0.1.19",
|
||||
"@backstage/theme": "^0.2.11",
|
||||
"@backstage/test-utils": "^0.1.20",
|
||||
"@backstage/theme": "^0.2.12",
|
||||
"@types/diff": "^5.0.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { mergeConfigSchemas } from '@backstage/config-loader';
|
||||
import { Command } from 'commander';
|
||||
import { JSONSchema7 as JSONSchema } from 'json-schema';
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Command } from 'commander';
|
||||
import { JSONSchema7 as JSONSchema } from 'json-schema';
|
||||
import { stringify as stringifyYaml } from 'yaml';
|
||||
import { loadCliConfig } from '../../lib/config';
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { mergeConfigSchemas } from '@backstage/config-loader';
|
||||
|
||||
export default async (cmd: Command) => {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { YarnInfoInspectData } from '../../lib/versioning';
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* TODO: possible types
|
||||
|
||||
@@ -24,14 +24,16 @@ import { tmpdir } from 'os';
|
||||
import tar, { CreateOptions } from 'tar';
|
||||
import { paths } from '../paths';
|
||||
import { run } from '../run';
|
||||
import { packageVersions } from '../version';
|
||||
import { ParallelOption } from '../parallel';
|
||||
import {
|
||||
dependencies as cliDependencies,
|
||||
devDependencies as cliDevDependencies,
|
||||
} from '../../../package.json';
|
||||
|
||||
// These packages aren't safe to pack in parallel since the CLI depends on them
|
||||
const UNSAFE_PACKAGES = [
|
||||
...Object.keys(packageVersions),
|
||||
'@backstage/cli-common',
|
||||
'@backstage/config-loader',
|
||||
...Object.keys(cliDependencies),
|
||||
...Object.keys(cliDevDependencies),
|
||||
];
|
||||
|
||||
type LernaPackage = {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"@backstage/cli": "{{versionQuery '@backstage/cli'}}",
|
||||
"@types/supertest": "{{versionQuery '@types/supertest' '2.0.8'}}",
|
||||
"supertest": "{{versionQuery 'supertest' '4.0.2'}}",
|
||||
"msw": "{{versionQuery 'msw' '0.29.0'}}"
|
||||
"msw": "{{versionQuery 'msw' '0.35.0'}}"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"@testing-library/user-event": "{{versionQuery '@testing-library/user-event' '13.1.8'}}",
|
||||
"@types/jest": "{{versionQuery '@types/jest' '26.0.7'}}",
|
||||
"@types/node": "{{versionQuery '@types/node' '14.14.32'}}",
|
||||
"msw": "{{versionQuery 'msw' '0.29.0'}}",
|
||||
"msw": "{{versionQuery 'msw' '0.35.0'}}",
|
||||
"cross-fetch": "{{versionQuery 'cross-fetch' '3.0.6'}}"
|
||||
},
|
||||
"files": [
|
||||
|
||||
+5
-2
@@ -4,12 +4,15 @@ import { ThemeProvider } from '@material-ui/core';
|
||||
import { lightTheme } from '@backstage/theme';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { msw, renderInTestApp } from '@backstage/test-utils';
|
||||
import {
|
||||
setupRequestMockHandlers,
|
||||
renderInTestApp,
|
||||
} from "@backstage/test-utils";
|
||||
|
||||
describe('ExampleComponent', () => {
|
||||
const server = setupServer();
|
||||
// Enable sane handlers for network requests
|
||||
msw.setupDefaultHandlers(server);
|
||||
setupRequestMockHandlers(server);
|
||||
|
||||
// setup mock response
|
||||
beforeEach(() => {
|
||||
|
||||
+2
-2
@@ -3,12 +3,12 @@ import { render } from '@testing-library/react';
|
||||
import { ExampleFetchComponent } from './ExampleFetchComponent';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { msw } from '@backstage/test-utils';
|
||||
import { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
|
||||
describe('ExampleFetchComponent', () => {
|
||||
const server = setupServer();
|
||||
// Enable sane handlers for network requests
|
||||
msw.setupDefaultHandlers(server);
|
||||
setupRequestMockHandlers(server);
|
||||
|
||||
// setup mock response
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/codemods
|
||||
|
||||
## 0.1.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/cli-common@0.1.5
|
||||
- @backstage/core-components@0.7.2
|
||||
- @backstage/core-app-api@0.1.19
|
||||
- @backstage/core-plugin-api@0.1.12
|
||||
|
||||
## 0.1.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/codemods",
|
||||
"description": "A collection of codemods for Backstage projects",
|
||||
"version": "0.1.19",
|
||||
"version": "0.1.20",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -31,7 +31,7 @@
|
||||
"backstage-codemods": "bin/backstage-codemods"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "0.1.4",
|
||||
"@backstage/cli-common": "0.1.5",
|
||||
"@backstage/core-app-api": "*",
|
||||
"@backstage/core-components": "*",
|
||||
"@backstage/core-plugin-api": "*",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/config-loader
|
||||
|
||||
## 0.7.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10615525f3: Switch to use the json and observable types from `@backstage/types`
|
||||
- ea21f7f567: bump `typescript-json-schema` from 0.50.1 to 0.51.0
|
||||
- Updated dependencies
|
||||
- @backstage/config@0.1.11
|
||||
- @backstage/cli-common@0.1.5
|
||||
- @backstage/errors@0.1.4
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
```ts
|
||||
import { AppConfig } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
|
||||
// @public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/config-loader",
|
||||
"description": "Config loading functionality used by Backstage backend, and CLI",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -30,9 +30,10 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.4",
|
||||
"@backstage/config": "^0.1.9",
|
||||
"@backstage/errors": "^0.1.3",
|
||||
"@backstage/cli-common": "^0.1.5",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/errors": "^0.1.4",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@types/json-schema": "^7.0.6",
|
||||
"ajv": "^7.0.3",
|
||||
"chokidar": "^3.5.2",
|
||||
@@ -40,7 +41,7 @@
|
||||
"json-schema": "^0.3.0",
|
||||
"json-schema-merge-allof": "^0.8.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"typescript-json-schema": "^0.50.1",
|
||||
"typescript-json-schema": "^0.51.0",
|
||||
"yaml": "^1.9.2",
|
||||
"yup": "^0.32.9"
|
||||
},
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppConfig, JsonObject } from '@backstage/config';
|
||||
import { AppConfig } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { assertError } from '@backstage/errors';
|
||||
|
||||
const ENV_PREFIX = 'APP_CONFIG_';
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
} from 'path';
|
||||
import { ConfigSchemaPackageEntry } from './types';
|
||||
import { getProgramFromFiles, generateSchema } from 'typescript-json-schema';
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { assertError } from '@backstage/errors';
|
||||
|
||||
type Item = {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonObject } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { ConfigVisibility } from './types';
|
||||
import { filterByVisibility, filterErrorsByVisibility } from './filtering';
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonObject, JsonValue } from '@backstage/config';
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import {
|
||||
ConfigVisibility,
|
||||
DEFAULT_CONFIG_VISIBILITY,
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppConfig, JsonObject } from '@backstage/config';
|
||||
import { AppConfig } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { compileConfigSchemas } from './compile';
|
||||
import { collectConfigSchemas } from './collect';
|
||||
import { filterByVisibility, filterErrorsByVisibility } from './filtering';
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppConfig, JsonObject } from '@backstage/config';
|
||||
import { AppConfig } from '@backstage/config';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* An sub-set of configuration schema.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonObject, JsonValue } from '@backstage/config';
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import { assertError } from '@backstage/errors';
|
||||
import { TransformFunc } from './types';
|
||||
import { isObject } from './utils';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import yaml from 'yaml';
|
||||
import { extname, dirname, resolve as resolvePath } from 'path';
|
||||
import { JsonObject, JsonValue } from '@backstage/config';
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import { isObject } from './utils';
|
||||
import { TransformFunc, EnvFunc, ReadFileFunc } from './types';
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonValue } from '@backstage/config';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { TransformFunc, EnvFunc } from './types';
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonValue } from '@backstage/config';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
|
||||
export type EnvFunc = (name: string) => Promise<string | undefined>;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JsonValue, JsonObject } from '@backstage/config';
|
||||
import { JsonValue, JsonObject } from '@backstage/types';
|
||||
|
||||
export function isObject(obj: JsonValue | undefined): obj is JsonObject {
|
||||
if (typeof obj !== 'object') {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/config
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10d267a1b7: Minor exports cleanup
|
||||
- 41c49884d2: Start using the new `@backstage/types` package. Initially, this means using the `Observable` and `Json*` types from there. The types also remain in their old places but deprecated, and will be removed in a future release.
|
||||
- 925a967f36: Replace usage of test-utils-core with test-utils
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import type { JsonArray as JsonArray_2 } from '@backstage/types';
|
||||
import { JsonObject as JsonObject_2 } from '@backstage/types';
|
||||
import type { JsonPrimitive as JsonPrimitive_2 } from '@backstage/types';
|
||||
import { JsonValue as JsonValue_2 } from '@backstage/types';
|
||||
|
||||
// @public
|
||||
export type AppConfig = {
|
||||
context: string;
|
||||
data: JsonObject;
|
||||
data: JsonObject_2;
|
||||
filteredKeys?: string[];
|
||||
};
|
||||
|
||||
@@ -17,8 +22,8 @@ export type Config = {
|
||||
};
|
||||
has(key: string): boolean;
|
||||
keys(): string[];
|
||||
get<T = JsonValue>(key?: string): T;
|
||||
getOptional<T = JsonValue>(key?: string): T | undefined;
|
||||
get<T = JsonValue_2>(key?: string): T;
|
||||
getOptional<T = JsonValue_2>(key?: string): T | undefined;
|
||||
getConfig(key: string): Config;
|
||||
getOptionalConfig(key: string): Config | undefined;
|
||||
getConfigArray(key: string): Config[];
|
||||
@@ -36,58 +41,39 @@ export type Config = {
|
||||
// @public
|
||||
export class ConfigReader implements Config {
|
||||
constructor(
|
||||
data: JsonObject | undefined,
|
||||
data: JsonObject_2 | undefined,
|
||||
context?: string,
|
||||
fallback?: ConfigReader | undefined,
|
||||
prefix?: string,
|
||||
);
|
||||
// (undocumented)
|
||||
static fromConfigs(configs: AppConfig[]): ConfigReader;
|
||||
// (undocumented)
|
||||
get<T = JsonValue>(key?: string): T;
|
||||
// (undocumented)
|
||||
get<T = JsonValue_2>(key?: string): T;
|
||||
getBoolean(key: string): boolean;
|
||||
// (undocumented)
|
||||
getConfig(key: string): ConfigReader;
|
||||
// (undocumented)
|
||||
getConfigArray(key: string): ConfigReader[];
|
||||
// (undocumented)
|
||||
getNumber(key: string): number;
|
||||
// (undocumented)
|
||||
getOptional<T = JsonValue>(key?: string): T | undefined;
|
||||
// (undocumented)
|
||||
getOptional<T = JsonValue_2>(key?: string): T | undefined;
|
||||
getOptionalBoolean(key: string): boolean | undefined;
|
||||
// (undocumented)
|
||||
getOptionalConfig(key: string): ConfigReader | undefined;
|
||||
// (undocumented)
|
||||
getOptionalConfigArray(key: string): ConfigReader[] | undefined;
|
||||
// (undocumented)
|
||||
getOptionalNumber(key: string): number | undefined;
|
||||
// (undocumented)
|
||||
getOptionalString(key: string): string | undefined;
|
||||
// (undocumented)
|
||||
getOptionalStringArray(key: string): string[] | undefined;
|
||||
// (undocumented)
|
||||
getString(key: string): string;
|
||||
// (undocumented)
|
||||
getStringArray(key: string): string[];
|
||||
// (undocumented)
|
||||
has(key: string): boolean;
|
||||
// (undocumented)
|
||||
keys(): string[];
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface JsonArray extends Array<JsonValue> {}
|
||||
// @public @deprecated
|
||||
export type JsonArray = JsonArray_2;
|
||||
|
||||
// @public
|
||||
export type JsonObject = {
|
||||
[key in string]?: JsonValue;
|
||||
};
|
||||
// @public @deprecated
|
||||
export type JsonObject = JsonObject_2;
|
||||
|
||||
// @public
|
||||
export type JsonPrimitive = number | string | boolean | null;
|
||||
// @public @deprecated
|
||||
export type JsonPrimitive = JsonPrimitive_2;
|
||||
|
||||
// @public
|
||||
export type JsonValue = JsonObject | JsonArray | JsonPrimitive;
|
||||
// @public @deprecated
|
||||
export type JsonValue = JsonValue_2;
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/config",
|
||||
"description": "Config API used by Backstage core, backend, and CLI",
|
||||
"version": "0.1.10",
|
||||
"version": "0.1.11",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -30,10 +30,11 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/types": "^0.1.1",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/test-utils-core": "^0.1.2",
|
||||
"@backstage/test-utils": "^0.1.20",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/node": "^14.14.32"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Temporarily re-export the JSON types from @backstage/types
|
||||
import type {
|
||||
JsonArray as CoreJsonArray,
|
||||
JsonObject as CoreJsonObject,
|
||||
JsonPrimitive as CoreJsonPrimitive,
|
||||
JsonValue as CoreJsonValue,
|
||||
} from '@backstage/types';
|
||||
|
||||
/**
|
||||
* A type representing all allowed JSON primitive values.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Please use the same type from `@backstage/types` instead
|
||||
*/
|
||||
export type JsonPrimitive = CoreJsonPrimitive;
|
||||
|
||||
/**
|
||||
* A type representing all allowed JSON object values.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Please use the same type from `@backstage/types` instead
|
||||
*/
|
||||
export type JsonObject = CoreJsonObject;
|
||||
|
||||
/**
|
||||
* A type representing all allowed JSON array values.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Please use the same type from `@backstage/types` instead
|
||||
*/
|
||||
export type JsonArray = CoreJsonArray;
|
||||
|
||||
/**
|
||||
* A type representing all allowed JSON values.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Please use the same type from `@backstage/types` instead
|
||||
*/
|
||||
export type JsonValue = CoreJsonValue;
|
||||
@@ -20,12 +20,11 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export { ConfigReader } from './reader';
|
||||
export type {
|
||||
AppConfig,
|
||||
Config,
|
||||
JsonArray,
|
||||
JsonObject,
|
||||
JsonPrimitive,
|
||||
JsonValue,
|
||||
} from './types';
|
||||
} from './deprecatedTypes';
|
||||
export { ConfigReader } from './reader';
|
||||
export type { AppConfig, Config } from './types';
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { withLogCollector } from '@backstage/test-utils-core';
|
||||
import { withLogCollector } from '@backstage/test-utils';
|
||||
import { ConfigReader } from './reader';
|
||||
|
||||
const DATA = {
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppConfig, Config, JsonValue, JsonObject } from './types';
|
||||
import { JsonValue, JsonObject } from '@backstage/types';
|
||||
import { AppConfig, Config } from './types';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import mergeWith from 'lodash/mergeWith';
|
||||
|
||||
@@ -71,6 +72,9 @@ export class ConfigReader implements Config {
|
||||
private filteredKeys?: string[];
|
||||
private notifiedFilteredKeys = new Set<string>();
|
||||
|
||||
/**
|
||||
* Instantiates the config reader from a list of application config objects.
|
||||
*/
|
||||
static fromConfigs(configs: AppConfig[]): ConfigReader {
|
||||
if (configs.length === 0) {
|
||||
return new ConfigReader(undefined);
|
||||
@@ -95,6 +99,7 @@ export class ConfigReader implements Config {
|
||||
private readonly prefix: string = '',
|
||||
) {}
|
||||
|
||||
/** {@inheritdoc Config.has} */
|
||||
has(key: string): boolean {
|
||||
const value = this.readValue(key);
|
||||
if (value !== undefined) {
|
||||
@@ -103,12 +108,14 @@ export class ConfigReader implements Config {
|
||||
return this.fallback?.has(key) ?? false;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.keys} */
|
||||
keys(): string[] {
|
||||
const localKeys = this.data ? Object.keys(this.data) : [];
|
||||
const fallbackKeys = this.fallback?.keys() ?? [];
|
||||
return [...new Set([...localKeys, ...fallbackKeys])];
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.get} */
|
||||
get<T = JsonValue>(key?: string): T {
|
||||
const value = this.getOptional(key);
|
||||
if (value === undefined) {
|
||||
@@ -117,6 +124,7 @@ export class ConfigReader implements Config {
|
||||
return value as T;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getOptional} */
|
||||
getOptional<T = JsonValue>(key?: string): T | undefined {
|
||||
const value = this.readValue(key);
|
||||
const fallbackValue = this.fallback?.getOptional<T>(key);
|
||||
@@ -153,6 +161,7 @@ export class ConfigReader implements Config {
|
||||
).value as T;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getConfig} */
|
||||
getConfig(key: string): ConfigReader {
|
||||
const value = this.getOptionalConfig(key);
|
||||
if (value === undefined) {
|
||||
@@ -161,6 +170,7 @@ export class ConfigReader implements Config {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getOptionalConfig} */
|
||||
getOptionalConfig(key: string): ConfigReader | undefined {
|
||||
const value = this.readValue(key);
|
||||
const fallbackConfig = this.fallback?.getOptionalConfig(key);
|
||||
@@ -176,6 +186,7 @@ export class ConfigReader implements Config {
|
||||
return fallbackConfig;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getConfigArray} */
|
||||
getConfigArray(key: string): ConfigReader[] {
|
||||
const value = this.getOptionalConfigArray(key);
|
||||
if (value === undefined) {
|
||||
@@ -184,6 +195,7 @@ export class ConfigReader implements Config {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getOptionalConfigArray} */
|
||||
getOptionalConfigArray(key: string): ConfigReader[] | undefined {
|
||||
const configs = this.readConfigValue<JsonObject[]>(key, values => {
|
||||
if (!Array.isArray(values)) {
|
||||
@@ -219,6 +231,7 @@ export class ConfigReader implements Config {
|
||||
return configs.map((obj, index) => this.copy(obj, `${key}[${index}]`));
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getNumber} */
|
||||
getNumber(key: string): number {
|
||||
const value = this.getOptionalNumber(key);
|
||||
if (value === undefined) {
|
||||
@@ -227,6 +240,7 @@ export class ConfigReader implements Config {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getOptionalNumber} */
|
||||
getOptionalNumber(key: string): number | undefined {
|
||||
const value = this.readConfigValue<string | number>(
|
||||
key,
|
||||
@@ -246,6 +260,7 @@ export class ConfigReader implements Config {
|
||||
return number;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getBoolean} */
|
||||
getBoolean(key: string): boolean {
|
||||
const value = this.getOptionalBoolean(key);
|
||||
if (value === undefined) {
|
||||
@@ -254,6 +269,7 @@ export class ConfigReader implements Config {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getOptionalBoolean} */
|
||||
getOptionalBoolean(key: string): boolean | undefined {
|
||||
return this.readConfigValue(
|
||||
key,
|
||||
@@ -261,6 +277,7 @@ export class ConfigReader implements Config {
|
||||
);
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getString} */
|
||||
getString(key: string): string {
|
||||
const value = this.getOptionalString(key);
|
||||
if (value === undefined) {
|
||||
@@ -269,6 +286,7 @@ export class ConfigReader implements Config {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getOptionalString} */
|
||||
getOptionalString(key: string): string | undefined {
|
||||
return this.readConfigValue(
|
||||
key,
|
||||
@@ -277,6 +295,7 @@ export class ConfigReader implements Config {
|
||||
);
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getStringArray} */
|
||||
getStringArray(key: string): string[] {
|
||||
const value = this.getOptionalStringArray(key);
|
||||
if (value === undefined) {
|
||||
@@ -285,6 +304,7 @@ export class ConfigReader implements Config {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** {@inheritdoc Config.getOptionalStringArray} */
|
||||
getOptionalStringArray(key: string): string[] | undefined {
|
||||
return this.readConfigValue(key, values => {
|
||||
if (!Array.isArray(values)) {
|
||||
|
||||
@@ -14,33 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A type representing all allowed JSON primitive values.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type JsonPrimitive = number | string | boolean | null;
|
||||
|
||||
/**
|
||||
* A type representing all allowed JSON object values.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type JsonObject = { [key in string]?: JsonValue };
|
||||
|
||||
/**
|
||||
* A type representing all allowed JSON array values.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface JsonArray extends Array<JsonValue> {}
|
||||
|
||||
/**
|
||||
* A type representing all allowed JSON values.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type JsonValue = JsonObject | JsonArray | JsonPrimitive;
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* A serialized form of configuration data that carries additional context.
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @backstage/core-app-api
|
||||
|
||||
## 0.1.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 10615525f3: Switch to use the json and observable types from `@backstage/types`
|
||||
- 41c49884d2: Start using the new `@backstage/types` package. Initially, this means using the `Observable` and `Json*` types from there. The types also remain in their old places but deprecated, and will be removed in a future release.
|
||||
- 925a967f36: Replace usage of test-utils-core with test-utils
|
||||
- 6b615e92c8: Api cleanup, adding `@public` where necessary and tweaking some comments
|
||||
- Updated dependencies
|
||||
- @backstage/config@0.1.11
|
||||
- @backstage/theme@0.2.12
|
||||
- @backstage/core-components@0.7.2
|
||||
- @backstage/core-plugin-api@0.1.12
|
||||
|
||||
## 0.1.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -40,7 +40,7 @@ import { IconComponent } from '@backstage/core-plugin-api';
|
||||
import { microsoftAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { OAuthApi } from '@backstage/core-plugin-api';
|
||||
import { OAuthRequestApi } from '@backstage/core-plugin-api';
|
||||
import { Observable } from '@backstage/core-plugin-api';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { oktaAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { oneloginAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { OpenIdConnectApi } from '@backstage/core-plugin-api';
|
||||
@@ -58,8 +58,6 @@ import { StorageApi } from '@backstage/core-plugin-api';
|
||||
import { StorageValueChange } from '@backstage/core-plugin-api';
|
||||
import { SubRouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AlertApiForwarder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export class AlertApiForwarder implements AlertApi {
|
||||
// (undocumented)
|
||||
@@ -68,8 +66,6 @@ export class AlertApiForwarder implements AlertApi {
|
||||
post(alert: AlertMessage): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ApiFactoryHolder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type ApiFactoryHolder = {
|
||||
get<T>(api: ApiRef<T>):
|
||||
@@ -83,8 +79,6 @@ export type ApiFactoryHolder = {
|
||||
| undefined;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ApiFactoryRegistry" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export class ApiFactoryRegistry implements ApiFactoryHolder {
|
||||
// (undocumented)
|
||||
@@ -109,11 +103,9 @@ export class ApiFactoryRegistry implements ApiFactoryHolder {
|
||||
>(scope: ApiFactoryScope, factory: ApiFactory<Api, Impl, Deps>): boolean;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ApiProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export const ApiProvider: {
|
||||
({ apis, children }: PropsWithChildren<ApiProviderProps>): JSX.Element;
|
||||
(props: PropsWithChildren<ApiProviderProps>): JSX.Element;
|
||||
propTypes: {
|
||||
apis: PropTypes.Validator<
|
||||
PropTypes.InferProps<{
|
||||
@@ -124,9 +116,7 @@ export const ApiProvider: {
|
||||
};
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ApiRegistry" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class ApiRegistry implements ApiHolder {
|
||||
constructor(apis: Map<string, unknown>);
|
||||
// Warning: (ae-forgotten-export) The symbol "ApiRegistryBuilder" needs to be exported by the entry point index.d.ts
|
||||
@@ -134,22 +124,14 @@ export class ApiRegistry implements ApiHolder {
|
||||
// (undocumented)
|
||||
static builder(): ApiRegistryBuilder;
|
||||
// Warning: (ae-forgotten-export) The symbol "ApiImpl" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
static from(apis: ApiImpl[]): ApiRegistry;
|
||||
// (undocumented)
|
||||
get<T>(api: ApiRef<T>): T | undefined;
|
||||
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
|
||||
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
|
||||
static with<T>(api: ApiRef<T>, impl: T): ApiRegistry;
|
||||
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
|
||||
// Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
|
||||
with<T>(api: ApiRef<T>, impl: T): ApiRegistry;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ApiResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class ApiResolver implements ApiHolder {
|
||||
constructor(factories: ApiFactoryHolder);
|
||||
// (undocumented)
|
||||
@@ -160,9 +142,7 @@ export class ApiResolver implements ApiHolder {
|
||||
): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AppComponents" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type AppComponents = {
|
||||
NotFoundErrorPage: ComponentType<{}>;
|
||||
BootErrorPage: ComponentType<BootErrorPageProps>;
|
||||
@@ -173,23 +153,17 @@ export type AppComponents = {
|
||||
SignInPage?: ComponentType<SignInPageProps>;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AppConfigLoader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export type AppConfigLoader = () => Promise<AppConfig[]>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AppContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type AppContext = {
|
||||
getPlugins(): BackstagePlugin<any, any>[];
|
||||
getSystemIcon(key: string): IconComponent | undefined;
|
||||
getComponents(): AppComponents;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AppOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type AppOptions = {
|
||||
apis?: Iterable<AnyApiFactory>;
|
||||
icons?: Partial<AppIcons> & {
|
||||
@@ -205,9 +179,8 @@ export type AppOptions = {
|
||||
// Warning: (ae-forgotten-export) The symbol "PartialKeys" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "TargetRouteMap" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "KeysWithType" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "AppRouteBinder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type AppRouteBinder = <
|
||||
ExternalRoutes extends {
|
||||
[name: string]: ExternalRouteRef;
|
||||
@@ -220,9 +193,7 @@ export type AppRouteBinder = <
|
||||
>,
|
||||
) => void;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AppThemeSelector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class AppThemeSelector implements AppThemeApi {
|
||||
constructor(themes: AppTheme[]);
|
||||
// (undocumented)
|
||||
@@ -237,9 +208,7 @@ export class AppThemeSelector implements AppThemeApi {
|
||||
setActiveThemeId(themeId?: string): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AtlassianAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class AtlassianAuth {
|
||||
// Warning: (ae-forgotten-export) The symbol "OAuthApiCreateOptions" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
@@ -252,9 +221,7 @@ export class AtlassianAuth {
|
||||
}: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "Auth0Auth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class Auth0Auth {
|
||||
// (undocumented)
|
||||
static create({
|
||||
@@ -266,9 +233,7 @@ export class Auth0Auth {
|
||||
}: OAuthApiCreateOptions): typeof auth0AuthApiRef.T;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "BackstageApp" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type BackstageApp = {
|
||||
getPlugins(): BackstagePlugin<any, any>[];
|
||||
getSystemIcon(key: string): IconComponent | undefined;
|
||||
@@ -276,19 +241,20 @@ export type BackstageApp = {
|
||||
getRouter(): ComponentType<{}>;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "BackstagePluginWithAnyOutput" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type BackstagePluginWithAnyOutput = Omit<
|
||||
BackstagePlugin<any, any>,
|
||||
'output'
|
||||
> & {
|
||||
output(): (PluginOutput | UnknownPluginOutput)[];
|
||||
output(): (
|
||||
| PluginOutput
|
||||
| {
|
||||
type: string;
|
||||
}
|
||||
)[];
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "BitbucketAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class BitbucketAuth {
|
||||
// (undocumented)
|
||||
static create({
|
||||
@@ -300,9 +266,7 @@ export class BitbucketAuth {
|
||||
}: OAuthApiCreateOptions): typeof bitbucketAuthApiRef.T;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "BitbucketSession" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type BitbucketSession = {
|
||||
providerInfo: {
|
||||
accessToken: string;
|
||||
@@ -313,9 +277,7 @@ export type BitbucketSession = {
|
||||
backstageIdentity: BackstageIdentity;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "BootErrorPageProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type BootErrorPageProps = {
|
||||
step: 'load-config' | 'load-chunk';
|
||||
error: Error;
|
||||
@@ -324,18 +286,13 @@ export type BootErrorPageProps = {
|
||||
export { ConfigReader };
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "PrivateAppImpl" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "createApp" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export function createApp(options?: AppOptions): PrivateAppImpl;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "defaultConfigLoader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export const defaultConfigLoader: AppConfigLoader;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ErrorAlerter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export class ErrorAlerter implements ErrorApi {
|
||||
constructor(alertApi: AlertApi, errorApi: ErrorApi);
|
||||
@@ -352,8 +309,6 @@ export class ErrorAlerter implements ErrorApi {
|
||||
post(error: Error, context?: ErrorContext): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ErrorApiForwarder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export class ErrorApiForwarder implements ErrorApi {
|
||||
// (undocumented)
|
||||
@@ -365,23 +320,17 @@ export class ErrorApiForwarder implements ErrorApi {
|
||||
post(error: Error, context?: ErrorContext): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ErrorBoundaryFallbackProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type ErrorBoundaryFallbackProps = {
|
||||
plugin?: BackstagePlugin;
|
||||
error: Error;
|
||||
resetError: () => void;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "FeatureFlagged" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export const FeatureFlagged: (props: FeatureFlaggedProps) => JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "FeatureFlaggedProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type FeatureFlaggedProps = {
|
||||
children: ReactNode;
|
||||
} & (
|
||||
@@ -393,15 +342,15 @@ export type FeatureFlaggedProps = {
|
||||
}
|
||||
);
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "FlatRoutesProps" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "FlatRoutes" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export const FlatRoutes: (props: FlatRoutesProps) => JSX.Element | null;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "GithubAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type FlatRoutesProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
// @public
|
||||
export class GithubAuth implements OAuthApi, SessionApi {
|
||||
// Warning: (ae-forgotten-export) The symbol "SessionManager" needs to be exported by the entry point index.d.ts
|
||||
constructor(sessionManager: SessionManager<GithubSession>);
|
||||
@@ -431,9 +380,7 @@ export class GithubAuth implements OAuthApi, SessionApi {
|
||||
signOut(): Promise<void>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "GithubSession" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type GithubSession = {
|
||||
providerInfo: {
|
||||
accessToken: string;
|
||||
@@ -444,9 +391,7 @@ export type GithubSession = {
|
||||
backstageIdentity: BackstageIdentity;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "GitlabAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class GitlabAuth {
|
||||
// (undocumented)
|
||||
static create({
|
||||
@@ -458,9 +403,7 @@ export class GitlabAuth {
|
||||
}: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "GoogleAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class GoogleAuth {
|
||||
// (undocumented)
|
||||
static create({
|
||||
@@ -472,8 +415,6 @@ export class GoogleAuth {
|
||||
}: OAuthApiCreateOptions): typeof googleAuthApiRef.T;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "LocalStorageFeatureFlags" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export class LocalStorageFeatureFlags implements FeatureFlagsApi {
|
||||
// (undocumented)
|
||||
@@ -486,9 +427,7 @@ export class LocalStorageFeatureFlags implements FeatureFlagsApi {
|
||||
save(options: FeatureFlagsSaveOptions): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "MicrosoftAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class MicrosoftAuth {
|
||||
// (undocumented)
|
||||
static create({
|
||||
@@ -500,17 +439,13 @@ export class MicrosoftAuth {
|
||||
}: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "NoOpAnalyticsApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export class NoOpAnalyticsApi implements AnalyticsApi {
|
||||
// (undocumented)
|
||||
captureEvent(_event: AnalyticsEvent): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "OAuth2" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class OAuth2
|
||||
implements
|
||||
OAuthApi,
|
||||
@@ -519,8 +454,10 @@ export class OAuth2
|
||||
BackstageIdentityApi,
|
||||
SessionApi
|
||||
{
|
||||
// Warning: (ae-forgotten-export) The symbol "Options" needs to be exported by the entry point index.d.ts
|
||||
constructor(options: Options);
|
||||
constructor(options: {
|
||||
sessionManager: SessionManager<OAuth2Session>;
|
||||
scopeTransform: (scopes: string[]) => string[];
|
||||
});
|
||||
// Warning: (ae-forgotten-export) The symbol "CreateOptions" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
@@ -553,9 +490,7 @@ export class OAuth2
|
||||
signOut(): Promise<void>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "OAuth2Session" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type OAuth2Session = {
|
||||
providerInfo: {
|
||||
idToken: string;
|
||||
@@ -567,8 +502,6 @@ export type OAuth2Session = {
|
||||
backstageIdentity: BackstageIdentity;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "OAuthRequestManager" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export class OAuthRequestManager implements OAuthRequestApi {
|
||||
// (undocumented)
|
||||
@@ -577,9 +510,7 @@ export class OAuthRequestManager implements OAuthRequestApi {
|
||||
createAuthRequester<T>(options: AuthRequesterOptions<T>): AuthRequester<T>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "OktaAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class OktaAuth {
|
||||
// (undocumented)
|
||||
static create({
|
||||
@@ -591,9 +522,7 @@ export class OktaAuth {
|
||||
}: OAuthApiCreateOptions): typeof oktaAuthApiRef.T;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "OneLoginAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class OneLoginAuth {
|
||||
// Warning: (ae-forgotten-export) The symbol "CreateOptions" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
@@ -606,9 +535,7 @@ export class OneLoginAuth {
|
||||
}: CreateOptions_2): typeof oneloginAuthApiRef.T;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SamlAuth" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class SamlAuth
|
||||
implements ProfileInfoApi, BackstageIdentityApi, SessionApi
|
||||
{
|
||||
@@ -636,16 +563,12 @@ export class SamlAuth
|
||||
signOut(): Promise<void>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SignInPageProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type SignInPageProps = {
|
||||
onResult(result: SignInResult): void;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SignInResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type SignInResult = {
|
||||
userId: string;
|
||||
profile: ProfileInfo;
|
||||
@@ -653,15 +576,11 @@ export type SignInResult = {
|
||||
signOut?: () => Promise<void>;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "UnhandledErrorForwarder" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class UnhandledErrorForwarder {
|
||||
static forward(errorApi: ErrorApi, errorContext: ErrorContext): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "UrlPatternDiscovery" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export class UrlPatternDiscovery implements DiscoveryApi {
|
||||
static compile(pattern: string): UrlPatternDiscovery;
|
||||
@@ -669,15 +588,14 @@ export class UrlPatternDiscovery implements DiscoveryApi {
|
||||
getBaseUrl(pluginId: string): Promise<string>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "WebStorage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class WebStorage implements StorageApi {
|
||||
constructor(namespace: string, errorApi: ErrorApi);
|
||||
// Warning: (ae-forgotten-export) The symbol "CreateStorageApiOptions" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
static create(options: CreateStorageApiOptions): WebStorage;
|
||||
static create(options: {
|
||||
errorApi: ErrorApi;
|
||||
namespace?: string;
|
||||
}): WebStorage;
|
||||
// (undocumented)
|
||||
forBucket(name: string): WebStorage;
|
||||
// (undocumented)
|
||||
@@ -692,7 +610,6 @@ export class WebStorage implements StorageApi {
|
||||
|
||||
// Warnings were encountered during analysis:
|
||||
//
|
||||
// src/apis/system/ApiProvider.d.ts:9:5 - (ae-forgotten-export) The symbol "ApiProviderProps" needs to be exported by the entry point index.d.ts
|
||||
// src/app/types.d.ts:89:5 - (ae-forgotten-export) The symbol "UnknownPluginOutput" needs to be exported by the entry point index.d.ts
|
||||
// src/app/types.d.ts:100:5 - (ae-forgotten-export) The symbol "AppIcons" needs to be exported by the entry point index.d.ts
|
||||
// src/apis/system/ApiProvider.d.ts:15:5 - (ae-forgotten-export) The symbol "ApiProviderProps" needs to be exported by the entry point index.d.ts
|
||||
// src/app/types.d.ts:152:5 - (ae-forgotten-export) The symbol "AppIcons" needs to be exported by the entry point index.d.ts
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/core-app-api",
|
||||
"description": "Core app API used by Backstage apps",
|
||||
"version": "0.1.18",
|
||||
"version": "0.1.19",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -29,10 +29,11 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-components": "^0.7.1",
|
||||
"@backstage/config": "^0.1.10",
|
||||
"@backstage/core-plugin-api": "^0.1.11",
|
||||
"@backstage/theme": "^0.2.11",
|
||||
"@backstage/core-components": "^0.7.2",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/core-plugin-api": "^0.1.12",
|
||||
"@backstage/theme": "^0.2.12",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@backstage/version-bridge": "^0.1.0",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -45,9 +46,8 @@
|
||||
"zen-observable": "^0.8.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.8.0",
|
||||
"@backstage/test-utils": "^0.1.19",
|
||||
"@backstage/test-utils-core": "^0.1.3",
|
||||
"@backstage/cli": "^0.8.1",
|
||||
"@backstage/test-utils": "^0.1.20",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/react-hooks": "^7.0.2",
|
||||
@@ -56,7 +56,7 @@
|
||||
"@types/node": "^14.14.32",
|
||||
"@types/zen-observable": "^0.8.0",
|
||||
"cross-fetch": "^3.0.6",
|
||||
"msw": "^0.29.0"
|
||||
"msw": "^0.35.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -13,11 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { AlertApi, AlertMessage, Observable } from '@backstage/core-plugin-api';
|
||||
|
||||
import { AlertApi, AlertMessage } from '@backstage/core-plugin-api';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { PublishSubject } from '../../../lib/subjects';
|
||||
|
||||
/**
|
||||
* Base implementation for the AlertApi that simply forwards alerts to consumers.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class AlertApiForwarder implements AlertApi {
|
||||
private readonly subject = new PublishSubject<AlertMessage>();
|
||||
|
||||
@@ -17,6 +17,8 @@ import { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
* Base implementation for the AnalyticsApi that does nothing.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class NoOpAnalyticsApi implements AnalyticsApi {
|
||||
captureEvent(_event: AnalyticsEvent): void {}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user