Merge branch 'backstage:master' into topic/update-backend-tasks-readme

This commit is contained in:
Andre Wanlin
2021-12-30 14:01:37 -06:00
committed by GitHub
227 changed files with 2829 additions and 1377 deletions
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-rollbar-backend': patch
---
Moved `@backstage/test-utils` to `devDependencies`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/backend-test-utils': patch
---
Lazy-load `testcontainers` module in order to avoid side-effects.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-auth-backend': patch
---
Replaces the usage of `got` with `node-fetch` in the `getUserPhoto` method of the Microsoft provider
-24
View File
@@ -1,24 +0,0 @@
---
'@backstage/create-app': patch
---
removed inline and internal CSS from index.html
To make this change to an existing app, apply the following changes to the `packages/app/public/index.html` file:
Remove internal style
```diff
- <style>
- #root {
- min-height: 100%;
- }
- </style>
```
Remove inline style from the body tag
```diff
- <body style="margin: 0">
+ <body>
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-cost-insights': patch
---
Fixed an accidental re-export of `@backstage/test-utils` that broke this plugin in the most recent release.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/test-utils': patch
---
JSON serialize and freeze values stored by the `MockStorageApi`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/techdocs-common': patch
---
Bump `@azure/identity` from `^1.5.0` to `^2.0.1`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/backend-common': patch
---
In-memory cache clients instantiated from the same cache manager now share the same memory space.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/backend-common': patch
---
Use the default CSP policy provided by `helmet` directly rather than a copy.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-auth-backend': patch
---
Update `auth0` and `onelogin` providers to allow for `authHandler` and `signIn.resolver` configuration.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-auth-backend': patch
---
Fixed bug on refresh token on Okta provider, now it gets the refresh token and it sends it into providerInfo
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-tech-insights': minor
---
fixes api auth in tech-insights plugin
-29
View File
@@ -1,29 +0,0 @@
---
'@backstage/plugin-auth-backend': minor
---
Avoid ever returning OAuth refresh tokens back to the client, and always exchange refresh tokens for a new one when available for all providers.
This comes with a breaking change to the TypeScript API for custom auth providers. The `refresh` method of `OAuthHandlers` implementation must now return a `{ response, refreshToken }` object rather than a direct response. Existing `refresh` implementations are typically migrated by changing an existing return expression that looks like this:
```ts
return await this.handleResult({
fullProfile,
params,
accessToken,
refreshToken,
});
```
Into the following:
```ts
return {
response: await this.handleResult({
fullProfile,
params,
accessToken,
}),
refreshToken,
};
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-search': patch
---
Internal cleanup of the exports structure
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/create-app': patch
---
Removed unused templating asset.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-app-backend': patch
---
Set `X-Frame-Options: deny` rather than the default `sameorigin` for all content served by the `app-backend`.`
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
Fix issue with plugin:serve for Plugins not using Lerna monorepo.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
remove inline CSS from serve_index.html
-9
View File
@@ -1,9 +0,0 @@
---
'@backstage/backend-common': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-scaffolder-backend': patch
---
Uptake changes to the GitHub Credentials Provider interface.
-7
View File
@@ -1,7 +0,0 @@
---
'@backstage/plugin-catalog-react': patch
---
When a user has zero owned entities when viewing an entity kind in the catalog
page, it will be automatically redirected to see all the entities. Furthermore,
for the kind User and Group there are no longer the owned selector.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/create-app': patch
---
Add a comment to the default backend about the fallback 404 handler.
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/plugin-techdocs': patch
---
Add the techdocs.sanitizer.allowedIframeHosts config.
This config allows all iframes which have the host of the attribute src in the 'allowedIframehosts' list to be displayed in the documentation.
-5
View File
@@ -1,5 +0,0 @@
---
'@techdocs/cli': patch
---
remove internal and inline CSS from index.html
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-rollbar-backend': patch
---
Replace the usage of `axios` with `node-fetch` in the Rollbar API
-7
View File
@@ -1,7 +0,0 @@
---
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-scaffolder-common': patch
---
Support navigating back to pre-filled templates to update inputs of scaffolder tasks for resubmission
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
Add Override Components for Components in @backstage/plugin-catalog-react
-7
View File
@@ -1,7 +0,0 @@
---
'@backstage/plugin-search': patch
---
Introduces a `<SearchType.Accordion />` variant, which operates on the same part of a search query as the existing `<SearchType />`, but in a more opinionated way (as a single-select control surface suitable for faceted search UIs).
Check the [search plugin storybook](https://backstage.io/storybook/?path=/story/plugins-search-searchtype--accordion) to see how it can be used.
@@ -1,5 +0,0 @@
---
'@backstage/plugin-search': patch
---
Captures the search term entered in the SearchBarBase as a `search` event.
-58
View File
@@ -1,58 +0,0 @@
---
'@backstage/create-app': patch
---
The `<SearchType />` filter in the composed `SearchPage.tsx` was replaced with the `<SearchType.Accordion />` variant.
This is an entirely optional change; if you wish to display a control surface for search `types` as a single-select accordion (as opposed to the current multi-select of checkboxes), you can make the following (or similar) changes to your search page layout:
```diff
--- a/packages/app/src/components/search/SearchPage.tsx
+++ b/packages/app/src/components/search/SearchPage.tsx
@@ -11,7 +11,7 @@ import {
SearchType,
DefaultResultListItem,
} from '@backstage/plugin-search';
-import { Content, Header, Page } from '@backstage/core-components';
+import { CatalogIcon, Content, DocsIcon, Header, Page } from '@backstage/core-components';
const useStyles = makeStyles((theme: Theme) => ({
bar: {
@@ -19,6 +19,7 @@ const useStyles = makeStyles((theme: Theme) => ({
},
filters: {
padding: theme.spacing(2),
+ marginTop: theme.spacing(2),
},
filter: {
'& + &': {
@@ -41,12 +42,23 @@ const SearchPage = () => {
</Paper>
</Grid>
<Grid item xs={3}>
+ <SearchType.Accordion
+ name="Result Type"
+ defaultValue="software-catalog"
+ types={[
+ {
+ value: 'software-catalog',
+ name: 'Software Catalog',
+ icon: <CatalogIcon />,
+ },
+ {
+ value: 'techdocs',
+ name: 'Documentation',
+ icon: <DocsIcon />,
+ },
+ ]}
+ />
<Paper className={classes.filters}>
- <SearchType
- values={['techdocs', 'software-catalog']}
- name="type"
- defaultValue="software-catalog"
- />
<SearchFilter.Select
className={classes.filter}
name="kind"
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-techdocs-backend': patch
---
Add support for API auth in DefaultTechDocsCollator
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Support custom file name for `catalog:write` action
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-kubernetes': patch
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-kubernetes-common': patch
---
implement dashboard link formatter for GKE
-13
View File
@@ -1,13 +0,0 @@
---
'@backstage/integration': minor
---
Create an interface for the GitHub credentials provider in order to support providing implementations.
We have changed the name of the `GithubCredentialsProvider` to `SingleInstanceGithubCredentialsProvider`.
`GithubCredentialsProvider` is now an interface that maybe implemented to provide a custom mechanism to retrieve GitHub credentials.
In a later release we will support configuring URL readers, scaffolder tasks, and processors with customer GitHub credentials providers.
If you want to uptake this release, you will need to replace all references to `GithubCredentialsProvider.create` with `SingleInstanceGithubCredentialsProvider.create`.
-41
View File
@@ -1,41 +0,0 @@
---
'@backstage/create-app': patch
---
Add a `scheduler` to the plugin environment, which can schedule collaborative tasks across backends. To apply the same change in your backend, follow the steps below.
First install the package:
```shell
# From the Backstage repository root
cd packages/backend
yarn add @backstage/backend-tasks
```
Add the scheduler to your plugin environment type:
```diff
// In packages/backend/src/types.ts
+import { PluginTaskScheduler } from '@backstage/backend-tasks';
export type PluginEnvironment = {
+ scheduler: PluginTaskScheduler;
```
And finally make sure to add such an instance to each plugin's environment:
```diff
// In packages/backend/src/index.ts
+import { TaskScheduler } from '@backstage/backend-tasks';
function makeCreateEnv(config: Config) {
// ...
+ const taskScheduler = TaskScheduler.fromConfig(config);
return (plugin: string): PluginEnvironment => {
// ...
+ const scheduler = taskScheduler.forPlugin(plugin);
return {
+ scheduler,
// ...
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-tech-insights': patch
---
Export `techInsightsApiRef` and associated types.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-insights': patch
---
remove unnecessary http request when running all checks
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/config-loader': patch
---
Bump `typescript-json-schema` from `^0.51.0` to `^0.52.0`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-tech-insights-backend-module-jsonfc': patch
---
ability to add custom operators
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
Add option to build command for minifying the generated code
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-api-docs': patch
'@backstage/plugin-catalog': patch
---
Support customizing index page layouts via outlets
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-auth-backend': patch
---
Enforce cookie SSL protection when in production for auth-backend sessions
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-api-docs': patch
---
Display entity title on `ApiDefinitionCard` if defined
+3
View File
@@ -124,6 +124,9 @@ jobs:
- name: check api reports and generate API reference
run: yarn build:api-reports:only --ci --docs
- name: verify changesets
run: node scripts/verify-changesets.js
- name: verify doc links
run: node scripts/verify-links.js
+59 -2
View File
@@ -39,6 +39,7 @@ kubernetes:
region: 'europe-west1'
skipTLSVerify: true
skipMetricsLookup: true
exposeDashboard: true
```
### `serviceLocatorMethod`
@@ -113,9 +114,13 @@ kubectl -n <NAMESPACE> get secret $(kubectl -n <NAMESPACE> get sa <SERVICE_ACCOU
Specifies the link to the Kubernetes dashboard managing this cluster.
Note that you should specify the app used for the dashboard using the
**dashboardApp property**, in order to properly format links to kubernetes
`dashboardApp` property, in order to properly format links to kubernetes
resources, otherwise it will assume that you're running the standard one.
Note also that this attribute is optional for some kinds of dashboards, such as
GKE, which requires additional parameters specified in the `dashboardParameters`
option.
##### `clusters.\*.dashboardApp` (optional)
Specifies the app that provides the Kubernetes dashboard.
@@ -124,11 +129,14 @@ This will be used for formatting links to kubernetes objects inside the
dashboard.
The supported dashboards are: `standard`, `rancher`, `openshift`, `gke`, `aks`,
`eks` However, not all of them are implemented yet, so please contribute!
`eks`. However, not all of them are implemented yet, so please contribute!
Note that it will default to the regular dashboard provided by the Kubernetes
project (`standard`), that can run in any Kubernetes cluster.
Note that for the `gke` app, you must provide additional information in the
`dashboardParameters` option.
Note that you can add your own formatter by registering it to the
`clusterLinksFormatters` dictionary, in the app project.
@@ -143,6 +151,43 @@ See also
https://github.com/backstage/backstage/tree/master/plugins/kubernetes/src/utils/clusterLinks/formatters
for real examples.
##### `clusters.\*.dashboardParameters` (optional)
Specifies additional information for the selected `dashboardApp` formatter.
Note that, even though `dashboardParameters` is optional, it might be mandatory
for some dashboards, such as GKE.
###### required parameters for GKE
| Name | Description |
| ----------- | ------------------------------------------------------------------------ |
| projectId | the ID of the GCP project containing your Kubernetes clusters |
| region | the region of GCP containing your Kubernetes clusters |
| clusterName | the name of your kubernetes cluster, within your `projectId` GCP project |
Note that the GKE cluster locator can automatically provide the values for the
`dashboardApp` and `dashboardParameters` options if you set the
`exposeDashboard` property to `true`.
Example:
```yaml
kubernetes:
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- type: 'config'
clusters:
- url: http://127.0.0.1:9999
name: my-cluster
dashboardApp: gke
dashboardParameters:
projectId: my-project
region: us-east1
clusterName: my-cluster
```
##### `clusters.\*.caData` (optional)
PEM-encoded certificate authority certificates.
@@ -184,6 +229,10 @@ For example:
Will configure the Kubernetes plugin to connect to all GKE clusters in the
project `gke-clusters` in the region `europe-west1`.
Note that the GKE cluster locator can automatically provide the values for the
`dashboardApp` and `dashboardParameters` options if you enable the
`exposeDashboard` option.
##### `projectId`
The Google Cloud project to look for Kubernetes clusters in.
@@ -203,6 +252,14 @@ presented by the API server. Defaults to `false`.
This determines whether the Kubernetes client looks up resource metrics
CPU/Memory for pods returned by the API server. Defaults to `false`.
##### `exposeDashboard`
This determines wether the `dashboardApp` and `dashboardParameters` should be
automatically configured in order to expose the GKE dashboard from the
Kubernetes plugin.
Defaults to `false`.
### `customResources` (optional)
Configures which [custom resources][3] to look for when returning an entity's
@@ -10,8 +10,7 @@ and find catalog entities. This is already set up by default by
`@backstage/create-app`.
If you want to change the default index page - such as to add a custom filter to
the catalog - you can replace the routing in `App.tsx` to point to your own
`CatalogIndexPage`.
the catalog - you can create your own `CatalogIndexPage`.
> Note: The catalog index page is designed to have a minimal code footprint to
> support easy customization, but creating a copy does introduce a possibility
@@ -21,12 +20,11 @@ the catalog - you can replace the routing in `App.tsx` to point to your own
For example, suppose that I want to allow filtering by a custom annotation added
to entities, `company.com/security-tier`. To start, I'll copy the code for the
default catalog page and create a component in a
[new plugin](../../plugins/create-a-plugin.md):
default catalog page and create a component.
```tsx
// imports, etc omitted for brevity. for full source see:
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx
export const CustomCatalogPage = ({
columns,
actions,
@@ -167,21 +165,7 @@ export const CustomCatalogPage = ({
};
```
This page itself can be exported as a routable extension in the plugin:
```ts
export const CustomCatalogIndexPage = myPlugin.provide(
createRoutableExtension({
name: 'CustomCatalogIndexPage',
component: () =>
import('./components/CustomCatalogPage').then(m => m.CustomCatalogPage),
mountPoint: catalogRouteRef,
}),
);
```
Finally, we can replace the catalog route in the Backstage application with our
new `CustomCatalogIndexPage`.
Finally, we can apply our new `CustomCatalogPage`.
```diff
# packages/app/src/App.tsx
@@ -189,7 +173,9 @@ const routes = (
<FlatRoutes>
<Navigate key="/" to="catalog" />
- <Route path="/catalog" element={<CatalogIndexPage />} />
+ <Route path="/catalog" element={<CustomCatalogIndexPage />} />
+ <Route path="/catalog" element={<CatalogIndexPage />}>
+ <CustomCatalogPage />
+ </Route>
```
The same method can be used to customize the _default_ filters with a different
+61 -42
View File
@@ -53,8 +53,10 @@ To add a custom theme to your Backstage app, you pass it as configuration to
For example, adding the theme that we created in the previous section can be
done like this:
```ts
```tsx
import { createApp } from '@backstage/app-defaults';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
const app = createApp({
apis: ...,
@@ -63,7 +65,11 @@ const app = createApp({
id: 'my-theme',
title: 'My Custom Theme',
variant: 'light',
theme: myTheme,
Provider: ({ children }) => (
<ThemeProvider theme={myTheme}>
<CssBaseline>{children}</CssBaseline>
</ThemeProvider>
),
}]
})
```
@@ -76,60 +82,67 @@ want to use the default themes, they are exported as `lightTheme` and
## Example of a custom theme
```ts
const themeOptions = createThemeOptions({
import {
createTheme,
genPageTheme,
lightTheme,
shapes,
} from '@backstage/theme';
const myTheme = createTheme({
palette: {
...lightTheme.palette,
primary: {
main: '#123456',
main: '#343b58',
},
secondary: {
main: '#123456',
main: '#565a6e',
},
error: {
main: '#123456',
main: '#8c4351',
},
warning: {
main: '#123456',
main: '#8f5e15',
},
info: {
main: '#123456',
main: '#34548a',
},
success: {
main: '#123456',
main: '#485e30',
},
background: {
default: '#123456',
paper: '#123456',
default: '#d5d6db',
paper: '#d5d6db',
},
banner: {
info: '#123456',
error: '#123456',
text: '#123456',
link: '#123456',
info: '#34548a',
error: '#8c4351',
text: '#343b58',
link: '#565a6e',
},
errorBackground: '#123456',
warningBackground: '#123456',
infoBackground: '#123456',
errorBackground: '#8c4351',
warningBackground: '#8f5e15',
infoBackground: '#343b58',
navigation: {
background: '#123456',
indicator: '#123456',
color: '#123456',
selectedColor: '#123456',
background: '#343b58',
indicator: '#8f5e15',
color: '#d5d6db',
selectedColor: '#ffffff',
},
},
defaultPageTheme: 'home',
fontFamily: 'Comic Sans',
fontFamily: 'Comic Sans MS',
/* below drives the header colors */
pageTheme: {
home: genPageTheme(['#123456', '#123456'], shapes.wave),
documentation: genPageTheme(['#123456', '#123456'], shapes.wave2),
tool: genPageTheme(['#123456', '#123456'], shapes.round),
service: genPageTheme(['#123456', '#123456'], shapes.wave),
website: genPageTheme(['#123456', '#123456'], shapes.wave),
library: genPageTheme(['#123456', '#123456'], shapes.wave),
other: genPageTheme(['#123456', '#123456'], shapes.wave),
app: genPageTheme(['#123456', '#123456'], shapes.wave),
apis: genPageTheme(['#123456', '#123456'], shapes.wave),
home: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
documentation: genPageTheme(['#8c4351', '#343b58'], shapes.wave2),
tool: genPageTheme(['#8c4351', '#343b58'], shapes.round),
service: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
website: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
library: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
other: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
app: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
apis: genPageTheme(['#8c4351', '#343b58'], shapes.wave),
},
});
```
@@ -162,7 +175,7 @@ wouldn't be enough to alter the `box-shadow` property or to add css rules that
aren't already defined like a margin. For these cases you should also create an
override.
```ts
```tsx
import { createApp } from '@backstage/core-app-api';
import { BackstageTheme, lightTheme } from '@backstage/theme';
/**
@@ -187,6 +200,16 @@ export const createCustomThemeOverrides = (
};
};
const customTheme: BackstageTheme = {
...lightTheme,
overrides: {
// These are the overrides that Backstage applies to `material-ui` components
...lightTheme.overrides,
// These are your custom overrides, either to `material-ui` or Backstage components.
...createCustomThemeOverrides(lightTheme),
},
};
const app = createApp({
apis: ...,
plugins: ...,
@@ -194,15 +217,11 @@ const app = createApp({
id: 'my-theme',
title: 'My Custom Theme',
variant: 'light',
theme: {
...lightTheme,
overrides: {
// These are the overrides that Backstage applies to `material-ui` components
...lightTheme.overrides,
// These are your custom overrides, either to `material-ui` or Backstage components.
...createCustomThemeOverrides(lightTheme),
},
},
Provider: ({ children }) => (
<ThemeProvider theme={customTheme}>
<CssBaseline>{children}</CssBaseline>
</ThemeProvider>
),
}]
});
```
+12
View File
@@ -1,5 +1,17 @@
# @backstage/backend-common
## 0.10.1
### Patch Changes
- 94cdf5d1bd: In-memory cache clients instantiated from the same cache manager now share the same memory space.
- 916b2f1f3e: Use the default CSP policy provided by `helmet` directly rather than a copy.
- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface.
- 995e4c7d9d: Added support for non-"amazonaws.com" hosts (for example when testing with LocalStack) in AwsS3UrlReader.
- Updated dependencies
- @backstage/integration@0.7.0
- @backstage/config-loader@0.9.1
## 0.10.0
### Minor Changes
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.10.0",
"version": "0.10.1",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -31,9 +31,9 @@
"dependencies": {
"@backstage/cli-common": "^0.1.6",
"@backstage/config": "^0.1.11",
"@backstage/config-loader": "^0.9.0",
"@backstage/config-loader": "^0.9.1",
"@backstage/errors": "^0.1.5",
"@backstage/integration": "^0.6.10",
"@backstage/integration": "^0.7.0",
"@backstage/types": "^0.1.1",
"@google-cloud/storage": "^5.8.0",
"@lerna/project": "^4.0.0",
@@ -81,8 +81,8 @@
}
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/test-utils": "^0.2.0",
"@backstage/cli": "^0.10.4",
"@backstage/test-utils": "^0.2.1",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
"@types/concat-stream": "^1.6.0",
@@ -178,7 +178,7 @@ describe('AwsS3UrlReader', () => {
),
).rejects.toThrow(
Error(
`Could not retrieve file from S3; caused by Error: not a valid AWS S3 URL: https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`,
`Could not retrieve file from S3; caused by Error: invalid AWS S3 URL, cannot parse region from host in https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`,
),
);
});
@@ -234,7 +234,7 @@ describe('AwsS3UrlReader', () => {
),
).rejects.toThrow(
Error(
`Could not retrieve file from S3; caused by Error: not a valid AWS S3 URL: https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`,
`Could not retrieve file from S3; caused by Error: invalid AWS S3 URL, cannot parse region from host in https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`,
),
);
});
@@ -332,4 +332,47 @@ describe('AwsS3UrlReader', () => {
expect(body.toString().trim()).toBe('site_name: Test');
});
});
describe('readNonAwsHost', () => {
let awsS3UrlReader: AwsS3UrlReader;
beforeAll(() => {
AWSMock.setSDKInstance(aws);
AWSMock.mock(
'S3',
'getObject',
Buffer.from(
require('fs').readFileSync(
path.resolve(
__dirname,
'__fixtures__/awsS3/awsS3-mock-object.yaml',
),
),
),
);
const s3 = new aws.S3();
awsS3UrlReader = new AwsS3UrlReader(
new AwsS3Integration(
readAwsS3IntegrationConfig(
new ConfigReader({
host: 'localhost:4566',
accessKeyId: 'fake-access-key',
secretAccessKey: 'fake-secret-key',
endpoint: 'http://localhost:4566',
s3ForcePathStyle: true,
}),
),
),
{ s3, treeResponseFactory },
);
});
it('returns contents of an object in a bucket', async () => {
const response = await awsS3UrlReader.read(
'http://localhost:4566/test-bucket/awsS3-mock-object.yaml',
);
expect(response.toString().trim()).toBe('site_name: Test');
});
});
});
@@ -27,12 +27,17 @@ import {
UrlReader,
} from './types';
import getRawBody from 'raw-body';
import { AwsS3Integration, ScmIntegrations } from '@backstage/integration';
import {
AwsS3Integration,
ScmIntegrations,
AwsS3IntegrationConfig,
} from '@backstage/integration';
import { ForwardedError, NotModifiedError } from '@backstage/errors';
import { ListObjectsV2Output, ObjectList } from 'aws-sdk/clients/s3';
const parseURL = (
url: string,
config: AwsS3IntegrationConfig,
): { path: string; bucket: string; region: string } => {
let { host, pathname } = new URL(url);
@@ -42,20 +47,45 @@ const parseURL = (
*/
pathname = pathname.substr(1);
let bucket;
let region;
/**
* Checks that the given URL is a valid S3 object url.
* Format of a Valid S3 URL: https://bucket-name.s3.Region.amazonaws.com/keyname
* Path style URLs: https://s3.Region.amazonaws.com/bucket-name/key-name
* Virtual hosted style URLs: https://bucket-name.s3.Region.amazonaws.com/key-name
* See https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access
*/
const validHost = new RegExp(
/^[a-z\d][a-z\d\.-]{1,61}[a-z\d]\.s3\.[a-z\d-]+\.amazonaws.com$/,
);
if (!validHost.test(host)) {
throw new Error(`not a valid AWS S3 URL: ${url}`);
if (config.s3ForcePathStyle) {
if (pathname.indexOf('/') < 0) {
throw new Error(
`invalid path-style AWS S3 URL, ${url} does not contain bucket in the path`,
);
}
[bucket] = pathname.split('/');
pathname = pathname.substr(bucket.length + 1);
} else {
if (host.indexOf('.') < 0) {
throw new Error(
`invalid virtual hosted-style AWS S3 URL, ${url} does not contain bucket prefix in the host`,
);
}
[bucket] = host.split('.');
host = host.substr(bucket.length + 1);
}
const [bucket] = host.split(/\.s3\.[a-z\d-]+\.amazonaws.com/);
host = host.substring(bucket.length);
const [, , region, ,] = host.split('.');
// Only extract region from *.amazonaws.com hosts
if (config.host === 'amazonaws.com') {
// At this point bucket prefix is removed from host for virtual hosted URLs
const match = host.match(/^s3\.([a-z\d-]+)\.amazonaws\.com$/);
if (!match) {
throw new Error(
`invalid AWS S3 URL, cannot parse region from host in ${url}`,
);
}
region = match[1];
} else {
region = '';
}
return {
path: pathname,
@@ -70,9 +100,12 @@ export class AwsS3UrlReader implements UrlReader {
return integrations.awsS3.list().map(integration => {
const creds = AwsS3UrlReader.buildCredentials(integration);
const s3 = new S3({
apiVersion: '2006-03-01',
credentials: creds,
endpoint: integration.config.endpoint,
s3ForcePathStyle: integration.config.s3ForcePathStyle,
});
const reader = new AwsS3UrlReader(integration, {
s3,
@@ -138,7 +171,7 @@ export class AwsS3UrlReader implements UrlReader {
options?: ReadUrlOptions,
): Promise<ReadUrlResponse> {
try {
const { path, bucket, region } = parseURL(url);
const { path, bucket, region } = parseURL(url, this.integration.config);
aws.config.update({ region: region });
let params;
@@ -178,7 +211,7 @@ export class AwsS3UrlReader implements UrlReader {
options?: ReadTreeOptions,
): Promise<ReadTreeResponse> {
try {
const { path, bucket, region } = parseURL(url);
const { path, bucket, region } = parseURL(url, this.integration.config);
const allObjects: ObjectList = [];
const responses = [];
let continuationToken: string | undefined;
+9
View File
@@ -1,5 +1,14 @@
# @backstage/backend-test-utils
## 0.1.12
### Patch Changes
- 130b7aadf2: Lazy-load `testcontainers` module in order to avoid side-effects.
- Updated dependencies
- @backstage/backend-common@0.10.1
- @backstage/cli@0.10.4
## 0.1.11
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-test-utils",
"description": "Test helpers library for Backstage backends",
"version": "0.1.11",
"version": "0.1.12",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -30,8 +30,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.10.0",
"@backstage/cli": "^0.10.3",
"@backstage/backend-common": "^0.10.1",
"@backstage/cli": "^0.10.4",
"@backstage/config": "^0.1.9",
"knex": "^0.95.1",
"mysql2": "^2.2.5",
@@ -41,7 +41,7 @@
"uuid": "^8.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"jest": "^26.0.1"
},
"files": [
+20
View File
@@ -1,5 +1,25 @@
# example-backend
## 0.2.59
### Patch Changes
- Updated dependencies
- @backstage/plugin-rollbar-backend@0.1.18
- @backstage/plugin-auth-backend@0.6.0
- @backstage/backend-common@0.10.1
- @backstage/plugin-app-backend@0.3.21
- @backstage/plugin-catalog-backend@0.19.4
- @backstage/plugin-scaffolder-backend@0.15.19
- @backstage/integration@0.7.0
- @backstage/plugin-techdocs-backend@0.12.2
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.4
- @backstage/plugin-permission-backend@0.2.3
- @backstage/plugin-permission-node@0.2.3
- @backstage/plugin-code-coverage-backend@0.1.18
- @backstage/plugin-scaffolder-backend-module-rails@0.2.2
- @backstage/plugin-todo-backend@0.1.17
## 0.2.58
### Patch Changes
+16 -16
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend",
"version": "0.2.58",
"version": "0.2.59",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -24,38 +24,38 @@
"migrate:create": "knex migrate:make -x ts"
},
"dependencies": {
"@backstage/backend-common": "^0.10.0",
"@backstage/backend-common": "^0.10.1",
"@backstage/backend-tasks": "^0.1.0",
"@backstage/catalog-client": "^0.5.3",
"@backstage/catalog-model": "^0.9.8",
"@backstage/config": "^0.1.10",
"@backstage/integration": "^0.6.10",
"@backstage/plugin-app-backend": "^0.3.20",
"@backstage/plugin-auth-backend": "^0.5.2",
"@backstage/integration": "^0.7.0",
"@backstage/plugin-app-backend": "^0.3.21",
"@backstage/plugin-auth-backend": "^0.6.0",
"@backstage/plugin-azure-devops-backend": "^0.2.6",
"@backstage/plugin-badges-backend": "^0.1.14",
"@backstage/plugin-catalog-backend": "^0.19.3",
"@backstage/plugin-code-coverage-backend": "^0.1.17",
"@backstage/plugin-catalog-backend": "^0.19.4",
"@backstage/plugin-code-coverage-backend": "^0.1.18",
"@backstage/plugin-graphql-backend": "^0.1.10",
"@backstage/plugin-jenkins-backend": "^0.1.10",
"@backstage/plugin-kubernetes-backend": "^0.4.1",
"@backstage/plugin-kafka-backend": "^0.2.13",
"@backstage/plugin-permission-backend": "^0.2.2",
"@backstage/plugin-permission-backend": "^0.2.3",
"@backstage/plugin-permission-common": "^0.3.0",
"@backstage/plugin-permission-node": "^0.2.2",
"@backstage/plugin-permission-node": "^0.2.3",
"@backstage/plugin-proxy-backend": "^0.2.15",
"@backstage/plugin-rollbar-backend": "^0.1.17",
"@backstage/plugin-scaffolder-backend": "^0.15.18",
"@backstage/plugin-scaffolder-backend-module-rails": "^0.2.1",
"@backstage/plugin-rollbar-backend": "^0.1.18",
"@backstage/plugin-scaffolder-backend": "^0.15.19",
"@backstage/plugin-scaffolder-backend-module-rails": "^0.2.2",
"@backstage/plugin-search-backend": "^0.3.0",
"@backstage/plugin-search-backend-node": "^0.4.2",
"@backstage/plugin-search-backend-module-elasticsearch": "^0.0.7",
"@backstage/plugin-search-backend-module-pg": "^0.2.3",
"@backstage/plugin-techdocs-backend": "^0.12.1",
"@backstage/plugin-techdocs-backend": "^0.12.2",
"@backstage/plugin-tech-insights-backend": "^0.1.4",
"@backstage/plugin-tech-insights-node": "^0.1.2",
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.3",
"@backstage/plugin-todo-backend": "^0.1.16",
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.4",
"@backstage/plugin-todo-backend": "^0.1.17",
"@gitbeaker/node": "^34.6.0",
"@octokit/rest": "^18.5.3",
"azure-devops-node-api": "^11.0.1",
@@ -72,7 +72,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@types/dockerode": "^3.3.0",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5"
+11
View File
@@ -1,5 +1,16 @@
# @backstage/cli
## 0.10.4
### Patch Changes
- 1d26017090: Fix issue with plugin:serve for Plugins not using Lerna monorepo.
- 9c3aaf3512: Bump `@typescript-eslint/eslint-plugin` to `4.33.0`
- 808828e4fa: remove inline CSS from serve_index.html
- 6e4080d31b: Add option to build command for minifying the generated code
- Updated dependencies
- @backstage/config-loader@0.9.1
## 0.10.3
### Patch Changes
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/cli",
"description": "CLI for developing Backstage plugins and apps",
"version": "0.10.3",
"version": "0.10.4",
"private": false,
"publishConfig": {
"access": "public"
@@ -30,7 +30,7 @@
"dependencies": {
"@backstage/cli-common": "^0.1.6",
"@backstage/config": "^0.1.11",
"@backstage/config-loader": "^0.9.0",
"@backstage/config-loader": "^0.9.1",
"@backstage/errors": "^0.1.5",
"@backstage/types": "^0.1.1",
"@hot-loader/react-dom": "^16.13.0",
@@ -51,7 +51,7 @@
"@svgr/rollup": "5.5.x",
"@svgr/webpack": "5.5.x",
"@types/webpack-env": "^1.15.2",
"@typescript-eslint/eslint-plugin": "^v4.30.0",
"@typescript-eslint/eslint-plugin": "^v4.33.0",
"@typescript-eslint/parser": "^v4.28.3",
"@yarnpkg/lockfile": "^1.1.0",
"bfj": "^7.0.2",
@@ -114,13 +114,13 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/backend-common": "^0.10.0",
"@backstage/backend-common": "^0.10.1",
"@backstage/config": "^0.1.11",
"@backstage/core-components": "^0.8.2",
"@backstage/core-plugin-api": "^0.4.0",
"@backstage/core-app-api": "^0.3.0",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@backstage/theme": "^0.2.14",
"@types/diff": "^5.0.0",
"@types/express": "^4.17.6",
+6
View File
@@ -1,5 +1,11 @@
# @backstage/config-loader
## 0.9.1
### Patch Changes
- 84663d59a3: Bump `typescript-json-schema` from `^0.51.0` to `^0.52.0`.
## 0.9.0
### Minor Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/config-loader",
"description": "Config loading functionality used by Backstage backend, and CLI",
"version": "0.9.0",
"version": "0.9.1",
"private": false,
"publishConfig": {
"access": "public",
+120
View File
@@ -1,5 +1,125 @@
# @backstage/create-app
## 0.4.10
### Patch Changes
- 79b342bd36: removed inline and internal CSS from index.html
To make this change to an existing app, apply the following changes to the `packages/app/public/index.html` file:
Remove internal style
```diff
- <style>
- #root {
- min-height: 100%;
- }
- </style>
```
Remove inline style from the body tag
```diff
- <body style="margin: 0">
+ <body>
```
- d33b65dc52: Removed unused templating asset.
- 613ad12960: Add a comment to the default backend about the fallback 404 handler.
- 20af5a701f: The `<SearchType />` filter in the composed `SearchPage.tsx` was replaced with the `<SearchType.Accordion />` variant.
This is an entirely optional change; if you wish to display a control surface for search `types` as a single-select accordion (as opposed to the current multi-select of checkboxes), you can make the following (or similar) changes to your search page layout:
```diff
--- a/packages/app/src/components/search/SearchPage.tsx
+++ b/packages/app/src/components/search/SearchPage.tsx
@@ -11,7 +11,7 @@ import {
SearchType,
DefaultResultListItem,
} from '@backstage/plugin-search';
-import { Content, Header, Page } from '@backstage/core-components';
+import { CatalogIcon, Content, DocsIcon, Header, Page } from '@backstage/core-components';
const useStyles = makeStyles((theme: Theme) => ({
bar: {
@@ -19,6 +19,7 @@ const useStyles = makeStyles((theme: Theme) => ({
},
filters: {
padding: theme.spacing(2),
+ marginTop: theme.spacing(2),
},
filter: {
'& + &': {
@@ -41,12 +42,23 @@ const SearchPage = () => {
</Paper>
</Grid>
<Grid item xs={3}>
+ <SearchType.Accordion
+ name="Result Type"
+ defaultValue="software-catalog"
+ types={[
+ {
+ value: 'software-catalog',
+ name: 'Software Catalog',
+ icon: <CatalogIcon />,
+ },
+ {
+ value: 'techdocs',
+ name: 'Documentation',
+ icon: <DocsIcon />,
+ },
+ ]}
+ />
<Paper className={classes.filters}>
- <SearchType
- values={['techdocs', 'software-catalog']}
- name="type"
- defaultValue="software-catalog"
- />
<SearchFilter.Select
className={classes.filter}
name="kind"
```
- 0dcd1dd64f: Add a `scheduler` to the plugin environment, which can schedule collaborative tasks across backends. To apply the same change in your backend, follow the steps below.
First install the package:
```shell
# From the Backstage repository root
cd packages/backend
yarn add @backstage/backend-tasks
```
Add the scheduler to your plugin environment type:
```diff
// In packages/backend/src/types.ts
+import { PluginTaskScheduler } from '@backstage/backend-tasks';
export type PluginEnvironment = {
+ scheduler: PluginTaskScheduler;
```
And finally make sure to add such an instance to each plugin's environment:
```diff
// In packages/backend/src/index.ts
+import { TaskScheduler } from '@backstage/backend-tasks';
function makeCreateEnv(config: Config) {
// ...
+ const taskScheduler = TaskScheduler.fromConfig(config);
return (plugin: string): PluginEnvironment => {
// ...
+ const scheduler = taskScheduler.forPlugin(plugin);
return {
+ scheduler,
// ...
```
## 0.4.9
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/create-app",
"description": "A CLI that helps you create your own Backstage app",
"version": "0.4.9",
"version": "0.4.10",
"private": false,
"publishConfig": {
"access": "public"
+7
View File
@@ -1,5 +1,12 @@
# @backstage/integration-react
## 0.1.17
### Patch Changes
- Updated dependencies
- @backstage/integration@0.7.0
## 0.1.16
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/integration-react",
"description": "Frontend package for managing integrations towards external systems",
"version": "0.1.16",
"version": "0.1.17",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -24,7 +24,7 @@
"@backstage/config": "^0.1.11",
"@backstage/core-components": "^0.8.2",
"@backstage/core-plugin-api": "^0.4.0",
"@backstage/integration": "^0.6.10",
"@backstage/integration": "^0.7.0",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -35,9 +35,9 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+18
View File
@@ -1,5 +1,23 @@
# @backstage/integration
## 0.7.0
### Minor Changes
- 7d4b4e937c: Create an interface for the GitHub credentials provider in order to support providing implementations.
We have changed the name of the `GithubCredentialsProvider` to `SingleInstanceGithubCredentialsProvider`.
`GithubCredentialsProvider` is now an interface that maybe implemented to provide a custom mechanism to retrieve GitHub credentials.
In a later release we will support configuring URL readers, scaffolder tasks, and processors with customer GitHub credentials providers.
If you want to uptake this release, you will need to replace all references to `GithubCredentialsProvider.create` with `SingleInstanceGithubCredentialsProvider.create`.
### Patch Changes
- cf2e20a792: Added `endpoint` and `s3ForcePathStyle` as optional configuration for AWS S3 integrations.
## 0.6.10
### Patch Changes
+2
View File
@@ -30,6 +30,8 @@ export class AwsS3Integration implements ScmIntegration {
// @public
export type AwsS3IntegrationConfig = {
host: string;
endpoint?: string;
s3ForcePathStyle?: boolean;
accessKeyId?: string;
secretAccessKey?: string;
roleArn?: string;
+15 -2
View File
@@ -167,10 +167,23 @@ export interface Config {
/** Integration configuration for AWS S3 Service */
awsS3?: Array<{
/**
* The host of the target that this matches on, e.g. "amazonaws.com".
* AWS Endpoint.
* The endpoint URI to send requests to. The default endpoint is built from the configured region.
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property
*
* Supports non-AWS providers, e.g. for LocalStack, endpoint may look like http://localhost:4566
* @visibility frontend
*/
host: string;
endpoint?: string;
/**
* Whether to use path style URLs when communicating with S3.
* Defaults to false.
* This allows providers like LocalStack, Minio and Wasabi (and possibly others) to be used.
* @visibility frontend
*/
s3ForcePathStyle?: boolean;
/**
* Account access key used to authenticate requests.
* @visibility backend
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/integration",
"description": "Helpers for managing integrations towards external systems",
"version": "0.6.10",
"version": "0.7.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -39,9 +39,9 @@
"lodash": "^4.17.21"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/config-loader": "^0.9.0",
"@backstage/test-utils": "^0.2.0",
"@backstage/cli": "^0.10.4",
"@backstage/config-loader": "^0.9.1",
"@backstage/test-utils": "^0.2.1",
"@types/jest": "^26.0.7",
"@types/luxon": "^2.0.4",
"msw": "^0.35.0"
@@ -24,7 +24,7 @@ describe('AwsS3Integration', () => {
integrations: {
awsS3: [
{
host: 'a.com',
endpoint: 'https://a.com',
accessKeyId: 'access key',
secretAccessKey: 'secret key',
},
+20 -2
View File
@@ -26,16 +26,33 @@ describe('readAwsS3IntegrationConfig', () => {
return new ConfigReader(data);
}
it('reads all values', () => {
it('reads all values (default)', () => {
const output = readAwsS3IntegrationConfig(
buildConfig({
host: 'amazonaws.com',
accessKeyId: 'fake-key',
secretAccessKey: 'fake-secret-key',
}),
);
expect(output).toEqual({
host: 'amazonaws.com',
s3ForcePathStyle: false,
accessKeyId: 'fake-key',
secretAccessKey: 'fake-secret-key',
});
});
it('reads all values (endpoint)', () => {
const output = readAwsS3IntegrationConfig(
buildConfig({
endpoint: 'http://localhost:4566',
s3ForcePathStyle: true,
accessKeyId: 'fake-key',
secretAccessKey: 'fake-secret-key',
}),
);
expect(output).toEqual({
host: 'localhost:4566',
endpoint: 'http://localhost:4566',
s3ForcePathStyle: true,
accessKeyId: 'fake-key',
secretAccessKey: 'fake-secret-key',
});
@@ -59,6 +76,7 @@ describe('readAwsS3IntegrationConfigs', () => {
);
expect(output).toContainEqual({
host: 'amazonaws.com',
s3ForcePathStyle: false,
accessKeyId: 'key',
secretAccessKey: 'secret',
});
+52 -15
View File
@@ -15,7 +15,6 @@
*/
import { Config } from '@backstage/config';
import { isValidHost } from '../helpers';
const AMAZON_AWS_HOST = 'amazonaws.com';
@@ -26,24 +25,38 @@ const AMAZON_AWS_HOST = 'amazonaws.com';
*/
export type AwsS3IntegrationConfig = {
/**
* The host of the target that this matches on, e.g. "amazonaws.com"
*
* Currently only "amazonaws.com" is supported.
* Host, derived from endpoint, and defaults to amazonaws.com
*/
host: string;
/**
* accessKeyId
* (Optional) AWS Endpoint.
* The endpoint URI to send requests to. The default endpoint is built from the configured region.
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property
*
* Supports non-AWS providers, e.g. for LocalStack, endpoint may look like http://localhost:4566
*/
endpoint?: string;
/**
* (Optional) Whether to use path style URLs when communicating with S3.
* Defaults to false.
* This allows providers like LocalStack, Minio and Wasabi (and possibly others) to be used.
*/
s3ForcePathStyle?: boolean;
/**
* (Optional) User access key id
*/
accessKeyId?: string;
/**
* secretAccessKey
* (Optional) User secret access key
*/
secretAccessKey?: string;
/**
* roleArn
* (Optional) ARN of role to be assumed
*/
roleArn?: string;
};
@@ -58,18 +71,42 @@ export type AwsS3IntegrationConfig = {
export function readAwsS3IntegrationConfig(
config: Config,
): AwsS3IntegrationConfig {
const host = config.getOptionalString('host') ?? AMAZON_AWS_HOST;
const endpoint = config.getOptionalString('endpoint');
const s3ForcePathStyle =
config.getOptionalBoolean('s3ForcePathStyle') ?? false;
let host;
let pathname;
if (endpoint) {
try {
const url = new URL(endpoint);
host = url.host;
pathname = url.pathname;
} catch {
throw new Error(
`invalid awsS3 integration config, endpoint '${endpoint}' is not a valid URL`,
);
}
if (pathname !== '/') {
throw new Error(
`invalid awsS3 integration config, endpoints cannot contain path, got '${endpoint}'`,
);
}
} else {
host = AMAZON_AWS_HOST;
}
const accessKeyId = config.getOptionalString('accessKeyId');
const secretAccessKey = config.getOptionalString('secretAccessKey');
const roleArn = config.getOptionalString('roleArn');
if (!isValidHost(host)) {
throw new Error(
`Invalid awsS3 integration config, '${host}' is not a valid host`,
);
}
return { host, accessKeyId, secretAccessKey, roleArn };
return {
host,
endpoint,
s3ForcePathStyle,
accessKeyId,
secretAccessKey,
roleArn,
};
}
/**
+9
View File
@@ -1,5 +1,14 @@
# @techdocs/cli
## 0.8.10
### Patch Changes
- 8fbc988bfc: remove internal and inline CSS from index.html
- Updated dependencies
- @backstage/techdocs-common@0.11.2
- @backstage/backend-common@0.10.1
## 0.8.9
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@techdocs/cli",
"description": "Utility CLI for managing TechDocs sites in Backstage.",
"version": "0.8.9",
"version": "0.8.10",
"private": false,
"publishConfig": {
"access": "public"
@@ -32,7 +32,7 @@
"techdocs-cli": "bin/techdocs-cli"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@types/commander": "^2.12.2",
"@types/fs-extra": "^9.0.6",
"@types/http-proxy": "^1.17.4",
@@ -56,10 +56,10 @@
"ext": "ts"
},
"dependencies": {
"@backstage/backend-common": "^0.10.0",
"@backstage/backend-common": "^0.10.1",
"@backstage/catalog-model": "^0.9.7",
"@backstage/config": "^0.1.10",
"@backstage/techdocs-common": "^0.11.1",
"@backstage/techdocs-common": "^0.11.2",
"@types/dockerode": "^3.3.0",
"commander": "^6.1.0",
"dockerode": "^3.3.1",
+9
View File
@@ -1,5 +1,14 @@
# @backstage/techdocs-common
## 0.11.2
### Patch Changes
- c2c8768771: Bump `@azure/identity` from `^1.5.0` to `^2.0.1`.
- Updated dependencies
- @backstage/backend-common@0.10.1
- @backstage/integration@0.7.0
## 0.11.1
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/techdocs-common",
"description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli",
"version": "0.11.1",
"version": "0.11.2",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -38,12 +38,12 @@
"dependencies": {
"@azure/identity": "^2.0.1",
"@azure/storage-blob": "^12.5.0",
"@backstage/backend-common": "^0.10.0",
"@backstage/backend-common": "^0.10.1",
"@backstage/catalog-model": "^0.9.7",
"@backstage/config": "^0.1.11",
"@backstage/errors": "^0.1.5",
"@backstage/search-common": "^0.2.1",
"@backstage/integration": "^0.6.10",
"@backstage/integration": "^0.7.0",
"@google-cloud/storage": "^5.6.0",
"@trendyol-js/openstack-swift-sdk": "^0.0.5",
"@types/express": "^4.17.6",
@@ -60,7 +60,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@types/fs-extra": "^9.0.5",
"@types/js-yaml": "^4.0.0",
"@types/mime-types": "^2.1.0",
+6
View File
@@ -1,5 +1,11 @@
# @backstage/test-utils
## 0.2.1
### Patch Changes
- c36b7794f7: JSON serialize and freeze values stored by the `MockStorageApi`.
## 0.2.0
### Minor Changes
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/test-utils",
"description": "Utilities to test Backstage plugins and apps.",
"version": "0.2.0",
"version": "0.2.1",
"private": false,
"publishConfig": {
"access": "public",
@@ -47,7 +47,7 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32"
},
+2 -2
View File
@@ -37,10 +37,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/core-app-api": "^0.3.0",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+2 -2
View File
@@ -35,10 +35,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/core-app-api": "^0.3.0",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+2 -2
View File
@@ -33,10 +33,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/core-app-api": "^0.3.0",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+9
View File
@@ -1,5 +1,14 @@
# @backstage/plugin-api-docs
## 0.6.20
### Patch Changes
- de81b7455e: Display entity title on `ApiDefinitionCard` if defined
- Updated dependencies
- @backstage/plugin-catalog@0.7.6
- @backstage/plugin-catalog-react@0.6.9
## 0.6.19
### Patch Changes
+23 -19
View File
@@ -5,7 +5,6 @@
```ts
/// <reference types="react" />
import { Action } from '@material-table/core';
import { ApiEntity } from '@backstage/catalog-model';
import { ApiRef } from '@backstage/core-plugin-api';
import { BackstagePlugin } from '@backstage/core-plugin-api';
@@ -15,6 +14,7 @@ import { ExternalRouteRef } from '@backstage/core-plugin-api';
import { default as React_2 } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
import { TableColumn } from '@backstage/core-components';
import { TableProps } from '@backstage/core-components';
import { UserListFilterKind } from '@backstage/plugin-catalog-react';
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
@@ -53,27 +53,17 @@ const apiDocsPlugin: BackstagePlugin<
export { apiDocsPlugin };
export { apiDocsPlugin as plugin };
// @public
export const ApiExplorerIndexPage: (
props: DefaultApiExplorerPageProps,
) => JSX.Element;
// Warning: (ae-missing-release-tag) "ApiExplorerPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const ApiExplorerPage: ({
initiallySelectedFilter,
columns,
actions,
}: {
initiallySelectedFilter?: UserListFilterKind | undefined;
columns?: TableColumn<CatalogTableRow>[] | undefined;
actions?:
| (
| Action<CatalogTableRow>
| {
action: (rowData: CatalogTableRow) => Action<CatalogTableRow>;
position: string;
}
| ((rowData: CatalogTableRow) => Action<CatalogTableRow>)
)[]
| undefined;
}) => JSX.Element;
export const ApiExplorerPage: (
props: DefaultApiExplorerPageProps,
) => JSX.Element;
// Warning: (ae-missing-release-tag) "ApiTypeTitle" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -110,6 +100,20 @@ export const ConsumedApisCard: ({ variant }: Props_2) => JSX.Element;
// @public (undocumented)
export const ConsumingComponentsCard: ({ variant }: Props_5) => JSX.Element;
// @public
export const DefaultApiExplorerPage: ({
initiallySelectedFilter,
columns,
actions,
}: DefaultApiExplorerPageProps) => JSX.Element;
// @public
export type DefaultApiExplorerPageProps = {
initiallySelectedFilter?: UserListFilterKind;
columns?: TableColumn<CatalogTableRow>[];
actions?: TableProps<CatalogTableRow>['actions'];
};
// Warning: (ae-missing-release-tag) "defaultDefinitionWidgets" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/plugin-api-docs",
"description": "A Backstage plugin that helps represent API entities in the frontend",
"version": "0.6.19",
"version": "0.6.20",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -34,8 +34,8 @@
"@backstage/catalog-model": "^0.9.7",
"@backstage/core-components": "^0.8.2",
"@backstage/core-plugin-api": "^0.4.0",
"@backstage/plugin-catalog": "^0.7.5",
"@backstage/plugin-catalog-react": "^0.6.8",
"@backstage/plugin-catalog": "^0.7.6",
"@backstage/plugin-catalog-react": "^0.6.9",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -54,10 +54,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/core-app-api": "^0.3.0",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,185 +14,31 @@
* limitations under the License.
*/
import { Entity, RELATION_MEMBER_OF } from '@backstage/catalog-model';
import { ConfigReader } from '@backstage/core-app-api';
import { TableColumn, TableProps } from '@backstage/core-components';
import {
ConfigApi,
configApiRef,
storageApiRef,
} from '@backstage/core-plugin-api';
import { CatalogTableRow } from '@backstage/plugin-catalog';
import {
CatalogApi,
catalogApiRef,
DefaultStarredEntitiesApi,
entityRouteRef,
starredEntitiesApiRef,
} from '@backstage/plugin-catalog-react';
import {
MockStorageApi,
TestApiProvider,
wrapInTestApp,
} from '@backstage/test-utils';
import DashboardIcon from '@material-ui/icons/Dashboard';
import { render } from '@testing-library/react';
import React from 'react';
import { apiDocsConfigRef } from '../../config';
import { renderInTestApp } from '@backstage/test-utils';
import { useOutlet } from 'react-router';
import { ApiExplorerPage } from './ApiExplorerPage';
describe('ApiCatalogPage', () => {
const catalogApi: Partial<CatalogApi> = {
getEntities: () =>
Promise.resolve({
items: [
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'API',
metadata: {
name: 'Entity1',
},
spec: { type: 'openapi' },
},
] as Entity[],
}),
getLocationByEntity: () =>
Promise.resolve({ id: 'id', type: 'github', target: 'url' }),
getEntityByName: async entityName => {
return {
apiVersion: 'backstage.io/v1alpha1',
kind: 'User',
metadata: { name: entityName.name },
relations: [
{
type: RELATION_MEMBER_OF,
target: { namespace: 'default', kind: 'Group', name: 'tools' },
},
],
};
},
};
jest.mock('react-router', () => ({
...jest.requireActual('react-router'),
useOutlet: jest.fn().mockReturnValue('Route Children'),
}));
const configApi: ConfigApi = new ConfigReader({
organization: {
name: 'My Company',
},
jest.mock('./DefaultApiExplorerPage', () => ({
DefaultApiExplorerPage: jest.fn().mockReturnValue('DefaultApiExplorerPage'),
}));
describe('ApiExplorerPage', () => {
it('renders provided router element', async () => {
const { getByText } = await renderInTestApp(<ApiExplorerPage />);
expect(getByText('Route Children')).toBeInTheDocument();
});
const apiDocsConfig = {
getApiDefinitionWidget: () => undefined,
};
it('renders DefaultApiExplorerPage home when no router children are provided', async () => {
(useOutlet as jest.Mock).mockReturnValueOnce(null);
const { getByText } = await renderInTestApp(<ApiExplorerPage />);
const storageApi = MockStorageApi.create();
const renderWrapped = (children: React.ReactNode) =>
render(
wrapInTestApp(
<TestApiProvider
apis={[
[catalogApiRef, catalogApi],
[configApiRef, configApi],
[storageApiRef, storageApi],
[
starredEntitiesApiRef,
new DefaultStarredEntitiesApi({ storageApi }),
],
[apiDocsConfigRef, apiDocsConfig],
]}
>
{children}
</TestApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name': entityRouteRef,
},
},
),
);
// this test right now causes some red lines in the log output when running tests
// related to some theme issues in mui-table
// https://github.com/mbrn/material-table/issues/1293
it('should render', async () => {
const { findByText } = renderWrapped(<ApiExplorerPage />);
expect(await findByText(/My Company API Explorer/)).toBeInTheDocument();
});
it('should render the default column of the grid', async () => {
const { getAllByRole } = renderWrapped(<ApiExplorerPage />);
const columnHeader = getAllByRole('button').filter(
c => c.tagName === 'SPAN',
);
const columnHeaderLabels = columnHeader.map(c => c.textContent);
expect(columnHeaderLabels).toEqual([
'Name',
'System',
'Owner',
'Type',
'Lifecycle',
'Description',
'Tags',
'Actions',
]);
});
it('should render the custom column passed as prop', async () => {
const columns: TableColumn<CatalogTableRow>[] = [
{ title: 'Foo', field: 'entity.foo' },
{ title: 'Bar', field: 'entity.bar' },
{ title: 'Baz', field: 'entity.spec.lifecycle' },
];
const { getAllByRole } = renderWrapped(
<ApiExplorerPage columns={columns} />,
);
const columnHeader = getAllByRole('button').filter(
c => c.tagName === 'SPAN',
);
const columnHeaderLabels = columnHeader.map(c => c.textContent);
expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']);
});
it('should render the default actions of an item in the grid', async () => {
const { findByTitle, findByText } = await renderWrapped(
<ApiExplorerPage />,
);
expect(await findByText(/All \(1\)/)).toBeInTheDocument();
expect(await findByTitle(/View/)).toBeInTheDocument();
expect(await findByTitle(/View/)).toBeInTheDocument();
expect(await findByTitle(/Edit/)).toBeInTheDocument();
expect(await findByTitle(/Add to favorites/)).toBeInTheDocument();
});
it('should render the custom actions of an item passed as prop', async () => {
const actions: TableProps<CatalogTableRow>['actions'] = [
() => {
return {
icon: () => <DashboardIcon fontSize="small" />,
tooltip: 'Foo Action',
disabled: false,
onClick: () => jest.fn(),
};
},
() => {
return {
icon: () => <DashboardIcon fontSize="small" />,
tooltip: 'Bar Action',
disabled: true,
onClick: () => jest.fn(),
};
},
];
const { findByTitle, findByText } = await renderWrapped(
<ApiExplorerPage actions={actions} />,
);
expect(await findByText(/All \(1\)/)).toBeInTheDocument();
expect(await findByTitle(/Foo Action/)).toBeInTheDocument();
expect(await findByTitle(/Bar Action/)).toBeInTheDocument();
expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled();
expect(getByText('DefaultApiExplorerPage')).toBeInTheDocument();
});
});
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,97 +14,19 @@
* limitations under the License.
*/
import {
Content,
ContentHeader,
CreateButton,
PageWithHeader,
SupportButton,
TableColumn,
TableProps,
} from '@backstage/core-components';
import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';
import {
CatalogTable,
CatalogTableRow,
FilteredEntityLayout,
EntityListContainer,
FilterContainer,
} from '@backstage/plugin-catalog';
import {
EntityKindPicker,
EntityLifecyclePicker,
EntityListProvider,
EntityOwnerPicker,
EntityTagPicker,
EntityTypePicker,
UserListFilterKind,
UserListPicker,
} from '@backstage/plugin-catalog-react';
import React from 'react';
import { createComponentRouteRef } from '../../routes';
import { useOutlet } from 'react-router';
import {
DefaultApiExplorerPage,
DefaultApiExplorerPageProps,
} from './DefaultApiExplorerPage';
const defaultColumns: TableColumn<CatalogTableRow>[] = [
CatalogTable.columns.createNameColumn({ defaultKind: 'API' }),
CatalogTable.columns.createSystemColumn(),
CatalogTable.columns.createOwnerColumn(),
CatalogTable.columns.createSpecTypeColumn(),
CatalogTable.columns.createSpecLifecycleColumn(),
CatalogTable.columns.createMetadataDescriptionColumn(),
CatalogTable.columns.createTagsColumn(),
];
/**
* ApiExplorerPage
* @public
*/
export const ApiExplorerPage = (props: DefaultApiExplorerPageProps) => {
const outlet = useOutlet();
type ApiExplorerPageProps = {
initiallySelectedFilter?: UserListFilterKind;
columns?: TableColumn<CatalogTableRow>[];
actions?: TableProps<CatalogTableRow>['actions'];
};
export const ApiExplorerPage = ({
initiallySelectedFilter = 'all',
columns,
actions,
}: ApiExplorerPageProps) => {
const configApi = useApi(configApiRef);
const generatedSubtitle = `${
configApi.getOptionalString('organization.name') ?? 'Backstage'
} API Explorer`;
const createComponentLink = useRouteRef(createComponentRouteRef);
return (
<PageWithHeader
themeId="apis"
title="APIs"
subtitle={generatedSubtitle}
pageTitleOverride="APIs"
>
<Content>
<ContentHeader title="">
<CreateButton
title="Register Existing API"
to={createComponentLink?.()}
/>
<SupportButton>All your APIs</SupportButton>
</ContentHeader>
<EntityListProvider>
<FilteredEntityLayout>
<FilterContainer>
<EntityKindPicker initialFilter="api" hidden />
<EntityTypePicker />
<UserListPicker initialFilter={initiallySelectedFilter} />
<EntityOwnerPicker />
<EntityLifecyclePicker />
<EntityTagPicker />
</FilterContainer>
<EntityListContainer>
<CatalogTable
columns={columns || defaultColumns}
actions={actions}
/>
</EntityListContainer>
</FilteredEntityLayout>
</EntityListProvider>
</Content>
</PageWithHeader>
);
return outlet || <DefaultApiExplorerPage {...props} />;
};
@@ -0,0 +1,198 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Entity, RELATION_MEMBER_OF } from '@backstage/catalog-model';
import { ConfigReader } from '@backstage/core-app-api';
import { TableColumn, TableProps } from '@backstage/core-components';
import {
ConfigApi,
configApiRef,
storageApiRef,
} from '@backstage/core-plugin-api';
import { CatalogTableRow } from '@backstage/plugin-catalog';
import {
CatalogApi,
catalogApiRef,
DefaultStarredEntitiesApi,
entityRouteRef,
starredEntitiesApiRef,
} from '@backstage/plugin-catalog-react';
import {
MockStorageApi,
TestApiProvider,
wrapInTestApp,
} from '@backstage/test-utils';
import DashboardIcon from '@material-ui/icons/Dashboard';
import { render } from '@testing-library/react';
import React from 'react';
import { apiDocsConfigRef } from '../../config';
import { DefaultApiExplorerPage } from './DefaultApiExplorerPage';
describe('DefaultApiExplorerPage', () => {
const catalogApi: Partial<CatalogApi> = {
getEntities: () =>
Promise.resolve({
items: [
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'API',
metadata: {
name: 'Entity1',
},
spec: { type: 'openapi' },
},
] as Entity[],
}),
getLocationByEntity: () =>
Promise.resolve({ id: 'id', type: 'github', target: 'url' }),
getEntityByName: async entityName => {
return {
apiVersion: 'backstage.io/v1alpha1',
kind: 'User',
metadata: { name: entityName.name },
relations: [
{
type: RELATION_MEMBER_OF,
target: { namespace: 'default', kind: 'Group', name: 'tools' },
},
],
};
},
};
const configApi: ConfigApi = new ConfigReader({
organization: {
name: 'My Company',
},
});
const apiDocsConfig = {
getApiDefinitionWidget: () => undefined,
};
const storageApi = MockStorageApi.create();
const renderWrapped = (children: React.ReactNode) =>
render(
wrapInTestApp(
<TestApiProvider
apis={[
[catalogApiRef, catalogApi],
[configApiRef, configApi],
[storageApiRef, storageApi],
[
starredEntitiesApiRef,
new DefaultStarredEntitiesApi({ storageApi }),
],
[apiDocsConfigRef, apiDocsConfig],
]}
>
{children}
</TestApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name': entityRouteRef,
},
},
),
);
// this test right now causes some red lines in the log output when running tests
// related to some theme issues in mui-table
// https://github.com/mbrn/material-table/issues/1293
it('should render', async () => {
const { findByText } = renderWrapped(<DefaultApiExplorerPage />);
expect(await findByText(/My Company API Explorer/)).toBeInTheDocument();
});
it('should render the default column of the grid', async () => {
const { getAllByRole } = renderWrapped(<DefaultApiExplorerPage />);
const columnHeader = getAllByRole('button').filter(
c => c.tagName === 'SPAN',
);
const columnHeaderLabels = columnHeader.map(c => c.textContent);
expect(columnHeaderLabels).toEqual([
'Name',
'System',
'Owner',
'Type',
'Lifecycle',
'Description',
'Tags',
'Actions',
]);
});
it('should render the custom column passed as prop', async () => {
const columns: TableColumn<CatalogTableRow>[] = [
{ title: 'Foo', field: 'entity.foo' },
{ title: 'Bar', field: 'entity.bar' },
{ title: 'Baz', field: 'entity.spec.lifecycle' },
];
const { getAllByRole } = renderWrapped(
<DefaultApiExplorerPage columns={columns} />,
);
const columnHeader = getAllByRole('button').filter(
c => c.tagName === 'SPAN',
);
const columnHeaderLabels = columnHeader.map(c => c.textContent);
expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']);
});
it('should render the default actions of an item in the grid', async () => {
const { findByTitle, findByText } = await renderWrapped(
<DefaultApiExplorerPage />,
);
expect(await findByText(/All \(1\)/)).toBeInTheDocument();
expect(await findByTitle(/View/)).toBeInTheDocument();
expect(await findByTitle(/View/)).toBeInTheDocument();
expect(await findByTitle(/Edit/)).toBeInTheDocument();
expect(await findByTitle(/Add to favorites/)).toBeInTheDocument();
});
it('should render the custom actions of an item passed as prop', async () => {
const actions: TableProps<CatalogTableRow>['actions'] = [
() => {
return {
icon: () => <DashboardIcon fontSize="small" />,
tooltip: 'Foo Action',
disabled: false,
onClick: () => jest.fn(),
};
},
() => {
return {
icon: () => <DashboardIcon fontSize="small" />,
tooltip: 'Bar Action',
disabled: true,
onClick: () => jest.fn(),
};
},
];
const { findByTitle, findByText } = await renderWrapped(
<DefaultApiExplorerPage actions={actions} />,
);
expect(await findByText(/All \(1\)/)).toBeInTheDocument();
expect(await findByTitle(/Foo Action/)).toBeInTheDocument();
expect(await findByTitle(/Bar Action/)).toBeInTheDocument();
expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled();
});
});
@@ -0,0 +1,118 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
Content,
ContentHeader,
CreateButton,
PageWithHeader,
SupportButton,
TableColumn,
TableProps,
} from '@backstage/core-components';
import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';
import {
CatalogTable,
CatalogTableRow,
FilteredEntityLayout,
EntityListContainer,
FilterContainer,
} from '@backstage/plugin-catalog';
import {
EntityKindPicker,
EntityLifecyclePicker,
EntityListProvider,
EntityOwnerPicker,
EntityTagPicker,
EntityTypePicker,
UserListFilterKind,
UserListPicker,
} from '@backstage/plugin-catalog-react';
import React from 'react';
import { createComponentRouteRef } from '../../routes';
const defaultColumns: TableColumn<CatalogTableRow>[] = [
CatalogTable.columns.createNameColumn({ defaultKind: 'API' }),
CatalogTable.columns.createSystemColumn(),
CatalogTable.columns.createOwnerColumn(),
CatalogTable.columns.createSpecTypeColumn(),
CatalogTable.columns.createSpecLifecycleColumn(),
CatalogTable.columns.createMetadataDescriptionColumn(),
CatalogTable.columns.createTagsColumn(),
];
/**
* DefaultApiExplorerPageProps
* @public
*/
export type DefaultApiExplorerPageProps = {
initiallySelectedFilter?: UserListFilterKind;
columns?: TableColumn<CatalogTableRow>[];
actions?: TableProps<CatalogTableRow>['actions'];
};
/**
* DefaultApiExplorerPage
* @public
*/
export const DefaultApiExplorerPage = ({
initiallySelectedFilter = 'all',
columns,
actions,
}: DefaultApiExplorerPageProps) => {
const configApi = useApi(configApiRef);
const generatedSubtitle = `${
configApi.getOptionalString('organization.name') ?? 'Backstage'
} API Explorer`;
const createComponentLink = useRouteRef(createComponentRouteRef);
return (
<PageWithHeader
themeId="apis"
title="APIs"
subtitle={generatedSubtitle}
pageTitleOverride="APIs"
>
<Content>
<ContentHeader title="">
<CreateButton
title="Register Existing API"
to={createComponentLink?.()}
/>
<SupportButton>All your APIs</SupportButton>
</ContentHeader>
<EntityListProvider>
<FilteredEntityLayout>
<FilterContainer>
<EntityKindPicker initialFilter="api" hidden />
<EntityTypePicker />
<UserListPicker initialFilter={initiallySelectedFilter} />
<EntityOwnerPicker />
<EntityLifecyclePicker />
<EntityTagPicker />
</FilterContainer>
<EntityListContainer>
<CatalogTable
columns={columns || defaultColumns}
actions={actions}
/>
</EntityListContainer>
</FilteredEntityLayout>
</EntityListProvider>
</Content>
</PageWithHeader>
);
};
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,4 +14,6 @@
* limitations under the License.
*/
export { ApiExplorerPage } from './ApiExplorerPage';
export { ApiExplorerPage as ApiExplorerIndexPage } from './ApiExplorerPage';
export { DefaultApiExplorerPage } from './DefaultApiExplorerPage';
export type { DefaultApiExplorerPageProps } from './DefaultApiExplorerPage';
+1
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
export * from './ApiExplorerPage';
export * from './ApiDefinitionCard';
export * from './ApisCards';
export * from './AsyncApiDefinitionWidget';
+1 -1
View File
@@ -53,7 +53,7 @@ export const ApiExplorerPage = apiDocsPlugin.provide(
createRoutableExtension({
name: 'ApiExplorerPage',
component: () =>
import('./components/ApiExplorerPage').then(m => m.ApiExplorerPage),
import('./components/ApiExplorerPage').then(m => m.ApiExplorerIndexPage),
mountPoint: rootRoute,
}),
);
+9
View File
@@ -1,5 +1,14 @@
# @backstage/plugin-app-backend
## 0.3.21
### Patch Changes
- 9d9cfc1b8a: Set `X-Frame-Options: deny` rather than the default `sameorigin` for all content served by the `app-backend`.`
- Updated dependencies
- @backstage/backend-common@0.10.1
- @backstage/config-loader@0.9.1
## 0.3.20
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/plugin-app-backend",
"description": "A Backstage backend plugin that serves the Backstage frontend app",
"version": "0.3.20",
"version": "0.3.21",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,8 +30,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.10.0",
"@backstage/config-loader": "^0.9.0",
"@backstage/backend-common": "^0.10.1",
"@backstage/config-loader": "^0.9.1",
"@backstage/config": "^0.1.11",
"@backstage/types": "^0.1.1",
"@types/express": "^4.17.6",
@@ -43,7 +43,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/types": "^0.1.1",
"@types/supertest": "^2.0.8",
"msw": "^0.35.0",
+40
View File
@@ -1,5 +1,45 @@
# @backstage/plugin-auth-backend
## 0.6.0
### Minor Changes
- c88cdacc1a: Avoid ever returning OAuth refresh tokens back to the client, and always exchange refresh tokens for a new one when available for all providers.
This comes with a breaking change to the TypeScript API for custom auth providers. The `refresh` method of `OAuthHandlers` implementation must now return a `{ response, refreshToken }` object rather than a direct response. Existing `refresh` implementations are typically migrated by changing an existing return expression that looks like this:
```ts
return await this.handleResult({
fullProfile,
params,
accessToken,
refreshToken,
});
```
Into the following:
```ts
return {
response: await this.handleResult({
fullProfile,
params,
accessToken,
}),
refreshToken,
};
```
### Patch Changes
- f0f81f6cc7: Replaces the usage of `got` with `node-fetch` in the `getUserPhoto` method of the Microsoft provider
- 2f26120a36: Update `auth0` and `onelogin` providers to allow for `authHandler` and `signIn.resolver` configuration.
- a9abafa9df: Fixed bug on refresh token on Okta provider, now it gets the refresh token and it sends it into providerInfo
- eb48e78886: Enforce cookie SSL protection when in production for auth-backend sessions
- Updated dependencies
- @backstage/test-utils@0.2.1
- @backstage/backend-common@0.10.1
## 0.5.2
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/plugin-auth-backend",
"description": "A Backstage backend plugin that handles authentication",
"version": "0.5.2",
"version": "0.6.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,12 +30,12 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.10.0",
"@backstage/backend-common": "^0.10.1",
"@backstage/catalog-client": "^0.5.3",
"@backstage/catalog-model": "^0.9.8",
"@backstage/config": "^0.1.11",
"@backstage/errors": "^0.1.5",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@google-cloud/firestore": "^4.15.1",
"@types/express": "^4.17.6",
"@types/passport": "^1.0.3",
@@ -72,7 +72,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@types/body-parser": "^1.19.0",
"@types/cookie-parser": "^1.4.2",
"@types/express-session": "^1.17.2",
+2 -2
View File
@@ -46,10 +46,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/core-app-api": "^0.3.0",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+2 -2
View File
@@ -43,10 +43,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/core-app-api": "^0.3.0",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+1 -1
View File
@@ -43,7 +43,7 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/dev-utils": "^0.2.15",
"@testing-library/jest-dom": "^5.10.1",
"cross-fetch": "^3.0.6"
+2 -2
View File
@@ -40,10 +40,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.10.3",
"@backstage/cli": "^0.10.4",
"@backstage/core-app-api": "^0.3.0",
"@backstage/dev-utils": "^0.2.15",
"@backstage/test-utils": "^0.2.0",
"@backstage/test-utils": "^0.2.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+10
View File
@@ -1,5 +1,15 @@
# @backstage/plugin-catalog-backend
## 0.19.4
### Patch Changes
- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface.
- 3a63491c5f: Filter out projects with missing `default_branch` from GitLab Discovery.
- Updated dependencies
- @backstage/backend-common@0.10.1
- @backstage/integration@0.7.0
## 0.19.3
### Patch Changes
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/plugin-catalog-backend",
"description": "The Backstage backend plugin that provides the Backstage catalog",
"version": "0.19.3",
"version": "0.19.4",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,12 +30,12 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.10.0",
"@backstage/backend-common": "^0.10.1",
"@backstage/catalog-client": "^0.5.3",
"@backstage/catalog-model": "^0.9.8",
"@backstage/config": "^0.1.11",
"@backstage/errors": "^0.1.5",
"@backstage/integration": "^0.6.10",
"@backstage/integration": "^0.7.0",
"@backstage/search-common": "^0.2.1",
"@backstage/types": "^0.1.1",
"@octokit/graphql": "^4.5.8",
@@ -62,9 +62,9 @@
"yup": "^0.32.9"
},
"devDependencies": {
"@backstage/backend-test-utils": "^0.1.11",
"@backstage/cli": "^0.10.3",
"@backstage/test-utils": "^0.2.0",
"@backstage/backend-test-utils": "^0.1.12",
"@backstage/cli": "^0.10.4",
"@backstage/test-utils": "^0.2.1",
"@types/core-js": "^2.5.4",
"@types/git-url-parse": "^9.0.0",
"@types/lodash": "^4.14.151",
@@ -184,6 +184,13 @@ describe('GitlabDiscoveryProcessor', () => {
last_activity_at: '2021-08-05T11:03:05.774Z',
web_url: 'https://gitlab.fake/3',
},
{
id: 4,
archived: false,
default_branch: undefined, // MISSING DEFAULT BRANCH
last_activity_at: '2021-08-05T11:03:05.774Z',
web_url: 'https://gitlab.fake/4',
},
],
};
default:
@@ -94,9 +94,16 @@ export class GitLabDiscoveryProcessor implements CatalogProcessor {
};
for await (const project of projects) {
result.scanned++;
if (!project.archived) {
result.matches.push(project);
if (project.archived) {
continue;
}
if (branch === '*' && project.default_branch === undefined) {
continue;
}
result.matches.push(project);
}
for (const project of result.matches) {

Some files were not shown because too many files have changed in this diff Show More