Merge branch 'master' into mobile-sidebar
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/test-utils': patch
|
||||
---
|
||||
|
||||
Add new `MockConfigApi` as a more discoverable and leaner method for mocking configuration.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
'@backstage/cli': minor
|
||||
---
|
||||
|
||||
ESLint upgraded to version 8 and all it's plugins updated to newest version.
|
||||
|
||||
If you use any custom plugins for ESLint please check compatibility.
|
||||
|
||||
```diff
|
||||
- "@typescript-eslint/eslint-plugin": "^v4.33.0",
|
||||
- "@typescript-eslint/parser": "^v4.28.3",
|
||||
+ "@typescript-eslint/eslint-plugin": "^5.9.0",
|
||||
+ "@typescript-eslint/parser": "^5.9.0",
|
||||
- "eslint": "^7.30.0",
|
||||
+ "eslint": "^8.6.0",
|
||||
- "eslint-plugin-import": "^2.20.2",
|
||||
- "eslint-plugin-jest": "^24.1.0",
|
||||
- "eslint-plugin-jsx-a11y": "^6.2.1",
|
||||
+ "eslint-plugin-import": "^2.25.4",
|
||||
+ "eslint-plugin-jest": "^25.3.4",
|
||||
+ "eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
- "eslint-plugin-react": "^7.12.4",
|
||||
- "eslint-plugin-react-hooks": "^4.0.0",
|
||||
+ "eslint-plugin-react": "^7.28.0",
|
||||
+ "eslint-plugin-react-hooks": "^4.3.0",
|
||||
```
|
||||
|
||||
Please consult changelogs from packages if you find any problems.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-graphql': patch
|
||||
---
|
||||
|
||||
Bump graphql versions
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
Fix missing search context issue with `HomePageSearchBar`
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
---
|
||||
|
||||
Add Override Components for Components in @backstage/plugin-catalog-react
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
'@backstage/plugin-pagerduty': patch
|
||||
'@backstage/plugin-splunk-on-call': patch
|
||||
---
|
||||
|
||||
Clean up emptystate.svg image, removing wrong white artifact from the background
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Update `config/eslint.js` to forbid imports of `@material-ui/icons/` as well.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
'@backstage/plugin-kubernetes-common': patch
|
||||
---
|
||||
|
||||
implement dashboard link formatter for GKE
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights': patch
|
||||
---
|
||||
|
||||
remove unnecessary http request when running all checks
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
---
|
||||
|
||||
Bump `testcontainers` dependency to version `8.1.2`
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Support customizing index page layouts via outlets
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-tasks': patch
|
||||
---
|
||||
|
||||
Updated README to clarify the following:
|
||||
|
||||
- Dashes cannot be used in the `id`, changed to an underscore in the example
|
||||
- The `timeout` is required, this was also added to the example
|
||||
- Added a note about tasks not running as expected for local development using persistent database
|
||||
@@ -5,7 +5,7 @@ updates:
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '04:00'
|
||||
open-pull-requests-limit: 5
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- dependencies
|
||||
- package-ecosystem: npm
|
||||
@@ -13,6 +13,6 @@ updates:
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '04:00'
|
||||
open-pull-requests-limit: 2
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- dependencies
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
for your contributions.
|
||||
days-before-issue-stale: 60
|
||||
days-before-issue-close: 7
|
||||
exempt-issue-labels: 'pinned,security,plugin,help wanted,good first issue,rfc'
|
||||
exempt-issue-labels: 'pinned,security,plugin,help wanted,good first issue,rfc,will-fix'
|
||||
stale-issue-label: stale
|
||||
stale-pr-message: >
|
||||
This PR has been automatically marked as stale because it has not had
|
||||
@@ -25,6 +25,6 @@ jobs:
|
||||
If you are the author and the PR has been closed, feel free to re-open the PR and continue the contribution!
|
||||
days-before-pr-stale: 7
|
||||
days-before-pr-close: 5
|
||||
exempt-pr-labels: reviewer-approved,awaiting-review
|
||||
exempt-pr-labels: reviewer-approved,awaiting-review,will-fix
|
||||
stale-pr-label: stale
|
||||
operations-per-run: 100
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
# [Backstage](https://backstage.io)
|
||||
|
||||
> 🎄 The maintainers will be taking a break over the holidays from week beginning 20th Dec. The Repository and Discord may be quieter than usual. We will be back next year, rested and restored, on Jan. 3. 🎄
|
||||
|
||||
> 🎅 Happy holidays and a Happy New Year to all, and especially those that have made this year special for Backstage! 🎅
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://www.cncf.io/projects)
|
||||
[](https://github.com/backstage/backstage/actions?query=workflow%3A%22Main+Master+Build%22)
|
||||
|
||||
@@ -129,8 +129,12 @@ function msUntilExpiry(token: string): number {
|
||||
|
||||
// Calls the specified url regularly using an auth token to set a token cookie
|
||||
// to authorize regular HTTP requests when loading techdocs
|
||||
async function setTokenCookie(url: string, getIdToken: () => Promise<string>) {
|
||||
const token = await getIdToken();
|
||||
async function setTokenCookie(url: string, identityApi: IdentityApi) {
|
||||
const { token } = await identityApi.getCredentials();
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
|
||||
await fetch(url, {
|
||||
mode: 'cors',
|
||||
credentials: 'include',
|
||||
@@ -138,11 +142,12 @@ async function setTokenCookie(url: string, getIdToken: () => Promise<string>) {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
// Call this function again a few minutes before the token expires
|
||||
const ms = msUntilExpiry(token) - 4 * 60 * 1000;
|
||||
setTimeout(
|
||||
() => {
|
||||
setTokenCookie(url, getIdToken);
|
||||
setTokenCookie(url, identityApi);
|
||||
},
|
||||
ms > 0 ? ms : 10000,
|
||||
);
|
||||
@@ -160,16 +165,13 @@ const app = createApp({
|
||||
providers={['guest', 'custom', ...providers]}
|
||||
title="Select a sign-in method"
|
||||
align="center"
|
||||
onResult={async result => {
|
||||
// When logged in, set a token cookie
|
||||
if (typeof result.getIdToken !== 'undefined') {
|
||||
setTokenCookie(
|
||||
await discoveryApi.getBaseUrl('cookie'),
|
||||
result.getIdToken,
|
||||
);
|
||||
}
|
||||
// Forward results
|
||||
props.onResult(result);
|
||||
onSignInSuccess={async (identityApi: IdentityApi) => {
|
||||
setTokenCookie(
|
||||
await discoveryApi.getBaseUrl('cookie'),
|
||||
identityApi,
|
||||
);
|
||||
|
||||
props.onSignInSuccess(identityApi);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ ExampleFetchComponent.tsx reference
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import { githubAuthApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { Table, TableColumn, Progress } from '@backstage/core-components';
|
||||
|
||||
@@ -35,9 +35,11 @@ We follow this structure for plugin packages (where `x` is the plugin name, for
|
||||
example `catalog` or `techdocs`):
|
||||
|
||||
- `x`: Contains the main frontend code of the plugin.
|
||||
- `x-module-<name>`: Contains optional modules related to the frontend plugin
|
||||
package.
|
||||
- `x-backend`: Contains the main backend code of the plugin.
|
||||
- `x-backend-module-<name>`: Contains optional modules related to the backend
|
||||
plugin.
|
||||
plugin package.
|
||||
- `x-react`: Contains shared widgets, hooks and similar that both the plugin
|
||||
itself (`x`) and third-party frontend plugins can depend on.
|
||||
- `x-node`: Contains utilities for backends that both the plugin backend itself
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<mxfile host="Chrome" modified="2021-12-30T23:10:43.723Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" etag="XmQE_awyVPeS9B3bWnM_" version="15.5.6" type="device"><diagram id="M4OCM2KiCGRnt6vHj1W_" name="Page-1">7V3bktq4Fv0aHknhCwYe06Q7kzmdOZ2kp2ZyXk4JW4AntkXZopvO149sZLAt+YKvEiFVU4OFcdtaa2svSXtvj7Sle/jog932M7KgM1In1mGkfRipqqLMDfK/sOXt2DIPj8KGjW9b9KRzwzf7J6SNE9q6ty0YpE7ECDnY3qUbTeR50MSpNuD76DV92ho56b+6AxvINHwzgcO2/mVbeEtb1fnk/MVv0N5s6Z82DPrFCpg/Nj7ae/TvjVRtHf07fu2C+Fr0/GALLPSaaNLuR9rSRwgfP7mHJXTCvo277fi7h5xvT/ftQw9X+cHBgb9bB924/+ur+fXpXg2e/sFjZaodr/MCnD2MHyS6XfwWd1H0kDC8zGSk3b1ubQy/7YAZfvtKSEHatth1yJFCPgLH3njkswPX5LbuXqCPbdLb72kzRuH5a9txlshBPmnxkEeudMc+Dn3C8ArwkGiij/cRIhdi/42cEn+7oF1NqTiNOfaaAHZC27YJTBWNNgJKps3p2ucOJR9on17Qvwud6U1oEf7RQ/rs6Q5GPt6iDfKA84jC3oq69R+I8Ru1HrDHKN3p8GDjvxOfv4eXejelRx8O9MrRwVt84JEH/Dt5kPhVeHj+WXQU/26NPBxjRzg/if5FZ1nvQ3skzSsHmT+et7Z3bH6wnfhGAwx8TB9DP36bOMrlQID2vkn7788v8AG9HVYfPj/O0cvy95+fNto4HjmAv4G44DzK9hCDQkb50AHYfkmPEa2zQ4kJmkOPMxPuz63tseXMkO9JgnDZ0iHq5t5/iR5HaZsC1p+H5fjnf9RP31+8P/bgiwV/fh+rhmAcYAfccg6k+qwjQiiFhLj24YPLndlMLO7EXBaCO7Pqo0keeWbXwh4uXDN1KPYU3XZC+YHdrpn420HfJjcH/fAU29vQX2VFoGtbVkTFjFgMjr96jI4+zM8t5EjNyEaCvgXgfG1GwProB0x8Y5hzuFqfvomFfaGDqa4zMzJT1VmZOeeozM5EpqJoAg0DzUcBKQcBtaILmeqCuZB5Iwmq9DdhkQV27nmDCYf/Pn9Z6v9b2IuvfzyZS//ZmE2+xEN//fGiPaFQVWW+U6epUaLCGPEAXNsJG57BFrmAttIbVJQ+KJXBu9uhRR9STaiMmggXyEifyKQo1uu1anIVhWWsjKnRk6LQJ0MrCs4qoGQTi8x4ocioKTThJxZ89miNp6UDr4GqUkrQqnSZikaXmTB0UavypYYckZYvymArpkW3nVAaO2e/sb3xSDWAG+oHJ3T9tJFcKm7e4FN3ySFHLl7g0GKNSx9PLaBeC7JFnZWvhCizfpdCGo8lXQmXX2g5fXbJhEUgP1S8WdunH5rV9ENSylwOXQTzQzl8mQrDl3oyV87tlqp0GU7mFt12Tdky/hVWUwaWL7xll87kS5FDTHDkLoZ98mivfODbMGAoELzargOiSKKkzU0SAJqkl6DPgfoYj9VCZ56CreLOXLCdeYqFSwVfTbvqzSnTmyM9CtsjvUSGBPWB2tTYRK6LvCszLRbTQspVt5o0zhrHZrpaq+Q+gFEVZQwDPN5j22Et6IZ0BaRnQyPNetA8pEHw4wZyLZAVXsxsryjPGZSXdHgW3QUqEz2zHmJU9IEn22q9NxdlNmMCDBy0GZuOHT65REZjTeHc0nlGM1dXmnGB0cwvRTprNByt06/RxFabjzN+23Hs5gavDBJHYUP1slaMvLW9ucErpa6JI8Dz4YW+j/yb9UqqaBROjhXfCbvH9LobzDVgng4NMy+VLg2zTRToxgfYlmuxQRyQh3fFKrvc8OAjgmu0Rvc+DKCfLJEPGXyFmKGUCxv+Ep3SWXeysz1G2fhwDHY78p8tldGU791XNJoT5aTVr2rpLDQE2IJrsHewXDJHHJT7lLE5sRcMcr0ms160I0oOnmKmxG2p/UnO7mX5luflqaz8RTxOZFaRPxVlQ1y9EaA7AvC7fCgCFN52UTGJYAt24UfSU87bnR+u2OPyUT2dcLR27N1vowvqTQRUbEWkaEFHLeYZXcoRUpyhd7robuxd1LC9buLefonIlMLcPoFDU3IimeqM3ANHvqUJI3zEfmXCiBUpWXjbDWOZwuWuvQMzP6KNMsdtix74pBiZCSInbrvvFPY6acji+i85h6OZ+KGVOROPQesoXZRC1FchpUSIuK4bSXaWxYhHR9m5UQ+kGi6LsfC+6zq5a3VutZKSAjLLM7f0xjYOCAL6+VQVMbaNoVwgJ/a3ZxfI0O0U9/SMkBPiIeSeAhP1pHBWIrnT4TaCnrhdWb7f6ki1lwAVawpnPJNbGDMN8DfgCkkmw1ZCjqsXtdZRxfy+k/eVI7+vMBFL3GlrDncaJ/gNWyfrWrkjmBwsvO+EU7k/EAdAwCetT5EIHAkfojybZhauq0Yot5Klk1OCuprORngL/XGe2vYhMOWKXq6zc1zMzAskW5lTV3llsrtz6hXXE4spIF8WV63Aqm44wNPs/XKgYlmPYg54yGJDrwRmQK3En24YwIuT7ZcCxqABJJct+w5Q9bxwJVa64gmTOhvWg0zdhCp9X5kEUszHGhfQGLhucSJOQYbqK81GEMEmZPF9JwSDLLOwqVY+C+Muq7UyC+MXg2cTCC/a7bjG+Vebe/TFFG5x5nba2GhbsnFpwwZ2X8Saq5yyiU8bXqh4r7Rhsz4uos0VzvLEJw03j7Ir1hQKkMLw4nz/niZIauM5tSOd3Kq2QLAtF+gXbKdltp05gcM61/F3ViBCL0xoOymq3nLaipGvTd7Bi1Hp1TLd6JD3yya76dInu+mlyW5yFqISCOPBKzbMSkvLWfDlBrHcVRvYTamEY+x3haElp6hOB/SK3IlAafG+RMmEq1xjqGhPilR13bhQlw6Zkf4xkbtDHumMaxs4q803+qLD4CpJZUfXrEraQleqWb5A1j58LQCtQirwhoC5Y7skb1KtTkzkedDEYBVfYXJJp3BfB89bwGjldfD8aoycQbARwytlPyd5St84X1FinGEsZ+JwvTrnzLiufdxoDFf1dRIOlmpnBsJuQ8kEZYvhPI2h5EZ09Qklp2ilRFC2GJvXGEpeem6vUKoMlMk1YiLaIsmWAZc8K04jmO5K6oo43qnEq50Q5hEmTanU+j3LgO4Q1ErHVaVfCFk99ilALvJ3W9u8gVgJRN7bzfoFsej9IDcEyxHkzYu6QpD7CHIr1RbzEFtQqv05xZwIVgbL5eOnmyFW9IdDW6Kiyz3VqDVrrJH+m1lD4VRZ7hk2uacVtWaIjWEzepzX58DGTiFkgq3WbLC5tc0Hh63CMq7IsPUzSBrCDZIGg5KYbyYNgxofgGs7YcMz2CIX0Fb6ZxRlJGjexElAlKdexVZUmjkR022RIVQb9ddzbo2zDyeRgffkTg3h3Gnjcq83Ay83cKWygVdNrBvAwNvecrxK4ZX14MMLr5kkBt6oAqa0I0N11z8VdmSIVaoAFCupmdmoSri0HKvufcTlmN64rO/Aw9hVM0y9AoYZ7MLSErk7gO2V7dj4jeGfBMvwydS/SQvyhoGDk3am8Eq9dKdvjAo7YXEHP4IVdJ5QYEcvziOmgjBGLgeBY7hbEln6shH3sCEwbN+tQGCb785Dyv+xbwNvw6ktUi1ct5r15++WpbM+FVb+nnbcfIQBffxxGMrZkuxVSmVv/GKRVCjf4mJajMKIEYQT330MEfkcvfBSu/8X</diagram></mxfile>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 149 KiB |
@@ -30,12 +30,15 @@ export const CustomCatalogPage = ({
|
||||
actions,
|
||||
initiallySelectedFilter = 'owned',
|
||||
}: CatalogPageProps) => {
|
||||
const createComponentLink = useRouteRef(
|
||||
catalogPlugin.externalRoutes.createComponent,
|
||||
);
|
||||
return (
|
||||
<PageWithHeader title={`${orgName} Catalog`} themeId="home">
|
||||
<EntityListProvider>
|
||||
<Content>
|
||||
<ContentHeader titleComponent={<CatalogKindHeader />}>
|
||||
<CreateButton title="Create Component" to={link} />
|
||||
<CreateButton title="Create Component" to={createComponentLink()} />
|
||||
<SupportButton>All your software catalog entities</SupportButton>
|
||||
</ContentHeader>
|
||||
<FilteredEntityLayout>
|
||||
|
||||
@@ -22,6 +22,13 @@ yarn backstage-cli versions:bump
|
||||
The reason for bumping all `@backstage` packages at once is to maintain the
|
||||
dependencies that they have between each other.
|
||||
|
||||
If you are using other plugins you can pass in the `--pattern` option to update
|
||||
more than just the `@backstage/*` dependencies.
|
||||
|
||||
```bash
|
||||
yarn backstage-cli versions:bump --pattern '@{backstage,roadiehq}/*'
|
||||
```
|
||||
|
||||
## Following create-app template changes
|
||||
|
||||
The `@backstage/create-app` command creates the initial structure of your
|
||||
|
||||
@@ -20,8 +20,7 @@ To use this integration, add configuration to your `app-config.yaml`:
|
||||
```yaml
|
||||
integrations:
|
||||
awsS3:
|
||||
- host: amazonaws.com
|
||||
accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
- accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
|
||||
```
|
||||
|
||||
@@ -35,8 +34,21 @@ instruct the AWS S3 reader to assume a role before accessing S3:
|
||||
```yaml
|
||||
integrations:
|
||||
awsS3:
|
||||
- host: amazonaws.com
|
||||
accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
- accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
|
||||
roleArn: 'arn:aws:iam::xxxxxxxxxxxx:role/example-role'
|
||||
```
|
||||
|
||||
Configuration allows specifying custom S3 endpoint, along with
|
||||
[path-style access](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html)
|
||||
to support integration with providers like
|
||||
[LocalStack](https://github.com/localstack/localstack):
|
||||
|
||||
```yaml
|
||||
integrations:
|
||||
awsS3:
|
||||
- endpoint: 'http://localhost:4566'
|
||||
s3ForcePathStyle: true
|
||||
accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
|
||||
```
|
||||
|
||||
@@ -594,6 +594,7 @@ Usage: backstage-cli versions:bump [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
-p, --pattern Override glob for matching packages to upgrade
|
||||
```
|
||||
|
||||
## versions:check
|
||||
|
||||
@@ -164,12 +164,110 @@ https://circleci.com.
|
||||
|
||||

|
||||
|
||||
## Package Architecture
|
||||
|
||||
Backstage relies heavily on NPM packages, both for distribution of libraries,
|
||||
and structuring of code within projects. While the way you structure your
|
||||
Backstage project is up to you, there is a set of established patterns that we
|
||||
encourage you to follow. These patterns can help set up a sound project
|
||||
structure as well as provide familiarity between different Backstage projects.
|
||||
|
||||
The following diagram shows an overview of the package architecture of
|
||||
Backstage. It takes the point of view of an individual plugin and all of the
|
||||
packages that it may contain, indicated by the thicker border and italic text.
|
||||
Surrounding the plugin are different package groups which are the different
|
||||
possible interface points of the plugin. Note that not all library package lists
|
||||
are complete as packages have been omitted for brevity.
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
NOTE: The diagram is exported from /docs/assets/architecture-overview/package-architecture.drawio
|
||||
It can be edited using https://www.diagrams.net/
|
||||
Export it as a PNG with 10px margin without transparent background
|
||||
-->
|
||||
|
||||
### Overview
|
||||
|
||||
The arrows in the diagram above indicate a runtime dependency on the code of the
|
||||
target package. This strict dependency graph only applies to runtime
|
||||
`dependencies`, and there may be `devDependencies` that break the rules of this
|
||||
table for the purpose of testing. While there are some arrows that show a
|
||||
dependency on a collection of frontend, backend and isomorphic packages, those
|
||||
still have to abide by important compatibility rules shown in the bottom left.
|
||||
|
||||
The `app` and `backend` packages are the entry points of a Backstage project.
|
||||
The `app` package is the frontend application that brings together a collection
|
||||
of frontend plugins and customizes them to fit an organization, while the
|
||||
`backend` package is the backend service that powers the Backstage application.
|
||||
Worth noting is that there can be more than one instance of each of these
|
||||
packages within a project. Particularly the `backend` packages can benefit from
|
||||
being split up into smaller deployment units that each serve their own purpose
|
||||
with a smaller collection of plugins.
|
||||
|
||||
### Plugin Packages
|
||||
|
||||
A typical plugin consists of up to five packages, two frontend ones, two
|
||||
backend, and one isomorphic packages. All packages within the plugin must share
|
||||
a common prefix, typically of the form `@<scope>/plugin-<plugin-id>`, but
|
||||
alternatives like `backstage-plugin-<plugin-id>` or
|
||||
`@scope/backstage-plugin-<plugin-id>` are also valid. Along with this prefix,
|
||||
each of the packages have their own unique suffix that denotes their role. In
|
||||
addition to these five plugin packages it's also possible for to a plugin to
|
||||
have additional frontend and backend modules that can be installed to enable
|
||||
optional features. For a full list of suffixes and their roles, see the
|
||||
[Plugin Package Structure ADR](../architecture-decisions/adr011-plugin-package-structure.md).
|
||||
|
||||
The `-react`, `-common`, and `-node` plugin packages together form the external
|
||||
library of a plugin. The plugin library enables other plugins to build on top of
|
||||
and extend a plugin, and likewise allows the plugin to depend on and extend
|
||||
other plugins. Because of this, it is preferable that plugin library packages
|
||||
allow duplicate installations of themselves, as you may end up with a mix of
|
||||
versions being installed as dependencies of various plugins. It is also
|
||||
forbidden for plugins to directly import non-library packages from other
|
||||
plugins, all communication between plugins must be handled through libraries and
|
||||
the application itself.
|
||||
|
||||
### Frontend Packages
|
||||
|
||||
The frontend packages are grouped into two main groups. The first one is
|
||||
"Frontend App Core", which is the set of packages that are only used by the
|
||||
`app` package itself. These packages help build up the core structure of the app
|
||||
as well as provide a foundation for the plugin libraries to rely upon.
|
||||
|
||||
The second group is the rest of the shared packages, further divided into
|
||||
"Frontend Plugin Core" and "Frontend Libraries". The core packages that are
|
||||
considered particularly stable and form the core of the frontend framework.
|
||||
Their most important role is to form the boundary around each plugin and provide
|
||||
a set of tools that helps you combine a collection of plugins into a running
|
||||
application. The rest of the frontend packages are more traditional libraries
|
||||
that serve as building blocks to create plugins.
|
||||
|
||||
### Backend Packages
|
||||
|
||||
The backend library packages do not currently share a similar plugin
|
||||
architecture as the frontend packages. They are instead simply a collection of
|
||||
building blocks and patterns that help you build backend services. This is
|
||||
however likely to change in the future.
|
||||
|
||||
### Common Packages
|
||||
|
||||
The common packages are the packages are effectively depended on by all other
|
||||
pages. This is a much smaller set of packages but they are also very pervasive.
|
||||
Because the common packages are isomorphic and must execute both in the frontend
|
||||
and backend, they are never allowed to depend on any of the frontend of backend
|
||||
packages.
|
||||
|
||||
The Backstage CLI is in a category of its own and is depended on by virtually
|
||||
all other packages. It's not a library in itself though, and must always be a
|
||||
development dependency only.
|
||||
|
||||
## Databases
|
||||
|
||||
As we have seen, both the `lighthouse-audit-service` and `catalog-backend`
|
||||
require a database to work with.
|
||||
|
||||
The Backstage backend and its builtin plugins are based on the
|
||||
The Backstage backend and its built-in plugins are based on the
|
||||
[Knex](http://knexjs.org/) library, and set up a separate logical database per
|
||||
plugin. This gives great isolation and lets them perform migrations and evolve
|
||||
separate from each other.
|
||||
@@ -184,7 +282,7 @@ yet.
|
||||
|
||||
## Cache
|
||||
|
||||
The Backstage backend and its builtin plugins are also able to leverage cache
|
||||
The Backstage backend and its built-in plugins are also able to leverage cache
|
||||
stores as a means of improving performance or reliability. Similar to how
|
||||
databases are supported, plugins receive logically separated cache connections,
|
||||
which are powered by [Keyv](https://github.com/lukechilds/keyv) under the hood.
|
||||
|
||||
@@ -135,7 +135,7 @@ changes, let's start by wiping this component clean.
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import { Table, TableColumn, Progress } from '@backstage/core-components';
|
||||
import { githubAuthApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
"start": "yarn workspace example-app start",
|
||||
"start-backend": "yarn workspace example-backend start",
|
||||
"build": "lerna run build",
|
||||
"build:api-reports": "yarn tsc:full && yarn build:api-reports:only",
|
||||
"build:api-reports": "yarn build:api-reports:only --tsc",
|
||||
"build:api-reports:only": "ts-node -T -P scripts/tsconfig.json scripts/api-extractor.ts",
|
||||
"build:api-docs": "yarn build:api-reports --docs",
|
||||
"tsc": "tsc",
|
||||
@@ -68,7 +68,7 @@
|
||||
"@types/webpack": "^5.28.0",
|
||||
"command-exists": "^1.2.9",
|
||||
"cross-env": "^7.0.0",
|
||||
"concurrently": "^6.0.0",
|
||||
"concurrently": "^7.0.0",
|
||||
"eslint-plugin-notice": "^0.9.10",
|
||||
"fs-extra": "9.1.0",
|
||||
"husky": "^6.0.0",
|
||||
|
||||
@@ -1,5 +1,49 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/cli@0.10.5
|
||||
- @backstage/plugin-search@0.5.4
|
||||
- @backstage/plugin-techdocs@0.12.13
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
- @backstage/plugin-catalog-react@0.6.10
|
||||
- @backstage/plugin-kubernetes@0.5.3
|
||||
- @backstage/core-app-api@0.3.1
|
||||
- @backstage/core-components@0.8.3
|
||||
- @backstage/plugin-apache-airflow@0.1.2
|
||||
- @backstage/plugin-azure-devops@0.1.9
|
||||
- @backstage/plugin-badges@0.2.18
|
||||
- @backstage/plugin-catalog@0.7.7
|
||||
- @backstage/plugin-catalog-graph@0.2.5
|
||||
- @backstage/plugin-catalog-import@0.7.8
|
||||
- @backstage/plugin-circleci@0.2.33
|
||||
- @backstage/plugin-cloudbuild@0.2.31
|
||||
- @backstage/plugin-code-coverage@0.1.21
|
||||
- @backstage/plugin-cost-insights@0.11.16
|
||||
- @backstage/plugin-explore@0.3.24
|
||||
- @backstage/plugin-gcp-projects@0.3.12
|
||||
- @backstage/plugin-github-actions@0.4.30
|
||||
- @backstage/plugin-graphiql@0.2.26
|
||||
- @backstage/plugin-home@0.4.9
|
||||
- @backstage/plugin-jenkins@0.5.16
|
||||
- @backstage/plugin-kafka@0.2.24
|
||||
- @backstage/plugin-lighthouse@0.2.33
|
||||
- @backstage/plugin-newrelic@0.3.12
|
||||
- @backstage/plugin-newrelic-dashboard@0.1.2
|
||||
- @backstage/plugin-org@0.3.33
|
||||
- @backstage/plugin-pagerduty@0.3.21
|
||||
- @backstage/plugin-rollbar@0.3.22
|
||||
- @backstage/plugin-scaffolder@0.11.17
|
||||
- @backstage/plugin-sentry@0.3.32
|
||||
- @backstage/plugin-shortcuts@0.1.18
|
||||
- @backstage/plugin-tech-insights@0.1.4
|
||||
- @backstage/plugin-tech-radar@0.5.1
|
||||
- @backstage/plugin-user-settings@0.3.15
|
||||
- @backstage/plugin-api-docs@0.6.21
|
||||
|
||||
## 0.2.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+42
-42
@@ -1,60 +1,60 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.58",
|
||||
"version": "0.2.59",
|
||||
"private": true,
|
||||
"bundled": true,
|
||||
"dependencies": {
|
||||
"@backstage/app-defaults": "^0.1.3",
|
||||
"@backstage/catalog-model": "^0.9.8",
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/core-components": "^0.8.3",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@backstage/integration-react": "^0.1.16",
|
||||
"@backstage/plugin-api-docs": "^0.6.19",
|
||||
"@backstage/plugin-azure-devops": "^0.1.8",
|
||||
"@backstage/plugin-apache-airflow": "^0.1.1",
|
||||
"@backstage/plugin-badges": "^0.2.17",
|
||||
"@backstage/plugin-catalog": "^0.7.5",
|
||||
"@backstage/plugin-catalog-graph": "^0.2.4",
|
||||
"@backstage/plugin-catalog-import": "^0.7.6",
|
||||
"@backstage/plugin-catalog-react": "^0.6.8",
|
||||
"@backstage/plugin-circleci": "^0.2.32",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.30",
|
||||
"@backstage/plugin-code-coverage": "^0.1.20",
|
||||
"@backstage/plugin-cost-insights": "^0.11.14",
|
||||
"@backstage/plugin-explore": "^0.3.23",
|
||||
"@backstage/plugin-gcp-projects": "^0.3.11",
|
||||
"@backstage/plugin-github-actions": "^0.4.28",
|
||||
"@backstage/plugin-graphiql": "^0.2.25",
|
||||
"@backstage/plugin-home": "^0.4.8",
|
||||
"@backstage/plugin-jenkins": "^0.5.15",
|
||||
"@backstage/plugin-kafka": "^0.2.23",
|
||||
"@backstage/plugin-kubernetes": "^0.5.2",
|
||||
"@backstage/plugin-lighthouse": "^0.2.32",
|
||||
"@backstage/plugin-newrelic": "^0.3.11",
|
||||
"@backstage/plugin-newrelic-dashboard": "^0.1.1",
|
||||
"@backstage/plugin-org": "^0.3.32",
|
||||
"@backstage/plugin-pagerduty": "0.3.20",
|
||||
"@backstage/plugin-rollbar": "^0.3.21",
|
||||
"@backstage/plugin-scaffolder": "^0.11.15",
|
||||
"@backstage/plugin-search": "^0.5.2",
|
||||
"@backstage/plugin-sentry": "^0.3.31",
|
||||
"@backstage/plugin-shortcuts": "^0.1.16",
|
||||
"@backstage/plugin-tech-radar": "^0.5.0",
|
||||
"@backstage/plugin-techdocs": "^0.12.11",
|
||||
"@backstage/plugin-api-docs": "^0.6.21",
|
||||
"@backstage/plugin-azure-devops": "^0.1.9",
|
||||
"@backstage/plugin-apache-airflow": "^0.1.2",
|
||||
"@backstage/plugin-badges": "^0.2.18",
|
||||
"@backstage/plugin-catalog": "^0.7.7",
|
||||
"@backstage/plugin-catalog-graph": "^0.2.5",
|
||||
"@backstage/plugin-catalog-import": "^0.7.8",
|
||||
"@backstage/plugin-catalog-react": "^0.6.10",
|
||||
"@backstage/plugin-circleci": "^0.2.33",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.31",
|
||||
"@backstage/plugin-code-coverage": "^0.1.21",
|
||||
"@backstage/plugin-cost-insights": "^0.11.16",
|
||||
"@backstage/plugin-explore": "^0.3.24",
|
||||
"@backstage/plugin-gcp-projects": "^0.3.12",
|
||||
"@backstage/plugin-github-actions": "^0.4.30",
|
||||
"@backstage/plugin-graphiql": "^0.2.26",
|
||||
"@backstage/plugin-home": "^0.4.9",
|
||||
"@backstage/plugin-jenkins": "^0.5.16",
|
||||
"@backstage/plugin-kafka": "^0.2.24",
|
||||
"@backstage/plugin-kubernetes": "^0.5.3",
|
||||
"@backstage/plugin-lighthouse": "^0.2.33",
|
||||
"@backstage/plugin-newrelic": "^0.3.12",
|
||||
"@backstage/plugin-newrelic-dashboard": "^0.1.2",
|
||||
"@backstage/plugin-org": "^0.3.33",
|
||||
"@backstage/plugin-pagerduty": "0.3.21",
|
||||
"@backstage/plugin-rollbar": "^0.3.22",
|
||||
"@backstage/plugin-scaffolder": "^0.11.17",
|
||||
"@backstage/plugin-search": "^0.5.4",
|
||||
"@backstage/plugin-sentry": "^0.3.32",
|
||||
"@backstage/plugin-shortcuts": "^0.1.18",
|
||||
"@backstage/plugin-tech-radar": "^0.5.1",
|
||||
"@backstage/plugin-techdocs": "^0.12.13",
|
||||
"@backstage/plugin-todo": "^0.1.17",
|
||||
"@backstage/plugin-user-settings": "^0.3.14",
|
||||
"@backstage/plugin-user-settings": "^0.3.15",
|
||||
"@backstage/search-common": "^0.2.0",
|
||||
"@backstage/plugin-tech-insights": "^0.1.2",
|
||||
"@backstage/plugin-tech-insights": "^0.1.4",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"@octokit/rest": "^18.5.3",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^1.2.2",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^1.0.13",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^1.0.11",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^1.4.2",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^1.3.2",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^1.3.2",
|
||||
"history": "^5.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 21ae56168e: Updated the Git class with the following:
|
||||
|
||||
- Added `depth` and `noCheckout` options to Git clone, using these you can create a bare clone that includes just the git history
|
||||
- New `log` function which you can use to view the commit history of a git repo
|
||||
|
||||
- eacc582473: Reverted the default CSP configuration to include `'unsafe-eval'` again, which was mistakenly removed in the previous version.
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -234,8 +234,13 @@ export class Git {
|
||||
remote: string;
|
||||
url: string;
|
||||
}): Promise<void>;
|
||||
// (undocumented)
|
||||
clone(options: { url: string; dir: string; ref?: string }): Promise<void>;
|
||||
clone(options: {
|
||||
url: string;
|
||||
dir: string;
|
||||
ref?: string;
|
||||
depth?: number;
|
||||
noCheckout?: boolean;
|
||||
}): Promise<void>;
|
||||
// (undocumented)
|
||||
commit(options: {
|
||||
dir: string;
|
||||
@@ -249,12 +254,10 @@ export class Git {
|
||||
email: string;
|
||||
};
|
||||
}): Promise<string>;
|
||||
// (undocumented)
|
||||
currentBranch(options: {
|
||||
dir: string;
|
||||
fullName?: boolean;
|
||||
}): Promise<string | undefined>;
|
||||
// (undocumented)
|
||||
fetch(options: { dir: string; remote?: string }): Promise<void>;
|
||||
// (undocumented)
|
||||
static fromAuth: (options: {
|
||||
@@ -264,7 +267,7 @@ export class Git {
|
||||
}) => Git;
|
||||
// (undocumented)
|
||||
init(options: { dir: string; defaultBranch?: string }): Promise<void>;
|
||||
// (undocumented)
|
||||
log(options: { dir: string; ref?: string }): Promise<ReadCommitResult[]>;
|
||||
merge(options: {
|
||||
dir: string;
|
||||
theirs: string;
|
||||
@@ -280,9 +283,7 @@ export class Git {
|
||||
}): Promise<MergeResult>;
|
||||
// (undocumented)
|
||||
push(options: { dir: string; remote: string }): Promise<PushResult>;
|
||||
// (undocumented)
|
||||
readCommit(options: { dir: string; sha: string }): Promise<ReadCommitResult>;
|
||||
// (undocumented)
|
||||
resolveRef(options: { dir: string; ref: string }): Promise<string>;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.10.1",
|
||||
"version": "0.10.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -81,7 +81,7 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@types/archiver": "^5.1.0",
|
||||
"@types/compression": "^1.7.0",
|
||||
|
||||
@@ -320,4 +320,21 @@ describe('Git', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('log', () => {
|
||||
it('should call isomorphic-git with the correct arguments', async () => {
|
||||
const dir = '/some/mock/dir';
|
||||
const ref = 'as43bd7';
|
||||
|
||||
const git = Git.fromAuth({});
|
||||
|
||||
await git.log({ dir, ref });
|
||||
|
||||
expect(isomorphic.log).toHaveBeenCalledWith({
|
||||
fs,
|
||||
dir,
|
||||
ref,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,12 +76,15 @@ export class Git {
|
||||
return git.commit({ fs, dir, message, author, committer });
|
||||
}
|
||||
|
||||
/** https://isomorphic-git.org/docs/en/clone */
|
||||
async clone(options: {
|
||||
url: string;
|
||||
dir: string;
|
||||
ref?: string;
|
||||
depth?: number;
|
||||
noCheckout?: boolean;
|
||||
}): Promise<void> {
|
||||
const { url, dir, ref } = options;
|
||||
const { url, dir, ref, depth, noCheckout } = options;
|
||||
this.config.logger?.info(`Cloning repo {dir=${dir},url=${url}}`);
|
||||
return git.clone({
|
||||
fs,
|
||||
@@ -90,7 +93,8 @@ export class Git {
|
||||
dir,
|
||||
ref,
|
||||
singleBranch: true,
|
||||
depth: 1,
|
||||
depth: depth ?? 1,
|
||||
noCheckout,
|
||||
onProgress: this.onProgressHandler(),
|
||||
headers: {
|
||||
'user-agent': 'git/@isomorphic-git',
|
||||
@@ -99,7 +103,7 @@ export class Git {
|
||||
});
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/currentBranch
|
||||
/** https://isomorphic-git.org/docs/en/currentBranch */
|
||||
async currentBranch(options: {
|
||||
dir: string;
|
||||
fullName?: boolean;
|
||||
@@ -110,7 +114,7 @@ export class Git {
|
||||
>;
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/fetch
|
||||
/** https://isomorphic-git.org/docs/en/fetch */
|
||||
async fetch(options: { dir: string; remote?: string }): Promise<void> {
|
||||
const { dir, remote = 'origin' } = options;
|
||||
this.config.logger?.info(
|
||||
@@ -138,7 +142,7 @@ export class Git {
|
||||
});
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/merge
|
||||
/** https://isomorphic-git.org/docs/en/merge */
|
||||
async merge(options: {
|
||||
dir: string;
|
||||
theirs: string;
|
||||
@@ -180,7 +184,7 @@ export class Git {
|
||||
});
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/readCommit
|
||||
/** https://isomorphic-git.org/docs/en/readCommit */
|
||||
async readCommit(options: {
|
||||
dir: string;
|
||||
sha: string;
|
||||
@@ -189,12 +193,25 @@ export class Git {
|
||||
return git.readCommit({ fs, dir, oid: sha });
|
||||
}
|
||||
|
||||
// https://isomorphic-git.org/docs/en/resolveRef
|
||||
/** https://isomorphic-git.org/docs/en/resolveRef */
|
||||
async resolveRef(options: { dir: string; ref: string }): Promise<string> {
|
||||
const { dir, ref } = options;
|
||||
return git.resolveRef({ fs, dir, ref });
|
||||
}
|
||||
|
||||
/** https://isomorphic-git.org/docs/en/log */
|
||||
async log(options: {
|
||||
dir: string;
|
||||
ref?: string;
|
||||
}): Promise<ReadCommitResult[]> {
|
||||
const { dir, ref } = options;
|
||||
return git.log({
|
||||
fs,
|
||||
dir,
|
||||
ref: ref ?? 'HEAD',
|
||||
});
|
||||
}
|
||||
|
||||
private onAuth = () => ({
|
||||
username: this.config.username,
|
||||
password: this.config.password,
|
||||
|
||||
@@ -228,6 +228,10 @@ export function applyCspDirectives(
|
||||
const result: ContentSecurityPolicyOptions['directives'] =
|
||||
helmet.contentSecurityPolicy.getDefaultDirectives();
|
||||
|
||||
// TODO(Rugvip): We currently use non-precompiled AJV for validation in the frontend, which uses eval.
|
||||
// It should be replaced by any other solution that doesn't require unsafe-eval.
|
||||
result['script-src'] = ["'self'", "'unsafe-eval'"];
|
||||
|
||||
if (directives) {
|
||||
for (const [key, value] of Object.entries(directives)) {
|
||||
if (value === false) {
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @backstage/backend-tasks
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e188b37024: Updated README to clarify the following:
|
||||
|
||||
- Dashes cannot be used in the `id`, changed to an underscore in the example
|
||||
- The `timeout` is required, this was also added to the example
|
||||
- Added a note about tasks not running as expected for local development using persistent database
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.10.2
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-tasks",
|
||||
"description": "Common distributed task management library for Backstage backends",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -29,7 +29,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.0",
|
||||
"@backstage/backend-common": "^0.10.2",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/errors": "^0.1.4",
|
||||
"@backstage/types": "^0.1.1",
|
||||
@@ -44,7 +44,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-test-utils": "^0.1.11",
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"jest": "^26.0.1",
|
||||
"wait-for-expect": "^3.0.2"
|
||||
},
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"mysql2": "^2.2.5",
|
||||
"pg": "^8.3.0",
|
||||
"sqlite3": "^5.0.1",
|
||||
"testcontainers": "^7.23.0",
|
||||
"testcontainers": "^8.1.2",
|
||||
"uuid": "^8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -41,11 +41,11 @@ export default async function createPlugin({
|
||||
discovery,
|
||||
factRetrievers: [
|
||||
createFactRetrieverRegistration(
|
||||
'* * * * *', // Example cron, every minute
|
||||
'1 1 1 * *', // Example cron, At 01:01 on day-of-month 1.
|
||||
entityOwnershipFactRetriever,
|
||||
),
|
||||
createFactRetrieverRegistration('* * * * *', entityMetadataFactRetriever),
|
||||
createFactRetrieverRegistration('* * * * *', techdocsFactRetriever),
|
||||
createFactRetrieverRegistration('1 1 1 * *', entityMetadataFactRetriever),
|
||||
createFactRetrieverRegistration('1 1 1 * *', techdocsFactRetriever),
|
||||
],
|
||||
factCheckerFactory: new JsonRulesEngineFactCheckerFactory({
|
||||
checks: [
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.10.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 37123b4851: Bump `css-loader` from `5.2.6` to `6.5.1`
|
||||
- 9534391ae4: Add --pattern option to override matching glob patterns for backstage versioning
|
||||
- 4ce51ab0f1: Internal refactor of the `react-use` imports to use `react-use/lib/*` instead.
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -80,6 +80,10 @@ module.exports = {
|
||||
name: '@material-ui/icons',
|
||||
message: "Please import '@material-ui/icons/<Icon>' instead.",
|
||||
},
|
||||
{
|
||||
name: '@material-ui/icons/', // because this is possible too ._.
|
||||
message: "Please import '@material-ui/icons/<Icon>' instead.",
|
||||
},
|
||||
...require('module').builtinModules,
|
||||
],
|
||||
// Avoid cross-package imports
|
||||
|
||||
+17
-15
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"version": "0.10.4",
|
||||
"version": "0.10.5",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -51,26 +51,26 @@
|
||||
"@svgr/rollup": "5.5.x",
|
||||
"@svgr/webpack": "5.5.x",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"@typescript-eslint/eslint-plugin": "^v4.33.0",
|
||||
"@typescript-eslint/parser": "^v4.28.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.9.0",
|
||||
"@typescript-eslint/parser": "^5.9.0",
|
||||
"@yarnpkg/lockfile": "^1.1.0",
|
||||
"bfj": "^7.0.2",
|
||||
"buffer": "^6.0.3",
|
||||
"chalk": "^4.0.0",
|
||||
"chokidar": "^3.3.1",
|
||||
"commander": "^6.1.0",
|
||||
"css-loader": "^5.2.6",
|
||||
"css-loader": "^6.5.1",
|
||||
"diff": "^5.0.0",
|
||||
"esbuild": "^0.14.1",
|
||||
"eslint": "^7.30.0",
|
||||
"eslint": "^8.6.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-formatter-friendly": "^7.0.0",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-jest": "^24.1.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.1",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^25.3.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-monorepo": "^0.3.2",
|
||||
"eslint-plugin-react": "^7.12.4",
|
||||
"eslint-plugin-react-hooks": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"express": "^4.17.1",
|
||||
"fork-ts-checker-webpack-plugin": "^4.0.5",
|
||||
"fs-extra": "9.1.0",
|
||||
@@ -83,6 +83,7 @@
|
||||
"json-schema": "^0.4.0",
|
||||
"jest-transform-yaml": "^0.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"minimatch": "3.0.4",
|
||||
"mini-css-extract-plugin": "^2.4.2",
|
||||
"node-libs-browser": "^2.2.1",
|
||||
"ora": "^5.3.0",
|
||||
@@ -114,12 +115,12 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/backend-common": "^0.10.2",
|
||||
"@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/core-components": "^0.8.3",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/dev-utils": "^0.2.16",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@types/diff": "^5.0.0",
|
||||
@@ -127,6 +128,7 @@
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
"@types/http-proxy": "^1.17.4",
|
||||
"@types/inquirer": "^8.1.3",
|
||||
"@types/minimatch": "^3.0.5",
|
||||
"@types/mock-fs": "^4.13.0",
|
||||
"@types/node": "^14.14.32",
|
||||
"@types/recursive-readdir": "^2.2.0",
|
||||
|
||||
@@ -214,6 +214,10 @@ export function registerCommands(program: CommanderStatic) {
|
||||
|
||||
program
|
||||
.command('versions:bump')
|
||||
.option(
|
||||
'--pattern <glob>',
|
||||
'Override glob for matching packages to upgrade',
|
||||
)
|
||||
.description('Bump Backstage packages to the latest versions')
|
||||
.action(lazy(() => import('./versions/bump').then(m => m.default)));
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import mockFs from 'mock-fs';
|
||||
import { Command } from 'commander';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { paths } from '../../lib/paths';
|
||||
import { mapDependencies } from '../../lib/versioning';
|
||||
@@ -36,6 +37,8 @@ const REGISTRY_VERSIONS: { [name: string]: string } = {
|
||||
'@backstage/core': '1.0.6',
|
||||
'@backstage/core-api': '1.0.7',
|
||||
'@backstage/theme': '2.0.0',
|
||||
'@backstage-extra/custom': '1.1.0',
|
||||
'@backstage-extra/custom-two': '2.0.0',
|
||||
};
|
||||
|
||||
const HEADER = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
@@ -83,7 +86,7 @@ describe('bump', () => {
|
||||
|
||||
it('should bump backstage dependencies', async () => {
|
||||
// Make sure all modules involved in package discovery are in the module cache before we mock fs
|
||||
await mapDependencies(paths.targetDir);
|
||||
await mapDependencies(paths.targetDir, '@backstage/*');
|
||||
|
||||
mockFs({
|
||||
'/yarn.lock': lockfileMock,
|
||||
@@ -123,9 +126,10 @@ describe('bump', () => {
|
||||
jest.spyOn(runObj, 'run').mockResolvedValue(undefined);
|
||||
|
||||
const { log: logs } = await withLogCollector(['log'], async () => {
|
||||
await bump();
|
||||
await bump({ pattern: null } as unknown as Command);
|
||||
});
|
||||
expect(logs.filter(Boolean)).toEqual([
|
||||
'Using default pattern glob @backstage/*',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Checking for updates of @backstage/core-api',
|
||||
@@ -178,9 +182,145 @@ describe('bump', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should bump backstage dependencies and dependencies matching pattern glob', async () => {
|
||||
// Make sure all modules involved in package discovery are in the module cache before we mock fs
|
||||
await mapDependencies(paths.targetDir, '@backstage/*');
|
||||
const customLockfileMock = `${lockfileMock}
|
||||
"@backstage-extra/custom@^1.1.0":
|
||||
version "1.1.0"
|
||||
|
||||
"@backstage-extra/custom@^1.0.1":
|
||||
version "1.0.1"
|
||||
|
||||
"@backstage-extra/custom-two@^1.0.0":
|
||||
version "1.0.0"
|
||||
`;
|
||||
const customLockfileMockResult = `${HEADER}
|
||||
"@backstage-extra/custom-two@^1.0.0":
|
||||
version "1.0.0"
|
||||
|
||||
"@backstage-extra/custom@^1.1.0":
|
||||
version "1.1.0"
|
||||
|
||||
"@backstage/core@^1.0.5":
|
||||
version "1.0.6"
|
||||
dependencies:
|
||||
"@backstage/core-api" "^1.0.6"
|
||||
|
||||
"@backstage/theme@^1.0.0":
|
||||
version "1.0.0"
|
||||
`;
|
||||
mockFs({
|
||||
'/yarn.lock': customLockfileMock,
|
||||
'/lerna.json': JSON.stringify({
|
||||
packages: ['packages/*'],
|
||||
}),
|
||||
'/packages/a/package.json': JSON.stringify({
|
||||
name: 'a',
|
||||
dependencies: {
|
||||
'@backstage/core': '^1.0.5',
|
||||
'@backstage-extra/custom': '^1.0.1',
|
||||
'@backstage-extra/custom-two': '^1.0.0',
|
||||
},
|
||||
}),
|
||||
'/packages/b/package.json': JSON.stringify({
|
||||
name: 'b',
|
||||
dependencies: {
|
||||
'@backstage/core': '^1.0.3',
|
||||
'@backstage/theme': '^1.0.0',
|
||||
'@backstage-extra/custom': '^1.1.0',
|
||||
'@backstage-extra/custom-two': '^1.0.0',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
paths.targetDir = '/';
|
||||
jest
|
||||
.spyOn(paths, 'resolveTargetRoot')
|
||||
.mockImplementation((...path) => resolvePath('/', ...path));
|
||||
jest.spyOn(runObj, 'runPlain').mockImplementation(async (...[, , , name]) =>
|
||||
JSON.stringify({
|
||||
type: 'inspect',
|
||||
data: {
|
||||
name: name,
|
||||
'dist-tags': {
|
||||
latest: REGISTRY_VERSIONS[name],
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
jest.spyOn(runObj, 'run').mockResolvedValue(undefined);
|
||||
|
||||
const { log: logs } = await withLogCollector(['log'], async () => {
|
||||
await bump({ pattern: '@{backstage,backstage-extra}/*' } as any);
|
||||
});
|
||||
expect(logs.filter(Boolean)).toEqual([
|
||||
'Using custom pattern glob @{backstage,backstage-extra}/*',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'Checking for updates of @backstage-extra/custom-two',
|
||||
'Checking for updates of @backstage-extra/custom',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Checking for updates of @backstage/core-api',
|
||||
'Some packages are outdated, updating',
|
||||
'unlocking @backstage-extra/custom@^1.0.1 ~> 1.1.0',
|
||||
'unlocking @backstage/core@^1.0.3 ~> 1.0.6',
|
||||
'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7',
|
||||
'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7',
|
||||
'bumping @backstage-extra/custom-two in a to ^2.0.0',
|
||||
'bumping @backstage/theme in b to ^2.0.0',
|
||||
'bumping @backstage-extra/custom-two in b to ^2.0.0',
|
||||
'Running yarn install to install new versions',
|
||||
'⚠️ The following packages may have breaking changes:',
|
||||
' @backstage-extra/custom-two : 1.0.0 ~> 2.0.0',
|
||||
' @backstage/theme : 1.0.0 ~> 2.0.0',
|
||||
' https://github.com/backstage/backstage/blob/master/packages/theme/CHANGELOG.md',
|
||||
'Version bump complete!',
|
||||
]);
|
||||
|
||||
expect(runObj.runPlain).toHaveBeenCalledTimes(6);
|
||||
expect(runObj.runPlain).toHaveBeenCalledWith(
|
||||
'yarn',
|
||||
'info',
|
||||
'--json',
|
||||
'@backstage/core',
|
||||
);
|
||||
expect(runObj.runPlain).toHaveBeenCalledWith(
|
||||
'yarn',
|
||||
'info',
|
||||
'--json',
|
||||
'@backstage/theme',
|
||||
);
|
||||
|
||||
expect(runObj.run).toHaveBeenCalledTimes(1);
|
||||
expect(runObj.run).toHaveBeenCalledWith('yarn', ['install']);
|
||||
|
||||
const lockfileContents = await fs.readFile('/yarn.lock', 'utf8');
|
||||
expect(lockfileContents).toEqual(customLockfileMockResult);
|
||||
|
||||
const packageA = await fs.readJson('/packages/a/package.json');
|
||||
expect(packageA).toEqual({
|
||||
name: 'a',
|
||||
dependencies: {
|
||||
'@backstage-extra/custom': '^1.0.1',
|
||||
'@backstage-extra/custom-two': '^2.0.0',
|
||||
'@backstage/core': '^1.0.5', // not bumped since new version is within range
|
||||
},
|
||||
});
|
||||
const packageB = await fs.readJson('/packages/b/package.json');
|
||||
expect(packageB).toEqual({
|
||||
name: 'b',
|
||||
dependencies: {
|
||||
'@backstage-extra/custom': '^1.1.0',
|
||||
'@backstage-extra/custom-two': '^2.0.0',
|
||||
'@backstage/core': '^1.0.3', // not bumped
|
||||
'@backstage/theme': '^2.0.0', // bumped since newer
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore not found packages', async () => {
|
||||
// Make sure all modules involved in package discovery are in the module cache before we mock fs
|
||||
await mapDependencies(paths.targetDir);
|
||||
await mapDependencies(paths.targetDir, '@backstage/*');
|
||||
mockFs({
|
||||
'/yarn.lock': lockfileMockResult,
|
||||
'/lerna.json': JSON.stringify({
|
||||
@@ -209,9 +349,10 @@ describe('bump', () => {
|
||||
jest.spyOn(runObj, 'run').mockResolvedValue(undefined);
|
||||
|
||||
const { log: logs } = await withLogCollector(['log'], async () => {
|
||||
await bump();
|
||||
await bump({ pattern: null } as unknown as Command);
|
||||
});
|
||||
expect(logs.filter(Boolean)).toEqual([
|
||||
'Using default pattern glob @backstage/*',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Package info not found, ignoring package @backstage/theme',
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
import fs from 'fs-extra';
|
||||
import chalk from 'chalk';
|
||||
import semver from 'semver';
|
||||
import minimatch from 'minimatch';
|
||||
import { Command } from 'commander';
|
||||
import { isError } from '@backstage/errors';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { run } from '../../lib/run';
|
||||
@@ -26,7 +28,7 @@ import {
|
||||
fetchPackageInfo,
|
||||
Lockfile,
|
||||
} from '../../lib/versioning';
|
||||
import { includedFilter, forbiddenDuplicatesFilter } from './lint';
|
||||
import { forbiddenDuplicatesFilter } from './lint';
|
||||
import { BACKSTAGE_JSON } from '@backstage/cli-common';
|
||||
|
||||
const DEP_TYPES = [
|
||||
@@ -36,6 +38,8 @@ const DEP_TYPES = [
|
||||
'optionalDependencies',
|
||||
];
|
||||
|
||||
const DEFAULT_PATTERN_GLOB = '@backstage/*';
|
||||
|
||||
type PkgVersionInfo = {
|
||||
range: string;
|
||||
target: string;
|
||||
@@ -43,14 +47,22 @@ type PkgVersionInfo = {
|
||||
location: string;
|
||||
};
|
||||
|
||||
export default async () => {
|
||||
export default async (cmd: Command) => {
|
||||
const lockfilePath = paths.resolveTargetRoot('yarn.lock');
|
||||
const lockfile = await Lockfile.load(lockfilePath);
|
||||
let pattern = cmd.pattern;
|
||||
|
||||
if (!pattern) {
|
||||
console.log(`Using default pattern glob ${DEFAULT_PATTERN_GLOB}`);
|
||||
pattern = DEFAULT_PATTERN_GLOB;
|
||||
} else {
|
||||
console.log(`Using custom pattern glob ${pattern}`);
|
||||
}
|
||||
|
||||
const findTargetVersion = createVersionFinder();
|
||||
|
||||
// First we discover all Backstage dependencies within our own repo
|
||||
const dependencyMap = await mapDependencies(paths.targetDir);
|
||||
const dependencyMap = await mapDependencies(paths.targetDir, pattern);
|
||||
|
||||
// Next check with the package registry to see which dependency ranges we need to bump
|
||||
const versionBumps = new Map<string, PkgVersionInfo[]>();
|
||||
@@ -88,10 +100,12 @@ export default async () => {
|
||||
}
|
||||
});
|
||||
|
||||
const filter = (name: string) => minimatch(name, pattern);
|
||||
|
||||
// Check for updates of transitive backstage dependencies
|
||||
await workerThreads(16, lockfile.keys(), async name => {
|
||||
// Only check @backstage packages and friends, we don't want this to do a full update of all deps
|
||||
if (!includedFilter(name)) {
|
||||
if (!filter(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -237,7 +251,7 @@ export default async () => {
|
||||
// Finally we make sure the new lockfile doesn't have any duplicates
|
||||
const dedupLockfile = await Lockfile.load(lockfilePath);
|
||||
const result = dedupLockfile.analyze({
|
||||
filter: includedFilter,
|
||||
filter,
|
||||
});
|
||||
|
||||
if (result.newVersions.length > 0) {
|
||||
|
||||
@@ -82,7 +82,10 @@ describe('mapDependencies', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
const dependencyMap = await mapDependencies(paths.targetDir);
|
||||
const dependencyMap = await mapDependencies(
|
||||
paths.targetDir,
|
||||
'@backstage/*',
|
||||
);
|
||||
expect(Array.from(dependencyMap)).toEqual([
|
||||
[
|
||||
'@backstage/core',
|
||||
|
||||
@@ -13,12 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import minimatch from 'minimatch';
|
||||
import { runPlain } from '../../lib/run';
|
||||
import { NotFoundError } from '../errors';
|
||||
|
||||
const PREFIX = '@backstage';
|
||||
|
||||
const DEP_TYPES = [
|
||||
'dependencies',
|
||||
'devDependencies',
|
||||
@@ -66,6 +64,7 @@ export async function fetchPackageInfo(
|
||||
/** Map all dependencies in the repo as dependency => dependents */
|
||||
export async function mapDependencies(
|
||||
targetDir: string,
|
||||
pattern: string,
|
||||
): Promise<Map<string, PkgVersionInfo[]>> {
|
||||
const { Project } = require('@lerna/project');
|
||||
const project = new Project(targetDir);
|
||||
@@ -78,7 +77,7 @@ export async function mapDependencies(
|
||||
);
|
||||
|
||||
for (const [name, range] of deps) {
|
||||
if (name.startsWith(PREFIX)) {
|
||||
if (minimatch(name, pattern)) {
|
||||
dependencyMap.set(
|
||||
name,
|
||||
(dependencyMap.get(name) ?? []).concat({
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { Table, TableColumn, Progress } from '@backstage/core-components';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
avatar: {
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/codemods
|
||||
|
||||
## 0.1.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
- @backstage/core-app-api@0.3.1
|
||||
- @backstage/core-components@0.8.3
|
||||
|
||||
## 0.1.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/codemods",
|
||||
"description": "A collection of codemods for Backstage projects",
|
||||
"version": "0.1.27",
|
||||
"version": "0.1.28",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/core-app-api
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4ce51ab0f1: Internal refactor of the `react-use` imports to use `react-use/lib/*` instead.
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
- @backstage/core-components@0.8.3
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/core-app-api",
|
||||
"description": "Core app API used by Backstage apps",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -30,9 +30,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/app-defaults": "^0.1.3",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-components": "^0.8.3",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@backstage/version-bridge": "^0.1.1",
|
||||
@@ -50,7 +50,7 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -24,7 +24,7 @@ import React, {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import {
|
||||
ApiProvider,
|
||||
ApiRegistry,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import React, { useMemo, useEffect, useState, PropsWithChildren } from 'react';
|
||||
import { useApi, appThemeApiRef, AppTheme } from '@backstage/core-plugin-api';
|
||||
import { useObservable } from 'react-use';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
|
||||
// This tries to find the most accurate match, but also falls back to less
|
||||
// accurate results in order to avoid errors.
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/core-components
|
||||
|
||||
## 0.8.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4ce51ab0f1: Internal refactor of the `react-use` imports to use `react-use/lib/*` instead.
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/core-components",
|
||||
"description": "Core components used by Backstage plugins and apps",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.3",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@backstage/errors": "^0.1.5",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@material-table/core": "^3.1.0",
|
||||
@@ -72,8 +72,8 @@
|
||||
"react-dom": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -19,7 +19,7 @@ import { act, fireEvent } from '@testing-library/react';
|
||||
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
import { CopyTextButton } from './CopyTextButton';
|
||||
import { errorApiRef } from '@backstage/core-plugin-api';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import useCopyToClipboard from 'react-use/lib/useCopyToClipboard';
|
||||
|
||||
jest.mock('popper.js', () => {
|
||||
const PopperJS = jest.requireActual('popper.js');
|
||||
@@ -32,14 +32,12 @@ jest.mock('popper.js', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('react-use', () => {
|
||||
const original = jest.requireActual('react-use');
|
||||
jest.mock('react-use/lib/useCopyToClipboard', () => {
|
||||
const original = jest.requireActual('react-use/lib/useCopyToClipboard');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useCopyToClipboard: jest
|
||||
.fn()
|
||||
.mockImplementation(original.useCopyToClipboard),
|
||||
__esModule: true,
|
||||
default: jest.fn().mockImplementation(original.default),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import IconButton from '@material-ui/core/IconButton';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import CopyIcon from '@material-ui/icons/FileCopy';
|
||||
import React, { MouseEventHandler, useEffect, useState } from 'react';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import useCopyToClipboard from 'react-use/lib/useCopyToClipboard';
|
||||
|
||||
/**
|
||||
* Properties for {@link CopyTextButton}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import React, { ReactNode, useState, useEffect } from 'react';
|
||||
import { useApi, storageApiRef } from '@backstage/core-plugin-api';
|
||||
import { useObservable } from 'react-use';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
import classNames from 'classnames';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useToggle } from 'react-use';
|
||||
import useToggle from 'react-use/lib/useToggle';
|
||||
import { AnsiLine } from './AnsiProcessor';
|
||||
|
||||
export function applySearchFilter(lines: AnsiLine[], searchText: string) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import useCopyToClipboard from 'react-use/lib/useCopyToClipboard';
|
||||
import { AnsiLine } from './AnsiProcessor';
|
||||
|
||||
export function useLogViewerSelection(lines: AnsiLine[]) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import List from '@material-ui/core/List';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useObservable } from 'react-use';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
import LoginRequestListItem from './LoginRequestListItem';
|
||||
import { useApi, oauthRequestApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
import Tooltip, { TooltipProps } from '@material-ui/core/Tooltip';
|
||||
import React, { useState } from 'react';
|
||||
import TextTruncate, { TextTruncateProps } from 'react-text-truncate';
|
||||
import { useMountedState } from 'react-use';
|
||||
import useMountedState from 'react-use/lib/useMountedState';
|
||||
|
||||
type Props = {
|
||||
text: TextTruncateProps['text'];
|
||||
|
||||
@@ -21,7 +21,7 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
import NavigateBeforeIcon from '@material-ui/icons/NavigateBefore';
|
||||
import NavigateNextIcon from '@material-ui/icons/NavigateNext';
|
||||
import { chunkArray } from './utils';
|
||||
import { useWindowSize } from 'react-use';
|
||||
import useWindowSize from 'react-use/lib/useWindowSize';
|
||||
|
||||
/* Import Components */
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { isEqual } from 'lodash';
|
||||
import qs from 'qs';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useDebounce } from 'react-use';
|
||||
import useDebounce from 'react-use/lib/useDebounce';
|
||||
|
||||
function stringify(queryParams: any): string {
|
||||
// Even though these setting don't look nice (e.g. escaped brackets), we should keep
|
||||
|
||||
@@ -21,7 +21,7 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import useLocalStorage from 'react-use/lib/useLocalStorage';
|
||||
import {
|
||||
sidebarConfig,
|
||||
SidebarContext,
|
||||
|
||||
@@ -25,7 +25,7 @@ import Button from '@material-ui/core/Button';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React, { useState } from 'react';
|
||||
import { useMount } from 'react-use';
|
||||
import useMount from 'react-use/lib/useMount';
|
||||
import { Progress } from '../../components/Progress';
|
||||
import { Content } from '../Content/Content';
|
||||
import { ContentHeader } from '../ContentHeader/ContentHeader';
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/core-plugin-api
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c534ef2242: Deprecated `OldIconComponent`. Existing usage should be replaced with `IconComponent`.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -623,7 +623,7 @@ export const oktaAuthApiRef: ApiRef<
|
||||
SessionApi
|
||||
>;
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export type OldIconComponent = ComponentType<SvgIconProps>;
|
||||
|
||||
// @alpha
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/core-plugin-api",
|
||||
"description": "Core API used by Backstage plugins",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.1",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -45,8 +45,8 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -43,5 +43,6 @@ export type IconComponent = ComponentType<{
|
||||
* migration, but it is not exported.
|
||||
*
|
||||
* @public
|
||||
* @deprecated This type will be removed, use {@link IconComponent} instead.
|
||||
*/
|
||||
export type OldIconComponent = ComponentType<SvgIconProps>;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# @backstage/create-app
|
||||
|
||||
## 0.4.11
|
||||
|
||||
## 0.4.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/create-app",
|
||||
"description": "A CLI that helps you create your own Backstage app",
|
||||
"version": "0.4.10",
|
||||
"version": "0.4.11",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/dev-utils
|
||||
|
||||
## 0.2.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4ce51ab0f1: Internal refactor of the `react-use` imports to use `react-use/lib/*` instead.
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
- @backstage/plugin-catalog-react@0.6.10
|
||||
- @backstage/core-app-api@0.3.1
|
||||
- @backstage/core-components@0.8.3
|
||||
|
||||
## 0.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/dev-utils",
|
||||
"description": "Utilities for developing Backstage plugins.",
|
||||
"version": "0.2.15",
|
||||
"version": "0.2.16",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -30,12 +30,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/app-defaults": "^0.1.3",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/core-components": "^0.8.3",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@backstage/catalog-model": "^0.9.7",
|
||||
"@backstage/integration-react": "^0.1.16",
|
||||
"@backstage/plugin-catalog-react": "^0.6.8",
|
||||
"@backstage/plugin-catalog-react": "^0.6.10",
|
||||
"@backstage/test-utils": "^0.2.0",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
@@ -55,7 +55,7 @@
|
||||
"react-dom": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.3",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/node": "^14.14.32"
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ import { appThemeApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { ListItemIcon, ListItemText, Menu, MenuItem } from '@material-ui/core';
|
||||
import AutoIcon from '@material-ui/icons/BrightnessAuto';
|
||||
import React, { cloneElement, useCallback, useState } from 'react';
|
||||
import { useObservable } from 'react-use';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
|
||||
type ThemeIconProps = {
|
||||
active?: boolean;
|
||||
|
||||
@@ -8,10 +8,13 @@ import { AnalyticsEvent } from '@backstage/core-plugin-api';
|
||||
import { ApiHolder } from '@backstage/core-plugin-api';
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
import { Config } from '@backstage/config';
|
||||
import { ConfigApi } from '@backstage/core-plugin-api';
|
||||
import { ErrorApi } from '@backstage/core-plugin-api';
|
||||
import { ErrorApiError } from '@backstage/core-plugin-api';
|
||||
import { ErrorApiErrorContext } from '@backstage/core-plugin-api';
|
||||
import { ExternalRouteRef } from '@backstage/core-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { ReactElement } from 'react';
|
||||
@@ -52,6 +55,43 @@ export class MockAnalyticsApi implements AnalyticsApi {
|
||||
// @public
|
||||
export function mockBreakpoint(options: { matches: boolean }): void;
|
||||
|
||||
// @public
|
||||
export class MockConfigApi implements ConfigApi {
|
||||
constructor(data: JsonObject);
|
||||
// (undocumented)
|
||||
get<T = JsonValue>(key?: string): T;
|
||||
// (undocumented)
|
||||
getBoolean(key: string): boolean;
|
||||
// (undocumented)
|
||||
getConfig(key: string): Config;
|
||||
// (undocumented)
|
||||
getConfigArray(key: string): Config[];
|
||||
// (undocumented)
|
||||
getNumber(key: string): number;
|
||||
// (undocumented)
|
||||
getOptional<T = JsonValue>(key?: string): T | undefined;
|
||||
// (undocumented)
|
||||
getOptionalBoolean(key: string): boolean | undefined;
|
||||
// (undocumented)
|
||||
getOptionalConfig(key: string): Config | undefined;
|
||||
// (undocumented)
|
||||
getOptionalConfigArray(key: string): Config[] | undefined;
|
||||
// (undocumented)
|
||||
getOptionalNumber(key: string): number | undefined;
|
||||
// (undocumented)
|
||||
getOptionalString(key: string): string | undefined;
|
||||
// (undocumented)
|
||||
getOptionalStringArray(key: string): string[] | undefined;
|
||||
// (undocumented)
|
||||
getString(key: string): string;
|
||||
// (undocumented)
|
||||
getStringArray(key: string): string[];
|
||||
// (undocumented)
|
||||
has(key: string): boolean;
|
||||
// (undocumented)
|
||||
keys(): string[];
|
||||
}
|
||||
|
||||
// @public
|
||||
export class MockErrorApi implements ErrorApi {
|
||||
constructor(options?: MockErrorApiOptions);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2022 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 { MockConfigApi } from './MockConfigApi';
|
||||
|
||||
describe('MockConfigApi', () => {
|
||||
it('is able to read some basic config', () => {
|
||||
const mock = new MockConfigApi({
|
||||
app: {
|
||||
title: 'Hello',
|
||||
},
|
||||
x: 1,
|
||||
y: false,
|
||||
z: [{ a: 3 }],
|
||||
});
|
||||
|
||||
expect(mock.getString('app.title')).toEqual('Hello');
|
||||
expect(mock.getNumber('x')).toEqual(1);
|
||||
expect(mock.getBoolean('y')).toEqual(false);
|
||||
expect(mock.getConfigArray('z')[0].getOptionalNumber('a')).toEqual(3);
|
||||
|
||||
expect(() => mock.getString('x')).toThrow(
|
||||
"Invalid type in config for key 'x' in 'mock-config', got number, wanted string",
|
||||
);
|
||||
expect(() => mock.getString('missing')).toThrow(
|
||||
"Missing required config value at 'missing'",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2022 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 { Config, ConfigReader } from '@backstage/config';
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import { ConfigApi } from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
* MockConfigApi is a thin wrapper around {@link @backstage/config#ConfigReader}
|
||||
* that can be used to mock configuration using a plain object.
|
||||
*
|
||||
* @public
|
||||
* @example
|
||||
* ```tsx
|
||||
* const mockConfig = new MockConfigApi({
|
||||
* app: { baseUrl: 'https://example.com' },
|
||||
* });
|
||||
*
|
||||
* const rendered = await renderInTestApp(
|
||||
* <TestApiProvider apis={[[configApiRef, mockConfig]]}>
|
||||
* <MyTestedComponent />
|
||||
* </TestApiProvider>,
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export class MockConfigApi implements ConfigApi {
|
||||
readonly #config: ConfigReader;
|
||||
|
||||
// NOTE: not extending in order to avoid inheriting the static `.fromConfigs`
|
||||
constructor(data: JsonObject) {
|
||||
this.#config = new ConfigReader(data);
|
||||
}
|
||||
|
||||
/** {@inheritdoc @backstage/config#Config.has} */
|
||||
has(key: string): boolean {
|
||||
return this.#config.has(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.keys} */
|
||||
keys(): string[] {
|
||||
return this.#config.keys();
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.get} */
|
||||
get<T = JsonValue>(key?: string): T {
|
||||
return this.#config.get(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptional} */
|
||||
getOptional<T = JsonValue>(key?: string): T | undefined {
|
||||
return this.#config.getOptional(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getConfig} */
|
||||
getConfig(key: string): Config {
|
||||
return this.#config.getConfig(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalConfig} */
|
||||
getOptionalConfig(key: string): Config | undefined {
|
||||
return this.#config.getOptionalConfig(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getConfigArray} */
|
||||
getConfigArray(key: string): Config[] {
|
||||
return this.#config.getConfigArray(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalConfigArray} */
|
||||
getOptionalConfigArray(key: string): Config[] | undefined {
|
||||
return this.#config.getOptionalConfigArray(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getNumber} */
|
||||
getNumber(key: string): number {
|
||||
return this.#config.getNumber(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalNumber} */
|
||||
getOptionalNumber(key: string): number | undefined {
|
||||
return this.#config.getOptionalNumber(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getBoolean} */
|
||||
getBoolean(key: string): boolean {
|
||||
return this.#config.getBoolean(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalBoolean} */
|
||||
getOptionalBoolean(key: string): boolean | undefined {
|
||||
return this.#config.getOptionalBoolean(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getString} */
|
||||
getString(key: string): string {
|
||||
return this.#config.getString(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalString} */
|
||||
getOptionalString(key: string): string | undefined {
|
||||
return this.#config.getOptionalString(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getStringArray} */
|
||||
getStringArray(key: string): string[] {
|
||||
return this.#config.getStringArray(key);
|
||||
}
|
||||
/** {@inheritdoc @backstage/config#Config.getOptionalStringArray} */
|
||||
getOptionalStringArray(key: string): string[] | undefined {
|
||||
return this.#config.getOptionalStringArray(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export { MockConfigApi } from './MockConfigApi';
|
||||
@@ -15,5 +15,6 @@
|
||||
*/
|
||||
|
||||
export * from './AnalyticsApi';
|
||||
export * from './ConfigApi';
|
||||
export * from './ErrorApi';
|
||||
export * from './StorageApi';
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/plugin-allure
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4ce51ab0f1: Internal refactor of the `react-use` imports to use `react-use/lib/*` instead.
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
- @backstage/plugin-catalog-react@0.6.10
|
||||
- @backstage/core-components@0.8.3
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-allure",
|
||||
"description": "A Backstage plugin that integrates with Allure",
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -23,9 +23,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.9.7",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/plugin-catalog-react": "^0.6.8",
|
||||
"@backstage/core-components": "^0.8.3",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@backstage/plugin-catalog-react": "^0.6.10",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -37,9 +37,9 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/dev-utils": "^0.2.16",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
MissingAnnotationEmptyState,
|
||||
Progress,
|
||||
} from '@backstage/core-components';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
const AllureReport = (props: { entity: Entity }) => {
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.5",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/core-components": "^0.8.3",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@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.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/dev-utils": "^0.2.16",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/plugin-apache-airflow
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4ce51ab0f1: Internal refactor of the `react-use` imports to use `react-use/lib/*` instead.
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
- @backstage/core-components@0.8.3
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-apache-airflow",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -20,8 +20,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/core-components": "^0.8.3",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
@@ -33,9 +33,9 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/dev-utils": "^0.2.16",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -31,7 +31,7 @@ import Typography from '@material-ui/core/Typography';
|
||||
import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { apacheAirflowApiRef } from '../../api';
|
||||
import { Dag } from '../../api/types';
|
||||
import { ScheduleIntervalLabel } from '../ScheduleIntervalLabel';
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { apacheAirflowApiRef } from '../../api';
|
||||
import { InstanceStatus } from '../../api/types';
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { apacheAirflowApiRef } from '../../api';
|
||||
import { InstanceVersion } from '../../api/types';
|
||||
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/plugin-api-docs
|
||||
|
||||
## 0.6.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 11b81683a9: Support customizing index page layouts via outlets
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@0.4.1
|
||||
- @backstage/plugin-catalog-react@0.6.10
|
||||
- @backstage/core-components@0.8.3
|
||||
- @backstage/plugin-catalog@0.7.7
|
||||
|
||||
## 0.6.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-api-docs",
|
||||
"description": "A Backstage plugin that helps represent API entities in the frontend",
|
||||
"version": "0.6.20",
|
||||
"version": "0.6.21",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -32,10 +32,10 @@
|
||||
"dependencies": {
|
||||
"@asyncapi/react-component": "^1.0.0-next.25",
|
||||
"@backstage/catalog-model": "^0.9.7",
|
||||
"@backstage/core-components": "^0.8.2",
|
||||
"@backstage/core-plugin-api": "^0.4.0",
|
||||
"@backstage/plugin-catalog": "^0.7.6",
|
||||
"@backstage/plugin-catalog-react": "^0.6.9",
|
||||
"@backstage/core-components": "^0.8.3",
|
||||
"@backstage/core-plugin-api": "^0.4.1",
|
||||
"@backstage/plugin-catalog": "^0.7.7",
|
||||
"@backstage/plugin-catalog-react": "^0.6.10",
|
||||
"@backstage/theme": "^0.2.14",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -54,9 +54,9 @@
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/core-app-api": "^0.3.0",
|
||||
"@backstage/dev-utils": "^0.2.15",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@backstage/core-app-api": "^0.3.1",
|
||||
"@backstage/dev-utils": "^0.2.16",
|
||||
"@backstage/test-utils": "^0.2.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/plugin-auth-backend
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e0e57817d2: Added Google Cloud Identity-Aware Proxy as an identity provider.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.10.2
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -9,6 +9,7 @@ import { CatalogApi } from '@backstage/catalog-client';
|
||||
import { Config } from '@backstage/config';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import express from 'express';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { JSONWebKey } from 'jose';
|
||||
import { Logger as Logger_2 } from 'winston';
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
@@ -59,8 +60,8 @@ export type Auth0ProviderOptions = {
|
||||
};
|
||||
|
||||
// @public
|
||||
export type AuthHandler<AuthResult> = (
|
||||
input: AuthResult,
|
||||
export type AuthHandler<TAuthResult> = (
|
||||
input: TAuthResult,
|
||||
) => Promise<AuthHandlerResult>;
|
||||
|
||||
// @public
|
||||
@@ -249,6 +250,11 @@ export const createBitbucketProvider: (
|
||||
options?: BitbucketProviderOptions | undefined,
|
||||
) => AuthProviderFactory;
|
||||
|
||||
// @public
|
||||
export function createGcpIapProvider(
|
||||
options: GcpIapProviderOptions,
|
||||
): AuthProviderFactory;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "createGithubProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
@@ -335,6 +341,26 @@ export const encodeState: (state: OAuthState) => string;
|
||||
// @public (undocumented)
|
||||
export const ensuresXRequestedWith: (req: express.Request) => boolean;
|
||||
|
||||
// @public
|
||||
export type GcpIapProviderOptions = {
|
||||
authHandler?: AuthHandler<GcpIapResult>;
|
||||
signIn: {
|
||||
resolver: SignInResolver<GcpIapResult>;
|
||||
};
|
||||
};
|
||||
|
||||
// @public
|
||||
export type GcpIapResult = {
|
||||
iapToken: GcpIapTokenInfo;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type GcpIapTokenInfo = {
|
||||
sub: string;
|
||||
email: string;
|
||||
[key: string]: JsonValue;
|
||||
};
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "TokenParams" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "getEntityClaims" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -661,14 +687,14 @@ export type SamlProviderOptions = {
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SignInInfo<AuthResult> = {
|
||||
export type SignInInfo<TAuthResult> = {
|
||||
profile: ProfileInfo;
|
||||
result: AuthResult;
|
||||
result: TAuthResult;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SignInResolver<AuthResult> = (
|
||||
info: SignInInfo<AuthResult>,
|
||||
export type SignInResolver<TAuthResult> = (
|
||||
info: SignInInfo<TAuthResult>,
|
||||
context: {
|
||||
tokenIssuer: TokenIssuer;
|
||||
catalogIdentityClient: CatalogIdentityClient;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-auth-backend",
|
||||
"description": "A Backstage backend plugin that handles authentication",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,12 +30,13 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.1",
|
||||
"@backstage/backend-common": "^0.10.2",
|
||||
"@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.1",
|
||||
"@backstage/types": "^0.1.1",
|
||||
"@google-cloud/firestore": "^4.15.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/passport": "^1.0.3",
|
||||
@@ -46,6 +47,7 @@
|
||||
"express-promise-router": "^4.1.0",
|
||||
"express-session": "^1.17.1",
|
||||
"fs-extra": "9.1.0",
|
||||
"google-auth-library": "^7.6.1",
|
||||
"helmet": "^4.0.0",
|
||||
"jose": "^1.27.1",
|
||||
"jwt-decode": "^3.1.0",
|
||||
@@ -72,7 +74,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.4",
|
||||
"@backstage/cli": "^0.10.5",
|
||||
"@types/body-parser": "^1.19.0",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express-session": "^1.17.2",
|
||||
@@ -83,7 +85,8 @@
|
||||
"@types/passport-saml": "^1.1.3",
|
||||
"@types/passport-strategy": "^0.2.35",
|
||||
"@types/xml2js": "^0.4.7",
|
||||
"msw": "^0.35.0"
|
||||
"msw": "^0.35.0",
|
||||
"supertest": "^6.1.3"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -13,5 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { createAwsAlbProvider } from './provider';
|
||||
export type { AwsAlbProviderOptions } from './provider';
|
||||
|
||||
@@ -18,7 +18,7 @@ import express from 'express';
|
||||
import { JWT } from 'jose';
|
||||
|
||||
import {
|
||||
ALB_ACCESSTOKEN_HEADER,
|
||||
ALB_ACCESS_TOKEN_HEADER,
|
||||
ALB_JWT_HEADER,
|
||||
AwsAlbAuthProvider,
|
||||
} from './provider';
|
||||
@@ -80,7 +80,7 @@ describe('AwsAlbAuthProvider', () => {
|
||||
header: jest.fn(name => {
|
||||
if (name === ALB_JWT_HEADER) {
|
||||
return mockJwt;
|
||||
} else if (name === ALB_ACCESSTOKEN_HEADER) {
|
||||
} else if (name === ALB_ACCESS_TOKEN_HEADER) {
|
||||
return mockAccessToken;
|
||||
}
|
||||
return undefined;
|
||||
@@ -88,7 +88,7 @@ describe('AwsAlbAuthProvider', () => {
|
||||
} as unknown as express.Request;
|
||||
const mockRequestWithoutJwt = {
|
||||
header: jest.fn(name => {
|
||||
if (name === ALB_ACCESSTOKEN_HEADER) {
|
||||
if (name === ALB_ACCESS_TOKEN_HEADER) {
|
||||
return mockAccessToken;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AuthHandler,
|
||||
AuthProviderFactory,
|
||||
@@ -35,7 +36,7 @@ import { AuthenticationError } from '@backstage/errors';
|
||||
import { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse';
|
||||
|
||||
export const ALB_JWT_HEADER = 'x-amzn-oidc-data';
|
||||
export const ALB_ACCESSTOKEN_HEADER = 'x-amzn-oidc-accesstoken';
|
||||
export const ALB_ACCESS_TOKEN_HEADER = 'x-amzn-oidc-accesstoken';
|
||||
|
||||
type Options = {
|
||||
region: string;
|
||||
@@ -134,7 +135,7 @@ export class AwsAlbAuthProvider implements AuthProviderRouteHandlers {
|
||||
|
||||
private async getResult(req: express.Request): Promise<AwsAlbResult> {
|
||||
const jwt = req.header(ALB_JWT_HEADER);
|
||||
const accessToken = req.header(ALB_ACCESSTOKEN_HEADER);
|
||||
const accessToken = req.header(ALB_ACCESS_TOKEN_HEADER);
|
||||
|
||||
if (jwt === undefined) {
|
||||
throw new AuthenticationError(
|
||||
@@ -144,7 +145,7 @@ export class AwsAlbAuthProvider implements AuthProviderRouteHandlers {
|
||||
|
||||
if (accessToken === undefined) {
|
||||
throw new AuthenticationError(
|
||||
`Missing ALB OIDC header: ${ALB_ACCESSTOKEN_HEADER}`,
|
||||
`Missing ALB OIDC header: ${ALB_ACCESS_TOKEN_HEADER}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 { ConflictError } from '@backstage/errors';
|
||||
import { OAuth2Client } from 'google-auth-library';
|
||||
import { createTokenValidator, parseRequestToken } from './helpers';
|
||||
|
||||
const validJwt =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZvbyIsImlzcyI6ImZvbyJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.T2BNS4G-6RoiFnXc8Q8TiwdWzTpNitY8jcsGM3N3-Yo';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('helpers', () => {
|
||||
describe('createTokenValidator', () => {
|
||||
it('runs the happy path', async () => {
|
||||
const mockClient = {
|
||||
getIapPublicKeys: async () => ({ pubkeys: '' }),
|
||||
verifySignedJwtWithCertsAsync: async () => ({
|
||||
getPayload: () => ({ sub: 's', email: 'e@mail.com' }),
|
||||
}),
|
||||
};
|
||||
const validator = createTokenValidator(
|
||||
'a',
|
||||
mockClient as unknown as OAuth2Client,
|
||||
);
|
||||
await expect(validator(validJwt)).resolves.toMatchObject({
|
||||
sub: 's',
|
||||
email: 'e@mail.com',
|
||||
});
|
||||
});
|
||||
|
||||
it('throws if the client throws', async () => {
|
||||
const mockClient = {
|
||||
getIapPublicKeys: async () => {
|
||||
throw new TypeError('bam');
|
||||
},
|
||||
};
|
||||
const validator = createTokenValidator(
|
||||
'a',
|
||||
mockClient as unknown as OAuth2Client,
|
||||
);
|
||||
await expect(validator(validJwt)).rejects.toThrowError(TypeError);
|
||||
});
|
||||
|
||||
it('rejects empty payload', async () => {
|
||||
const mockClient = {
|
||||
getIapPublicKeys: async () => ({ pubkeys: '' }),
|
||||
verifySignedJwtWithCertsAsync: async () => ({
|
||||
getPayload: () => undefined,
|
||||
}),
|
||||
};
|
||||
const validator = createTokenValidator(
|
||||
'a',
|
||||
mockClient as unknown as OAuth2Client,
|
||||
);
|
||||
await expect(validator(validJwt)).rejects.toMatchObject({
|
||||
name: 'TypeError',
|
||||
message: 'Token had no payload',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseRequestToken', () => {
|
||||
it('runs the happy path', async () => {
|
||||
await expect(
|
||||
parseRequestToken(
|
||||
validJwt,
|
||||
async () => ({ sub: 's', email: 'e@mail.com' } as any),
|
||||
),
|
||||
).resolves.toMatchObject({
|
||||
iapToken: {
|
||||
sub: 's',
|
||||
email: 'e@mail.com',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects bad tokens', async () => {
|
||||
await expect(
|
||||
parseRequestToken(7, undefined as any),
|
||||
).rejects.toMatchObject({
|
||||
name: 'AuthenticationError',
|
||||
message: 'Missing Google IAP header: x-goog-iap-jwt-assertion',
|
||||
});
|
||||
await expect(
|
||||
parseRequestToken(undefined, undefined as any),
|
||||
).rejects.toMatchObject({
|
||||
name: 'AuthenticationError',
|
||||
message: 'Missing Google IAP header: x-goog-iap-jwt-assertion',
|
||||
});
|
||||
await expect(
|
||||
parseRequestToken('', undefined as any),
|
||||
).rejects.toMatchObject({
|
||||
name: 'AuthenticationError',
|
||||
message: 'Missing Google IAP header: x-goog-iap-jwt-assertion',
|
||||
});
|
||||
});
|
||||
|
||||
it('translates validator errors', async () => {
|
||||
await expect(
|
||||
parseRequestToken(validJwt, async () => {
|
||||
throw new ConflictError('Ouch');
|
||||
}),
|
||||
).rejects.toMatchObject({
|
||||
name: 'AuthenticationError',
|
||||
message: 'Google IAP token verification failed, ConflictError: Ouch',
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects bad token payloads', async () => {
|
||||
await expect(
|
||||
parseRequestToken(validJwt, async () => ({ sub: 'a' } as any)),
|
||||
).rejects.toMatchObject({
|
||||
name: 'AuthenticationError',
|
||||
message: 'Google IAP token payload is missing sub and/or email claim',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user