Merge branch 'master' into fact-retriever-async
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@backstage/plugin-code-coverage': minor
|
||||
---
|
||||
|
||||
Cleaned up API exports.
|
||||
|
||||
The `Router` export has been removed; users are expected to use `EntityCodeCoverageContent` instead.
|
||||
|
||||
The `isPluginApplicableToEntity` helper has been deprecated, in favor of the `isCodeCoverageAvailable` helper.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-code-coverage-backend': minor
|
||||
---
|
||||
|
||||
Cleaned up API exports.
|
||||
|
||||
The `CodeCoverageApi` and `makeRouter` exports have been removed from the backend, since they were not meant to be exported in the first place.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-fossa': patch
|
||||
---
|
||||
|
||||
Allow configuration of base URL for Fossa links
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-tech-radar': patch
|
||||
---
|
||||
|
||||
Update tech-radar documentation on how to use an external json data source with dates.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': minor
|
||||
---
|
||||
|
||||
Add new endpoints to Kubernetes backend plugin
|
||||
|
||||
BREAKING: Kubernetes backend plugin now depends on CatalogApi
|
||||
|
||||
```typescript
|
||||
// Create new CatalogClient
|
||||
const catalogApi = new CatalogClient({ discoveryApi: env.discovery });
|
||||
const { router } = await KubernetesBuilder.createBuilder({
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
// Inject it into createBuilder params
|
||||
catalogApi,
|
||||
}).build();
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
new setUserAsOwner flag for publish:gitlab action
|
||||
|
||||
The field default is `false`. When true it will use the token configured in the gitlab integration for the matching host, to try and set the user logged in via `repoUrlPicker` `requestUserCredentials` OAuth flow as owner of the repository created in GitLab.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
'@backstage/plugin-gcp-projects': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-techdocs-module-addons-contrib': patch
|
||||
---
|
||||
|
||||
Updated dependency `@react-hookz/web` to `^15.0.0`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/config-loader': patch
|
||||
---
|
||||
|
||||
Updated dependency `typescript-json-schema` to `^0.54.0`.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
'@backstage/plugin-kubernetes-common': patch
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
---
|
||||
|
||||
Updated dependency `@kubernetes/client-node` to `^0.17.0`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': minor
|
||||
---
|
||||
|
||||
Allowed post method on /refresh path
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
@@ -178,7 +178,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
cron:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: backstage/actions/cron@v0.5.0
|
||||
- uses: backstage/actions/cron@v0.5.2
|
||||
with:
|
||||
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
|
||||
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
|
||||
|
||||
@@ -69,17 +69,17 @@ jobs:
|
||||
working-directory: ./example-app
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: './example-app'
|
||||
file: ./example-app/packages/backend/Dockerfile
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -10,4 +10,4 @@ jobs:
|
||||
if: github.repository == 'backstage/backstage'
|
||||
steps:
|
||||
- name: Issue sync
|
||||
uses: backstage/actions/issue-sync@v0.5.0
|
||||
uses: backstage/actions/issue-sync@v0.5.2
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# This workflow is used to trigger the "PR Review Comment" workflow. This chaining is needed
|
||||
# because workflows triggered by pull_request_review_comment do not have access to secrets.
|
||||
|
||||
name: PR Review Comment Trigger
|
||||
on:
|
||||
pull_request_review_comment:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# The "PR Review Comment" workflow will check the success status of this workflow and only mark
|
||||
# the PR for re-review if this workflow was successful, which is when the author leaves a review comment.
|
||||
if: github.repository == 'backstage/backstage' && github.event.comment.user.id == github.event.pull_request.user.id
|
||||
|
||||
steps:
|
||||
- run: echo "This PR needs another review"
|
||||
@@ -0,0 +1,24 @@
|
||||
# This workflow is triggered by "PR Review Comment Trigger"
|
||||
|
||||
name: PR Review Comment
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [PR Review Comment Trigger]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
re-review:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# The triggering workflow will report success if the PR needs re-review
|
||||
if: github.repository == 'backstage/backstage' && github.event.workflow_run.conclusion == 'success'
|
||||
|
||||
steps:
|
||||
- uses: backstage/actions/re-review@v0.5.2
|
||||
with:
|
||||
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
|
||||
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
|
||||
installation-id: ${{ secrets.BACKSTAGE_GOALIE_INSTALLATION_ID }}
|
||||
project-id: PVT_kwDOBFKqdc02LQ
|
||||
issue-number: ${{ github.event.workflow_run.pull_requests[0].number }}
|
||||
@@ -9,9 +9,6 @@ on:
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
pull_request_review_comment:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
@@ -21,7 +18,7 @@ jobs:
|
||||
if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request )
|
||||
steps:
|
||||
- name: PR sync
|
||||
uses: backstage/actions/pr-sync@v0.5.0
|
||||
uses: backstage/actions/pr-sync@v0.5.2
|
||||
with:
|
||||
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
|
||||
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.0
|
||||
uses: backstage/actions/yarn-install@v0.5.2
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
- name: storybook yarn install
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi
|
||||
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
|
||||
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
|
||||
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
|
||||
| [Expedia Group](https://www.expediagroup.com) | [@guillermomanzo](https://github.com/guillermomanzo), [Sheena Sharma](mailto:shesharma@expediagroup.com) | EG Common Developer Toolkit |
|
||||
| [Expedia Group](https://www.expediagroup.com) | [@guillermomanzo](https://github.com/guillermomanzo), [Sheena Sharma](mailto:shesharma@expediagroup.com), [@ajbw](https://github.com/ajbw) | EG Common Developer Toolkit |
|
||||
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
|
||||
| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling |
|
||||
| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
|
||||
@@ -188,5 +188,5 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi
|
||||
| [Cho Tot](https://www.chotot.com) | [Chotot Team](mailto:sre@chotot.vn) | Internal developer portal, service catalog with CI/CD tools. |
|
||||
| [William Hill](https://www.williamhillgroup.com/) | [Pat Mills](mailto:pat.mills@williamhill.com), [Nathan Flynn](mailto:nflynn@williamhill.co.uk), and [Nishkarsh Raj](mailto:nishkarsh.raj@williamhill.co.uk) | William Hill are leveraging Backstage to build our Engineering Portal. Our mission is to centralize the software catalog inventory to enable service discoverability, reduce the onboarding time for new Engineers, provide a single pane of glass to accelerate Developer Productivity and Save Engineers time. Our aspiration is to create an InnerSource community focussed on organization-wide patterns that are re-usable and can be self-served with the Scaffolder. |
|
||||
| [Vodafone NewZealand Limited](https://vodafone.co.nz) | [Ankit Gupta](mailto:ankit.gupta@vodafone.nz), [DevOps COE](mailto:devopstooling@vodafone.nz) | Vodafone NZ are leveraging Backstage to build centralised and self service Engineering Portal. Our mission is to standardised Pipeline templates across the Engineering teams, One shop stop to create the pipelines and repository with a template approach which reduces creation part from days to minutes and no wait time for developers. A unified view for Azure DevOps pipeline, Azure Repo pull requests, Deployment status from Azure RedHat Openshift-ArgoCD and SonarQube Security and code quality scans report on a single pan to provide a streamlined view for all microservices across the app stack. |
|
||||
| [Coamo](http://www.coamo.com.br) | [@holiiveira](https://github.com/holiiveira), [@gpxlnx](https://github.com/gpxlnx) | We're starting to use it as the main tool of a DevOps platform. Our goal is to provide software templates, centralize our software catalog enabling efficient service discovery, and make it easy to manage the entire software ecosystem in one place.
|
||||
| [Coamo](http://www.coamo.com.br) | [@holiiveira](https://github.com/holiiveira), [@gpxlnx](https://github.com/gpxlnx) | We're starting to use it as the main tool of a DevOps platform. Our goal is to provide software templates, centralize our software catalog enabling efficient service discovery, and make it easy to manage the entire software ecosystem in one place.
|
||||
|
|
||||
|
||||
@@ -350,6 +350,7 @@ router.get('/auth/providerA/handler/frame');
|
||||
router.post('/auth/providerA/handler/frame');
|
||||
router.post('/auth/providerA/logout');
|
||||
router.get('/auth/providerA/refresh'); // if supported
|
||||
router.post('/auth/providerA/refresh'); // if supported
|
||||
```
|
||||
|
||||
As you can see each endpoint is prefixed with both `/auth` and its provider
|
||||
|
||||
@@ -79,7 +79,7 @@ privateKey: |
|
||||
### Including in Integrations Config
|
||||
|
||||
Once the credentials are stored in a YAML file generated by `create-github-app`,
|
||||
or manually by following the [GitHub Enterprise](#gitHub-enterprise)
|
||||
or manually by following the [GitHub Enterprise](#github-enterprise)
|
||||
instructions, they can be included in the `app-config.yaml` under the
|
||||
`integrations` section.
|
||||
|
||||
|
||||
@@ -341,7 +341,8 @@ separate Docker images.
|
||||
The backend container can be built by running the following command:
|
||||
|
||||
```bash
|
||||
yarn run docker-build
|
||||
yarn run build
|
||||
yarn run build-image
|
||||
```
|
||||
|
||||
This will create a container called `example-backend`.
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Adopters Community Sessions
|
||||
date: June 15, 2022
|
||||
category: Upcoming
|
||||
category: Meetup
|
||||
description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc.
|
||||
youtubeUrl: https://youtu.be/aKZnjnE5Wy8
|
||||
youtubeImgUrl: https://backstage.io/img/b-sessions.png
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: Contributor Community Sessions
|
||||
date: June 22, 2022
|
||||
category: Upcoming
|
||||
category: Meetup
|
||||
description: Join the maintainers and contributors for the Contributor Community Sessions
|
||||
youtubeUrl: https://youtu.be/aKZnjnE5Wy8
|
||||
youtubeUrl: https://youtu.be/E-jWqWXBxUY
|
||||
youtubeImgUrl: https://backstage.io/img/b-sessions.png
|
||||
rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com
|
||||
eventUrl: https://github.com/backstage/community/issues/49
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Adopters Community Sessions
|
||||
date: July 20, 2022
|
||||
category: Upcoming
|
||||
description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc.
|
||||
youtubeUrl: https://youtu.be/4VFNlPxWcx8
|
||||
youtubeImgUrl: https://backstage.io/img/b-sessions.png
|
||||
rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com
|
||||
eventUrl: https://github.com/backstage/community/issues/52
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Contributor Community Sessions
|
||||
date: July 27, 2022
|
||||
category: Upcoming
|
||||
description: Join the maintainers and contributors for the Contributor Community Sessions
|
||||
youtubeUrl: https://youtu.be/4VFNlPxWcx8
|
||||
youtubeImgUrl: https://backstage.io/img/b-sessions.png
|
||||
rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com
|
||||
eventUrl: https://github.com/backstage/community/issues/52
|
||||
@@ -34,7 +34,7 @@ const Background = props => {
|
||||
<Block.Container style={{ justifyContent: 'flex-start' }}>
|
||||
<Block.MediaFrame>
|
||||
<iframe
|
||||
src="https://www.youtube.com/embed/aKZnjnE5Wy8"
|
||||
src="https://www.youtube.com/embed/4VFNlPxWcx8"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
@@ -45,7 +45,7 @@ const Background = props => {
|
||||
<iframe
|
||||
width="300"
|
||||
height="500"
|
||||
src="https://www.youtube.com/live_chat?v=aKZnjnE5Wy8&embed_domain=backstage.io&dark_theme=1"
|
||||
src="https://www.youtube.com/live_chat?v=4VFNlPxWcx8&embed_domain=backstage.io&dark_theme=1"
|
||||
></iframe>
|
||||
</Block.MediaFrame>
|
||||
</Block.Container>
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend';
|
||||
import { Router } from 'express';
|
||||
import { PluginEnvironment } from '../types';
|
||||
import { CatalogClient } from '@backstage/catalog-client';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
const catalogApi = new CatalogClient({ discoveryApi: env.discovery });
|
||||
const { router } = await KubernetesBuilder.createBuilder({
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
catalogApi,
|
||||
}).build();
|
||||
return router;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
"json-schema-merge-allof": "^0.8.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"typescript-json-schema": "^0.53.0",
|
||||
"typescript-json-schema": "^0.54.0",
|
||||
"yaml": "^1.9.2",
|
||||
"yup": "^0.32.9"
|
||||
},
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"react-syntax-highlighter": "^15.4.5",
|
||||
"react-text-truncate": "^0.19.0",
|
||||
"react-use": "^17.3.2",
|
||||
"@react-hookz/web": "^14.0.0",
|
||||
"@react-hookz/web": "^15.0.0",
|
||||
"react-virtualized-auto-sizer": "^1.0.6",
|
||||
"react-window": "^1.8.6",
|
||||
"remark-gfm": "^3.0.1",
|
||||
|
||||
@@ -140,6 +140,7 @@ export async function createRouter(
|
||||
}
|
||||
if (provider.refresh) {
|
||||
r.get('/refresh', provider.refresh.bind(provider));
|
||||
r.post('/refresh', provider.refresh.bind(provider));
|
||||
}
|
||||
|
||||
router.use(`/${providerId}`, r);
|
||||
|
||||
@@ -10,27 +10,10 @@ import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "CodeCoverageApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export interface CodeCoverageApi {
|
||||
// (undocumented)
|
||||
name: string;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function createRouter(options: RouterOptions): Promise<express.Router>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "makeRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const makeRouter: (options: RouterOptions) => Promise<express.Router>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RouterOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface RouterOptions {
|
||||
// (undocumented)
|
||||
config: Config;
|
||||
|
||||
@@ -20,4 +20,5 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export * from './service/router';
|
||||
export { createRouter } from './service/router';
|
||||
export type { RouterOptions } from './service/router';
|
||||
|
||||
@@ -35,6 +35,11 @@ import { Jacoco } from './converter/jacoco';
|
||||
import { Converter } from './converter';
|
||||
import { getEntitySourceLocation } from '@backstage/catalog-model';
|
||||
|
||||
/**
|
||||
* Options for {@link createRouter}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface RouterOptions {
|
||||
config: Config;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
@@ -211,6 +216,11 @@ export const makeRouter = async (
|
||||
return router;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a code-coverage plugin backend router.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export async function createRouter(
|
||||
options: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
|
||||
@@ -9,8 +9,6 @@ import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "codeCoveragePlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const codeCoveragePlugin: BackstagePlugin<
|
||||
{
|
||||
@@ -19,20 +17,12 @@ export const codeCoveragePlugin: BackstagePlugin<
|
||||
{}
|
||||
>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "EntityCodeCoverageContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export const EntityCodeCoverageContent: () => JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "isCodeCoverageAvailable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
const isCodeCoverageAvailable: (entity: Entity) => boolean;
|
||||
export { isCodeCoverageAvailable };
|
||||
export { isCodeCoverageAvailable as isPluginApplicableToEntity };
|
||||
// @public
|
||||
export function isCodeCoverageAvailable(entity: Entity): boolean;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "Router" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export const Router: () => JSX.Element;
|
||||
// @public @deprecated (undocumented)
|
||||
export const isPluginApplicableToEntity: typeof isCodeCoverageAvailable;
|
||||
```
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import 'highlight.js/styles/atom-one-dark.css';
|
||||
import highlight from 'highlight.js';
|
||||
|
||||
|
||||
@@ -13,16 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { CodeCoveragePage } from './CodeCoveragePage';
|
||||
import { MissingAnnotationEmptyState } from '@backstage/core-components';
|
||||
|
||||
export const isCodeCoverageAvailable = (entity: Entity) =>
|
||||
Boolean(entity.metadata.annotations?.['backstage.io/code-coverage']);
|
||||
/**
|
||||
* Returns true if the given entity has code coverage enabled.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function isCodeCoverageAvailable(entity: Entity) {
|
||||
return Boolean(entity.metadata.annotations?.['backstage.io/code-coverage']);
|
||||
}
|
||||
|
||||
export const Router = () => {
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const Router = (): JSX.Element => {
|
||||
const { entity } = useEntity();
|
||||
|
||||
if (!isCodeCoverageAvailable(entity)) {
|
||||
@@ -30,5 +40,6 @@ export const Router = () => {
|
||||
<MissingAnnotationEmptyState annotation="backstage.io/code-coverage" />
|
||||
);
|
||||
}
|
||||
|
||||
return <CodeCoveragePage />;
|
||||
};
|
||||
|
||||
@@ -20,9 +20,13 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
import { isCodeCoverageAvailable } from './components/Router';
|
||||
|
||||
export { codeCoveragePlugin, EntityCodeCoverageContent } from './plugin';
|
||||
export {
|
||||
Router,
|
||||
isCodeCoverageAvailable,
|
||||
isCodeCoverageAvailable as isPluginApplicableToEntity,
|
||||
} from './components/Router';
|
||||
export { isCodeCoverageAvailable };
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @deprecated Use `isPluginApplicableToEntity` instead.
|
||||
*/
|
||||
export const isPluginApplicableToEntity = isCodeCoverageAvailable;
|
||||
|
||||
@@ -23,6 +23,9 @@ import {
|
||||
discoveryApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const codeCoveragePlugin = createPlugin({
|
||||
id: 'code-coverage',
|
||||
routes: {
|
||||
@@ -37,6 +40,11 @@ export const codeCoveragePlugin = createPlugin({
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
* An entity code coverage page.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const EntityCodeCoverageContent = codeCoveragePlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'EntityCodeCoverageContent',
|
||||
|
||||
@@ -43,9 +43,12 @@ proxy:
|
||||
headers:
|
||||
Authorization: token ${FOSSA_API_TOKEN}
|
||||
|
||||
# if you have a fossa organization, configure your id here
|
||||
fossa:
|
||||
# if you have a fossa organization, configure your id here
|
||||
organizationId: <your-fossa-organization-id>
|
||||
# if you have a self-managed fossa instance,
|
||||
# configure the baseUrl to use for links to the fossa page here
|
||||
externalLinkBaseUrl: <your fossa url>
|
||||
```
|
||||
|
||||
4. Get an api-token and provide `FOSSA_AUTH_HEADER` as env variable (https://app.fossa.com/account/settings/integrations/api_tokens)
|
||||
|
||||
Vendored
+7
-1
@@ -20,6 +20,12 @@ export interface Config {
|
||||
* The organization id in fossa.
|
||||
* @visibility frontend
|
||||
*/
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
|
||||
/**
|
||||
* The base url to use for external links (from Backstage to Fossa).
|
||||
* @visibility frontend
|
||||
*/
|
||||
externalLinkBaseUrl?: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -175,6 +175,58 @@ describe('FossaClient', () => {
|
||||
expect(summary).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should allow custom external link base url', async () => {
|
||||
client = new FossaClient({
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
organizationId: '8736',
|
||||
externalLinkBaseUrl: 'https://custom.fossa.com', // overrides the default app.fossa.com
|
||||
});
|
||||
server.use(
|
||||
rest.get(`${mockBaseUrl}/fossa/projects`, (req, res, ctx) => {
|
||||
const expectedQuery =
|
||||
'count=1000&page=0&sort=title%2B&organizationId=8736&title=our-service';
|
||||
if (req.url.searchParams.toString() !== expectedQuery) {
|
||||
return res(
|
||||
ctx.status(500),
|
||||
ctx.body(
|
||||
`${req.url.searchParams.toString()} !== ${expectedQuery}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return res(
|
||||
ctx.json([
|
||||
{
|
||||
locator: 'custom+8736/our-service',
|
||||
title: 'our-service',
|
||||
default_branch: 'develop',
|
||||
revisions: [
|
||||
{
|
||||
updatedAt: '2020-01-01T00:00:00Z',
|
||||
dependency_count: 160,
|
||||
unresolved_licensing_issue_count: 5,
|
||||
unresolved_issue_count: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
]),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
const summary = await client.getFindingSummary('our-service');
|
||||
|
||||
expect(summary).toEqual({
|
||||
timestamp: '2020-01-01T00:00:00Z',
|
||||
issueCount: 5,
|
||||
dependencyCount: 160,
|
||||
projectDefaultBranch: 'develop',
|
||||
projectUrl:
|
||||
'https://custom.fossa.com/projects/custom%2B8736%2Four-service',
|
||||
} as FindingSummary);
|
||||
});
|
||||
|
||||
it('should handle 404 status', async () => {
|
||||
server.use(
|
||||
rest.get(`${mockBaseUrl}/fossa/projects`, (_req, res, ctx) => {
|
||||
|
||||
@@ -36,20 +36,24 @@ export class FossaClient implements FossaApi {
|
||||
discoveryApi: DiscoveryApi;
|
||||
identityApi: IdentityApi;
|
||||
organizationId?: string;
|
||||
externalLinkBaseUrl: string;
|
||||
private readonly limit = pLimit(5);
|
||||
|
||||
constructor({
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
organizationId,
|
||||
externalLinkBaseUrl = 'https://app.fossa.com',
|
||||
}: {
|
||||
discoveryApi: DiscoveryApi;
|
||||
identityApi: IdentityApi;
|
||||
organizationId?: string;
|
||||
externalLinkBaseUrl?: string;
|
||||
}) {
|
||||
this.discoveryApi = discoveryApi;
|
||||
this.identityApi = identityApi;
|
||||
this.organizationId = organizationId;
|
||||
this.externalLinkBaseUrl = externalLinkBaseUrl;
|
||||
}
|
||||
|
||||
private async callApi<T>(
|
||||
@@ -104,9 +108,9 @@ export class FossaClient implements FossaApi {
|
||||
revision.unresolved_issue_count,
|
||||
dependencyCount: revision.dependency_count,
|
||||
projectDefaultBranch: project.default_branch,
|
||||
projectUrl: `https://app.fossa.com/projects/${encodeURIComponent(
|
||||
project.locator,
|
||||
)}`,
|
||||
projectUrl: `${
|
||||
this.externalLinkBaseUrl
|
||||
}/projects/${encodeURIComponent(project.locator)}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ export const fossaPlugin = createPlugin({
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
organizationId: configApi.getOptionalString('fossa.organizationId'),
|
||||
externalLinkBaseUrl: configApi.getOptionalString(
|
||||
'fossa.externalLinkBaseUrl',
|
||||
),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"@react-hookz/web": "^14.0.0",
|
||||
"@react-hookz/web": "^15.0.0",
|
||||
"react-router-dom": "6.0.0-beta.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
import { Config } from '@backstage/config';
|
||||
import { Duration } from 'luxon';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
@@ -108,6 +109,7 @@ export class KubernetesBuilder {
|
||||
protected buildRouter(
|
||||
objectsProvider: KubernetesObjectsProvider,
|
||||
clusterSupplier: KubernetesClustersSupplier,
|
||||
catalogApi: CatalogApi,
|
||||
): express.Router;
|
||||
// (undocumented)
|
||||
protected buildServiceLocator(
|
||||
@@ -155,6 +157,8 @@ export interface KubernetesClustersSupplier {
|
||||
|
||||
// @alpha (undocumented)
|
||||
export interface KubernetesEnvironment {
|
||||
// (undocumented)
|
||||
catalogApi: CatalogApi;
|
||||
// (undocumented)
|
||||
config: Config;
|
||||
// (undocumented)
|
||||
@@ -268,6 +272,8 @@ export interface ObjectToFetch {
|
||||
|
||||
// @alpha (undocumented)
|
||||
export interface RouterOptions {
|
||||
// (undocumented)
|
||||
catalogApi: CatalogApi;
|
||||
// (undocumented)
|
||||
clusterSupplier?: KubernetesClustersSupplier;
|
||||
// (undocumented)
|
||||
|
||||
@@ -37,12 +37,14 @@
|
||||
"dependencies": {
|
||||
"@azure/identity": "^2.0.4",
|
||||
"@backstage/backend-common": "^0.14.1-next.2",
|
||||
"@backstage/catalog-client": "^1.0.4-next.1",
|
||||
"@backstage/catalog-model": "^1.1.0-next.2",
|
||||
"@backstage/config": "^1.0.1",
|
||||
"@backstage/errors": "^1.1.0-next.0",
|
||||
"@backstage/plugin-kubernetes-common": "^0.4.0-next.1",
|
||||
"@backstage/plugin-auth-node": "^0.2.3-next.1",
|
||||
"@backstage/plugin-kubernetes-common": "^0.4.0-next.0",
|
||||
"@google-cloud/container": "^4.0.0",
|
||||
"@kubernetes/client-node": "^0.16.0",
|
||||
"@kubernetes/client-node": "^0.17.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/luxon": "^2.0.4",
|
||||
"aws-sdk": "^2.840.0",
|
||||
|
||||
@@ -0,0 +1,545 @@
|
||||
/*
|
||||
* 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 { errorHandler } from '@backstage/backend-common';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import Router from 'express-promise-router';
|
||||
import { addResourceRoutesToRouter } from './resourcesRoutes';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
describe('resourcesRoutes', () => {
|
||||
let app: express.Express;
|
||||
|
||||
beforeAll(() => {
|
||||
app = express();
|
||||
app.use(express.json());
|
||||
const router = Router();
|
||||
addResourceRoutesToRouter(
|
||||
router,
|
||||
{
|
||||
getEntityByRef: jest.fn().mockImplementation(entityRef => {
|
||||
if (entityRef.name === 'noentity') {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
return Promise.resolve({
|
||||
kind: entityRef.kind,
|
||||
metadata: {
|
||||
name: entityRef.name,
|
||||
namespace: entityRef.namespace,
|
||||
},
|
||||
} as Entity);
|
||||
}),
|
||||
} as any,
|
||||
{
|
||||
getKubernetesObjectsByEntity: jest.fn().mockImplementation(args => {
|
||||
if (args.entity.metadata.name === 'inject500') {
|
||||
return Promise.reject(new Error('some internal error'));
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
items: [
|
||||
{
|
||||
clusterOne: {
|
||||
pods: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'pod1',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}),
|
||||
getCustomResourcesByEntity: jest.fn().mockImplementation(args => {
|
||||
if (args.entity.metadata.name === 'inject500') {
|
||||
return Promise.reject(new Error('some internal error'));
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
items: [
|
||||
{
|
||||
clusterOne: {
|
||||
pods: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'pod1',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}),
|
||||
} as any,
|
||||
);
|
||||
app.use('/', router);
|
||||
app.use(errorHandler());
|
||||
});
|
||||
|
||||
describe('POST /resources/workloads/query', () => {
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('200 happy path', async () => {
|
||||
await request(app)
|
||||
.post('/resources/workloads/query')
|
||||
.send({
|
||||
entityRef: 'kind:namespacec/someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(200, {
|
||||
items: [
|
||||
{
|
||||
clusterOne: {
|
||||
pods: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'pod1',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when missing entity ref', async () => {
|
||||
await request(app)
|
||||
.post('/resources/workloads/query')
|
||||
.send({
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: { name: 'InputError', message: 'entity is a required field' },
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/workloads/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when bad entity ref', async () => {
|
||||
await request(app)
|
||||
.post('/resources/workloads/query')
|
||||
.send({
|
||||
entityRef: 'ffff',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: {
|
||||
name: 'InputError',
|
||||
message:
|
||||
'Invalid entity ref, Error: Entity reference "ffff" had missing or empty kind (e.g. did not start with "component:" or similar)',
|
||||
},
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/workloads/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when no entity in catalog', async () => {
|
||||
await request(app)
|
||||
.post('/resources/workloads/query')
|
||||
.send({
|
||||
entityRef: 'noentity:noentity',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: {
|
||||
name: 'InputError',
|
||||
message: 'Entity ref missing, noentity:default/noentity',
|
||||
},
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/workloads/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('401 when no Auth header', async () => {
|
||||
await request(app)
|
||||
.post('/resources/workloads/query')
|
||||
.send({
|
||||
entityRef: 'component:someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.expect(401, {
|
||||
error: { name: 'AuthenticationError', message: 'No Backstage token' },
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/workloads/query',
|
||||
},
|
||||
response: { statusCode: 401 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('401 when invalid Auth header', async () => {
|
||||
await request(app)
|
||||
.post('/resources/workloads/query')
|
||||
.send({
|
||||
entityRef: 'component:someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'ffffff')
|
||||
.expect(401, {
|
||||
error: { name: 'AuthenticationError', message: 'No Backstage token' },
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/workloads/query',
|
||||
},
|
||||
response: { statusCode: 401 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('500 handle gracefully', async () => {
|
||||
await request(app)
|
||||
.post('/resources/workloads/query')
|
||||
.send({
|
||||
entityRef: 'inject500:inject500/inject500',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(500, {
|
||||
error: {
|
||||
name: 'Error',
|
||||
message: 'some internal error',
|
||||
level: 'error',
|
||||
service: 'backstage',
|
||||
},
|
||||
request: { method: 'POST', url: '/resources/workloads/query' },
|
||||
response: { statusCode: 500 },
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('POST /resources/custom/query', () => {
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('200 happy path', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'component:someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: [
|
||||
{
|
||||
group: 'someGroup',
|
||||
apiVersion: 'someApiVersion',
|
||||
plural: 'somePlural',
|
||||
},
|
||||
],
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(200, {
|
||||
items: [
|
||||
{
|
||||
clusterOne: {
|
||||
pods: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'pod1',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when missing custom resources', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'component:someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: {
|
||||
name: 'InputError',
|
||||
message: 'customResources is a required field',
|
||||
},
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/custom/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when custom resources not array', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'component:someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: 'somestring',
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: {
|
||||
name: 'InputError',
|
||||
message: 'customResources must be an array',
|
||||
},
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/custom/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when custom resources empty', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'component:someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: [],
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: {
|
||||
name: 'InputError',
|
||||
message: 'at least 1 customResource is required',
|
||||
},
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/custom/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when missing entity ref', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: [
|
||||
{
|
||||
group: 'someGroup',
|
||||
apiVersion: 'someApiVersion',
|
||||
plural: 'somePlural',
|
||||
},
|
||||
],
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: { name: 'InputError', message: 'entity is a required field' },
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/custom/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when bad entity ref', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'ffff',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: [
|
||||
{
|
||||
group: 'someGroup',
|
||||
apiVersion: 'someApiVersion',
|
||||
plural: 'somePlural',
|
||||
},
|
||||
],
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: {
|
||||
name: 'InputError',
|
||||
message:
|
||||
'Invalid entity ref, Error: Entity reference "ffff" had missing or empty kind (e.g. did not start with "component:" or similar)',
|
||||
},
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/custom/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('400 when no entity in catalog', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'noentity:noentity',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: [
|
||||
{
|
||||
group: 'someGroup',
|
||||
apiVersion: 'someApiVersion',
|
||||
plural: 'somePlural',
|
||||
},
|
||||
],
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(400, {
|
||||
error: {
|
||||
name: 'InputError',
|
||||
message: 'Entity ref missing, noentity:default/noentity',
|
||||
},
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/custom/query',
|
||||
},
|
||||
response: { statusCode: 400 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('401 when no Auth header', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'component:someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: [
|
||||
{
|
||||
group: 'someGroup',
|
||||
apiVersion: 'someApiVersion',
|
||||
plural: 'somePlural',
|
||||
},
|
||||
],
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.expect(401, {
|
||||
error: { name: 'AuthenticationError', message: 'No Backstage token' },
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/custom/query',
|
||||
},
|
||||
response: { statusCode: 401 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('401 when invalid Auth header', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'component:someComponent',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: [
|
||||
{
|
||||
group: 'someGroup',
|
||||
apiVersion: 'someApiVersion',
|
||||
plural: 'somePlural',
|
||||
},
|
||||
],
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'ffffff')
|
||||
.expect(401, {
|
||||
error: { name: 'AuthenticationError', message: 'No Backstage token' },
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '/resources/custom/query',
|
||||
},
|
||||
response: { statusCode: 401 },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('500 handle gracefully', async () => {
|
||||
await request(app)
|
||||
.post('/resources/custom/query')
|
||||
.send({
|
||||
entityRef: 'inject500:inject500/inject500',
|
||||
auth: {
|
||||
google: 'something',
|
||||
},
|
||||
customResources: [
|
||||
{
|
||||
group: 'someGroup',
|
||||
apiVersion: 'someApiVersion',
|
||||
plural: 'somePlural',
|
||||
},
|
||||
],
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Authorization', 'Bearer Zm9vYmFy')
|
||||
.expect(500, {
|
||||
error: {
|
||||
name: 'Error',
|
||||
message: 'some internal error',
|
||||
level: 'error',
|
||||
service: 'backstage',
|
||||
},
|
||||
request: { method: 'POST', url: '/resources/custom/query' },
|
||||
response: { statusCode: 500 },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 {
|
||||
CompoundEntityRef,
|
||||
parseEntityRef,
|
||||
stringifyEntityRef,
|
||||
} from '@backstage/catalog-model';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
import { InputError, AuthenticationError } from '@backstage/errors';
|
||||
import express, { Request } from 'express';
|
||||
import { KubernetesObjectsProvider } from '../types/types';
|
||||
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
|
||||
|
||||
export const addResourceRoutesToRouter = (
|
||||
router: express.Router,
|
||||
catalogApi: CatalogApi,
|
||||
objectsProvider: KubernetesObjectsProvider,
|
||||
) => {
|
||||
const getEntityByReq = async (req: Request<any>) => {
|
||||
const rawEntityRef = req.body.entityRef;
|
||||
if (rawEntityRef && typeof rawEntityRef !== 'string') {
|
||||
throw new InputError(`entity query must be a string`);
|
||||
} else if (!rawEntityRef) {
|
||||
throw new InputError('entity is a required field');
|
||||
}
|
||||
let entityRef: CompoundEntityRef | undefined = undefined;
|
||||
|
||||
try {
|
||||
entityRef = parseEntityRef(rawEntityRef);
|
||||
} catch (error) {
|
||||
throw new InputError(`Invalid entity ref, ${error}`);
|
||||
}
|
||||
|
||||
const token = getBearerTokenFromAuthorizationHeader(
|
||||
req.headers.authorization,
|
||||
);
|
||||
|
||||
if (!token) {
|
||||
throw new AuthenticationError('No Backstage token');
|
||||
}
|
||||
|
||||
const entity = await catalogApi.getEntityByRef(entityRef, {
|
||||
token: token,
|
||||
});
|
||||
|
||||
if (!entity) {
|
||||
throw new InputError(
|
||||
`Entity ref missing, ${stringifyEntityRef(entityRef)}`,
|
||||
);
|
||||
}
|
||||
return entity;
|
||||
};
|
||||
|
||||
router.post('/resources/workloads/query', async (req, res) => {
|
||||
const entity = await getEntityByReq(req);
|
||||
const response = await objectsProvider.getKubernetesObjectsByEntity({
|
||||
entity,
|
||||
auth: req.body.auth,
|
||||
});
|
||||
res.json(response);
|
||||
});
|
||||
|
||||
router.post('/resources/custom/query', async (req, res) => {
|
||||
const entity = await getEntityByReq(req);
|
||||
|
||||
if (!req.body.customResources) {
|
||||
throw new InputError('customResources is a required field');
|
||||
} else if (!Array.isArray(req.body.customResources)) {
|
||||
throw new InputError('customResources must be an array');
|
||||
} else if (req.body.customResources.length === 0) {
|
||||
throw new InputError('at least 1 customResource is required');
|
||||
}
|
||||
|
||||
const response = await objectsProvider.getCustomResourcesByEntity({
|
||||
entity,
|
||||
customResources: req.body.customResources,
|
||||
auth: req.body.auth,
|
||||
});
|
||||
res.json(response);
|
||||
});
|
||||
};
|
||||
@@ -31,11 +31,13 @@ import {
|
||||
import { KubernetesBuilder } from './KubernetesBuilder';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
import { PodStatus } from '@kubernetes/client-node';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
|
||||
describe('KubernetesBuilder', () => {
|
||||
let app: express.Express;
|
||||
let kubernetesFanOutHandler: jest.Mocked<KubernetesFanOutHandler>;
|
||||
let config: Config;
|
||||
let catalogApi: CatalogApi;
|
||||
|
||||
beforeAll(async () => {
|
||||
const logger = getVoidLogger();
|
||||
@@ -69,7 +71,13 @@ describe('KubernetesBuilder', () => {
|
||||
getKubernetesObjectsByEntity: jest.fn(),
|
||||
} as any;
|
||||
|
||||
const { router } = await KubernetesBuilder.createBuilder({ config, logger })
|
||||
catalogApi = {} as CatalogApi;
|
||||
|
||||
const { router } = await KubernetesBuilder.createBuilder({
|
||||
config,
|
||||
logger,
|
||||
catalogApi,
|
||||
})
|
||||
.setObjectsProvider(kubernetesFanOutHandler)
|
||||
.setClusterSupplier(clusterSupplier)
|
||||
.build();
|
||||
@@ -240,6 +248,7 @@ describe('KubernetesBuilder', () => {
|
||||
const { router } = await KubernetesBuilder.createBuilder({
|
||||
logger,
|
||||
config,
|
||||
catalogApi,
|
||||
})
|
||||
.setClusterSupplier(clusterSupplier)
|
||||
.setServiceLocator(serviceLocator)
|
||||
|
||||
@@ -37,6 +37,8 @@ import {
|
||||
KubernetesFanOutHandler,
|
||||
} from './KubernetesFanOutHandler';
|
||||
import { KubernetesClientBasedFetcher } from './KubernetesFetcher';
|
||||
import { addResourceRoutesToRouter } from '../routes/resourcesRoutes';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -45,6 +47,7 @@ import { KubernetesClientBasedFetcher } from './KubernetesFetcher';
|
||||
export interface KubernetesEnvironment {
|
||||
logger: Logger;
|
||||
config: Config;
|
||||
catalogApi: CatalogApi;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +122,11 @@ export class KubernetesBuilder {
|
||||
objectTypesToFetch: this.getObjectTypesToFetch(),
|
||||
});
|
||||
|
||||
const router = this.buildRouter(objectsProvider, clusterSupplier);
|
||||
const router = this.buildRouter(
|
||||
objectsProvider,
|
||||
clusterSupplier,
|
||||
this.env.catalogApi,
|
||||
);
|
||||
|
||||
return {
|
||||
clusterSupplier,
|
||||
@@ -226,11 +233,13 @@ export class KubernetesBuilder {
|
||||
protected buildRouter(
|
||||
objectsProvider: KubernetesObjectsProvider,
|
||||
clusterSupplier: KubernetesClustersSupplier,
|
||||
catalogApi: CatalogApi,
|
||||
): express.Router {
|
||||
const logger = this.env.logger;
|
||||
const router = Router();
|
||||
router.use(express.json());
|
||||
|
||||
// @deprecated
|
||||
router.post('/services/:serviceId', async (req, res) => {
|
||||
const serviceId = req.params.serviceId;
|
||||
const requestBody: ObjectsByEntityRequest = req.body;
|
||||
@@ -259,6 +268,9 @@ export class KubernetesBuilder {
|
||||
})),
|
||||
});
|
||||
});
|
||||
|
||||
addResourceRoutesToRouter(router, catalogApi, objectsProvider);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import { Logger } from 'winston';
|
||||
import { KubernetesClustersSupplier } from '../types/types';
|
||||
import express from 'express';
|
||||
import { KubernetesBuilder } from './KubernetesBuilder';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -27,6 +28,7 @@ import { KubernetesBuilder } from './KubernetesBuilder';
|
||||
export interface RouterOptions {
|
||||
logger: Logger;
|
||||
config: Config;
|
||||
catalogApi: CatalogApi;
|
||||
clusterSupplier?: KubernetesClustersSupplier;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
errorHandler,
|
||||
notFoundHandler,
|
||||
requestLoggingHandler,
|
||||
SingleHostDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
import compression from 'compression';
|
||||
import cors from 'cors';
|
||||
@@ -26,6 +27,7 @@ import helmet from 'helmet';
|
||||
import { Logger } from 'winston';
|
||||
import { createRouter } from './router';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { CatalogClient } from '@backstage/catalog-client';
|
||||
|
||||
export interface ApplicationOptions {
|
||||
enableCors: boolean;
|
||||
@@ -39,6 +41,10 @@ export async function createStandaloneApplication(
|
||||
const config = new ConfigReader({});
|
||||
const app = express();
|
||||
|
||||
const catalogApi = new CatalogClient({
|
||||
discoveryApi: SingleHostDiscovery.fromConfig(config),
|
||||
});
|
||||
|
||||
app.use(helmet());
|
||||
if (enableCors) {
|
||||
app.use(cors());
|
||||
@@ -46,7 +52,7 @@ export async function createStandaloneApplication(
|
||||
app.use(compression());
|
||||
app.use(express.json());
|
||||
app.use(requestLoggingHandler());
|
||||
app.use('/', await createRouter({ logger, config }));
|
||||
app.use('/', await createRouter({ logger, config, catalogApi }));
|
||||
app.use(notFoundHandler());
|
||||
app.use(errorHandler());
|
||||
|
||||
|
||||
@@ -38,8 +38,9 @@
|
||||
"url": "https://github.com/backstage/backstage/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^1.1.0-next.1",
|
||||
"@backstage/catalog-model": "^1.1.0-next.2",
|
||||
"@kubernetes/client-node": "^0.16.0"
|
||||
"@kubernetes/client-node": "^0.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.18.0-next.2"
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"@backstage/plugin-catalog-react": "^1.1.2-next.2",
|
||||
"@backstage/plugin-kubernetes-common": "^0.4.0-next.1",
|
||||
"@backstage/theme": "^0.2.16-next.1",
|
||||
"@kubernetes/client-node": "^0.16.0",
|
||||
"@kubernetes/client-node": "^0.17.0",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
|
||||
@@ -14,3 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import '@testing-library/jest-dom';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { TextDecoder, TextEncoder } from 'util';
|
||||
|
||||
// These are missing from jest-node, so not available on global.
|
||||
Object.defineProperty(global, 'TextEncoder', {
|
||||
value: TextEncoder,
|
||||
});
|
||||
|
||||
Object.defineProperty(global, 'TextDecoder', {
|
||||
value: TextDecoder,
|
||||
});
|
||||
|
||||
@@ -388,6 +388,7 @@ export function createPublishGitlabAction(options: {
|
||||
gitCommitMessage?: string | undefined;
|
||||
gitAuthorName?: string | undefined;
|
||||
gitAuthorEmail?: string | undefined;
|
||||
setUserAsOwner?: boolean | undefined;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
|
||||
@@ -32,6 +32,9 @@ const mockGitlabClient = {
|
||||
Users: {
|
||||
current: jest.fn(),
|
||||
},
|
||||
ProjectMembers: {
|
||||
add: jest.fn(),
|
||||
},
|
||||
};
|
||||
jest.mock('@gitbeaker/node', () => ({
|
||||
Gitlab: class {
|
||||
@@ -113,6 +116,7 @@ describe('publish:gitlab', () => {
|
||||
});
|
||||
|
||||
it('should work when there is a token provided through ctx.input', async () => {
|
||||
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
@@ -135,6 +139,7 @@ describe('publish:gitlab', () => {
|
||||
});
|
||||
|
||||
it('should call the correct Gitlab APIs when the owner is an organization', async () => {
|
||||
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
@@ -168,6 +173,7 @@ describe('publish:gitlab', () => {
|
||||
});
|
||||
|
||||
it('should call initRepoAndPush with the correct values', async () => {
|
||||
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
@@ -187,6 +193,7 @@ describe('publish:gitlab', () => {
|
||||
});
|
||||
|
||||
it('should call initRepoAndPush with the correct default branch', async () => {
|
||||
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
@@ -241,6 +248,7 @@ describe('publish:gitlab', () => {
|
||||
config: customAuthorConfig,
|
||||
});
|
||||
|
||||
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
@@ -286,6 +294,7 @@ describe('publish:gitlab', () => {
|
||||
config: customAuthorConfig,
|
||||
});
|
||||
|
||||
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
@@ -305,6 +314,7 @@ describe('publish:gitlab', () => {
|
||||
});
|
||||
|
||||
it('should call output with the remoteUrl and repoContentsUrl', async () => {
|
||||
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
@@ -321,4 +331,54 @@ describe('publish:gitlab', () => {
|
||||
'http://mockurl/-/blob/master',
|
||||
);
|
||||
});
|
||||
|
||||
it('should call the correct Gitlab APIs when setUserAsOwner option is true and integration config has a token', async () => {
|
||||
const customAuthorConfig = new ConfigReader({
|
||||
integrations: {
|
||||
gitlab: [
|
||||
{
|
||||
host: 'gitlab.com',
|
||||
token: 'tokenlols',
|
||||
apiBaseUrl: 'https://api.gitlab.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const customAuthorIntegrations =
|
||||
ScmIntegrations.fromConfig(customAuthorConfig);
|
||||
const customAuthorAction = createPublishGitlabAction({
|
||||
integrations: customAuthorIntegrations,
|
||||
config: customAuthorConfig,
|
||||
});
|
||||
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
id: 123456,
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
});
|
||||
|
||||
await customAuthorAction.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
repoUrl: 'gitlab.com?repo=repo&owner=owner',
|
||||
token: 'token',
|
||||
setUserAsOwner: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner');
|
||||
expect(mockGitlabClient.Users.current).toHaveBeenCalled();
|
||||
expect(mockGitlabClient.ProjectMembers.add).toHaveBeenCalledWith(
|
||||
123456,
|
||||
12345,
|
||||
50,
|
||||
);
|
||||
expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({
|
||||
namespace_id: 1234,
|
||||
name: 'repo',
|
||||
visibility: 'private',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,6 +43,7 @@ export function createPublishGitlabAction(options: {
|
||||
gitCommitMessage?: string;
|
||||
gitAuthorName?: string;
|
||||
gitAuthorEmail?: string;
|
||||
setUserAsOwner?: boolean;
|
||||
}>({
|
||||
id: 'publish:gitlab',
|
||||
description:
|
||||
@@ -92,6 +93,12 @@ export function createPublishGitlabAction(options: {
|
||||
type: 'string',
|
||||
description: 'The token to use for authorization to GitLab',
|
||||
},
|
||||
setUserAsOwner: {
|
||||
title: 'Set User As Owner',
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Set the token user as owner of the newly created repository. Requires a token authorized to do the edit in the integration configuration for the matching host',
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
@@ -116,6 +123,7 @@ export function createPublishGitlabAction(options: {
|
||||
gitCommitMessage = 'initial commit',
|
||||
gitAuthorName,
|
||||
gitAuthorEmail,
|
||||
setUserAsOwner = false,
|
||||
} = ctx.input;
|
||||
const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
|
||||
|
||||
@@ -149,19 +157,35 @@ export function createPublishGitlabAction(options: {
|
||||
id: number;
|
||||
};
|
||||
|
||||
const { id: userId } = (await client.Users.current()) as {
|
||||
id: number;
|
||||
};
|
||||
|
||||
if (!targetNamespace) {
|
||||
const { id } = (await client.Users.current()) as {
|
||||
id: number;
|
||||
};
|
||||
targetNamespace = id;
|
||||
targetNamespace = userId;
|
||||
}
|
||||
|
||||
const { http_url_to_repo } = await client.Projects.create({
|
||||
const { id: projectId, http_url_to_repo } = await client.Projects.create({
|
||||
namespace_id: targetNamespace,
|
||||
name: repo,
|
||||
visibility: repoVisibility,
|
||||
});
|
||||
|
||||
// When setUserAsOwner is true the input token is expected to come from an unprivileged user GitLab
|
||||
// OAuth flow. In this case GitLab works in a way that allows the unprivileged user to
|
||||
// create the repository, but not to push the default protected branch (e.g. master).
|
||||
// In order to set the user as owner of the newly created repository we need to check that the
|
||||
// GitLab integration configuration for the matching host contains a token and use
|
||||
// such token to bootstrap a new privileged client.
|
||||
if (setUserAsOwner && integrationConfig.config.token) {
|
||||
const adminClient = new Gitlab({
|
||||
host: integrationConfig.config.baseUrl,
|
||||
token: integrationConfig.config.token,
|
||||
});
|
||||
|
||||
await adminClient.ProjectMembers.add(projectId, userId, 50);
|
||||
}
|
||||
|
||||
const remoteUrl = (http_url_to_repo as string).replace(/\.git$/, '');
|
||||
const repoContentsUrl = `${remoteUrl}/-/blob/${defaultBranch}`;
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"@react-hookz/web": "^13.0.0",
|
||||
"@react-hookz/web": "^15.0.0",
|
||||
"@rjsf/core": "^3.2.1",
|
||||
"@rjsf/material-ui": "^3.2.1",
|
||||
"@types/json-schema": "^7.0.9",
|
||||
|
||||
@@ -90,9 +90,17 @@ export class MyOwnClient implements TechRadarApi {
|
||||
|
||||
const data = await fetch('https://mydata.json').then(res => res.json());
|
||||
|
||||
// maybe you'll need to do some data transformation here to make it look like TechRadarLoaderResponse
|
||||
|
||||
return data;
|
||||
// For example, this converts the timeline dates into date objects
|
||||
return {
|
||||
...data,
|
||||
entries: data.entries.map(entry => ({
|
||||
...entry,
|
||||
timeline: entry.timeline.map(timeline => ({
|
||||
...timeline,
|
||||
date: new Date(timeline.date),
|
||||
})),
|
||||
})),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"@react-hookz/web": "^14.0.0",
|
||||
"@react-hookz/web": "^15.0.0",
|
||||
"git-url-parse": "^12.0.0",
|
||||
"react-use": "^17.2.4"
|
||||
},
|
||||
|
||||
@@ -219,8 +219,6 @@ const ALLOW_WARNINGS = [
|
||||
'plugins/circleci',
|
||||
'plugins/cloudbuild',
|
||||
'plugins/code-climate',
|
||||
'plugins/code-coverage',
|
||||
'plugins/code-coverage-backend',
|
||||
'plugins/config-schema',
|
||||
'plugins/cost-insights',
|
||||
'plugins/dynatrace',
|
||||
|
||||
@@ -344,17 +344,17 @@
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
|
||||
"@azure/msal-common@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.0.0.tgz#f4b52c6d9591cf8720dcb24c1d21fce2d186f871"
|
||||
integrity sha512-EkaHGjv0kw1RljhboeffM91b+v9d5VtmyG+0a/gvdqjbLu3kDzEfoaS5BNM9QqMzbxgZylsjAjQDtxdHLX/ziA==
|
||||
"@azure/msal-common@^7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.1.0.tgz#b77dbf9ae581f1ed254f81d56422e3cdd6664b32"
|
||||
integrity sha512-WyfqE5mY/rggjqvq0Q5DxLnA33KSb0vfsUjxa95rycFknI03L5GPYI4HTU9D+g0PL5TtsQGnV3xzAGq9BFCVJQ==
|
||||
|
||||
"@azure/msal-node@^1.1.0", "@azure/msal-node@^1.3.0":
|
||||
version "1.10.0"
|
||||
resolved "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.10.0.tgz#ee3a26201c4899cc6928cc331c31d3568d3cb728"
|
||||
integrity sha512-oSv9mg199FpRTe+fZ3o9NDYpKShOHqeceaNcCHJcKUaAaCojAbfbxD1Cvsti8BEsLKE6x0HcnjilnM1MKmZekA==
|
||||
version "1.11.0"
|
||||
resolved "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.11.0.tgz#d8bd3f15c1f05bf806ba6f9479c48c2eddd6a98d"
|
||||
integrity sha512-KW/XEexfCrPzdYbjY7NVmhq9okZT3Jvck55CGXpz9W5asxeq3EtrP45p+ZXtQVEfko0YJdolpCNqWUyXvanWZg==
|
||||
dependencies:
|
||||
"@azure/msal-common" "^7.0.0"
|
||||
"@azure/msal-common" "^7.1.0"
|
||||
jsonwebtoken "^8.5.1"
|
||||
uuid "^8.3.0"
|
||||
|
||||
@@ -2288,9 +2288,9 @@
|
||||
xcase "^2.0.1"
|
||||
|
||||
"@google-cloud/container@^4.0.0":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/@google-cloud/container/-/container-4.0.1.tgz#a3206d3030539e09b7beee8f351fad86c77af79d"
|
||||
integrity sha512-JpsOsdKnCQm1b5aVNnO/2Urdg+qbCLi/srEnTupRj73Pu5wXLHXOCe3vy8Z2GvyCqu7qr89fMREQ4kO4QijnHA==
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/@google-cloud/container/-/container-4.1.0.tgz#cf929184f668fc40ca8b864b7f638228ae67fc98"
|
||||
integrity sha512-LpVT3wxG73iX/5deF4a2KIEZ7sULF2mksrzyA25OVGtyxFclSZT2Gs5uho5USSLkoKg/Ou+l+ekGMrgBQbLDag==
|
||||
dependencies:
|
||||
google-gax "^3.0.1"
|
||||
|
||||
@@ -3528,10 +3528,10 @@
|
||||
dependencies:
|
||||
ioredis "^5.1.0"
|
||||
|
||||
"@kubernetes/client-node@^0.16.0":
|
||||
version "0.16.3"
|
||||
resolved "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.16.3.tgz#a26a5abbd6e45603b4f75f0baff00e19853e5be7"
|
||||
integrity sha512-L7IckuyuPfhd+/Urib8MRas9D6sfKEq8IaITYcaE6LlU+Y8MeD7MTbuW6Yb2WdeRuFN8HPSS47mxPnOUNYBXEg==
|
||||
"@kubernetes/client-node@^0.17.0":
|
||||
version "0.17.0"
|
||||
resolved "https://registry.npmjs.org/@kubernetes/client-node/-/client-node-0.17.0.tgz#cbf69ff6c8a311c1461275169612ac46db00fe3f"
|
||||
integrity sha512-oKQfRf7RPpJIF2Ft92g6jefbW3Mddf6IzcfpBNDWrAy66LmyAWds6fQTMsdutGPuXV6KD29u6RfM3rdzddGMIA==
|
||||
dependencies:
|
||||
"@types/js-yaml" "^4.0.1"
|
||||
"@types/node" "^10.12.0"
|
||||
@@ -3545,7 +3545,7 @@
|
||||
isomorphic-ws "^4.0.1"
|
||||
js-yaml "^4.1.0"
|
||||
jsonpath-plus "^0.19.0"
|
||||
openid-client "^4.1.1"
|
||||
openid-client "^5.1.6"
|
||||
request "^2.88.0"
|
||||
rfc4648 "^1.3.0"
|
||||
shelljs "^0.8.5"
|
||||
@@ -4438,9 +4438,9 @@
|
||||
react-is "^16.8.0 || ^17.0.0"
|
||||
|
||||
"@maxim_mazurok/gapi.client.calendar@^3.0.20220408":
|
||||
version "3.0.20220624"
|
||||
resolved "https://registry.npmjs.org/@maxim_mazurok/gapi.client.calendar/-/gapi.client.calendar-3.0.20220624.tgz#17817142e348ce811415dfb111299fbdac2450a0"
|
||||
integrity sha512-5+x4A6l8GY+dojvXUBQGc0Y4JOm9lBY1YZfCAEEZPjBcXkx0vs/CenPnmAu/fwQgGSrQLipxFV+pS6RL3L28mg==
|
||||
version "3.0.20220701"
|
||||
resolved "https://registry.npmjs.org/@maxim_mazurok/gapi.client.calendar/-/gapi.client.calendar-3.0.20220701.tgz#4ee9089e8164269743e61ec36e79e095aa0926b6"
|
||||
integrity sha512-3CjbVZysFdUmGWZwjYGsV3z+kViaVpiWvgR7/DX5nUtb1YWIaS0jNUCch1YVN9aDFaCWuI3UV/STveSPvUspgw==
|
||||
dependencies:
|
||||
"@types/gapi.client" "*"
|
||||
|
||||
@@ -5271,11 +5271,6 @@
|
||||
resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz#a167e46c10d05a07ab299fc518793b0cff8f6924"
|
||||
integrity sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==
|
||||
|
||||
"@panva/asn1.js@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz#dd55ae7b8129e02049f009408b97c61ccf9032f6"
|
||||
integrity sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==
|
||||
|
||||
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
|
||||
@@ -5329,18 +5324,11 @@
|
||||
resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
|
||||
|
||||
"@react-hookz/deep-equal@^1.0.1", "@react-hookz/deep-equal@^1.0.2":
|
||||
"@react-hookz/deep-equal@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/@react-hookz/deep-equal/-/deep-equal-1.0.2.tgz#4e8bdeda027379dcf8b62a42e5f75f0351b11b35"
|
||||
integrity sha512-cM5kPFb6EFH5q52WzRxfRX9+8g5kq78McWOYs6e1seo+nK6NpfLupT5uOCIJp37jU8ayd4Su8ni3HRFTN2C2kg==
|
||||
|
||||
"@react-hookz/web@^13.0.0":
|
||||
version "13.3.0"
|
||||
resolved "https://registry.npmjs.org/@react-hookz/web/-/web-13.3.0.tgz#257e31049e92a121912fe1e67bdd01dbec5a203b"
|
||||
integrity sha512-KswgkmqBVVDo6UnBFfssrojmDisogxC4jGZmd976R8YHoS3zdQJxjqICpOBSRohbRyYhYS9Cprw7BuV/CZcMaw==
|
||||
dependencies:
|
||||
"@react-hookz/deep-equal" "^1.0.1"
|
||||
|
||||
"@react-hookz/web@^14.0.0":
|
||||
version "14.7.1"
|
||||
resolved "https://registry.npmjs.org/@react-hookz/web/-/web-14.7.1.tgz#5e39e6fc21331cc4ae95f36e8135ad763e6c29fb"
|
||||
@@ -5348,6 +5336,13 @@
|
||||
dependencies:
|
||||
"@react-hookz/deep-equal" "^1.0.2"
|
||||
|
||||
"@react-hookz/web@^15.0.0":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.npmjs.org/@react-hookz/web/-/web-15.0.1.tgz#a6e5460dd16e54ccc0b899e1eed4ae29e871060f"
|
||||
integrity sha512-nvVLUsDFv3fpZcINoy3I4MeaX8+yoKU21m2Ey2g0VAVqOMp+0GBBC6OHkzT2lRa2fiPIVuJwlmboSKQt7segfQ==
|
||||
dependencies:
|
||||
"@react-hookz/deep-equal" "^1.0.2"
|
||||
|
||||
"@repeaterjs/repeater@^3.0.4":
|
||||
version "3.0.4"
|
||||
resolved "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz#a04d63f4d1bf5540a41b01a921c9a7fddc3bd1ca"
|
||||
@@ -7496,9 +7491,9 @@
|
||||
eslint-visitor-keys "^3.0.0"
|
||||
|
||||
"@uiw/react-codemirror@^4.9.3":
|
||||
version "4.9.5"
|
||||
resolved "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.9.5.tgz#0f66c09dfc355baef5a7020f206da8db90bae223"
|
||||
integrity sha512-KHgP/PII9Gv4iEUzbdO95qpSSPy27iSHzxQ01mBPWC4UvzuA0eQY2h64gzi/ld68esbKMGYoevgOBPCRJwNN1A==
|
||||
version "4.10.4"
|
||||
resolved "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.10.4.tgz#f26833d5cfc4c63de1858c587218efd9f85f18e2"
|
||||
integrity sha512-eMl/Xtmhhjo1Hmx0P1NgwVlviOUCdjSYPKHn0bgUG6aLgZjCo1l0MJDDuLikGp8YlDrXcDKgiuXPt4GykBaUmg==
|
||||
dependencies:
|
||||
"@babel/runtime" ">=7.11.0"
|
||||
"@codemirror/theme-one-dark" "^6.0.0"
|
||||
@@ -7853,13 +7848,6 @@ anafanafo@2.0.0:
|
||||
dependencies:
|
||||
char-width-table-consumer "^1.0.0"
|
||||
|
||||
ansi-align@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
|
||||
integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
|
||||
dependencies:
|
||||
string-width "^3.0.0"
|
||||
|
||||
ansi-colors@^4.1.1, ansi-colors@^4.1.3:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
|
||||
@@ -8423,9 +8411,9 @@ aws-sdk-mock@^5.2.1:
|
||||
traverse "^0.6.6"
|
||||
|
||||
aws-sdk@^2.1122.0, aws-sdk@^2.840.0, aws-sdk@^2.948.0:
|
||||
version "2.1167.0"
|
||||
resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1167.0.tgz#e8614bce1a7355782734b6928792f14d11b39231"
|
||||
integrity sha512-hUJzAqWVfNYpct1S+GjyPIc2s+GZcAhbWVqIG4qbLYZ3+sBTcjv3lLH5zx7K+qcTGINDU0g4EsMi6hIrAU+blg==
|
||||
version "2.1168.0"
|
||||
resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1168.0.tgz#7936459edee0c999065f1ecf2ef0bea89ea056c1"
|
||||
integrity sha512-9+WYoYTHHjLqeWdSSLbNpmc/NgnZpX4LGiyYjXenh4WNRBXshXI0XioTK8BQgDscVzB978EJV8kG1nZGE3USzw==
|
||||
dependencies:
|
||||
buffer "4.9.2"
|
||||
events "1.1.1"
|
||||
@@ -8946,20 +8934,6 @@ bottleneck@^2.15.3:
|
||||
resolved "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91"
|
||||
integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==
|
||||
|
||||
boxen@^5.0.0:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50"
|
||||
integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==
|
||||
dependencies:
|
||||
ansi-align "^3.0.0"
|
||||
camelcase "^6.2.0"
|
||||
chalk "^4.1.0"
|
||||
cli-boxes "^2.2.1"
|
||||
string-width "^4.2.2"
|
||||
type-fest "^0.20.2"
|
||||
widest-line "^3.1.0"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
@@ -9678,11 +9652,6 @@ clean-stack@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
||||
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
|
||||
|
||||
cli-boxes@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
|
||||
integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
|
||||
|
||||
cli-cursor@^2.0.0, cli-cursor@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
|
||||
@@ -10231,18 +10200,6 @@ config-chain@^1.1.12:
|
||||
ini "^1.3.4"
|
||||
proto-list "~1.2.1"
|
||||
|
||||
configstore@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
|
||||
integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
|
||||
dependencies:
|
||||
dot-prop "^5.2.0"
|
||||
graceful-fs "^4.1.2"
|
||||
make-dir "^3.0.0"
|
||||
unique-string "^2.0.0"
|
||||
write-file-atomic "^3.0.0"
|
||||
xdg-basedir "^4.0.0"
|
||||
|
||||
connect-history-api-fallback@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8"
|
||||
@@ -10674,11 +10631,6 @@ crypto-browserify@^3.11.0:
|
||||
randombytes "^2.0.0"
|
||||
randomfill "^1.0.3"
|
||||
|
||||
crypto-random-string@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
||||
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
|
||||
|
||||
css-box-model@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1"
|
||||
@@ -11779,7 +11731,7 @@ dot-case@^3.0.4:
|
||||
no-case "^3.0.4"
|
||||
tslib "^2.0.3"
|
||||
|
||||
dot-prop@^5.1.0, dot-prop@^5.2.0:
|
||||
dot-prop@^5.1.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88"
|
||||
integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
|
||||
@@ -11922,11 +11874,6 @@ emittery@^0.8.1:
|
||||
resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860"
|
||||
integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==
|
||||
|
||||
emoji-regex@^7.0.1:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
|
||||
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
@@ -12299,11 +12246,6 @@ escalade@^3.1.1:
|
||||
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
|
||||
escape-goat@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
|
||||
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
|
||||
|
||||
escape-html@^1.0.3, escape-html@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
@@ -14199,23 +14141,6 @@ got@11.8.3:
|
||||
p-cancelable "^2.0.0"
|
||||
responselike "^2.0.0"
|
||||
|
||||
got@^11.8.0:
|
||||
version "11.8.5"
|
||||
resolved "https://registry.npmjs.org/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046"
|
||||
integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==
|
||||
dependencies:
|
||||
"@sindresorhus/is" "^4.0.0"
|
||||
"@szmarczak/http-timer" "^4.0.5"
|
||||
"@types/cacheable-request" "^6.0.1"
|
||||
"@types/responselike" "^1.0.0"
|
||||
cacheable-lookup "^5.0.3"
|
||||
cacheable-request "^7.0.2"
|
||||
decompress-response "^6.0.0"
|
||||
http2-wrapper "^1.0.0-beta.5.2"
|
||||
lowercase-keys "^2.0.0"
|
||||
p-cancelable "^2.0.0"
|
||||
responselike "^2.0.0"
|
||||
|
||||
got@^9.6.0:
|
||||
version "9.6.0"
|
||||
resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
|
||||
@@ -14517,11 +14442,6 @@ has-values@^1.0.0:
|
||||
is-number "^3.0.0"
|
||||
kind-of "^4.0.0"
|
||||
|
||||
has-yarn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
|
||||
integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
@@ -15027,11 +14947,6 @@ import-from@^3.0.0:
|
||||
dependencies:
|
||||
resolve-from "^5.0.0"
|
||||
|
||||
import-lazy@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
|
||||
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
|
||||
|
||||
import-lazy@~4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153"
|
||||
@@ -15553,7 +15468,7 @@ is-in-browser@^1.0.2, is-in-browser@^1.1.3:
|
||||
resolved "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"
|
||||
integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=
|
||||
|
||||
is-installed-globally@^0.4.0, is-installed-globally@~0.4.0:
|
||||
is-installed-globally@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520"
|
||||
integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==
|
||||
@@ -15593,11 +15508,6 @@ is-node-process@^1.0.1:
|
||||
resolved "https://registry.npmjs.org/is-node-process/-/is-node-process-1.0.1.tgz#4fc7ac3a91e8aac58175fe0578abbc56f2831b23"
|
||||
integrity sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==
|
||||
|
||||
is-npm@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8"
|
||||
integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==
|
||||
|
||||
is-number-object@^1.0.4:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
|
||||
@@ -15880,11 +15790,6 @@ is-wsl@^2.2.0:
|
||||
dependencies:
|
||||
is-docker "^2.0.0"
|
||||
|
||||
is-yarn-global@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
|
||||
integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
|
||||
|
||||
isarray@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||
@@ -16543,13 +16448,6 @@ joi@^17.4.0:
|
||||
"@sideway/formula" "^3.0.0"
|
||||
"@sideway/pinpoint" "^2.0.0"
|
||||
|
||||
jose@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz#29746a18d9fff7dcf9d5d2a6f62cb0c7cd27abd3"
|
||||
integrity sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==
|
||||
dependencies:
|
||||
"@panva/asn1.js" "^1.0.0"
|
||||
|
||||
jose@^4.1.4:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.npmjs.org/jose/-/jose-4.5.0.tgz#92829d8cf846351eb55aaaf94f252fb1d191f2d5"
|
||||
@@ -17196,7 +17094,7 @@ language-tags@^1.0.5:
|
||||
dependencies:
|
||||
language-subtag-registry "~0.3.2"
|
||||
|
||||
latest-version@5.1.0, latest-version@^5.1.0:
|
||||
latest-version@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
|
||||
integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
|
||||
@@ -17802,9 +17700,9 @@ log-update@^4.0.0:
|
||||
wrap-ansi "^6.2.0"
|
||||
|
||||
logform@^2.3.2, logform@^2.4.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.npmjs.org/logform/-/logform-2.4.1.tgz#512c9eaef738044d1c619790ba0f806c80d9d3a9"
|
||||
integrity sha512-7XB/tqc3VRbri9pRjU6E97mQ8vC27ivJ3lct4jhyT+n0JNDd4YKldFl0D75NqDp46hk8RC7Ma1Vjv/UPf67S+A==
|
||||
version "2.4.2"
|
||||
resolved "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz#a617983ac0334d0c3b942c34945380062795b47c"
|
||||
integrity sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==
|
||||
dependencies:
|
||||
"@colors/colors" "1.5.0"
|
||||
fecha "^4.2.0"
|
||||
@@ -17952,7 +17850,7 @@ make-dir@^3.0.0, make-dir@^3.1.0:
|
||||
dependencies:
|
||||
semver "^6.0.0"
|
||||
|
||||
make-error@^1, make-error@^1.1.1, make-error@^1.3.6:
|
||||
make-error@^1, make-error@^1.1.1:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||
@@ -19342,9 +19240,9 @@ node-releases@^2.0.1:
|
||||
integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==
|
||||
|
||||
nodemon@^2.0.2:
|
||||
version "2.0.18"
|
||||
resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.18.tgz#0f5a3aa7b4587f2626e6f01369deba89cb0462a2"
|
||||
integrity sha512-uAvrKipi2zAz8E7nkSz4qW4F4zd5fs2wNGsTx+xXlP8KXqd9ucE0vY9wankOsPboeDyuUGN9vsXGV1pLn80l/A==
|
||||
version "2.0.19"
|
||||
resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz#cac175f74b9cb8b57e770d47841995eebe4488bd"
|
||||
integrity sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==
|
||||
dependencies:
|
||||
chokidar "^3.5.2"
|
||||
debug "^3.2.7"
|
||||
@@ -19352,10 +19250,10 @@ nodemon@^2.0.2:
|
||||
minimatch "^3.0.4"
|
||||
pstree.remy "^1.1.8"
|
||||
semver "^5.7.1"
|
||||
simple-update-notifier "^1.0.7"
|
||||
supports-color "^5.5.0"
|
||||
touch "^3.1.0"
|
||||
undefsafe "^2.0.5"
|
||||
update-notifier "^5.1.0"
|
||||
|
||||
nopt@1.0.10, nopt@~1.0.10:
|
||||
version "1.0.10"
|
||||
@@ -19873,20 +19771,7 @@ openapi-types@^12.0.0:
|
||||
resolved "https://registry.npmjs.org/openapi-types/-/openapi-types-12.0.0.tgz#458a99d048f9eae1c067e15d56a8bfb3726041f1"
|
||||
integrity sha512-6Wd9k8nmGQHgCbehZCP6wwWcfXcvinhybUTBatuhjRsCxUIujuYFZc9QnGeae75CyHASewBtxs0HX/qwREReUw==
|
||||
|
||||
openid-client@^4.1.1:
|
||||
version "4.9.0"
|
||||
resolved "https://registry.npmjs.org/openid-client/-/openid-client-4.9.0.tgz#bdfc9194435316df419f759ce177635146b43074"
|
||||
integrity sha512-ThBbvRUUZwxUKBVK2UpDNIZ3eJkvtqWI8s5Dm+naV+gJdL+yRhT+8ywqct1gy5uL+xVS5+A/nhFcpJIisH2x6Q==
|
||||
dependencies:
|
||||
aggregate-error "^3.1.0"
|
||||
got "^11.8.0"
|
||||
jose "^2.0.5"
|
||||
lru-cache "^6.0.0"
|
||||
make-error "^1.3.6"
|
||||
object-hash "^2.0.1"
|
||||
oidc-token-hash "^5.0.1"
|
||||
|
||||
openid-client@^5.1.3:
|
||||
openid-client@^5.1.3, openid-client@^5.1.6:
|
||||
version "5.1.8"
|
||||
resolved "https://registry.npmjs.org/openid-client/-/openid-client-5.1.8.tgz#3a24910288b32c32f548fb6e391f44178ce6370f"
|
||||
integrity sha512-EPxJY6bT7YIYQEXSGxRC5flQ3GUhLy98ufdto6+BVBrFGPmwjUpy4xBcYuU/Wt9nPkO/3EgljBrr6Ezx4lp1RQ==
|
||||
@@ -20535,10 +20420,10 @@ path-case@^3.0.4:
|
||||
dot-case "^3.0.4"
|
||||
tslib "^2.0.3"
|
||||
|
||||
path-equal@1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/path-equal/-/path-equal-1.1.2.tgz#260e7c449c4c2022f68cc5fa6e617e892858250d"
|
||||
integrity sha512-p5kxPPwCdbf5AdXzT1bUBJomhgBlEjRBavYNr1XUpMFIE4Hnf2roueCMXudZK5tnaAu1tTmp3GPzqwJK45IHEA==
|
||||
path-equal@^1.1.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.npmjs.org/path-equal/-/path-equal-1.2.2.tgz#fa2997f0a829de22ec8f5f86461ca5590d49b832"
|
||||
integrity sha512-AUJvbcle1Zgb1TgtftHYknlrgrSYyI1ytrYgSbKUHSybwqUDnbD2cw9PIWivuMvsN+GTXmr/DRN4VBXpHG6aGg==
|
||||
|
||||
path-exists@^2.0.0:
|
||||
version "2.1.0"
|
||||
@@ -21581,17 +21466,10 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||
resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
pupa@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62"
|
||||
integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==
|
||||
dependencies:
|
||||
escape-goat "^2.0.0"
|
||||
|
||||
puppeteer@^15.0.0:
|
||||
version "15.2.0"
|
||||
resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-15.2.0.tgz#9cd81334f9c6a2e1c972b5a7ecf3f18ab3bfb978"
|
||||
integrity sha512-6Mzj5pbq4J4DxJE5o6V+arrOB9Gma0CxOLP1zKYMrMR7AYuNaPzsK7pBrpDwI64W6Mxk5G7NqiLSFTrgSzR1zg==
|
||||
version "15.3.1"
|
||||
resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-15.3.1.tgz#0ff9b433a8fc3798f5ec82ea4b31ec47857219cf"
|
||||
integrity sha512-Z+SpYBiS1zUzMXV7Wnhe2pyuVCFAFRTq1UrUWHB2CkLos5v7bXvXYuZ3Fn5pSN5IObxijyx4opNYKTCRnGni6Q==
|
||||
dependencies:
|
||||
cross-fetch "3.1.5"
|
||||
debug "4.3.4"
|
||||
@@ -23227,13 +23105,6 @@ semver-compare@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
||||
integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w=
|
||||
|
||||
semver-diff@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
|
||||
integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==
|
||||
dependencies:
|
||||
semver "^6.3.0"
|
||||
|
||||
semver-store@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9"
|
||||
@@ -23244,7 +23115,7 @@ semver-store@^0.3.0:
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
semver@7.0.0:
|
||||
semver@7.0.0, semver@~7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
|
||||
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
|
||||
@@ -23515,6 +23386,13 @@ simple-swizzle@^0.2.2:
|
||||
dependencies:
|
||||
is-arrayish "^0.3.1"
|
||||
|
||||
simple-update-notifier@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz#7edf75c5bdd04f88828d632f762b2bc32996a9cc"
|
||||
integrity sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==
|
||||
dependencies:
|
||||
semver "~7.0.0"
|
||||
|
||||
sinon@^13.0.2:
|
||||
version "13.0.2"
|
||||
resolved "https://registry.npmjs.org/sinon/-/sinon-13.0.2.tgz#c6a8ddd655dc1415bbdc5ebf0e5b287806850c3a"
|
||||
@@ -24186,7 +24064,7 @@ string-width@^1.0.1, string-width@^1.0.2:
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@@ -24203,15 +24081,6 @@ string-width@^2.1.1:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
string-width@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
||||
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
|
||||
dependencies:
|
||||
emoji-regex "^7.0.1"
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^5.1.0"
|
||||
|
||||
string-width@^5.0.0:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
|
||||
@@ -24267,7 +24136,7 @@ string_decoder@~1.1.1:
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-ansi@5.2.0, strip-ansi@^5.1.0:
|
||||
strip-ansi@5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
|
||||
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
|
||||
@@ -25349,15 +25218,15 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typescript-json-schema@^0.53.0:
|
||||
version "0.53.1"
|
||||
resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.53.1.tgz#9204547f3e145169b40928998366ff6d28b81d32"
|
||||
integrity sha512-Hg+RnOKUd38MOzC0rDft03a8xvwO+gCcj1F77smw2tCoZYQpFoLtrXWBGdvCX+REliko5WYel2kux17HPFqjLQ==
|
||||
typescript-json-schema@^0.54.0:
|
||||
version "0.54.0"
|
||||
resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.54.0.tgz#b3fc42ad90df6a0f6ab57571ebc8b4d41125df4f"
|
||||
integrity sha512-/MNhm1pjdxXiVspjjyRCrQAA1B768cRzHU83aIqN5vQqQEW2NgyyKOfcguiRIMM64lseIZIelegnHOHEu7YDCg==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.9"
|
||||
"@types/node" "^16.9.2"
|
||||
glob "^7.1.7"
|
||||
path-equal "1.1.2"
|
||||
path-equal "^1.1.2"
|
||||
safe-stable-stringify "^2.2.0"
|
||||
ts-node "^10.2.1"
|
||||
typescript "~4.6.0"
|
||||
@@ -25510,13 +25379,6 @@ unique-slug@^2.0.0:
|
||||
dependencies:
|
||||
imurmurhash "^0.1.4"
|
||||
|
||||
unique-string@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
|
||||
integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
|
||||
dependencies:
|
||||
crypto-random-string "^2.0.0"
|
||||
|
||||
unist-builder@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz#728baca4767c0e784e1e64bb44b5a5a753021a04"
|
||||
@@ -25664,26 +25526,6 @@ upath@^2.0.1:
|
||||
resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b"
|
||||
integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==
|
||||
|
||||
update-notifier@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9"
|
||||
integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==
|
||||
dependencies:
|
||||
boxen "^5.0.0"
|
||||
chalk "^4.1.0"
|
||||
configstore "^5.0.1"
|
||||
has-yarn "^2.1.0"
|
||||
import-lazy "^2.1.0"
|
||||
is-ci "^2.0.0"
|
||||
is-installed-globally "^0.4.0"
|
||||
is-npm "^5.0.0"
|
||||
is-yarn-global "^0.3.0"
|
||||
latest-version "^5.1.0"
|
||||
pupa "^2.1.1"
|
||||
semver "^7.3.4"
|
||||
semver-diff "^3.1.1"
|
||||
xdg-basedir "^4.0.0"
|
||||
|
||||
upper-case-first@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324"
|
||||
@@ -25995,9 +25837,9 @@ vm-browserify@^1.0.1:
|
||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||
|
||||
vm2@^3.9.6:
|
||||
version "3.9.9"
|
||||
resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.9.tgz#c0507bc5fbb99388fad837d228badaaeb499ddc5"
|
||||
integrity sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw==
|
||||
version "3.9.10"
|
||||
resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.10.tgz#c66543096b5c44c8861a6465805c23c7cc996a44"
|
||||
integrity sha512-AuECTSvwu2OHLAZYhG716YzwodKCIJxB6u1zG7PgSQwIgAlEaoXH52bxdcvT8GkGjnYK7r7yWDW0m0sOsPuBjQ==
|
||||
dependencies:
|
||||
acorn "^8.7.0"
|
||||
acorn-walk "^8.2.0"
|
||||
@@ -26311,13 +26153,6 @@ wide-align@^1.1.0, wide-align@^1.1.2, wide-align@^1.1.5:
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2 || 3 || 4"
|
||||
|
||||
widest-line@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
|
||||
integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
|
||||
dependencies:
|
||||
string-width "^4.0.0"
|
||||
|
||||
window-size@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075"
|
||||
@@ -26489,11 +26324,6 @@ xcase@^2.0.1:
|
||||
resolved "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz#c7fa72caa0f440db78fd5673432038ac984450b9"
|
||||
integrity sha1-x/pyyqD0QNt4/VZzQyA4rJhEULk=
|
||||
|
||||
xdg-basedir@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
|
||||
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
|
||||
|
||||
xhr@^2.0.1:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d"
|
||||
|
||||
Reference in New Issue
Block a user