Merge branch 'master' of https://github.com/spotify/backstage into samiram/pagerduty-plugin
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-circleci': patch
|
||||
'@backstage/plugin-jenkins': patch
|
||||
---
|
||||
|
||||
Refactor to support ADR004 module exporting.
|
||||
|
||||
For more information, see https://backstage.io/docs/architecture-decisions/adrs-adr004.
|
||||
@@ -131,6 +131,7 @@ npm
|
||||
nvm
|
||||
oauth
|
||||
Oauth
|
||||
oidc
|
||||
Okta
|
||||
Oldsberg
|
||||
onboarding
|
||||
@@ -229,3 +230,4 @@ yaml
|
||||
Zalando
|
||||
Zhou
|
||||
Zolotusky
|
||||
zoomable
|
||||
|
||||
@@ -19,4 +19,4 @@ jobs:
|
||||
# Calls out to `changeset version`, but also runs prettier
|
||||
version: yarn release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
|
||||
|
||||
@@ -6,4 +6,4 @@ registry "https://registry.npmjs.org/"
|
||||
disable-self-update-check true
|
||||
lastUpdateCheck 1580389148099
|
||||
yarn-path ".yarn/releases/yarn-1.22.1.js"
|
||||
network-timeout 600000
|
||||
network-timeout 300000
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# Process for becoming a maintainer
|
||||
|
||||
## Your organization is not yet a maintainer
|
||||
## a) Your organization is not yet a maintainer
|
||||
|
||||
- Express interest to the sponsors that your organization is interested in becoming a maintainer. Becoming a maintainer generally means that you are going to be spending substantial time on Backstage for the foreseeable future. You should have domain expertise and be extremely proficient in TypeScript.
|
||||
- We will expect you to start contributing increasingly complicated PRs, under the guidance of the existing maintainers.
|
||||
@@ -8,7 +8,7 @@
|
||||
- As you gain experience with the code base and our standards, we will ask you to do code reviews for incoming PRs.
|
||||
- After a period of approximately 2-3 months of working together and making sure we see eye to eye, the existing sponsors and maintainers will confer and decide whether to grant maintainer status or not. We make no guarantees on the length of time this will take, but 2-3 months is the approximate goal.
|
||||
|
||||
## Your organization is currently a maintainer
|
||||
## b) Your organization is currently a maintainer
|
||||
|
||||
To become a maintainer you need to demonstrate the following:
|
||||
|
||||
|
||||
+6
-3
@@ -38,7 +38,7 @@ proxy:
|
||||
headers:
|
||||
Authorization:
|
||||
$env: TRAVISCI_AUTH_TOKEN
|
||||
travis-api-version: 3
|
||||
travis-api-version: '3'
|
||||
|
||||
'/newrelic/apm/api':
|
||||
target: https://api.newrelic.com/v2
|
||||
@@ -72,8 +72,8 @@ sentry:
|
||||
|
||||
rollbar:
|
||||
organization: my-company
|
||||
accountToken:
|
||||
$env: ROLLBAR_ACCOUNT_TOKEN
|
||||
# NOTE: The rollbar-backend & accountToken key may be deprecated in the future (replaced by a proxy config)
|
||||
accountToken: my-rollbar-account-token
|
||||
|
||||
lighthouse:
|
||||
baseUrl: http://localhost:3003
|
||||
@@ -296,6 +296,9 @@ costInsights:
|
||||
bigQuery:
|
||||
name: BigQuery
|
||||
icon: search
|
||||
events:
|
||||
name: Events
|
||||
icon: data
|
||||
metrics:
|
||||
DAU:
|
||||
name: Daily Active Users
|
||||
|
||||
@@ -6,57 +6,71 @@ description: Documentation on Auth backend classes
|
||||
|
||||
## How Does Authentication Work?
|
||||
|
||||
The Backstage application can use various authentication providers for
|
||||
authentication. A provider has to implement an `AuthProviderRouteHandlers`
|
||||
interface for handling authentication. This interface consists of four methods.
|
||||
Each of these methods is hosted at an endpoint `/auth/[provider]/method`, where
|
||||
`method` performs a certain operation as follows:
|
||||
The Backstage application can use various external authentication providers for
|
||||
authentication. An external provider is wrapped using an
|
||||
`AuthProviderRouteHandlers` interface for handling authentication. This
|
||||
interface consists of four methods. Each of these methods is hosted at an
|
||||
endpoint (by default) `/api/auth/[provider]/method`, where `method` performs a
|
||||
certain operation as follows:
|
||||
|
||||
```
|
||||
/auth/[provider]/start -> start
|
||||
/auth/[provider]/handler/frame -> frameHandler
|
||||
/auth/[provider]/refresh -> refresh
|
||||
/auth/[provider]/logout -> logout
|
||||
/auth/[provider]/start -> Initiate a login from the web page
|
||||
/auth/[provider]/handler/frame -> Handle a finished authentication operation
|
||||
/auth/[provider]/refresh -> Refresh the validity of a login
|
||||
/auth/[provider]/logout -> Log out a logged-in user
|
||||
```
|
||||
|
||||
For more information on how these methods are used and for which purpose, refer
|
||||
to the [OAuth documentation](oauth.md).
|
||||
The flow is as follows:
|
||||
|
||||
For details on the parameters, input and output conditions for each method,
|
||||
refer to the type documentation under
|
||||
`plugins/auth-backend/src/providers/types.ts`.
|
||||
1. A user attempts to sign in.
|
||||
2. A popup window is opened, pointing to the `auth` endpoint. That endpoint does
|
||||
initial preparations and then re-directs the user to an external
|
||||
authenticator, still inside the popup.
|
||||
3. The authenticator validates the user and returns the result of the validation
|
||||
(success OR failure), to the wrapper's endpoint (`handler/frame`).
|
||||
4. The `handler/frame` rendered b´webpage will issue the appropriate response to
|
||||
the webpage that opened the popup window, and the popup is closed.
|
||||
5. The user signs out by clicking on a UI interface and the webpage makes a
|
||||
request to logout the user.
|
||||
|
||||
There are currently two different classes for two authentication mechanisms that
|
||||
implement this interface: an `OAuthAdapter` for [OAuth](https://oauth.net/2/)
|
||||
based mechanisms and a `SAMLAuthProvider` for
|
||||
[SAML](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html)
|
||||
based mechanisms.
|
||||
[SAML](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html).
|
||||
|
||||
### OAuth mechanisms
|
||||
If you do not have an `OAuth2` or `SAML` based authentication provider, look in
|
||||
the section [below](#implementing-your-own-auth-wrapper).
|
||||
|
||||
### OAuth Mechanisms
|
||||
|
||||
For more information on how these methods are used and for which purpose, refer
|
||||
to the [OAuth documentation](oauth.md).
|
||||
|
||||
Currently OAuth is assumed to be the de facto authentication mechanism for
|
||||
Backstage based applications.
|
||||
|
||||
Backstage comes with a "batteries-included" set of supported commonly used OAuth
|
||||
providers: Okta, GitHub, Google, GitLab, and a generic OAuth2 provider.
|
||||
providers: Okta, GitHub, Google, GitLab, and a generic OAuth2 provider. For a
|
||||
list of available providers, look at the available wrappers in
|
||||
`backstage/plugins/auth-backend/src/providers/`.
|
||||
|
||||
All of these use the authorization flow of OAuth2 to implement authentication.
|
||||
All of these use the **authorization flow** of OAuth2 to implement
|
||||
authentication.
|
||||
|
||||
If your authentication provider is any of the above mentioned (except generic
|
||||
OAuth2) providers, you can configure them by setting the right variables in
|
||||
`app-config.yaml` under the `auth` section.
|
||||
If your authentication provider is any of the above mentioned providers, you can
|
||||
configure them by setting the right variables in `app-config.yaml` under the
|
||||
`auth` section.
|
||||
|
||||
### Configuration
|
||||
|
||||
Each authentication provider (except SAML) needs five parameters: an OAuth
|
||||
client ID, a client secret, an authorization endpoint and a token endpoint, and
|
||||
an app origin. The app origin is the URL at which the frontend of the
|
||||
application is hosted, and it is read from the `app.baseUrl` config. This is
|
||||
required because the application opens a popup window to perform the
|
||||
authentication, and once the flow is completed, the popup window sends a
|
||||
`postMessage` to the frontend application to indicate the result of the
|
||||
operation. Also this URL is used to verify that authentication requests are
|
||||
coming from only this endpoint.
|
||||
client ID, a client secret, an authorization endpoint, a token endpoint, and an
|
||||
app origin. The app origin is the URL at which the frontend of the application
|
||||
is hosted, and it is read from the `app.baseUrl` config. This is required
|
||||
because the application opens a popup window to perform the authentication, and
|
||||
once the flow is completed, the popup window sends a `postMessage` to the
|
||||
frontend application to indicate the result of the operation. Also this URL is
|
||||
used to verify that authentication requests are coming from only this endpoint.
|
||||
|
||||
These values are configured via the `app-config.yaml` present in the root of
|
||||
your app folder.
|
||||
@@ -85,20 +99,60 @@ auth:
|
||||
...
|
||||
```
|
||||
|
||||
## Technical Notes
|
||||
## Implementing Your Own Auth Wrapper
|
||||
|
||||
### OAuthEnvironmentHandler
|
||||
The core interface of any auth wrapper is the `AuthProviderRouteHandlers`
|
||||
interface. This interface has four methods corresponding to the API described in
|
||||
the initial section. Any auth wrapper will have to implement this interface.
|
||||
|
||||
The concept of an "env" is core to the way the auth backend works. It uses an
|
||||
When initiating a login, a pop-up window is created by the frontend, to allow
|
||||
the user to initiate a login. This login request is done to the `/start`
|
||||
endpoint which is handled by the `start` method.
|
||||
|
||||
The `start` method re-directs to the external auth provider who authenticates
|
||||
the request and re-directs the request to the `/frame/handler` endpoint, which
|
||||
is handled by the `frameHandler` method.
|
||||
|
||||
The `frameHandler` returns an HTML response, containing a script that does a
|
||||
`postMessage` to the frontend's window, containing the result of the request.
|
||||
The `WebMessageResponse` type is the message sent by the `postMessage` to the
|
||||
frontend.
|
||||
|
||||
A `postMessageResponse` utility function wraps the logic of generating a
|
||||
`postMessage` response that ensures that CORS is successfully handled. This
|
||||
function takes an `express.Response`, a `WebMessageResponse` and the URL of the
|
||||
frontend (`appOrigin`) as parameters and return an HTML page with the script and
|
||||
the message.
|
||||
|
||||
### OAuth Wrapping Interfaces.
|
||||
|
||||
Each OAuth external provider is supported by a corresponding
|
||||
[Passport](https://github.com/jaredhanson/passport) strategy. For a generic
|
||||
OAuth2 provider, passport has a `passport-oauth2` strategy. The strategy class
|
||||
handles the implementation details of working with each provider.
|
||||
|
||||
Each strategy is wrapped by an `OAuthHandlers` interface.
|
||||
|
||||
This interface cannot be directly used as an Express HTTP request handler. To do
|
||||
so, `OAuthHandlers` are wrapped in an `OAuthAdapter`, which implements the
|
||||
`AuthProviderRouterHandlers` interface.
|
||||
|
||||
#### Env
|
||||
|
||||
The concept of an `env` is core to the way the auth backend works. It uses an
|
||||
`env` query parameter to identify the environment in which the application is
|
||||
running (`development`, `staging`, `production`, etc). Each runtime can support
|
||||
multiple environments at the same time and the right handler for each request is
|
||||
identified and dispatched to based on the `env` parameter. All
|
||||
`AuthProviderRouteHandlers` are wrapped within an `OAuthEnvironmentHandler`.
|
||||
running (`development`, `staging`, `production`, etc). Each runtime can
|
||||
simultaneously support multiple environments at the same time and the right
|
||||
handler for each request is identified and dispatched to, based on the `env`
|
||||
parameter.
|
||||
|
||||
To instantiate multiple OAuth providers for different environments, use
|
||||
`OAuthEnvironmentHandler` is a utility wrapper for an `OAuthHandlers` that
|
||||
implements the `AuthProviderRouteHandlers` interface while supporting multiple
|
||||
`env`s.
|
||||
|
||||
To instantiate OAuth providers (the same but for different environments), use
|
||||
`OAuthEnvironmentHandler.mapConfig`. It's a helper to iterate over a
|
||||
configuration object that is a map of environment to configurations. See one of
|
||||
configuration object that is a map of environments to configurations. See one of
|
||||
the existing OAuth providers for an example of how it is used.
|
||||
|
||||
Given the following configuration:
|
||||
@@ -113,13 +167,18 @@ production:
|
||||
```
|
||||
|
||||
The `OAuthEnvironmentHandler.mapConfig(config, envConfig => ...)` call will
|
||||
split the `config` by the top level `development` and `production` keys, and
|
||||
pass on each block as `envConfig`.
|
||||
split the config by the top level `development` and `production` keys, and pass
|
||||
on each block as `envConfig`.
|
||||
|
||||
For a list of currently available providers, look in the `factories` module
|
||||
located in `plugins/auth-backend/src/providers/factories.ts`
|
||||
For convenience, the `AuthProviderFactory` is a factory function that has to be
|
||||
implemented which can then generate a `AuthProviderRouteHandlers` for a given
|
||||
provider.
|
||||
|
||||
### OAuth2 provider
|
||||
All of the supported providers provide an `AuthProviderFactory` that returns an
|
||||
`OAuthEnvironmentHandler`, capable of handling authentication for multiple
|
||||
environments.
|
||||
|
||||
### OAuth2 Provider
|
||||
|
||||
The `oauth2` provider abstracts a generic **OAuth2 + OIDC** based authentication
|
||||
provider. What this means is that after the application has been given
|
||||
|
||||
+1
-1
@@ -93,6 +93,6 @@ sign-in methods.
|
||||
More details are provided in dedicated sections of the documentation.
|
||||
|
||||
- [OAuth](./oauth.md): Description of the generic OAuth flow implemented by the
|
||||
[auth-backend](../../plugins/auth-backend).
|
||||
[auth-backend](https://github.com/backstage/backstage/tree/master/plugins/auth-backend).
|
||||
- [Glossary](./glossary.md): Glossary of some common terms related to the auth
|
||||
flows.
|
||||
|
||||
@@ -31,6 +31,7 @@ we recommend that you name them `catalog-info.yaml`.
|
||||
- [Kind: Resource](#kind-resource)
|
||||
- [Kind: System](#kind-system)
|
||||
- [Kind: Domain](#kind-domain)
|
||||
- [Kind: Location](#kind-location)
|
||||
|
||||
## Overall Shape Of An Entity
|
||||
|
||||
@@ -381,7 +382,7 @@ spec:
|
||||
type: website
|
||||
lifecycle: production
|
||||
owner: artist-relations@example.com
|
||||
implementsApis:
|
||||
providesApis:
|
||||
- artist-api
|
||||
```
|
||||
|
||||
@@ -445,12 +446,35 @@ group of people in an organizational structure.
|
||||
|
||||
### `spec.implementsApis` [optional]
|
||||
|
||||
**NOTE**: This field was marked for deprecation on Nov 25nd, 2020. It will be
|
||||
removed entirely from the model on Dec 14th, 2020 in the repository and will not
|
||||
be present in released packages following the next release after that. Please
|
||||
update your code to not consume this field before the removal date.
|
||||
|
||||
Links APIs that are implemented by the component, e.g. `artist-api`. This field
|
||||
is optional.
|
||||
|
||||
The software catalog expects a list of one or more strings that references the
|
||||
names of other entities of the `kind` `API`.
|
||||
|
||||
This field has the same behavior as `spec.providesApis`.
|
||||
|
||||
### `spec.providesApis` [optional]
|
||||
|
||||
Links APIs that are provided by the component, e.g. `artist-api`. This field is
|
||||
optional.
|
||||
|
||||
The software catalog expects a list of one or more strings that references the
|
||||
names of other entities of the `kind` `API`.
|
||||
|
||||
### `spec.consumesApis` [optional]
|
||||
|
||||
Links APIs that are consumed by the component, e.g. `artist-api`. This field is
|
||||
optional.
|
||||
|
||||
The software catalog expects a list of one or more strings that references the
|
||||
names of other entities of the `kind` `API`.
|
||||
|
||||
## Kind: Template
|
||||
|
||||
Describes the following entity kind:
|
||||
@@ -861,3 +885,58 @@ This kind is not yet defined, but is reserved [for future use](system-model.md).
|
||||
## Kind: Domain
|
||||
|
||||
This kind is not yet defined, but is reserved [for future use](system-model.md).
|
||||
|
||||
## Kind: Location
|
||||
|
||||
Describes the following entity kind:
|
||||
|
||||
| Field | Value |
|
||||
| ------------ | ----------------------- |
|
||||
| `apiVersion` | `backstage.io/v1alpha1` |
|
||||
| `kind` | `Location` |
|
||||
|
||||
A location is a marker that references other places to look for catalog data.
|
||||
|
||||
Descriptor files for this kind may look as follows.
|
||||
|
||||
```yaml
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Location
|
||||
metadata:
|
||||
name: org-data
|
||||
spec:
|
||||
type: url
|
||||
targets:
|
||||
- http://github.com/myorg/myproject/org-data-dump/catalog-info-staff.yaml
|
||||
- http://github.com/myorg/myproject/org-data-dump/catalog-info-consultants.yaml
|
||||
```
|
||||
|
||||
In addition to the [common envelope metadata](#common-to-all-kinds-the-metadata)
|
||||
shape, this kind has the following structure.
|
||||
|
||||
### `apiVersion` and `kind` [required]
|
||||
|
||||
Exactly equal to `backstage.io/v1alpha1` and `Location`, respectively.
|
||||
|
||||
### `spec.type` [optional]
|
||||
|
||||
The single location type, that's common to the targets specified in the spec. If
|
||||
it is left out, it is inherited from the location type that originally read the
|
||||
entity data. For example, if you have a `url` type location, that when read
|
||||
results in a `Location` kind entity with no `spec.type`, then the referenced
|
||||
targets in the entity will implicitly also be of `url` type. This is useful
|
||||
because you can define a hierarchy of things in a directory structure using
|
||||
relative target paths (see below), and it will work out no matter if it's
|
||||
consumed locally on disk from a `file` location, or as uploaded on a VCS.
|
||||
|
||||
### `spec.target` [optional]
|
||||
|
||||
A single target as a string. Can be either an absolute path/URL (depending on
|
||||
the type), or a relative path such as `./details/catalog-info.yaml` which is
|
||||
resolved relative to the location of this Location entity itself.
|
||||
|
||||
### `spec.targets` [optional]
|
||||
|
||||
A list of targets as strings. They can all be either absolute paths/URLs
|
||||
(depending on the type), or relative paths such as `./details/catalog-info.yaml`
|
||||
which are resolved relative to the location of this Location entity itself.
|
||||
|
||||
@@ -51,7 +51,7 @@ spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
owner: group:pet-managers
|
||||
implementsApis:
|
||||
providesApis:
|
||||
- petstore
|
||||
- internal/streetlights
|
||||
- hello-world
|
||||
@@ -66,7 +66,7 @@ catalog that is of kind `Group`, namespace `default` (which, actually, also can
|
||||
be left out in its own yaml file because that's the default value there too),
|
||||
and name `pet-managers`.
|
||||
|
||||
The entries in `implementsApis` are also references. In this case, none of them
|
||||
The entries in `providesApis` are also references. In this case, none of them
|
||||
needs to specify a kind since we know from the context that that's the only kind
|
||||
that's supported here. The second entry specifies a namespace but the other ones
|
||||
don't, and in this context, the default is to refer to the same namespace as the
|
||||
|
||||
@@ -45,17 +45,28 @@ entity, but there will always be one ultimate owner.
|
||||
This relation is commonly generated based on `spec.owner` of the owned entity,
|
||||
where present.
|
||||
|
||||
### `consumesApi` and `providesApi`
|
||||
### `providesApi` and `apiProvidedBy`
|
||||
|
||||
A relation with an [API](descriptor-format.md#kind-api) entity, typically from a
|
||||
[Component](descriptor-format.md#kind-component) or
|
||||
[System](descriptor-format.md#kind-system).
|
||||
|
||||
These relations express that a component or system either exposes an API -
|
||||
meaning that it hosts callable endpoints from which you can consume that API -
|
||||
or that they are dependent on being able to consume that API.
|
||||
These relations express that a component or system exposes an API - meaning that
|
||||
it hosts callable endpoints from which you can consume that API.
|
||||
|
||||
This relation is commonly generated based on `spec.implementsApis` of the
|
||||
This relation is commonly generated based on `spec.providesApis` of the
|
||||
component or system in question.
|
||||
|
||||
### `consumesApi` and `apiConsumedBy`
|
||||
|
||||
A relation with an [API](descriptor-format.md#kind-api) entity, typically from a
|
||||
[Component](descriptor-format.md#kind-component) or
|
||||
[System](descriptor-format.md#kind-system).
|
||||
|
||||
These relations express that a component or system consumes an API - meaning
|
||||
that it depends on endpoints of the API.
|
||||
|
||||
This relation is commonly generated based on `spec.consumesApis` of the
|
||||
component or system in question.
|
||||
|
||||
### `dependsOn` and `dependencyOf`
|
||||
|
||||
@@ -9,7 +9,7 @@ description: Documentation on TechDocs Architecture
|
||||
When you deploy Backstage (with TechDocs enabled by default), you get a basic
|
||||
out-of-the box experience.
|
||||
|
||||

|
||||
<img data-zoomable src="../../assets/techdocs/architecture-basic.drawio.svg" alt="TechDocs Architecture diagram" />
|
||||
|
||||
> Note: See below for our recommended deployment architecture which takes care
|
||||
> of stability, scalability and speed.
|
||||
@@ -43,7 +43,7 @@ channel to talk about it.
|
||||
|
||||
This is how we recommend deploying TechDocs in production environment.
|
||||
|
||||

|
||||
<img data-zoomable src="../../assets/techdocs/architecture-recommended.drawio.svg" alt="TechDocs Architecture diagram" />
|
||||
|
||||
The key difference in the recommended deployment approach is where the docs are
|
||||
built.
|
||||
|
||||
@@ -6,7 +6,53 @@ description: Documentation on How Configuring App with plugins
|
||||
|
||||
## Adding existing plugins to your app
|
||||
|
||||
Coming soon!
|
||||
The following steps assume that you have created a new Backstage app and want to
|
||||
add an existing plugin to it. We are using the
|
||||
[CircleCI](https://github.com/backstage/backstage/blob/master/plugins/circleci/README.md)
|
||||
plugin in this example.
|
||||
|
||||
1. Add the plugin's NPM package to the repo:
|
||||
|
||||
```bash
|
||||
yarn add @backstage/plugin-circleci
|
||||
```
|
||||
|
||||
2. Add the plugin itself:
|
||||
|
||||
```js
|
||||
// packages/app/src/plugins.ts
|
||||
export { plugin as Circleci } from '@backstage/plugin-circleci';
|
||||
```
|
||||
|
||||
3. Register the plugin router:
|
||||
|
||||
```jsx
|
||||
// packages/app/src/components/catalog/EntityPage.tsx
|
||||
|
||||
import { Router as CircleCIRouter } from '@backstage/plugin-circleci';
|
||||
|
||||
// Then somewhere inside <EntityPageLayout>
|
||||
<EntityPageLayout.Content
|
||||
path="/ci-cd/*"
|
||||
title="CI/CD"
|
||||
element={<CircleCIRouter />}
|
||||
/>;
|
||||
```
|
||||
|
||||
Note that stand-alone plugins that are not "attached" to the Software Catalog
|
||||
would be added outside the `EntityPage`.
|
||||
|
||||
4. [Optional] Add proxy config:
|
||||
|
||||
```yaml
|
||||
// app-config.yaml
|
||||
proxy:
|
||||
'/circleci/api':
|
||||
target: https://circleci.com/api/v1.1
|
||||
headers:
|
||||
Circle-Token:
|
||||
$env: CIRCLECI_AUTH_TOKEN
|
||||
```
|
||||
|
||||
### Adding a plugin page to the Sidebar
|
||||
|
||||
|
||||
@@ -79,11 +79,11 @@ want to ensure some stability.
|
||||
|
||||
### [`cli`](https://github.com/backstage/backstage/tree/master/packages/cli/)
|
||||
|
||||
The main toolchain used for Backstage development. The interface that is
|
||||
considered for stability are the various commands and options passed to those
|
||||
commands, as well as the environment variables read by the CLI. The build output
|
||||
may change over time and is not considered a breaking change unless it is likely
|
||||
to affect external tooling.
|
||||
The main toolchain used for Backstage development. The various CLI commands and
|
||||
options passed to those commands, as well as the environment variables read by
|
||||
the CLI, are considered to be the interface that the stability index refers to.
|
||||
The build output may change over time and is not considered a breaking change
|
||||
unless it is likely to affect external tooling.
|
||||
|
||||
Stability: `2`
|
||||
|
||||
|
||||
+20
-13
@@ -52,19 +52,7 @@ configuration will lead to the proxy acting on backend requests to
|
||||
|
||||
The value inside each route is either a simple URL string, or an object on the
|
||||
format accepted by
|
||||
[http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware). It
|
||||
is also possible to limit the forwarded HTTP methods with the configuration
|
||||
`allowedMethods`, for example `allowedMethods: ['GET']` to enforce read-only
|
||||
access.
|
||||
|
||||
By default, the proxy will only forward safe HTTP request headers to the target.
|
||||
Those are based on the headers that are considered safe for CORS and includes
|
||||
headers like `content-type` or `last-modified`, as well as all headers that are
|
||||
set by the proxy. If the proxy should forward other headers like
|
||||
`authorization`, this must be enabled by the `allowedHeaders` config, for
|
||||
example `allowedHeaders: ['Authorization']`. This should help to not
|
||||
accidentally forward confidential headers (`cookie`, `X-Auth-Request-User`) to
|
||||
third-parties.
|
||||
[http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware).
|
||||
|
||||
If the value is a string, it is assumed to correspond to:
|
||||
|
||||
@@ -85,3 +73,22 @@ except with the following caveats for convenience:
|
||||
`'^/api/proxy/larger-example/v1/': '/'` is added. That means that a request to
|
||||
`/api/proxy/larger-example/v1/some/path` will be translated to a request to
|
||||
`http://larger.example.com:8080/svc.v1/some/path`.
|
||||
|
||||
There are also additional settings:
|
||||
|
||||
- `allowedMethods`: Limit the forwarded HTTP methods. For example
|
||||
`allowedMethods: ['GET']` enforces read-only access.
|
||||
- `allowedHeaders`: A list of headers that should be forwarded to and received
|
||||
from the target.
|
||||
|
||||
By default, the proxy will only forward safe HTTP request headers to the target.
|
||||
Those are based on the headers that are considered safe for CORS and includes
|
||||
headers like `content-type` or `last-modified`, as well as all headers that are
|
||||
set by the proxy. If the proxy should forward other headers like
|
||||
`authorization`, this must be enabled by the `allowedHeaders` config, for
|
||||
example `allowedHeaders: ['Authorization']`. This should help to not
|
||||
accidentally forward confidential headers (`cookie`, `X-Auth-Request-User`) to
|
||||
third-parties.
|
||||
|
||||
The same logic applies to headers that are sent from the target back to the
|
||||
frontend.
|
||||
|
||||
@@ -4,7 +4,7 @@ title: createPlugin
|
||||
description: Documentation on createPlugin
|
||||
---
|
||||
|
||||
Taking a plugin config as argument and returns a new plugin.
|
||||
Takes a plugin config as an argument and returns a new plugin.
|
||||
|
||||
## Plugin Config
|
||||
|
||||
@@ -28,18 +28,22 @@ type PluginHooks = {
|
||||
|
||||
### Creating a basic plugin
|
||||
|
||||
Showcasing adding multiple routes, a feature flag and a redirect.
|
||||
Showcasing adding a route and a feature flag.
|
||||
|
||||
```jsx
|
||||
import { createPlugin } from '@backstage/core';
|
||||
import { createPlugin, createRouteRef } from '@backstage/core';
|
||||
import ExampleComponent from './components/ExampleComponent';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
path: '/new-plugin',
|
||||
title: 'New Plugin',
|
||||
});
|
||||
|
||||
export default createPlugin({
|
||||
id: 'new-plugin',
|
||||
register({ router, featureFlags }) {
|
||||
router.addRoute(rootRouteRef, ExampleComponent);
|
||||
featureFlags.register('enable-example-component');
|
||||
|
||||
router.registerRoute('/new-plugin', ExampleComponent);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -204,3 +204,8 @@ For more information about custom pages, click [here](https://docusaurus.io/docs
|
||||
# Full Documentation
|
||||
|
||||
Full documentation can be found on the [website](https://docusaurus.io/).
|
||||
|
||||
## Additional notes
|
||||
|
||||
- If you want to make images zoomable on click, add the `data-zoomable` attribute to your `img` element.
|
||||
- In a docs or blog `.md` file, convert `` syntax to `<img data-zoomable src="/microsite/static/img/code.png" alt="This is image" />`
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: Kubernetes
|
||||
author: Spotify
|
||||
authorUrl: https://github.com/spotify
|
||||
category: Kubernetes
|
||||
description: Surfaces components in a Kubernetes container orchestration environment into the Backstage catalog.
|
||||
documentation: https://github.com/backstage/backstage/tree/master/plugins/kubernetes
|
||||
iconUrl: https://raw.githubusercontent.com/cncf/artwork/master/projects/kubernetes/icon/color/kubernetes-icon-color.png
|
||||
npmPackageName: '@backstage/plugin-kubernetes'
|
||||
tags:
|
||||
- kubernetes
|
||||
- k8s
|
||||
@@ -17,7 +17,7 @@
|
||||
"@spotify/prettier-config": "^9.0.0",
|
||||
"docusaurus": "^2.0.0-alpha.66",
|
||||
"js-yaml": "^3.14.0",
|
||||
"prettier": "^2.2.0"
|
||||
"prettier": "^2.2.1"
|
||||
},
|
||||
"prettier": "@spotify/prettier-config"
|
||||
}
|
||||
|
||||
@@ -86,7 +86,11 @@ const siteConfig = {
|
||||
},
|
||||
|
||||
// Add custom scripts here that would be placed in <script> tags.
|
||||
scripts: ['https://buttons.github.io/buttons.js'],
|
||||
scripts: [
|
||||
'https://buttons.github.io/buttons.js',
|
||||
'https://unpkg.com/medium-zoom@1.0.6/dist/medium-zoom.min.js',
|
||||
'/js/medium-zoom.js',
|
||||
],
|
||||
|
||||
// On page navigation for the current documentation page.
|
||||
onPageNav: 'separate',
|
||||
|
||||
@@ -1094,3 +1094,8 @@ code {
|
||||
margin: 0 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Zoomed images using the medium-zoom library should be on top of screen. */
|
||||
.medium-zoom-image {
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Ref: https://github.com/francoischalifour/medium-zoom#options
|
||||
window.addEventListener(
|
||||
'load',
|
||||
() => {
|
||||
mediumZoom('[data-zoomable]', {
|
||||
margin: 20,
|
||||
background: '#000',
|
||||
});
|
||||
},
|
||||
false,
|
||||
);
|
||||
+4
-4
@@ -5204,10 +5204,10 @@ prepend-http@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
|
||||
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
|
||||
|
||||
prettier@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.0.tgz#8a03c7777883b29b37fb2c4348c66a78e980418b"
|
||||
integrity sha512-yYerpkvseM4iKD/BXLYUkQV5aKt4tQPqaGW6EsZjzyu0r7sVZZNPJW4Y8MyKmicp6t42XUPcBVA+H6sB3gqndw==
|
||||
prettier@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
|
||||
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
|
||||
|
||||
prismjs@^1.17.1:
|
||||
version "1.21.0"
|
||||
|
||||
@@ -1,5 +1,67 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7eb8bfe4a]
|
||||
- Updated dependencies [fe7257ff0]
|
||||
- Updated dependencies [a2cfa311a]
|
||||
- Updated dependencies [69f38457f]
|
||||
- Updated dependencies [bec334b33]
|
||||
- Updated dependencies [303c5ea17]
|
||||
- Updated dependencies [b4488ddb0]
|
||||
- Updated dependencies [4a655c89d]
|
||||
- Updated dependencies [08835a61d]
|
||||
- Updated dependencies [a9fd599f7]
|
||||
- Updated dependencies [8a16e8af8]
|
||||
- Updated dependencies [bcc211a08]
|
||||
- Updated dependencies [00670a96e]
|
||||
- Updated dependencies [da2ad65cb]
|
||||
- Updated dependencies [ebf37bbae]
|
||||
- @backstage/plugin-api-docs@0.3.1
|
||||
- @backstage/plugin-cost-insights@0.4.2
|
||||
- @backstage/plugin-sentry@0.2.4
|
||||
- @backstage/plugin-welcome@0.2.2
|
||||
- @backstage/cli@0.4.0
|
||||
- @backstage/catalog-model@0.4.0
|
||||
- @backstage/plugin-catalog-import@0.3.0
|
||||
- @backstage/plugin-scaffolder@0.3.2
|
||||
- @backstage/plugin-kubernetes@0.3.1
|
||||
- @backstage/plugin-techdocs@0.3.1
|
||||
- @backstage/plugin-catalog@0.2.5
|
||||
- @backstage/test-utils@0.1.4
|
||||
- @backstage/plugin-circleci@0.2.3
|
||||
- @backstage/plugin-cloudbuild@0.2.3
|
||||
- @backstage/plugin-github-actions@0.2.3
|
||||
- @backstage/plugin-jenkins@0.3.2
|
||||
- @backstage/plugin-lighthouse@0.2.4
|
||||
- @backstage/plugin-register-component@0.2.3
|
||||
- @backstage/plugin-rollbar@0.2.5
|
||||
- @backstage/plugin-search@0.2.2
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [294295453]
|
||||
- Updated dependencies [f3bb55ee3]
|
||||
- Updated dependencies [4b53294a6]
|
||||
- Updated dependencies [6f70ed7a9]
|
||||
- Updated dependencies [ab94c9542]
|
||||
- Updated dependencies [3a201c5d5]
|
||||
- Updated dependencies [f538e2c56]
|
||||
- Updated dependencies [2daf18e80]
|
||||
- Updated dependencies [069cda35f]
|
||||
- Updated dependencies [8697dea5b]
|
||||
- Updated dependencies [b623cc275]
|
||||
- @backstage/cli@0.3.2
|
||||
- @backstage/plugin-api-docs@0.3.0
|
||||
- @backstage/plugin-techdocs@0.3.0
|
||||
- @backstage/plugin-catalog@0.2.4
|
||||
- @backstage/catalog-model@0.3.1
|
||||
- @backstage/plugin-rollbar@0.2.4
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+22
-21
@@ -1,43 +1,44 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.5",
|
||||
"private": true,
|
||||
"bundled": true,
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.3.0",
|
||||
"@backstage/cli": "^0.3.1",
|
||||
"@backstage/catalog-model": "^0.4.0",
|
||||
"@backstage/cli": "^0.4.0",
|
||||
"@backstage/core": "^0.3.2",
|
||||
"@backstage/plugin-api-docs": "^0.2.2",
|
||||
"@backstage/plugin-catalog": "^0.2.3",
|
||||
"@backstage/plugin-circleci": "^0.2.2",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.2",
|
||||
"@backstage/plugin-cost-insights": "^0.4.1",
|
||||
"@backstage/plugin-api-docs": "^0.3.1",
|
||||
"@backstage/plugin-catalog": "^0.2.5",
|
||||
"@backstage/plugin-catalog-import": "^0.3.0",
|
||||
"@backstage/plugin-circleci": "^0.2.3",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.3",
|
||||
"@backstage/plugin-cost-insights": "^0.4.2",
|
||||
"@backstage/plugin-explore": "^0.2.1",
|
||||
"@backstage/plugin-gcp-projects": "^0.2.1",
|
||||
"@backstage/plugin-github-actions": "^0.2.2",
|
||||
"@backstage/plugin-github-actions": "^0.2.3",
|
||||
"@backstage/plugin-gitops-profiles": "^0.2.1",
|
||||
"@backstage/plugin-graphiql": "^0.2.1",
|
||||
"@backstage/plugin-jenkins": "^0.3.1",
|
||||
"@backstage/plugin-kubernetes": "^0.3.0",
|
||||
"@backstage/plugin-lighthouse": "^0.2.3",
|
||||
"@backstage/plugin-jenkins": "^0.3.2",
|
||||
"@backstage/plugin-kubernetes": "^0.3.1",
|
||||
"@backstage/plugin-lighthouse": "^0.2.4",
|
||||
"@backstage/plugin-newrelic": "^0.2.1",
|
||||
"@backstage/plugin-pagerduty": "0.2.1",
|
||||
"@backstage/plugin-register-component": "^0.2.2",
|
||||
"@backstage/plugin-rollbar": "^0.2.3",
|
||||
"@backstage/plugin-scaffolder": "^0.3.1",
|
||||
"@backstage/plugin-search": "^0.2.1",
|
||||
"@backstage/plugin-sentry": "^0.2.3",
|
||||
"@backstage/plugin-register-component": "^0.2.3",
|
||||
"@backstage/plugin-rollbar": "^0.2.5",
|
||||
"@backstage/plugin-scaffolder": "^0.3.2",
|
||||
"@backstage/plugin-sentry": "^0.2.4",
|
||||
"@backstage/plugin-search": "^0.2.2",
|
||||
"@backstage/plugin-tech-radar": "^0.3.0",
|
||||
"@backstage/plugin-techdocs": "^0.2.3",
|
||||
"@backstage/plugin-techdocs": "^0.3.1",
|
||||
"@backstage/plugin-user-settings": "^0.2.2",
|
||||
"@backstage/plugin-welcome": "^0.2.1",
|
||||
"@backstage/test-utils": "^0.1.3",
|
||||
"@backstage/plugin-welcome": "^0.2.2",
|
||||
"@backstage/test-utils": "^0.1.4",
|
||||
"@backstage/theme": "^0.2.1",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@octokit/rest": "^18.0.0",
|
||||
"@roadiehq/backstage-plugin-buildkite": "^0.1.3",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^0.2.15",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^0.2.16",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^0.6.3",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^0.2.8",
|
||||
"history": "^5.0.0",
|
||||
|
||||
@@ -34,6 +34,7 @@ import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar';
|
||||
import { Router as LighthouseRouter } from '@backstage/plugin-lighthouse';
|
||||
import { Router as RegisterComponentRouter } from '@backstage/plugin-register-component';
|
||||
import { Router as SettingsRouter } from '@backstage/plugin-user-settings';
|
||||
import { Router as ImportComponentRouter } from '@backstage/plugin-catalog-import';
|
||||
import { Route, Routes, Navigate } from 'react-router';
|
||||
|
||||
import { EntityPage } from './components/catalog/EntityPage';
|
||||
@@ -67,6 +68,10 @@ const catalogRouteRef = createRouteRef({
|
||||
const AppRoutes = () => (
|
||||
<Routes>
|
||||
<Navigate key="/" to="/catalog" />
|
||||
<Route
|
||||
path="/catalog-import/*"
|
||||
element={<ImportComponentRouter catalogRouteRef={catalogRouteRef} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${catalogRouteRef.path}/*`}
|
||||
element={<CatalogRouter EntityPage={EntityPage} />}
|
||||
|
||||
@@ -13,67 +13,70 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ApiEntity, Entity } from '@backstage/catalog-model';
|
||||
import { EmptyState } from '@backstage/core';
|
||||
import {
|
||||
isPluginApplicableToEntity as isTravisCIAvailable,
|
||||
RecentTravisCIBuildsWidget,
|
||||
Router as TravisCIRouter,
|
||||
} from '@roadiehq/backstage-plugin-travis-ci';
|
||||
ApiDefinitionCard,
|
||||
Router as ApiDocsRouter,
|
||||
} from '@backstage/plugin-api-docs';
|
||||
import {
|
||||
AboutCard,
|
||||
EntityPageLayout,
|
||||
useEntity,
|
||||
} from '@backstage/plugin-catalog';
|
||||
import {
|
||||
isPluginApplicableToEntity as isCircleCIAvailable,
|
||||
Router as CircleCIRouter,
|
||||
} from '@backstage/plugin-circleci';
|
||||
import {
|
||||
isPluginApplicableToEntity as isCloudbuildAvailable,
|
||||
Router as CloudbuildRouter,
|
||||
} from '@backstage/plugin-cloudbuild';
|
||||
import {
|
||||
isPluginApplicableToEntity as isGitHubActionsAvailable,
|
||||
RecentWorkflowRunsCard,
|
||||
Router as GitHubActionsRouter,
|
||||
} from '@backstage/plugin-github-actions';
|
||||
import {
|
||||
Router as CloudbuildRouter,
|
||||
isPluginApplicableToEntity as isCloudbuildAvailable,
|
||||
} from '@backstage/plugin-cloudbuild';
|
||||
import {
|
||||
Router as JenkinsRouter,
|
||||
isPluginApplicableToEntity as isJenkinsAvailable,
|
||||
LatestRunCard as JenkinsLatestRunCard,
|
||||
Router as JenkinsRouter,
|
||||
} from '@backstage/plugin-jenkins';
|
||||
import {
|
||||
isPluginApplicableToEntity as isCircleCIAvailable,
|
||||
Router as CircleCIRouter,
|
||||
} from '@backstage/plugin-circleci';
|
||||
import { Router as ApiDocsRouter } from '@backstage/plugin-api-docs';
|
||||
import { Router as SentryRouter } from '@backstage/plugin-sentry';
|
||||
import { EmbeddedDocsRouter as DocsRouter } from '@backstage/plugin-techdocs';
|
||||
import { Router as KubernetesRouter } from '@backstage/plugin-kubernetes';
|
||||
import {
|
||||
Router as GitHubInsightsRouter,
|
||||
isPluginApplicableToEntity as isGitHubAvailable,
|
||||
ReadMeCard,
|
||||
LanguagesCard,
|
||||
ReleasesCard,
|
||||
} from '@roadiehq/backstage-plugin-github-insights';
|
||||
import React, { ReactNode } from 'react';
|
||||
import {
|
||||
AboutCard,
|
||||
EntityPageLayout,
|
||||
useEntity,
|
||||
} from '@backstage/plugin-catalog';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { Button, Grid } from '@material-ui/core';
|
||||
import { EmptyState } from '@backstage/core';
|
||||
import {
|
||||
EmbeddedRouter as LighthouseRouter,
|
||||
LastLighthouseAuditCard,
|
||||
isPluginApplicableToEntity as isLighthouseAvailable,
|
||||
} from '@backstage/plugin-lighthouse/';
|
||||
LastLighthouseAuditCard,
|
||||
} from '@backstage/plugin-lighthouse';
|
||||
import { Router as SentryRouter } from '@backstage/plugin-sentry';
|
||||
import { EmbeddedDocsRouter as DocsRouter } from '@backstage/plugin-techdocs';
|
||||
import { Button, Grid } from '@material-ui/core';
|
||||
import {
|
||||
isPluginApplicableToEntity as isBuildkiteAvailable,
|
||||
Router as BuildkiteRouter,
|
||||
} from '@roadiehq/backstage-plugin-buildkite';
|
||||
import {
|
||||
isPluginApplicableToEntity as isGitHubAvailable,
|
||||
LanguagesCard,
|
||||
ReadMeCard,
|
||||
ReleasesCard,
|
||||
Router as GitHubInsightsRouter,
|
||||
} from '@roadiehq/backstage-plugin-github-insights';
|
||||
import {
|
||||
Router as PullRequestsRouter,
|
||||
isPluginApplicableToEntity as isPullRequestsAvailable,
|
||||
PullRequestsStatsCard,
|
||||
Router as PullRequestsRouter,
|
||||
} from '@roadiehq/backstage-plugin-github-pull-requests';
|
||||
import {
|
||||
isPluginApplicableToEntity as isPagerDutyAvailable,
|
||||
PagerDutyCard,
|
||||
} from '@backstage/plugin-pagerduty';
|
||||
import {
|
||||
Router as BuildkiteRouter,
|
||||
isPluginApplicableToEntity as isBuildkiteAvailable,
|
||||
} from '@roadiehq/backstage-plugin-buildkite';
|
||||
isPluginApplicableToEntity as isTravisCIAvailable,
|
||||
RecentTravisCIBuildsWidget,
|
||||
Router as TravisCIRouter,
|
||||
} from '@roadiehq/backstage-plugin-travis-ci';
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
export const CICDSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
// This component is just an example of how you can implement your company's logic in entity page.
|
||||
@@ -138,7 +141,7 @@ const RecentCICDRunsSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const OverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
const ComponentOverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
<Grid item md={6}>
|
||||
<AboutCard entity={entity} variant="gridItem" />
|
||||
@@ -178,7 +181,7 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout.Content
|
||||
path="/"
|
||||
title="Overview"
|
||||
element={<OverviewContent entity={entity} />}
|
||||
element={<ComponentOverviewContent entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/ci-cd/*"
|
||||
@@ -223,7 +226,7 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout.Content
|
||||
path="/"
|
||||
title="Overview"
|
||||
element={<OverviewContent entity={entity} />}
|
||||
element={<ComponentOverviewContent entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/ci-cd/*"
|
||||
@@ -262,12 +265,13 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
);
|
||||
|
||||
const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayout.Content
|
||||
path="/*"
|
||||
title="Overview"
|
||||
element={<OverviewContent entity={entity} />}
|
||||
element={<ComponentOverviewContent entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/docs/*"
|
||||
@@ -277,8 +281,7 @@ const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
</EntityPageLayout>
|
||||
);
|
||||
|
||||
export const EntityPage = () => {
|
||||
const { entity } = useEntity();
|
||||
export const ComponentEntityPage = ({ entity }: { entity: Entity }) => {
|
||||
switch (entity?.spec?.type) {
|
||||
case 'service':
|
||||
return <ServiceEntityPage entity={entity} />;
|
||||
@@ -288,3 +291,47 @@ export const EntityPage = () => {
|
||||
return <DefaultEntityPage entity={entity} />;
|
||||
}
|
||||
};
|
||||
|
||||
const ApiOverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
<Grid container spacing={3}>
|
||||
<Grid item md={6}>
|
||||
<AboutCard entity={entity} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
const ApiDefinitionContent = ({ entity }: { entity: ApiEntity }) => (
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<ApiDefinitionCard apiEntity={entity} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
const ApiEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayout.Content
|
||||
path="/*"
|
||||
title="Overview"
|
||||
element={<ApiOverviewContent entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/definition/*"
|
||||
title="Definition"
|
||||
element={<ApiDefinitionContent entity={entity as ApiEntity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
);
|
||||
|
||||
export const EntityPage = () => {
|
||||
const { entity } = useEntity();
|
||||
|
||||
switch (entity?.kind?.toLowerCase()) {
|
||||
case 'component':
|
||||
return <ComponentEntityPage entity={entity} />;
|
||||
case 'api':
|
||||
return <ApiEntityPage entity={entity} />;
|
||||
default:
|
||||
return <DefaultEntityPage entity={entity} />;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -37,6 +37,7 @@ export { plugin as Kubernetes } from '@backstage/plugin-kubernetes';
|
||||
export { plugin as Cloudbuild } from '@backstage/plugin-cloudbuild';
|
||||
export { plugin as CostInsights } from '@backstage/plugin-cost-insights';
|
||||
export { plugin as GitHubInsights } from '@roadiehq/backstage-plugin-github-insights';
|
||||
export { plugin as CatalogImport } from '@backstage/plugin-catalog-import';
|
||||
export { plugin as UserSettings } from '@backstage/plugin-user-settings';
|
||||
export { plugin as PagerDuty } from '@backstage/plugin-pagerduty';
|
||||
export { plugin as Buildkite } from '@roadiehq/backstage-plugin-buildkite';
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 612368274: Allow the `backend.listen.port` config to be both a number or a string.
|
||||
- Updated dependencies [4e7091759]
|
||||
- Updated dependencies [b4488ddb0]
|
||||
- @backstage/config-loader@0.4.0
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 3aa7efb3f: Added support for passing false as a CSP field value, to drop it from the defaults in the backend
|
||||
- b3d4e4e57: Move the frontend visibility declarations of integrations config from @backstage/backend-common to @backstage/integration
|
||||
- Updated dependencies [b3d4e4e57]
|
||||
- @backstage/integration@0.1.2
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
Vendored
+10
-10
@@ -29,7 +29,7 @@ export interface Config {
|
||||
/** Address of the interface that the backend should bind to. */
|
||||
address?: string;
|
||||
/** Port that the backend should listen to. */
|
||||
port?: number;
|
||||
port?: string | number;
|
||||
};
|
||||
|
||||
/** HTTPS configuration for the backend. If omitted the backend will serve HTTP */
|
||||
@@ -79,8 +79,15 @@ export interface Config {
|
||||
optionsSuccessStatus?: number;
|
||||
};
|
||||
|
||||
/** */
|
||||
csp?: object;
|
||||
/**
|
||||
* Content Security Policy options.
|
||||
*
|
||||
* The keys are the plain policy ID, e.g. "upgrade-insecure-requests". The
|
||||
* values are on the format that the helmet library expects them, as an
|
||||
* array of strings. There is also the special value false, which means to
|
||||
* remove the default value that Backstage puts in place for that policy.
|
||||
*/
|
||||
csp?: { [policyId: string]: string[] | false };
|
||||
};
|
||||
|
||||
/** Configuration for integrations towards various external repository provider systems */
|
||||
@@ -89,7 +96,6 @@ export interface Config {
|
||||
azure?: Array<{
|
||||
/**
|
||||
* The hostname of the given Azure instance
|
||||
* @visibility frontend
|
||||
*/
|
||||
host: string;
|
||||
/**
|
||||
@@ -103,7 +109,6 @@ export interface Config {
|
||||
bitbucket?: Array<{
|
||||
/**
|
||||
* The hostname of the given Bitbucket instance
|
||||
* @visibility frontend
|
||||
*/
|
||||
host: string;
|
||||
/**
|
||||
@@ -113,7 +118,6 @@ export interface Config {
|
||||
token?: string;
|
||||
/**
|
||||
* The base url for the BitBucket API, for example https://api.bitbucket.org/2.0
|
||||
* @visibility frontend
|
||||
*/
|
||||
apiBaseUrl?: string;
|
||||
/**
|
||||
@@ -132,7 +136,6 @@ export interface Config {
|
||||
github?: Array<{
|
||||
/**
|
||||
* The hostname of the given GitHub instance
|
||||
* @visibility frontend
|
||||
*/
|
||||
host: string;
|
||||
/**
|
||||
@@ -142,12 +145,10 @@ export interface Config {
|
||||
token?: string;
|
||||
/**
|
||||
* The base url for the GitHub API, for example https://api.github.com
|
||||
* @visibility frontend
|
||||
*/
|
||||
apiBaseUrl?: string;
|
||||
/**
|
||||
* The base url for GitHub raw resources, for example https://raw.githubusercontent.com
|
||||
* @visibility frontend
|
||||
*/
|
||||
rawBaseUrl?: string;
|
||||
}>;
|
||||
@@ -156,7 +157,6 @@ export interface Config {
|
||||
gitlab?: Array<{
|
||||
/**
|
||||
* The hostname of the given GitLab instance
|
||||
* @visibility frontend
|
||||
*/
|
||||
host: string;
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -31,8 +31,8 @@
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.1",
|
||||
"@backstage/config": "^0.1.1",
|
||||
"@backstage/config-loader": "^0.3.0",
|
||||
"@backstage/integration": "^0.1.1",
|
||||
"@backstage/config-loader": "^0.4.0",
|
||||
"@backstage/integration": "^0.1.2",
|
||||
"@types/cors": "^2.8.6",
|
||||
"@types/express": "^4.17.6",
|
||||
"archiver": "^5.0.2",
|
||||
@@ -67,8 +67,8 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.3.1",
|
||||
"@backstage/test-utils": "^0.1.3",
|
||||
"@backstage/cli": "^0.4.0",
|
||||
"@backstage/test-utils": "^0.1.4",
|
||||
"@types/archiver": "^3.1.1",
|
||||
"@types/compression": "^1.7.0",
|
||||
"@types/concat-stream": "^1.6.0",
|
||||
|
||||
@@ -235,6 +235,40 @@ describe('GithubUrlReader', () => {
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
});
|
||||
|
||||
it('includes the subdomain in the github url', async () => {
|
||||
worker.resetHandlers();
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://ghe.github.com/backstage/mock/archive/repo.tar.gz',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('Content-Type', 'application/x-gzip'),
|
||||
ctx.body(repoBuffer),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const processor = new GithubUrlReader(
|
||||
{
|
||||
host: 'ghe.github.com',
|
||||
apiBaseUrl: 'https://api.github.com',
|
||||
},
|
||||
{ treeResponseFactory },
|
||||
);
|
||||
|
||||
const response = await processor.readTree(
|
||||
'https://ghe.github.com/backstage/mock/tree/repo/docs',
|
||||
);
|
||||
|
||||
const files = await response.files();
|
||||
|
||||
expect(files.length).toBe(1);
|
||||
const indexMarkdownFile = await files[0].content();
|
||||
|
||||
expect(indexMarkdownFile.toString()).toBe('# Test\n');
|
||||
});
|
||||
|
||||
it('must specify a branch', async () => {
|
||||
const processor = new GithubUrlReader(
|
||||
{
|
||||
|
||||
@@ -179,7 +179,7 @@ export class GithubUrlReader implements UrlReader {
|
||||
name: repoName,
|
||||
ref,
|
||||
protocol,
|
||||
source,
|
||||
resource,
|
||||
full_name,
|
||||
filepath,
|
||||
} = parseGitUri(url);
|
||||
@@ -194,8 +194,9 @@ export class GithubUrlReader implements UrlReader {
|
||||
// TODO(Rugvip): use API to fetch URL instead
|
||||
const response = await fetch(
|
||||
new URL(
|
||||
`${protocol}://${source}/${full_name}/archive/${ref}.tar.gz`,
|
||||
`${protocol}://${resource}/${full_name}/archive/${ref}.tar.gz`,
|
||||
).toString(),
|
||||
getRawRequestOptions(this.config),
|
||||
);
|
||||
if (!response.ok) {
|
||||
const message = `Failed to read tree from ${url}, ${response.status} ${response.statusText}`;
|
||||
|
||||
@@ -126,7 +126,7 @@ describe('TarArchiveResponse', () => {
|
||||
const res = new TarArchiveResponse(stream, 'mock-repo/docs/', '/tmp');
|
||||
const dir = await res.dir();
|
||||
|
||||
expect(dir).toMatch(/^\/tmp\/.*$/);
|
||||
expect(dir).toMatch(/^[\/\\]tmp[\/\\].*$/);
|
||||
await expect(
|
||||
fs.readFile(resolvePath(dir, 'index.md'), 'utf8'),
|
||||
).resolves.toBe('# Test\n');
|
||||
|
||||
@@ -126,7 +126,7 @@ describe('ZipArchiveResponse', () => {
|
||||
const res = new ZipArchiveResponse(stream, 'mock-repo/docs/', '/tmp');
|
||||
const dir = await res.dir();
|
||||
|
||||
expect(dir).toMatch(/^\/tmp\/.*$/);
|
||||
expect(dir).toMatch(/^[\/\\]tmp[\/\\].*$/);
|
||||
await expect(
|
||||
fs.readFile(resolvePath(dir, 'index.md'), 'utf8'),
|
||||
).resolves.toBe('# Test\n');
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { applyCspDirectives } from './ServiceBuilderImpl';
|
||||
|
||||
describe('ServiceBuilderImpl', () => {
|
||||
describe('applyCspDirectives', () => {
|
||||
it('copies actual values', () => {
|
||||
const result = applyCspDirectives({ key: ['value'] });
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
'default-src': ["'self'"],
|
||||
key: ['value'],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('removes false value keys', () => {
|
||||
const result = applyCspDirectives({ 'upgrade-insecure-requests': false });
|
||||
expect(result!['upgrade-insecure-requests']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ import { Config } from '@backstage/config';
|
||||
import compression from 'compression';
|
||||
import cors from 'cors';
|
||||
import express, { Router } from 'express';
|
||||
import helmet from 'helmet';
|
||||
import helmet, { HelmetOptions } from 'helmet';
|
||||
import * as http from 'http';
|
||||
import stoppable from 'stoppable';
|
||||
import { Logger } from 'winston';
|
||||
@@ -56,7 +56,7 @@ const DEFAULT_CSP = {
|
||||
'script-src': ["'self'"],
|
||||
'script-src-attr': ["'none'"],
|
||||
'style-src': ["'self'", 'https:', "'unsafe-inline'"],
|
||||
'upgrade-insecure-requests': [],
|
||||
'upgrade-insecure-requests': [] as string[],
|
||||
};
|
||||
|
||||
export class ServiceBuilderImpl implements ServiceBuilder {
|
||||
@@ -64,7 +64,7 @@ export class ServiceBuilderImpl implements ServiceBuilder {
|
||||
private host: string | undefined;
|
||||
private logger: Logger | undefined;
|
||||
private corsOptions: cors.CorsOptions | undefined;
|
||||
private cspOptions: CspOptions | undefined;
|
||||
private cspOptions: Record<string, string[] | false> | undefined;
|
||||
private httpsSettings: HttpsSettings | undefined;
|
||||
private enableMetrics: boolean = true;
|
||||
private routers: [string, Router][];
|
||||
@@ -85,7 +85,10 @@ export class ServiceBuilderImpl implements ServiceBuilder {
|
||||
|
||||
const baseOptions = readBaseOptions(backendConfig);
|
||||
if (baseOptions.listenPort) {
|
||||
this.port = baseOptions.listenPort;
|
||||
this.port =
|
||||
typeof baseOptions.listenPort === 'string'
|
||||
? parseInt(baseOptions.listenPort, 10)
|
||||
: baseOptions.listenPort;
|
||||
}
|
||||
if (baseOptions.listenHost) {
|
||||
this.host = baseOptions.listenHost;
|
||||
@@ -154,20 +157,11 @@ export class ServiceBuilderImpl implements ServiceBuilder {
|
||||
host,
|
||||
logger,
|
||||
corsOptions,
|
||||
cspOptions,
|
||||
httpsSettings,
|
||||
helmetOptions,
|
||||
} = this.getOptions();
|
||||
|
||||
app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
...DEFAULT_CSP,
|
||||
...cspOptions,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
app.use(helmet(helmetOptions));
|
||||
if (corsOptions) {
|
||||
app.use(cors(corsOptions));
|
||||
}
|
||||
@@ -214,16 +208,38 @@ export class ServiceBuilderImpl implements ServiceBuilder {
|
||||
host: string;
|
||||
logger: Logger;
|
||||
corsOptions?: cors.CorsOptions;
|
||||
cspOptions?: CspOptions;
|
||||
httpsSettings?: HttpsSettings;
|
||||
helmetOptions: HelmetOptions;
|
||||
} {
|
||||
return {
|
||||
port: this.port ?? DEFAULT_PORT,
|
||||
host: this.host ?? DEFAULT_HOST,
|
||||
logger: this.logger ?? getRootLogger(),
|
||||
corsOptions: this.corsOptions,
|
||||
cspOptions: this.cspOptions,
|
||||
httpsSettings: this.httpsSettings,
|
||||
helmetOptions: {
|
||||
contentSecurityPolicy: {
|
||||
directives: applyCspDirectives(this.cspOptions),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function applyCspDirectives(
|
||||
directives: Record<string, string[] | false> | undefined,
|
||||
): CspOptions | undefined {
|
||||
const result: CspOptions = { ...DEFAULT_CSP };
|
||||
|
||||
if (directives) {
|
||||
for (const [key, value] of Object.entries(directives)) {
|
||||
if (value === false) {
|
||||
delete result[key];
|
||||
} else {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { readCspOptions } from './config';
|
||||
|
||||
describe('config', () => {
|
||||
describe('readCspOptions', () => {
|
||||
it('reads valid values', () => {
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{ context: '', data: { csp: { key: ['value'] } } },
|
||||
]);
|
||||
expect(readCspOptions(config)).toEqual(
|
||||
expect.objectContaining({
|
||||
key: ['value'],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('accepts false', () => {
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{ context: '', data: { csp: { key: false } } },
|
||||
]);
|
||||
expect(readCspOptions(config)).toEqual(
|
||||
expect.objectContaining({
|
||||
key: false,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects invalid value types', () => {
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{ context: '', data: { csp: { key: [4] } } },
|
||||
]);
|
||||
expect(() => readCspOptions(config)).toThrow(/wanted string-array/);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ import { Config } from '@backstage/config';
|
||||
import { CorsOptions } from 'cors';
|
||||
|
||||
export type BaseOptions = {
|
||||
listenPort?: number;
|
||||
listenPort?: string | number;
|
||||
listenHost?: string;
|
||||
};
|
||||
|
||||
@@ -89,8 +89,19 @@ export function readBaseOptions(config: Config): BaseOptions {
|
||||
});
|
||||
}
|
||||
|
||||
const port = config.getOptional('listen.port');
|
||||
if (
|
||||
typeof port !== 'undefined' &&
|
||||
typeof port !== 'number' &&
|
||||
typeof port !== 'string'
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid type in config for key 'backend.listen.post', got ${typeof port}, wanted string or number`,
|
||||
);
|
||||
}
|
||||
|
||||
return removeUnknown({
|
||||
listenPort: config.getOptionalNumber('listen.port'),
|
||||
listenPort: port,
|
||||
listenHost: config.getOptionalString('listen.host'),
|
||||
baseUrl: config.getOptionalString('baseUrl'),
|
||||
});
|
||||
@@ -134,24 +145,33 @@ export function readCorsOptions(config: Config): CorsOptions | undefined {
|
||||
* Attempts to read a CSP options object from the root of a config object.
|
||||
*
|
||||
* @param config The root of a backend config object
|
||||
* @returns A CSP options object, or undefined if not specified
|
||||
* @returns A CSP options object, or undefined if not specified. Values can be
|
||||
* false as well, which means to remove the default behavior for that
|
||||
* key.
|
||||
*
|
||||
* @example
|
||||
* ```yaml
|
||||
* backend:
|
||||
* csp:
|
||||
* connect-src: ["'self'", 'http:', 'https:']
|
||||
* upgrade-insecure-requests: false
|
||||
* ```
|
||||
*/
|
||||
export function readCspOptions(config: Config): CspOptions | undefined {
|
||||
export function readCspOptions(
|
||||
config: Config,
|
||||
): Record<string, string[] | false> | undefined {
|
||||
const cc = config.getOptionalConfig('csp');
|
||||
if (!cc) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result: CspOptions = {};
|
||||
const result: Record<string, string[] | false> = {};
|
||||
for (const key of cc.keys()) {
|
||||
result[key] = cc.getStringArray(key);
|
||||
if (cc.get(key) === false) {
|
||||
result[key] = false;
|
||||
} else {
|
||||
result[key] = cc.getStringArray(key);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ae95c7ff3]
|
||||
- Updated dependencies [b4488ddb0]
|
||||
- Updated dependencies [612368274]
|
||||
- Updated dependencies [6a6c7c14e]
|
||||
- Updated dependencies [08835a61d]
|
||||
- Updated dependencies [a9fd599f7]
|
||||
- Updated dependencies [e42402b47]
|
||||
- Updated dependencies [bcc211a08]
|
||||
- Updated dependencies [3619ea4c4]
|
||||
- @backstage/plugin-techdocs-backend@0.3.1
|
||||
- @backstage/plugin-catalog-backend@0.3.0
|
||||
- @backstage/backend-common@0.3.3
|
||||
- @backstage/plugin-proxy-backend@0.2.2
|
||||
- @backstage/catalog-model@0.4.0
|
||||
- @backstage/plugin-kubernetes-backend@0.2.1
|
||||
- @backstage/plugin-app-backend@0.3.2
|
||||
- example-app@0.2.5
|
||||
- @backstage/plugin-auth-backend@0.2.5
|
||||
- @backstage/plugin-scaffolder-backend@0.3.3
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [50eff1d00]
|
||||
- Updated dependencies [ff1301d28]
|
||||
- Updated dependencies [4b53294a6]
|
||||
- Updated dependencies [3aa7efb3f]
|
||||
- Updated dependencies [1ec19a3f4]
|
||||
- Updated dependencies [ab94c9542]
|
||||
- Updated dependencies [3a201c5d5]
|
||||
- Updated dependencies [2daf18e80]
|
||||
- Updated dependencies [069cda35f]
|
||||
- Updated dependencies [b3d4e4e57]
|
||||
- Updated dependencies [700a212b4]
|
||||
- @backstage/plugin-auth-backend@0.2.4
|
||||
- @backstage/plugin-app-backend@0.3.1
|
||||
- @backstage/plugin-techdocs-backend@0.3.0
|
||||
- @backstage/backend-common@0.3.2
|
||||
- @backstage/plugin-catalog-backend@0.2.3
|
||||
- @backstage/catalog-model@0.3.1
|
||||
- @backstage/plugin-rollbar-backend@0.1.4
|
||||
- example-app@0.2.4
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -7,7 +7,7 @@ WORKDIR /usr/src/app
|
||||
# and along with yarn.lock and the root package.json, that's enough to run yarn install.
|
||||
ADD yarn.lock package.json skeleton.tar ./
|
||||
|
||||
RUN yarn install --frozen-lockfile --production
|
||||
RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)"
|
||||
|
||||
# This will copy the contents of the dist-workspace when running the build-image command.
|
||||
# Do not use this Dockerfile outside of that command, as it will copy in the source code instead.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.5",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"private": true,
|
||||
@@ -18,24 +18,24 @@
|
||||
"migrate:create": "knex migrate:make -x ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.3.1",
|
||||
"@backstage/catalog-model": "^0.3.0",
|
||||
"@backstage/backend-common": "^0.3.3",
|
||||
"@backstage/catalog-model": "^0.4.0",
|
||||
"@backstage/config": "^0.1.1",
|
||||
"@backstage/plugin-app-backend": "^0.3.0",
|
||||
"@backstage/plugin-auth-backend": "^0.2.3",
|
||||
"@backstage/plugin-catalog-backend": "^0.2.2",
|
||||
"@backstage/plugin-app-backend": "^0.3.2",
|
||||
"@backstage/plugin-auth-backend": "^0.2.5",
|
||||
"@backstage/plugin-catalog-backend": "^0.3.0",
|
||||
"@backstage/plugin-graphql-backend": "^0.1.3",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.2.0",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.1",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.3",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.3.2",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.2.1",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.2",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.4",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.3.3",
|
||||
"@backstage/plugin-sentry-backend": "^0.1.3",
|
||||
"@backstage/plugin-techdocs-backend": "^0.2.2",
|
||||
"@backstage/plugin-techdocs-backend": "^0.3.1",
|
||||
"@gitbeaker/node": "^25.2.0",
|
||||
"@octokit/rest": "^18.0.0",
|
||||
"azure-devops-node-api": "^10.1.1",
|
||||
"dockerode": "^3.2.0",
|
||||
"example-app": "^0.2.3",
|
||||
"example-app": "^0.2.5",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
"knex": "^0.21.6",
|
||||
@@ -45,7 +45,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.3.1",
|
||||
"@backstage/cli": "^0.4.0",
|
||||
"@types/dockerode": "^2.5.32",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/express-serve-static-core": "^4.17.5",
|
||||
|
||||
@@ -28,6 +28,7 @@ export default async function createPlugin(env: PluginEnvironment) {
|
||||
entitiesCatalog,
|
||||
locationsCatalog,
|
||||
higherOrderOperation,
|
||||
locationAnalyzer,
|
||||
} = await builder.build();
|
||||
|
||||
useHotCleanup(
|
||||
@@ -39,6 +40,7 @@ export default async function createPlugin(env: PluginEnvironment) {
|
||||
entitiesCatalog,
|
||||
locationsCatalog,
|
||||
higherOrderOperation,
|
||||
locationAnalyzer,
|
||||
logger: env.logger,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/catalog-client
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [08835a61d]
|
||||
- Updated dependencies [a9fd599f7]
|
||||
- Updated dependencies [bcc211a08]
|
||||
- @backstage/catalog-model@0.4.0
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/catalog-client",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -20,12 +20,12 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.3.0",
|
||||
"@backstage/catalog-model": "^0.4.0",
|
||||
"@backstage/config": "^0.1.1",
|
||||
"cross-fetch": "^3.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.3.1",
|
||||
"@backstage/cli": "^0.4.0",
|
||||
"@types/jest": "^26.0.7",
|
||||
"msw": "^0.21.2"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,54 @@
|
||||
# @backstage/catalog-model
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- bcc211a08: k8s-plugin: refactor approach to use annotation based label-selector
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 08835a61d: Add support for relative targets and implicit types in Location entities.
|
||||
- a9fd599f7: Add Analyze location endpoint to catalog backend. Add catalog-import plugin and replace import-component with it. To start using Analyze location endpoint, you have add it to the `createRouter` function options in the `\backstage\packages\backend\src\plugins\catalog.ts` file:
|
||||
|
||||
```ts
|
||||
export default async function createPlugin(env: PluginEnvironment) {
|
||||
const builder = new CatalogBuilder(env);
|
||||
const {
|
||||
entitiesCatalog,
|
||||
locationsCatalog,
|
||||
higherOrderOperation,
|
||||
locationAnalyzer, //<--
|
||||
} = await builder.build();
|
||||
|
||||
return await createRouter({
|
||||
entitiesCatalog,
|
||||
locationsCatalog,
|
||||
higherOrderOperation,
|
||||
locationAnalyzer, //<--
|
||||
logger: env.logger,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ab94c9542: Add `providesApis` and `consumesApis` to the component entity spec.
|
||||
- 2daf18e80: Start emitting all known relation types from the core entity kinds, based on their spec data.
|
||||
- 069cda35f: Marked the field `spec.implementsApis` on `Component` entities for deprecation on Dec 14th, 2020.
|
||||
|
||||
Code that consumes these fields should remove those usages as soon as possible and migrate to using
|
||||
relations instead. Producers should fill the field `spec.providesApis` instead, which has the same
|
||||
semantic.
|
||||
|
||||
After Dec 14th, the fields will be removed from types and classes of the Backstage repository. At
|
||||
the first release after that, they will not be present in released packages either.
|
||||
|
||||
If your catalog-info.yaml files still contain this field after the deletion, they will still be
|
||||
valid and your ingestion will not break, but they won't be visible in the types for consuming code, and the expected relations will not be generated based on them either.
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Examples with relative paths
|
||||
|
||||
These examples use Location entities with relative paths
|
||||
[see #3513](https://github.com/backstage/backstage/pull/3513).
|
||||
|
||||
The `examples` sibling directory will be replaced with these contents no sooner
|
||||
than December 16 2020, to give consumers time to adopt the above change.
|
||||
|
||||
The contents of this directory is here for consumers who are on the edge and
|
||||
want to use the new facility before December 16.
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Location
|
||||
metadata:
|
||||
name: acme-corp
|
||||
description: A collection of all Backstage example Groups
|
||||
spec:
|
||||
targets:
|
||||
- ./acme/org.yaml
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Group
|
||||
metadata:
|
||||
name: backstage
|
||||
description: The backstage sub-department
|
||||
spec:
|
||||
type: sub-department
|
||||
parent: infrastructure
|
||||
ancestors: [infrastructure, acme-corp]
|
||||
children: [team-a, team-b]
|
||||
descendants: [team-a, team-b]
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Group
|
||||
metadata:
|
||||
name: boxoffice
|
||||
description: The boxoffice sub-department
|
||||
spec:
|
||||
type: sub-department
|
||||
parent: infrastructure
|
||||
ancestors: [infrastructure, acme-corp]
|
||||
children: [team-c, team-d]
|
||||
descendants: [team-c, team-d]
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Group
|
||||
metadata:
|
||||
name: infrastructure
|
||||
description: The infra department
|
||||
spec:
|
||||
type: department
|
||||
parent: acme-corp
|
||||
ancestors: [acme-corp]
|
||||
children: [backstage, boxoffice]
|
||||
descendants: [backstage, boxoffice, team-a, team-b, team-c, team-d]
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Group
|
||||
metadata:
|
||||
name: acme-corp
|
||||
description: The acme-corp organization
|
||||
spec:
|
||||
type: organization
|
||||
ancestors: []
|
||||
children: [infrastructure]
|
||||
descendants:
|
||||
[infrastructure, backstage, boxoffice, team-a, team-b, team-c, team-d]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Location
|
||||
metadata:
|
||||
name: example-groups
|
||||
description: A collection of all Backstage example Groups
|
||||
spec:
|
||||
targets:
|
||||
- ./infrastructure-group.yaml
|
||||
- ./boxoffice-group.yaml
|
||||
- ./backstage-group.yaml
|
||||
- ./team-a-group.yaml
|
||||
- ./team-b-group.yaml
|
||||
- ./team-c-group.yaml
|
||||
- ./team-d-group.yaml
|
||||
@@ -0,0 +1,58 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Group
|
||||
metadata:
|
||||
name: team-a
|
||||
description: Team A
|
||||
spec:
|
||||
type: team
|
||||
parent: backstage
|
||||
ancestors: [backstage, infrastructure, acme-corp]
|
||||
children: []
|
||||
descendants: []
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: breanna.davison
|
||||
spec:
|
||||
profile:
|
||||
displayName: Breanna Davison
|
||||
email: breanna-davison@example.com
|
||||
picture: https://example.com/staff/breanna.jpeg
|
||||
memberOf: [team-a]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: janelle.dawe
|
||||
spec:
|
||||
profile:
|
||||
displayName: Janelle Dawe
|
||||
email: janelle-dawe@example.com
|
||||
picture: https://example.com/staff/janelle.jpeg
|
||||
memberOf: [team-a]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: nigel.manning
|
||||
spec:
|
||||
profile:
|
||||
displayName: Nigel Manning
|
||||
email: nigel-manning@example.com
|
||||
picture: https://example.com/staff/nigel.jpeg
|
||||
memberOf: [team-a]
|
||||
---
|
||||
# This user is added as an example, to make it more easy for the "Guest"
|
||||
# sign-in option to demonstrate some entities being owned. In a regular org,
|
||||
# a guest user would probably not be registered like this.
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: guest
|
||||
spec:
|
||||
profile:
|
||||
displayName: Guest User
|
||||
email: guest@example.com
|
||||
picture: https://example.com/staff/the-ceos-dog.jpeg
|
||||
memberOf: [team-a]
|
||||
@@ -0,0 +1,66 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Group
|
||||
metadata:
|
||||
name: team-b
|
||||
description: Team B
|
||||
spec:
|
||||
type: team
|
||||
parent: backstage
|
||||
ancestors: [backstage, infrastructure, acme-corp]
|
||||
children: []
|
||||
descendants: []
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: amelia.park
|
||||
spec:
|
||||
profile:
|
||||
displayName: Amelia Park
|
||||
email: amelia-park@example.com
|
||||
picture: https://example.com/staff/amelia.jpeg
|
||||
memberOf: [team-b]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: colette.brock
|
||||
spec:
|
||||
profile:
|
||||
displayName: Colette Brock
|
||||
email: colette-brock@example.com
|
||||
picture: https://example.com/staff/colette.jpeg
|
||||
memberOf: [team-b]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: jenny.doe
|
||||
spec:
|
||||
profile:
|
||||
displayName: Jenny Doe
|
||||
email: jenny-doe@example.com
|
||||
picture: https://example.com/staff/jenny.jpeg
|
||||
memberOf: [team-b]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: jonathon.page
|
||||
spec:
|
||||
profile:
|
||||
displayName: Jonathon Page
|
||||
email: jonathon-page@example.com
|
||||
picture: https://example.com/staff/jonathon.jpeg
|
||||
memberOf: [team-b]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: justine.barrow
|
||||
spec:
|
||||
profile:
|
||||
displayName: Justine Barrow
|
||||
email: justine-barrow@example.com
|
||||
picture: https://example.com/staff/justine.jpeg
|
||||
memberOf: [team-b]
|
||||
@@ -0,0 +1,66 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Group
|
||||
metadata:
|
||||
name: team-c
|
||||
description: Team C
|
||||
spec:
|
||||
type: team
|
||||
parent: boxoffice
|
||||
ancestors: [boxoffice, infrastructure, acme-corp]
|
||||
children: []
|
||||
descendants: []
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: calum.leavy
|
||||
spec:
|
||||
profile:
|
||||
displayName: Calum Leavy
|
||||
email: calum-leavy@example.com
|
||||
picture: https://example.com/staff/calum.jpeg
|
||||
memberOf: [team-c]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: frank.tiernan
|
||||
spec:
|
||||
profile:
|
||||
displayName: Frank Tiernan
|
||||
email: frank-tiernan@example.com
|
||||
picture: https://example.com/staff/frank.jpeg
|
||||
memberOf: [team-c]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: peadar.macmahon
|
||||
spec:
|
||||
profile:
|
||||
displayName: Peadar MacMahon
|
||||
email: peadar-macmahon@example.com
|
||||
picture: https://example.com/staff/peadar.jpeg
|
||||
memberOf: [team-c]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: sarah.gilroy
|
||||
spec:
|
||||
profile:
|
||||
displayName: Sarah Gilroy
|
||||
email: sarah-gilroy@example.com
|
||||
picture: https://example.com/staff/sarah.jpeg
|
||||
memberOf: [team-c]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: tara.macgovern
|
||||
spec:
|
||||
profile:
|
||||
displayName: Tara MacGovern
|
||||
email: tara-macgovern@example.com
|
||||
picture: https://example.com/staff/tara.jpeg
|
||||
memberOf: [team-c]
|
||||
@@ -0,0 +1,33 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Group
|
||||
metadata:
|
||||
name: team-d
|
||||
description: Team D
|
||||
spec:
|
||||
type: team
|
||||
parent: boxoffice
|
||||
ancestors: [boxoffice, infrastructure, acme-corp]
|
||||
children: []
|
||||
descendants: []
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: eva.macdowell
|
||||
spec:
|
||||
profile:
|
||||
displayName: Eva MacDowell
|
||||
email: eva-macdowell@example.com
|
||||
picture: https://example.com/staff/eva.jpeg
|
||||
memberOf: [team-d]
|
||||
---
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: lucy.sheehan
|
||||
spec:
|
||||
profile:
|
||||
displayName: Lucy Sheehan
|
||||
email: lucy-sheehan@example.com
|
||||
picture: https://example.com/staff/lucy.jpeg
|
||||
memberOf: [team-d]
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Location
|
||||
metadata:
|
||||
name: example-apis
|
||||
description: A collection of all Backstage example APIs
|
||||
spec:
|
||||
targets:
|
||||
- ./apis/hello-world-api.yaml
|
||||
- ./apis/petstore-api.yaml
|
||||
- ./apis/spotify-api.yaml
|
||||
- ./apis/streetlights-api.yaml
|
||||
- ./apis/swapi-graphql.yaml
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Location
|
||||
metadata:
|
||||
name: example-components
|
||||
description: A collection of all Backstage example components
|
||||
spec:
|
||||
targets:
|
||||
- ./components/artist-lookup-component.yaml
|
||||
- ./components/petstore-component.yaml
|
||||
- ./components/playback-order-component.yaml
|
||||
- ./components/podcast-api-component.yaml
|
||||
- ./components/queue-proxy-component.yaml
|
||||
- ./components/searcher-component.yaml
|
||||
- ./components/playback-lib-component.yaml
|
||||
- ./components/www-artist-component.yaml
|
||||
- ./components/shuffle-api-component.yaml
|
||||
@@ -0,0 +1,48 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: API
|
||||
metadata:
|
||||
name: hello-world
|
||||
description: Hello World example for gRPC
|
||||
spec:
|
||||
type: grpc
|
||||
lifecycle: deprecated
|
||||
owner: team-c
|
||||
definition: |
|
||||
// Copyright 2015 gRPC 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
option java_package = "io.grpc.examples.helloworld";
|
||||
option java_outer_classname = "HelloWorldProto";
|
||||
option objc_class_prefix = "HLW";
|
||||
|
||||
package helloworld;
|
||||
|
||||
// The greeting service definition.
|
||||
service Greeter {
|
||||
// Sends a greeting
|
||||
rpc SayHello (HelloRequest) returns (HelloReply) {}
|
||||
}
|
||||
|
||||
// The request message containing the user's name.
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: API
|
||||
metadata:
|
||||
name: petstore
|
||||
description: The petstore API
|
||||
tags:
|
||||
- store
|
||||
- rest
|
||||
spec:
|
||||
type: openapi
|
||||
lifecycle: experimental
|
||||
owner: team-c
|
||||
definition: |
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: Swagger Petstore
|
||||
license:
|
||||
name: MIT
|
||||
servers:
|
||||
- url: http://petstore.swagger.io/v1
|
||||
paths:
|
||||
/pets:
|
||||
get:
|
||||
summary: List all pets
|
||||
operationId: listPets
|
||||
tags:
|
||||
- pets
|
||||
parameters:
|
||||
- name: limit
|
||||
in: query
|
||||
description: How many items to return at one time (max 100)
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'200':
|
||||
description: A paged array of pets
|
||||
headers:
|
||||
x-next:
|
||||
description: A link to the next page of responses
|
||||
schema:
|
||||
type: string
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pets"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
post:
|
||||
summary: Create a pet
|
||||
operationId: createPets
|
||||
tags:
|
||||
- pets
|
||||
responses:
|
||||
'201':
|
||||
description: Null response
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/pets/{petId}:
|
||||
get:
|
||||
summary: Info for a specific pet
|
||||
operationId: showPetById
|
||||
tags:
|
||||
- pets
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
description: The id of the pet to retrieve
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Expected response to a valid request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
components:
|
||||
schemas:
|
||||
Pet:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
Pets:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
Error:
|
||||
type: object
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: API
|
||||
metadata:
|
||||
name: spotify
|
||||
description: The Spotify web API
|
||||
tags:
|
||||
- spotify
|
||||
- rest
|
||||
annotations:
|
||||
# The annotation is deprecated, we use placeholders (see below) instead, remove it later.
|
||||
backstage.io/definition-at-location: 'url:https://raw.githubusercontent.com/APIs-guru/openapi-directory/master/APIs/spotify.com/v1/swagger.yaml'
|
||||
spec:
|
||||
type: openapi
|
||||
lifecycle: production
|
||||
owner: team-a
|
||||
definition:
|
||||
$text: https://github.com/APIs-guru/openapi-directory/blob/master/APIs/spotify.com/v1/swagger.yaml
|
||||
@@ -0,0 +1,221 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: API
|
||||
metadata:
|
||||
name: streetlights
|
||||
description: The Smartylighting Streetlights API allows you to remotely manage the city lights.
|
||||
tags:
|
||||
- mqtt
|
||||
spec:
|
||||
type: asyncapi
|
||||
lifecycle: production
|
||||
owner: team-c
|
||||
definition: |
|
||||
asyncapi: 2.0.0
|
||||
info:
|
||||
title: Streetlights API
|
||||
version: '1.0.0'
|
||||
description: |
|
||||
The Smartylighting Streetlights API allows you to remotely manage the city lights.
|
||||
|
||||
### Check out its awesome features:
|
||||
|
||||
* Turn a specific streetlight on/off 🌃
|
||||
* Dim a specific streetlight 😎
|
||||
* Receive real-time information about environmental lighting conditions 📈
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
servers:
|
||||
production:
|
||||
url: api.streetlights.smartylighting.com:{port}
|
||||
protocol: mqtt
|
||||
description: Test broker
|
||||
variables:
|
||||
port:
|
||||
description: Secure connection (TLS) is available through port 8883.
|
||||
default: '1883'
|
||||
enum:
|
||||
- '1883'
|
||||
- '8883'
|
||||
security:
|
||||
- apiKey: []
|
||||
- supportedOauthFlows:
|
||||
- streetlights:on
|
||||
- streetlights:off
|
||||
- streetlights:dim
|
||||
- openIdConnectWellKnown: []
|
||||
|
||||
defaultContentType: application/json
|
||||
|
||||
channels:
|
||||
smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured:
|
||||
description: The topic on which measured values may be produced and consumed.
|
||||
parameters:
|
||||
streetlightId:
|
||||
$ref: '#/components/parameters/streetlightId'
|
||||
subscribe:
|
||||
summary: Receive information about environmental lighting conditions of a particular streetlight.
|
||||
operationId: receiveLightMeasurement
|
||||
traits:
|
||||
- $ref: '#/components/operationTraits/kafka'
|
||||
message:
|
||||
$ref: '#/components/messages/lightMeasured'
|
||||
|
||||
smartylighting/streetlights/1/0/action/{streetlightId}/turn/on:
|
||||
parameters:
|
||||
streetlightId:
|
||||
$ref: '#/components/parameters/streetlightId'
|
||||
publish:
|
||||
operationId: turnOn
|
||||
traits:
|
||||
- $ref: '#/components/operationTraits/kafka'
|
||||
message:
|
||||
$ref: '#/components/messages/turnOnOff'
|
||||
|
||||
smartylighting/streetlights/1/0/action/{streetlightId}/turn/off:
|
||||
parameters:
|
||||
streetlightId:
|
||||
$ref: '#/components/parameters/streetlightId'
|
||||
publish:
|
||||
operationId: turnOff
|
||||
traits:
|
||||
- $ref: '#/components/operationTraits/kafka'
|
||||
message:
|
||||
$ref: '#/components/messages/turnOnOff'
|
||||
|
||||
smartylighting/streetlights/1/0/action/{streetlightId}/dim:
|
||||
parameters:
|
||||
streetlightId:
|
||||
$ref: '#/components/parameters/streetlightId'
|
||||
publish:
|
||||
operationId: dimLight
|
||||
traits:
|
||||
- $ref: '#/components/operationTraits/kafka'
|
||||
message:
|
||||
$ref: '#/components/messages/dimLight'
|
||||
|
||||
components:
|
||||
messages:
|
||||
lightMeasured:
|
||||
name: lightMeasured
|
||||
title: Light measured
|
||||
summary: Inform about environmental lighting conditions for a particular streetlight.
|
||||
contentType: application/json
|
||||
traits:
|
||||
- $ref: '#/components/messageTraits/commonHeaders'
|
||||
payload:
|
||||
$ref: "#/components/schemas/lightMeasuredPayload"
|
||||
turnOnOff:
|
||||
name: turnOnOff
|
||||
title: Turn on/off
|
||||
summary: Command a particular streetlight to turn the lights on or off.
|
||||
traits:
|
||||
- $ref: '#/components/messageTraits/commonHeaders'
|
||||
payload:
|
||||
$ref: "#/components/schemas/turnOnOffPayload"
|
||||
dimLight:
|
||||
name: dimLight
|
||||
title: Dim light
|
||||
summary: Command a particular streetlight to dim the lights.
|
||||
traits:
|
||||
- $ref: '#/components/messageTraits/commonHeaders'
|
||||
payload:
|
||||
$ref: "#/components/schemas/dimLightPayload"
|
||||
|
||||
schemas:
|
||||
lightMeasuredPayload:
|
||||
type: object
|
||||
properties:
|
||||
lumens:
|
||||
type: integer
|
||||
minimum: 0
|
||||
description: Light intensity measured in lumens.
|
||||
sentAt:
|
||||
$ref: "#/components/schemas/sentAt"
|
||||
turnOnOffPayload:
|
||||
type: object
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
enum:
|
||||
- on
|
||||
- off
|
||||
description: Whether to turn on or off the light.
|
||||
sentAt:
|
||||
$ref: "#/components/schemas/sentAt"
|
||||
dimLightPayload:
|
||||
type: object
|
||||
properties:
|
||||
percentage:
|
||||
type: integer
|
||||
description: Percentage to which the light should be dimmed to.
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
sentAt:
|
||||
$ref: "#/components/schemas/sentAt"
|
||||
sentAt:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Date and time when the message was sent.
|
||||
|
||||
securitySchemes:
|
||||
apiKey:
|
||||
type: apiKey
|
||||
in: user
|
||||
description: Provide your API key as the user and leave the password empty.
|
||||
supportedOauthFlows:
|
||||
type: oauth2
|
||||
description: Flows to support OAuth 2.0
|
||||
flows:
|
||||
implicit:
|
||||
authorizationUrl: 'https://authserver.example/auth'
|
||||
scopes:
|
||||
'streetlights:on': Ability to switch lights on
|
||||
'streetlights:off': Ability to switch lights off
|
||||
'streetlights:dim': Ability to dim the lights
|
||||
password:
|
||||
tokenUrl: 'https://authserver.example/token'
|
||||
scopes:
|
||||
'streetlights:on': Ability to switch lights on
|
||||
'streetlights:off': Ability to switch lights off
|
||||
'streetlights:dim': Ability to dim the lights
|
||||
clientCredentials:
|
||||
tokenUrl: 'https://authserver.example/token'
|
||||
scopes:
|
||||
'streetlights:on': Ability to switch lights on
|
||||
'streetlights:off': Ability to switch lights off
|
||||
'streetlights:dim': Ability to dim the lights
|
||||
authorizationCode:
|
||||
authorizationUrl: 'https://authserver.example/auth'
|
||||
tokenUrl: 'https://authserver.example/token'
|
||||
refreshUrl: 'https://authserver.example/refresh'
|
||||
scopes:
|
||||
'streetlights:on': Ability to switch lights on
|
||||
'streetlights:off': Ability to switch lights off
|
||||
'streetlights:dim': Ability to dim the lights
|
||||
openIdConnectWellKnown:
|
||||
type: openIdConnect
|
||||
openIdConnectUrl: 'https://authserver.example/.well-known'
|
||||
|
||||
parameters:
|
||||
streetlightId:
|
||||
description: The ID of the streetlight.
|
||||
schema:
|
||||
type: string
|
||||
|
||||
messageTraits:
|
||||
commonHeaders:
|
||||
headers:
|
||||
type: object
|
||||
properties:
|
||||
my-app-header:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
|
||||
operationTraits:
|
||||
kafka:
|
||||
bindings:
|
||||
kafka:
|
||||
clientId: my-app-id
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: artist-lookup
|
||||
description: Artist Lookup
|
||||
tags:
|
||||
- java
|
||||
- data
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
owner: team-a
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: petstore
|
||||
description: Petstore
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
owner: team-c
|
||||
implementsApis:
|
||||
- petstore
|
||||
- streetlights
|
||||
- hello-world
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: playback-sdk
|
||||
description: Audio and video playback SDK
|
||||
spec:
|
||||
type: library
|
||||
lifecycle: experimental
|
||||
owner: team-c
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: playback-order
|
||||
description: Playback Order
|
||||
tags:
|
||||
- java
|
||||
- playback
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: production
|
||||
owner: user:guest
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: podcast-api
|
||||
description: Podcast API
|
||||
tags:
|
||||
- java
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
owner: team-b
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: queue-proxy
|
||||
description: Queue Proxy
|
||||
tags:
|
||||
- go
|
||||
- website
|
||||
spec:
|
||||
type: website
|
||||
lifecycle: production
|
||||
owner: team-b
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: searcher
|
||||
description: Searcher
|
||||
tags:
|
||||
- go
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: production
|
||||
owner: user:guest
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: shuffle-api
|
||||
description: Shuffle API
|
||||
tags:
|
||||
- go
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: production
|
||||
owner: user:guest
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: www-artist
|
||||
description: Artist main website
|
||||
spec:
|
||||
type: website
|
||||
lifecycle: production
|
||||
owner: team-a
|
||||
@@ -0,0 +1,7 @@
|
||||
# Example Entities
|
||||
|
||||
NOTE: These are being replaced with the contents of the `examples-relative`
|
||||
sibling directory, after December 16 2020. If you are using this example data
|
||||
you will need to be using a released version of the catalog backend which
|
||||
supports relative targets in Location entities
|
||||
[see #3513](https://github.com/backstage/backstage/pull/3513) after that time.
|
||||
@@ -42,3 +42,17 @@ spec:
|
||||
email: nigel-manning@example.com
|
||||
picture: https://example.com/staff/nigel.jpeg
|
||||
memberOf: [team-a]
|
||||
---
|
||||
# This user is added as an example, to make it more easy for the "Guest"
|
||||
# sign-in option to demonstrate some entities being owned. In a regular org,
|
||||
# a guest user would probably not be registered like this.
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: User
|
||||
metadata:
|
||||
name: guest
|
||||
spec:
|
||||
profile:
|
||||
displayName: Guest User
|
||||
email: guest@example.com
|
||||
picture: https://example.com/staff/the-ceos-dog.jpeg
|
||||
memberOf: [team-a]
|
||||
|
||||
@@ -6,7 +6,7 @@ metadata:
|
||||
spec:
|
||||
type: grpc
|
||||
lifecycle: deprecated
|
||||
owner: grpc@example.com
|
||||
owner: team-c
|
||||
definition: |
|
||||
// Copyright 2015 gRPC authors.
|
||||
//
|
||||
|
||||
@@ -9,7 +9,7 @@ metadata:
|
||||
spec:
|
||||
type: openapi
|
||||
lifecycle: experimental
|
||||
owner: pets@example.com
|
||||
owner: team-c
|
||||
definition: |
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
|
||||
@@ -12,6 +12,6 @@ metadata:
|
||||
spec:
|
||||
type: openapi
|
||||
lifecycle: production
|
||||
owner: spotify@example.com
|
||||
owner: team-a
|
||||
definition:
|
||||
$text: https://github.com/APIs-guru/openapi-directory/blob/master/APIs/spotify.com/v1/swagger.yaml
|
||||
|
||||
@@ -8,7 +8,7 @@ metadata:
|
||||
spec:
|
||||
type: asyncapi
|
||||
lifecycle: production
|
||||
owner: streetlights@example.com
|
||||
owner: team-c
|
||||
definition: |
|
||||
asyncapi: 2.0.0
|
||||
info:
|
||||
|
||||
@@ -6,7 +6,7 @@ metadata:
|
||||
spec:
|
||||
type: graphql
|
||||
lifecycle: production
|
||||
owner: yoda@dagobah.space
|
||||
owner: team-b
|
||||
definition: |
|
||||
schema {
|
||||
query: Root
|
||||
|
||||
@@ -9,4 +9,4 @@ metadata:
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
owner: artists@example.com
|
||||
owner: team-a
|
||||
|
||||
@@ -6,7 +6,7 @@ metadata:
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
owner: pets@example.com
|
||||
owner: team-c
|
||||
implementsApis:
|
||||
- petstore
|
||||
- streetlights
|
||||
|
||||
@@ -6,4 +6,4 @@ metadata:
|
||||
spec:
|
||||
type: library
|
||||
lifecycle: experimental
|
||||
owner: players@example.com
|
||||
owner: team-c
|
||||
|
||||
@@ -9,4 +9,4 @@ metadata:
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: production
|
||||
owner: guest
|
||||
owner: user:guest
|
||||
|
||||
@@ -8,4 +8,4 @@ metadata:
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
owner: players@example.com
|
||||
owner: team-b
|
||||
|
||||
@@ -9,4 +9,4 @@ metadata:
|
||||
spec:
|
||||
type: website
|
||||
lifecycle: production
|
||||
owner: tools@example.com
|
||||
owner: team-b
|
||||
|
||||
@@ -8,4 +8,4 @@ metadata:
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: production
|
||||
owner: guest
|
||||
owner: user:guest
|
||||
|
||||
@@ -8,4 +8,4 @@ metadata:
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: production
|
||||
owner: guest
|
||||
owner: user:guest
|
||||
|
||||
@@ -6,4 +6,4 @@ metadata:
|
||||
spec:
|
||||
type: website
|
||||
lifecycle: production
|
||||
owner: artists@example.com
|
||||
owner: team-a
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/catalog-model",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,7 +29,7 @@
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.3.1",
|
||||
"@backstage/cli": "^0.4.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/lodash": "^4.14.151",
|
||||
|
||||
@@ -84,6 +84,14 @@ export function parseEntityName(
|
||||
* @param context The context of defaults that the parsing happens within
|
||||
* @returns The compound form of the reference
|
||||
*/
|
||||
export function parseEntityRef(
|
||||
ref: EntityRef,
|
||||
context?: { defaultKind: string; defaultNamespace: string },
|
||||
): {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
export function parseEntityRef(
|
||||
ref: EntityRef,
|
||||
context?: { defaultKind: string },
|
||||
@@ -100,14 +108,6 @@ export function parseEntityRef(
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
export function parseEntityRef(
|
||||
ref: EntityRef,
|
||||
context?: { defaultKind: string; defaultNamespace: string },
|
||||
): {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
export function parseEntityRef(
|
||||
ref: EntityRef,
|
||||
context: EntityRefContext = {},
|
||||
|
||||
@@ -34,6 +34,8 @@ describe('ComponentV1alpha1Validator', () => {
|
||||
lifecycle: 'production',
|
||||
owner: 'me',
|
||||
implementsApis: ['api-0'],
|
||||
providesApis: ['api-0'],
|
||||
consumesApis: ['api-0'],
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -121,4 +123,44 @@ describe('ComponentV1alpha1Validator', () => {
|
||||
(entity as any).spec.implementsApis = [];
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('accepts missing providesApis', async () => {
|
||||
delete (entity as any).spec.providesApis;
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('rejects empty providesApis', async () => {
|
||||
(entity as any).spec.providesApis = [''];
|
||||
await expect(validator.check(entity)).rejects.toThrow(/providesApis/);
|
||||
});
|
||||
|
||||
it('rejects undefined providesApis', async () => {
|
||||
(entity as any).spec.providesApis = [undefined];
|
||||
await expect(validator.check(entity)).rejects.toThrow(/providesApis/);
|
||||
});
|
||||
|
||||
it('accepts no providesApis', async () => {
|
||||
(entity as any).spec.providesApis = [];
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('accepts missing consumesApis', async () => {
|
||||
delete (entity as any).spec.consumesApis;
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('rejects empty consumesApis', async () => {
|
||||
(entity as any).spec.consumesApis = [''];
|
||||
await expect(validator.check(entity)).rejects.toThrow(/consumesApis/);
|
||||
});
|
||||
|
||||
it('rejects undefined consumesApis', async () => {
|
||||
(entity as any).spec.consumesApis = [undefined];
|
||||
await expect(validator.check(entity)).rejects.toThrow(/consumesApis/);
|
||||
});
|
||||
|
||||
it('accepts no consumesApis', async () => {
|
||||
(entity as any).spec.consumesApis = [];
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,15 +30,8 @@ const schema = yup.object<Partial<ComponentEntityV1alpha1>>({
|
||||
lifecycle: yup.string().required().min(1),
|
||||
owner: yup.string().required().min(1),
|
||||
implementsApis: yup.array(yup.string().required()).notRequired(),
|
||||
kubernetes: yup
|
||||
.object<any>({
|
||||
selector: yup
|
||||
.object<any>({
|
||||
matchLabels: yup.object<any>().required(),
|
||||
})
|
||||
.required(),
|
||||
})
|
||||
.notRequired(),
|
||||
providesApis: yup.array(yup.string().required()).notRequired(),
|
||||
consumesApis: yup.array(yup.string().required()).notRequired(),
|
||||
})
|
||||
.required(),
|
||||
});
|
||||
@@ -50,14 +43,14 @@ export interface ComponentEntityV1alpha1 extends Entity {
|
||||
type: string;
|
||||
lifecycle: string;
|
||||
owner: string;
|
||||
/**
|
||||
* @deprecated This field will disappear on Dec 14th, 2020. Please remove
|
||||
* any consuming code. The new field providesApis provides the
|
||||
* same functionality like before.
|
||||
*/
|
||||
implementsApis?: string[];
|
||||
kubernetes?: {
|
||||
selector: {
|
||||
matchLabels: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
providesApis?: string[];
|
||||
consumesApis?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -54,9 +54,9 @@ describe('LocationV1alpha1Validator', () => {
|
||||
await expect(validator.check(entity)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('rejects missing type', async () => {
|
||||
it('accepts missing type', async () => {
|
||||
delete (entity as any).spec.type;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/type/);
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('rejects wrong type', async () => {
|
||||
|
||||
@@ -26,7 +26,7 @@ const schema = yup.object<Partial<LocationEntityV1alpha1>>({
|
||||
kind: yup.string().required().equals([KIND]),
|
||||
spec: yup
|
||||
.object({
|
||||
type: yup.string().required().min(1),
|
||||
type: yup.string().notRequired().min(1),
|
||||
target: yup.string().notRequired().min(1),
|
||||
targets: yup.array(yup.string().required()).notRequired(),
|
||||
})
|
||||
@@ -37,7 +37,7 @@ export interface LocationEntityV1alpha1 extends Entity {
|
||||
apiVersion: typeof API_VERSION[number];
|
||||
kind: typeof KIND;
|
||||
spec: {
|
||||
type: string;
|
||||
type?: string;
|
||||
target?: string;
|
||||
targets?: string[];
|
||||
};
|
||||
|
||||
@@ -33,7 +33,9 @@ export const RELATION_OWNER_OF = 'ownerOf';
|
||||
* A relation with an API entity, typically from a component or system
|
||||
*/
|
||||
export const RELATION_CONSUMES_API = 'consumesApi';
|
||||
export const RELATION_API_CONSUMED_BY = 'apiConsumedBy';
|
||||
export const RELATION_PROVIDES_API = 'providesApi';
|
||||
export const RELATION_API_PROVIDED_BY = 'apiProvidedBy';
|
||||
|
||||
/**
|
||||
* A relation denoting a dependency on another entity.
|
||||
|
||||
@@ -15,5 +15,9 @@
|
||||
*/
|
||||
|
||||
export type { Location, LocationSpec } from './types';
|
||||
export { locationSchema, locationSpecSchema } from './validation';
|
||||
export {
|
||||
locationSchema,
|
||||
locationSpecSchema,
|
||||
analyzeLocationSchema,
|
||||
} from './validation';
|
||||
export { LOCATION_ANNOTATION } from './annotation';
|
||||
|
||||
@@ -34,3 +34,10 @@ export const locationSchema = yup
|
||||
})
|
||||
.noUnknown()
|
||||
.required();
|
||||
|
||||
export const analyzeLocationSchema = yup
|
||||
.object<{ location: LocationSpec }>({
|
||||
location: locationSpecSchema,
|
||||
})
|
||||
.noUnknown()
|
||||
.required();
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 00670a96e: sort product panels and navigation menu by greatest cost
|
||||
update tsconfig.json to use ES2020 api
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b4488ddb0: Added a type alias for PositionError = GeolocationPositionError
|
||||
- 4a655c89d: Bump versions of `esbuild` and `rollup-plugin-esbuild`
|
||||
- 8a16e8af8: Support `.npmrc` when building with private NPM registries
|
||||
- Updated dependencies [4e7091759]
|
||||
- Updated dependencies [b4488ddb0]
|
||||
- @backstage/config-loader@0.4.0
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 294295453: Only load config that applies to the target package for frontend build and serve tasks. Also added `--package <name>` flag to scope the config schema used by the `config:print` and `config:check` commands.
|
||||
- f538e2c56: Make versions:bump install new versions of dependencies that were within the specified range as well as install new versions of transitive @backstage dependencies.
|
||||
- 8697dea5b: Bump Rollup
|
||||
- b623cc275: Narrow down the version range of rollup-plugin-esbuild to avoid breaking change in newer version
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+12
@@ -97,3 +97,15 @@ declare module '*.module.sass' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
// NOTE(freben): Both the fix, and the placement of the fix, are not great.
|
||||
//
|
||||
// The fix is because the PositionError was renamed to
|
||||
// GeolocationPositionError outside of our control, and react-use is dependent
|
||||
// on the old name.
|
||||
//
|
||||
// The placement is because it's the one location we have at the moment, where
|
||||
// a central .d.ts file is imported by the frontend and can be amended.
|
||||
//
|
||||
// After both TS and react-use are bumped high enough, this should be removed.
|
||||
type PositionError = GeolocationPositionError;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"incremental": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react",
|
||||
"lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2019", "ESNext.Promise"],
|
||||
"lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2020", "ESNext.Promise"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"noEmit": false,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user