Merge branch 'master' of github.com:spotify/backstage into feat/backend-plugin

* 'master' of github.com:spotify/backstage: (30 commits)
  fix(techdocs-core): use the content of the readme as long description for the pypi package (#2578)
  chore: add contrib to CONTRIBUTING.md (#2585)
  Fix typo (#2584)
  backend-common: default config env to development
  v0.1.1-alpha.23
  TechDocs: Inject CSS transformer and initial backstage style integration for reader (#2560)
  bug(gql): use import to import the graphql module
  Rename file
  [blog] Announce CNCF Sandbox (#2568)
  document cleaning - tutorial quickstarts (#2520)
  Simplify codecov flag names
  chore(scaffolder-backend): typo in visibility
  Kubernetes plugins boilerplate (#2559)
  CHANGELOG: add entry for SessionApi refactor
  Upload package specific code coverage to codecov
  Add codecov flags for core and core-api packages
  TechDocs: Enable allowVulnerableTags in sanitize-html (#2554)
  chore: trust the Boolean :)
  docs: regenerate api reference docs
  core: refactor SessionStateApi to SessionApi with sign-in/out
  ...
This commit is contained in:
blam
2020-09-24 10:54:04 +02:00
150 changed files with 2452 additions and 993 deletions
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-api-docs",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,10 +20,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/plugin-catalog": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/plugin-catalog": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@kyma-project/asyncapi-react": "^0.11.0",
"@material-icons/font": "^1.0.2",
"@material-ui/core": "^4.11.0",
@@ -39,9 +39,9 @@
"swagger-ui-react": "^3.31.1"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-app-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,8 +20,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/config-loader": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/config-loader": "^0.1.1-alpha.23",
"@types/express": "^4.17.6",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
@@ -30,7 +30,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@types/supertest": "^2.0.8",
"msw": "^0.20.5",
"supertest": "^4.0.2"
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-auth-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,8 +20,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/config": "^0.1.1-alpha.23",
"@types/express": "^4.17.6",
"compression": "^1.7.4",
"cookie-parser": "^1.4.5",
@@ -49,7 +49,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@types/body-parser": "^1.19.0",
"@types/cookie-parser": "^1.4.2",
"@types/jwt-decode": "2.2.1",
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-catalog-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,9 +20,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/config": "^0.1.1-alpha.23",
"@types/express": "^4.17.6",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
@@ -40,7 +40,7 @@
"yup": "^0.29.1"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@types/git-url-parse": "^9.0.0",
"@types/lodash": "^4.14.151",
"@types/node-fetch": "^2.5.7",
+9 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-catalog-graphql",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,9 +20,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/config": "^0.1.1-alpha.23",
"@graphql-modules/core": "^0.7.17",
"apollo-server": "^2.16.1",
"graphql": "^15.3.0",
@@ -32,16 +32,16 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@types/express": "^4.17.7",
"@types/supertest": "^2.0.8",
"@backstage/cli": "^0.1.1-alpha.23",
"@graphql-codegen/cli": "^1.17.7",
"@graphql-codegen/typescript": "^1.17.7",
"@graphql-codegen/typescript-resolvers": "^1.17.7",
"ts-node": "^8.10.2",
"@types/express": "^4.17.7",
"@types/supertest": "^2.0.8",
"eslint-plugin-graphql": "^4.0.0",
"msw": "^0.20.5",
"supertest": "^4.0.2"
"supertest": "^4.0.2",
"ts-node": "^8.10.2"
},
"files": [
"dist"
@@ -22,6 +22,7 @@ import { Config } from '@backstage/config';
import { CatalogClient } from '../service/client';
import GraphQLJSON, { GraphQLJSONObject } from 'graphql-type-json';
import { Entity } from '@backstage/catalog-model';
import typeDefs from '../schema';
export interface ModuleOptions {
logger: Logger;
@@ -31,8 +32,6 @@ export interface ModuleOptions {
export async function createModule(
options: ModuleOptions,
): Promise<GraphQLModule> {
const { default: typeDefs } = require('../schema');
const catalogClient = new CatalogClient(
options.config.getString('backend.baseUrl'),
);
+9 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-catalog",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,11 +21,11 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/plugin-scaffolder": "^0.1.1-alpha.22",
"@backstage/plugin-techdocs": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/plugin-scaffolder": "^0.1.1-alpha.23",
"@backstage/plugin-techdocs": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -41,9 +41,9 @@
"swr": "^0.3.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/react-hooks": "^3.3.0",
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-circleci",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,10 +21,10 @@
"postpack": "backstage-cli postpack"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/plugin-catalog": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/plugin-catalog": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -38,8 +38,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+1 -2
View File
@@ -24,8 +24,7 @@ import { Entity } from '@backstage/catalog-model';
import { WarningPanel } from '@backstage/core';
export const isPluginApplicableToEntity = (entity: Entity) =>
Boolean(entity.metadata.annotations?.[CIRCLECI_ANNOTATION]) &&
entity.metadata.annotations?.[CIRCLECI_ANNOTATION] !== '';
Boolean(entity.metadata.annotations?.[CIRCLECI_ANNOTATION]);
export const Router = ({ entity }: { entity: Entity }) =>
!isPluginApplicableToEntity(entity) ? (
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-explore",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,8 +21,8 @@
"start": "backstage-cli plugin:serve"
},
"dependencies": {
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -33,9 +33,9 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-gcp-projects",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,8 +21,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -32,8 +32,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-github-actions",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,11 +21,11 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/core-api": "^0.1.1-alpha.22",
"@backstage/plugin-catalog": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/core-api": "^0.1.1-alpha.23",
"@backstage/plugin-catalog": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -40,8 +40,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
@@ -23,13 +23,12 @@ import { GITHUB_ACTIONS_ANNOTATION } from './useProjectName';
import { WarningPanel } from '@backstage/core';
export const isPluginApplicableToEntity = (entity: Entity) =>
Boolean(entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION]) &&
entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] !== '';
Boolean(entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION]);
export const Router = ({ entity }: { entity: Entity }) =>
// TODO(shmidt-i): move warning to a separate standardized component
!isPluginApplicableToEntity(entity) ? (
<WarningPanel title=" GitHubActions plugin:">
<WarningPanel title="GitHubActions plugin:">
<pre>{GITHUB_ACTIONS_ANNOTATION}</pre> annotation is missing on the
entity.
</WarningPanel>
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-gitops-profiles",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,8 +21,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -32,8 +32,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/plugin-graphiql",
"description": "Backstage plugin for browsing GraphQL APIs",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"private": false,
"publishConfig": {
"access": "public",
@@ -31,8 +31,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -43,9 +43,9 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-graphql-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -19,10 +19,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/plugin-catalog-graphql": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/config": "^0.1.1-alpha.23",
"@backstage/plugin-catalog-graphql": "^0.1.1-alpha.23",
"@graphql-modules/core": "^0.7.17",
"@backstage/backend-common": "^0.1.1-alpha.22",
"@types/express": "^4.17.6",
"apollo-server": "^2.16.1",
"apollo-server-express": "^2.16.1",
@@ -36,7 +36,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@types/supertest": "^2.0.8",
"eslint-plugin-graphql": "^4.0.0",
"msw": "^0.20.5",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-identity-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,7 +20,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@types/express": "^4.17.6",
"compression": "^1.7.4",
"cors": "^2.8.5",
@@ -33,7 +33,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"jest-fetch-mock": "^3.0.3",
"msw": "^0.20.5"
},
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-jenkins",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,10 +21,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/plugin-catalog": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/plugin-catalog": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -36,8 +36,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+1 -2
View File
@@ -23,8 +23,7 @@ import { WarningPanel } from '@backstage/core';
import { CITable } from './BuildsPage/lib/CITable';
export const isPluginApplicableToEntity = (entity: Entity) =>
Boolean(entity.metadata.annotations?.[JENKINS_ANNOTATION]) &&
entity.metadata.annotations?.[JENKINS_ANNOTATION] !== '';
Boolean(entity.metadata.annotations?.[JENKINS_ANNOTATION]);
export const Router = ({ entity }: { entity: Entity }) => {
return !isPluginApplicableToEntity(entity) ? (
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
};
+11
View File
@@ -0,0 +1,11 @@
# Kubernetes Backend
WORK IN PROGRESS
This is the backend part of the Kubernetes plugin.
It responds to Kubernetes requests from the frontend.
## Links
- [The Backstage homepage](https://backstage.io)
+42
View File
@@ -0,0 +1,42 @@
{
"name": "@backstage/plugin-kubernetes-backend",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"private": false,
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"scripts": {
"start": "backstage-cli backend:dev",
"build": "backstage-cli backend:build",
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"prepack": "backstage-cli prepack",
"postpack": "backstage-cli postpack",
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.23",
"@types/express": "^4.17.6",
"compression": "^1.7.4",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"fs-extra": "^9.0.0",
"helmet": "^4.0.0",
"morgan": "^1.10.0",
"winston": "^3.2.1",
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.23",
"jest-fetch-mock": "^3.0.3"
},
"files": [
"dist"
]
}
@@ -0,0 +1,23 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '@backstage/backend-common';
describe('test', () => {
it('unbreaks the test runner', () => {
expect(true).toBeTruthy();
});
});
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './service/router';
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import yn from 'yn';
import { getRootLogger } from '@backstage/backend-common';
import { startStandaloneServer } from './service/standaloneServer';
const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 3004;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
startStandaloneServer({ port, enableCors, logger }).catch(err => {
logger.error(err);
process.exit(1);
});
process.on('SIGINT', () => {
logger.info('CTRL+C pressed; exiting.');
process.exit(0);
});
@@ -0,0 +1,45 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import express from 'express';
import Router from 'express-promise-router';
import { Logger } from 'winston';
export interface RouterOptions {
logger: Logger;
}
const makeRouter = (logger: Logger): express.Router => {
const router = Router();
router.use(express.json());
router.get('/services/:serviceId', async (req, res) => {
const serviceId = req.params.serviceId;
logger.info(`HERE ${serviceId}`);
res.send({ serviceId });
});
return router;
};
export async function createRouter(
options: RouterOptions,
): Promise<express.Router> {
const logger = options.logger;
logger.info('Initializing Kubernetes backend');
return makeRouter(logger);
}
@@ -0,0 +1,52 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
errorHandler,
notFoundHandler,
requestLoggingHandler,
} from '@backstage/backend-common';
import compression from 'compression';
import cors from 'cors';
import express from 'express';
import helmet from 'helmet';
import { Logger } from 'winston';
import { createRouter } from './router';
export interface ApplicationOptions {
enableCors: boolean;
logger: Logger;
}
export async function createStandaloneApplication(
options: ApplicationOptions,
): Promise<express.Application> {
const { enableCors, logger } = options;
const app = express();
app.use(helmet());
if (enableCors) {
app.use(cors());
}
app.use(compression());
app.use(express.json());
app.use(requestLoggingHandler());
app.use('/', await createRouter({ logger }));
app.use(notFoundHandler());
app.use(errorHandler());
return app;
}
@@ -0,0 +1,50 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Server } from 'http';
import { Logger } from 'winston';
import { createStandaloneApplication } from './standaloneApplication';
export interface ServerOptions {
port: number;
enableCors: boolean;
logger: Logger;
}
export async function startStandaloneServer(
options: ServerOptions,
): Promise<Server> {
const logger = options.logger.child({ service: 'kubernetes-backend' });
logger.debug('Creating application...');
const app = await createStandaloneApplication({
enableCors: options.enableCors,
logger,
});
logger.debug('Starting application server...');
return await new Promise((resolve, reject) => {
const server = app.listen(options.port, (err?: Error) => {
if (err) {
reject(err);
return;
}
logger.info(`Listening on port ${options.port}`);
resolve(server);
});
});
}
@@ -0,0 +1,19 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require('jest-fetch-mock').enableMocks();
export {};
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
extends: [require.resolve('@backstage/cli/config/eslint')],
};
+13
View File
@@ -0,0 +1,13 @@
# kubernetes
Welcome to the kubernetes plugin!
_This plugin was created through the Backstage CLI_
## Getting started
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/kubernetes](http://localhost:3000/kubernetes).
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createDevApp } from '@backstage/dev-utils';
import { plugin } from '../src';
createDevApp().registerPlugin(plugin).render();
+47
View File
@@ -0,0 +1,47 @@
{
"name": "@backstage/plugin-kubernetes",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
"types": "dist/index.d.ts"
},
"scripts": {
"build": "backstage-cli plugin:build",
"start": "backstage-cli plugin:serve",
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"diff": "backstage-cli plugin:diff",
"prepack": "backstage-cli prepack",
"postpack": "backstage-cli postpack",
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "6.0.0-beta.0",
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
"@types/jest": "^26.0.7",
"@types/node": "^12.0.0",
"jest-fetch-mock": "^3.0.3"
},
"files": [
"dist"
]
}
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Entity } from '@backstage/catalog-model';
import { Route, Routes } from 'react-router-dom';
import { rootCatalogKubernetesRouteRef } from './plugin';
import { KubernetesContent } from './components/KubernetesContent';
import { WarningPanel } from '@backstage/core';
const KUBERNETES_ANNOTATION = 'backstage.io/kubernetes';
export const Router = ({ entity }: { entity: Entity }) => {
const kubernetesAnnotationValue =
entity.metadata.annotations?.[KUBERNETES_ANNOTATION];
if (!kubernetesAnnotationValue) {
return (
<WarningPanel title="Kubernetes plugin:">
<pre>{KUBERNETES_ANNOTATION}</pre> annotation is missing on the entity.
</WarningPanel>
);
}
return (
<Routes>
<Route
path={`/${rootCatalogKubernetesRouteRef.path}`}
element={<KubernetesContent entity={entity} />}
/>
</Routes>
);
};
@@ -0,0 +1,43 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DiscoveryApi } from '@backstage/core';
import { KubernetesApi } from './types';
export class KubernetesBackendClient implements KubernetesApi {
private readonly discoveryApi: DiscoveryApi;
constructor(options: { discoveryApi: DiscoveryApi }) {
this.discoveryApi = options.discoveryApi;
}
private async getRequired(path: string): Promise<any> {
const url = `${await this.discoveryApi.getBaseUrl('kubernetes')}${path}`;
const response = await fetch(url);
if (!response.ok) {
const payload = await response.text();
const message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
throw new Error(message);
}
return await response.json();
}
async getObjectsByServiceId(serviceId: String): Promise<{}> {
return await this.getRequired(`/services/${serviceId}`);
}
}
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createApiRef } from '@backstage/core';
export const kubernetesApiRef = createApiRef<KubernetesApi>({
id: 'plugin.kubernetes.service',
description:
'Used by the Kubernetes plugin to make requests to accompanying backend',
});
export interface KubernetesApi {
getObjectsByServiceId(serviceId: String): Promise<{}>;
}
@@ -0,0 +1,72 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { FC, useEffect, useState } from 'react';
import { Typography, Grid } from '@material-ui/core';
import {
InfoCard,
Page,
pageTheme,
Content,
ContentHeader,
useApi,
} from '@backstage/core';
import { Entity } from '@backstage/catalog-model';
import { kubernetesApiRef } from '../../api/types';
// TODO this is a temporary component used to construct the Kubernetes plugin boilerplate
export const KubernetesContent: FC<{ entity: Entity }> = ({ entity }) => {
const kubernetesApi = useApi(kubernetesApiRef);
const [kubernetesObjects, setKubernetesObjects] = useState<{} | undefined>(
undefined,
);
const [error, setError] = useState<string | undefined>(undefined);
useEffect(() => {
kubernetesApi
.getObjectsByServiceId(entity.metadata.name)
.then(result => {
setKubernetesObjects(result);
})
.catch(e => {
setError(e.message);
});
}, [entity.metadata.name, kubernetesApi]);
return (
<Page theme={pageTheme.tool}>
<Content>
<ContentHeader title="This is where you would see your kubernetes objects" />
<Grid container spacing={3} direction="column">
<Grid item>
<InfoCard title="This is where you would see your kubernetes objects">
<Typography variant="body1">
{kubernetesObjects === undefined && <div>loading....</div>}
{error !== undefined && <div>{error}</div>}
{kubernetesObjects !== undefined && (
<div>
backend response: {JSON.stringify(kubernetesObjects)}
</div>
)}
</Typography>
</InfoCard>
</Grid>
</Grid>
</Content>
</Page>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { KubernetesContent } from './KubernetesContent';
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { plugin } from './plugin';
export { Router } from './Router';
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { plugin } from './plugin';
describe('kubernetes', () => {
it('should export plugin', () => {
expect(plugin).toBeDefined();
});
});
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
createApiFactory,
createPlugin,
createRouteRef,
discoveryApiRef,
} from '@backstage/core';
import { KubernetesBackendClient } from './api/KubernetesBackendClient';
import { kubernetesApiRef } from './api/types';
export const rootCatalogKubernetesRouteRef = createRouteRef({
path: '*',
title: 'Kubernetes',
});
export const plugin = createPlugin({
id: 'kubernetes',
apis: [
createApiFactory({
api: kubernetesApiRef,
deps: { discoveryApi: discoveryApiRef },
factory: ({ discoveryApi }) =>
new KubernetesBackendClient({ discoveryApi }),
}),
],
});
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '@testing-library/jest-dom';
require('jest-fetch-mock').enableMocks();
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-lighthouse",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,9 +21,9 @@
"start": "backstage-cli plugin:serve"
},
"dependencies": {
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/config": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -34,9 +34,9 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-newrelic",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,8 +21,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -31,8 +31,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-proxy-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -19,8 +19,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/config": "^0.1.1-alpha.23",
"@types/express": "^4.17.6",
"@types/http-proxy-middleware": "^0.19.3",
"express": "^4.17.1",
@@ -35,7 +35,7 @@
"yup": "^0.29.1"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@types/node-fetch": "^2.5.7",
"@types/supertest": "^2.0.8",
"@types/uuid": "^8.0.0",
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-register-component",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,10 +21,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/plugin-catalog": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/plugin-catalog": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -36,8 +36,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
@@ -14,57 +14,38 @@
* limitations under the License.
*/
import { cleanup, fireEvent, render } from '@testing-library/react';
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { act } from 'react-dom/test-utils';
import RegisterComponentForm, { Props } from './RegisterComponentForm';
import { RegisterComponentForm } from './RegisterComponentForm';
const setup = (props?: Partial<Props>) => {
return {
rendered: render(
<RegisterComponentForm
onSubmit={jest.fn()}
submitting={false}
{...props}
/>,
),
};
};
describe('RegisterComponentForm', () => {
afterEach(() => cleanup());
it('should initially render a disabled button', async () => {
const { rendered } = setup();
render(<RegisterComponentForm onSubmit={jest.fn()} />);
expect(
await rendered.findByText(
'Enter the full path to the component.yaml file in GitHub, GitLab, Bitbucket or Azure to start tracking your component.',
),
await screen.findByText(/Enter the full path to the catalog-info.yaml/),
).toBeInTheDocument();
const submit = (await rendered.getByTestId(
'registerComponentFormSubmit',
)) as HTMLButtonElement;
expect(submit.disabled).toBeTruthy();
expect(screen.getByText('Submit').closest('button')).toBeDisabled();
});
it('should enable a submit form when data when component url is set ', async () => {
const { rendered } = setup();
const input = (await rendered.getByRole('textbox')) as HTMLInputElement;
it('should enable a submit button when the target url is set ', async () => {
render(<RegisterComponentForm onSubmit={jest.fn()} />);
await act(async () => {
// react-hook-form uses `input` event for changes
fireEvent.input(input, {
target: { value: 'https://example.com/blob/master/component.yaml' },
});
await userEvent.type(
await screen.findByLabelText('Entity file URL', { exact: false }),
'https://example.com/blob/master/component.yaml',
);
});
const submit = (await rendered.getByTestId(
'registerComponentFormSubmit',
)) as HTMLButtonElement;
expect(submit.disabled).toBeFalsy();
expect(screen.getByText('Submit').closest('button')).not.toBeDisabled();
});
it('should show spinner while submitting', async () => {
render(<RegisterComponentForm onSubmit={jest.fn()} submitting />);
expect(screen.getByTestId('loading-progress')).toBeInTheDocument();
});
});
it('should show spinner while submitting', async () => {
const { rendered } = setup({ submitting: true });
expect(rendered.getByTestId('loading-progress')).toBeInTheDocument();
});
@@ -19,15 +19,15 @@ import {
Button,
FormControl,
FormHelperText,
LinearProgress,
TextField,
Select,
MenuItem,
InputLabel,
LinearProgress,
MenuItem,
Select,
TextField,
} from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import React, { FC } from 'react';
import { useForm, Controller } from 'react-hook-form';
import React from 'react';
import { Controller, useForm } from 'react-hook-form';
import { ComponentIdValidators } from '../../util/validate';
const useStyles = makeStyles<BackstageTheme>(theme => ({
@@ -39,14 +39,17 @@ const useStyles = makeStyles<BackstageTheme>(theme => ({
submit: {
marginTop: theme.spacing(1),
},
select: {
minWidth: 120,
},
}));
export type Props = {
onSubmit: (formData: Record<string, string>) => Promise<void>;
submitting: boolean;
submitting?: boolean;
};
const RegisterComponentForm: FC<Props> = ({ onSubmit, submitting }) => {
export const RegisterComponentForm = ({ onSubmit, submitting }: Props) => {
const { control, register, handleSubmit, errors, formState } = useForm({
mode: 'onChange',
});
@@ -67,14 +70,14 @@ const RegisterComponentForm: FC<Props> = ({ onSubmit, submitting }) => {
<TextField
id="registerComponentInput"
variant="outlined"
label="Component file URL"
label="Entity file URL"
data-testid="componentLocationInput"
error={hasErrors}
placeholder="https://example.com/user/some-service/blob/master/component.yaml"
placeholder="https://example.com/user/some-service/blob/master/catalog-info.yaml"
name="componentLocation"
required
margin="normal"
helperText="Enter the full path to the component.yaml file in GitHub, GitLab, Bitbucket or Azure to start tracking your component."
helperText="Enter the full path to the catalog-info.yaml file in GitHub, GitLab, Bitbucket or Azure to start tracking your component."
inputRef={register({
required: true,
validate: ComponentIdValidators,
@@ -88,8 +91,8 @@ const RegisterComponentForm: FC<Props> = ({ onSubmit, submitting }) => {
)}
</FormControl>
<FormControl variant="outlined">
<InputLabel id="scmLabel">SCM Detection</InputLabel>
<FormControl variant="outlined" className={classes.select}>
<InputLabel id="scmLabel">Host type</InputLabel>
<Controller
control={control}
name="scmType"
@@ -112,8 +115,6 @@ const RegisterComponentForm: FC<Props> = ({ onSubmit, submitting }) => {
/>
</FormControl>
<Button
id="registerComponentFormSubmit"
data-testid="registerComponentFormSubmit"
variant="contained"
color="primary"
type="submit"
@@ -125,5 +126,3 @@ const RegisterComponentForm: FC<Props> = ({ onSubmit, submitting }) => {
</form>
);
};
export default RegisterComponentForm;
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { default } from './RegisterComponentForm';
export { RegisterComponentForm } from './RegisterComponentForm';
@@ -14,21 +14,24 @@
* limitations under the License.
*/
import React from 'react';
import { render, cleanup } from '@testing-library/react';
import { RegisterComponentPage } from './RegisterComponentPage';
import { ThemeProvider } from '@material-ui/core';
import { lightTheme } from '@backstage/theme';
import {
errorApiRef,
ApiProvider,
ApiRegistry,
createRouteRef,
errorApiRef,
} from '@backstage/core';
import { catalogApiRef } from '@backstage/plugin-catalog';
import { lightTheme } from '@backstage/theme';
import { ThemeProvider } from '@material-ui/core';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { RegisterComponentPage } from './RegisterComponentPage';
const errorApi = { post: () => {} };
const errorApi: jest.Mocked<typeof errorApiRef.T> = {
post: jest.fn(),
error$: jest.fn(),
};
const catalogApi: jest.Mocked<typeof catalogApiRef.T> = {
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
@@ -40,35 +43,31 @@ const catalogApi: jest.Mocked<typeof catalogApiRef.T> = {
getEntityByName: jest.fn(),
};
const setup = () => ({
rendered: render(
<MemoryRouter>
<ApiProvider
apis={ApiRegistry.from([
[errorApiRef, errorApi],
[catalogApiRef, catalogApi],
])}
>
<ThemeProvider theme={lightTheme}>
<RegisterComponentPage
catalogRouteRef={createRouteRef({
path: '/catalog',
title: 'Service Catalog',
})}
/>
</ThemeProvider>
</ApiProvider>
</MemoryRouter>,
),
});
const Wrapper = ({ children }: { children?: React.ReactNode }) => (
<MemoryRouter>
<ApiProvider
apis={ApiRegistry.with(errorApiRef, errorApi).with(
catalogApiRef,
catalogApi,
)}
>
<ThemeProvider theme={lightTheme}>{children}</ThemeProvider>
</ApiProvider>
</MemoryRouter>
);
describe('RegisterComponentPage', () => {
afterEach(() => cleanup());
it('should render', () => {
const { rendered } = setup();
expect(
rendered.getByText('Register existing component'),
).toBeInTheDocument();
render(
<RegisterComponentPage
catalogRouteRef={createRouteRef({
path: '/catalog',
title: 'Service Catalog',
})}
/>,
{ wrapper: Wrapper },
);
expect(screen.getByText('Register existing component')).toBeInTheDocument();
});
});
@@ -28,7 +28,7 @@ import {
ContentHeader,
RouteRef,
} from '@backstage/core';
import RegisterComponentForm from '../RegisterComponentForm';
import { RegisterComponentForm } from '../RegisterComponentForm';
import { catalogApiRef } from '@backstage/plugin-catalog';
import { useMountedState } from 'react-use';
import { Entity, Location } from '@backstage/catalog-model';
@@ -55,6 +55,7 @@ const FormStates = {
} as const;
type ValuesOf<T> = T extends Record<any, infer V> ? V : never;
export const RegisterComponentPage = ({
catalogRouteRef,
}: {
@@ -85,9 +86,9 @@ export const RegisterComponentPage = ({
const { scmType, componentLocation: target } = formData;
try {
const typeMapping = [
{ url: /https:\/\/gitlab\.com\/.*/, type: 'gitlab' },
{ url: /https:\/\/bitbucket\.org\/.*/, type: 'bitbucket/api' },
{ url: /https:\/\/dev\.azure\.com\/.*/, type: 'azure/api' },
{ url: /^https:\/\/gitlab\.com\/.*/, type: 'gitlab' },
{ url: /^https:\/\/bitbucket\.org\/.*/, type: 'bitbucket/api' },
{ url: /^https:\/\/dev\.azure\.com\/.*/, type: 'azure/api' },
{ url: /.*/, type: 'github' },
];
@@ -14,47 +14,40 @@
* limitations under the License.
*/
import { Entity } from '@backstage/catalog-model';
import { createRouteRef } from '@backstage/core';
import { lightTheme } from '@backstage/theme';
import { ThemeProvider } from '@material-ui/core';
import { cleanup, render } from '@testing-library/react';
import React, { ComponentProps } from 'react';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { RegisterComponentResultDialog } from './RegisterComponentResultDialog';
import { createRouteRef } from '@backstage/core';
const setup = (
props?: Partial<ComponentProps<typeof RegisterComponentResultDialog>>,
) => ({
rendered: render(
<MemoryRouter>
<ThemeProvider theme={lightTheme}>
<RegisterComponentResultDialog
onClose={() => {}}
entities={[]}
catalogRouteRef={createRouteRef({
path: '/catalog',
title: 'Service Catalog',
})}
{...props}
/>
</ThemeProvider>
</MemoryRouter>,
),
});
const Wrapper = ({ children }: { children?: React.ReactNode }) => (
<MemoryRouter>
<ThemeProvider theme={lightTheme}>{children}</ThemeProvider>
</MemoryRouter>
);
describe('RegisterComponentResultDialog', () => {
afterEach(() => cleanup());
it('should render', () => {
const { rendered } = setup();
expect(
rendered.getByText('Component Registration Result'),
).toBeInTheDocument();
});
});
render(
<RegisterComponentResultDialog
onClose={() => {}}
entities={[]}
catalogRouteRef={createRouteRef({
path: '/catalog',
title: 'Service Catalog',
})}
/>,
{ wrapper: Wrapper },
);
it('should show a list of components if success', async () => {
const { rendered } = setup({
entities: [
expect(screen.getByText('Registration Result')).toBeInTheDocument();
});
it('should show a list of components if success', async () => {
const entities: Entity[] = [
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
@@ -75,14 +68,26 @@ it('should show a list of components if success', async () => {
type: 'service',
},
},
],
});
];
expect(
rendered.getByText(
'The following components have been succefully created:',
),
).toBeInTheDocument();
expect(rendered.getByText('Component1')).toBeInTheDocument();
expect(rendered.getByText('Component2')).toBeInTheDocument();
render(
<RegisterComponentResultDialog
onClose={() => {}}
entities={entities}
catalogRouteRef={createRouteRef({
path: '/catalog',
title: 'Service Catalog',
})}
/>,
{ wrapper: Wrapper },
);
expect(
screen.getByText(
'The following entities have been successfully created:',
),
).toBeInTheDocument();
expect(screen.getByText('Component1')).toBeInTheDocument();
expect(screen.getByText('Component2')).toBeInTheDocument();
});
});
@@ -73,10 +73,10 @@ export const RegisterComponentResultDialog = ({
catalogRouteRef,
}: Props) => (
<Dialog open onClose={onClose} classes={classes}>
<DialogTitle>Component Registration Result</DialogTitle>
<DialogTitle>Registration Result</DialogTitle>
<DialogContent>
<DialogContentText>
The following components have been succefully created:
The following entities have been successfully created:
</DialogContentText>
<List>
{entities.map((entity: any, index: number) => {
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-rollbar-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,8 +20,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/config": "^0.1.1-alpha.23",
"@types/express": "^4.17.6",
"axios": "^0.20.0",
"camelcase-keys": "^6.2.2",
@@ -37,7 +37,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@types/supertest": "^2.0.8",
"jest-fetch-mock": "^3.0.3",
"supertest": "^4.0.2"
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-rollbar",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,10 +21,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/plugin-catalog": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/plugin-catalog": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -37,9 +37,9 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/react-hooks": "^3.3.0",
+1 -1
View File
@@ -23,7 +23,7 @@ import { ROLLBAR_ANNOTATION } from '../constants';
import { EntityPageRollbar } from './EntityPageRollbar/EntityPageRollbar';
export const isPluginApplicableToEntity = (entity: Entity) =>
entity.metadata.annotations?.[ROLLBAR_ANNOTATION] !== '';
Boolean(entity.metadata.annotations?.[ROLLBAR_ANNOTATION]);
type Props = {
entity: Entity;
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-scaffolder-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,9 +20,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/config": "^0.1.1-alpha.23",
"@gitbeaker/core": "^23.5.0",
"@gitbeaker/node": "^23.5.0",
"@octokit/rest": "^18.0.0",
@@ -46,7 +46,7 @@
"yaml": "^1.10.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@octokit/types": "^5.4.1",
"@types/fs-extra": "^9.0.1",
"@types/git-url-parse": "^9.0.0",
@@ -21,18 +21,18 @@ import { JsonValue } from '@backstage/config';
import { RequiredTemplateValues } from '../templater';
import { Repository, Remote, Signature, Cred } from 'nodegit';
export type RepoVisilityOptions = 'private' | 'internal' | 'public';
export type RepoVisibilityOptions = 'private' | 'internal' | 'public';
interface GithubPublisherParams {
client: Octokit;
token: string;
repoVisibility: RepoVisilityOptions;
repoVisibility: RepoVisibilityOptions;
}
export class GithubPublisher implements PublisherBase {
private client: Octokit;
private token: string;
private repoVisibility: RepoVisilityOptions;
private repoVisibility: RepoVisibilityOptions;
constructor({
client,
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-scaffolder",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,10 +21,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/plugin-catalog": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/plugin-catalog": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -41,9 +41,9 @@
"swr": "^0.3.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-sentry-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,7 +20,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@types/express": "^4.17.6",
"axios": "^0.20.0",
"compression": "^1.7.4",
@@ -34,7 +34,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"jest-fetch-mock": "^3.0.3"
},
"files": [
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-sentry",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,9 +21,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -36,8 +36,8 @@
"timeago.js": "^4.0.2"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-tech-radar",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,9 +21,9 @@
"start": "backstage-cli plugin:serve"
},
"dependencies": {
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -35,8 +35,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-techdocs-backend",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,9 +20,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/config": "^0.1.1-alpha.22",
"@backstage/backend-common": "^0.1.1-alpha.23",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/config": "^0.1.1-alpha.23",
"@types/dockerode": "^2.5.34",
"@types/express": "^4.17.6",
"command-exists-promise": "^2.0.2",
@@ -38,7 +38,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@types/node-fetch": "^2.5.7",
"supertest": "^4.0.2"
},
+9 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-techdocs",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -22,12 +22,12 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/core-api": "^0.1.1-alpha.22",
"@backstage/plugin-catalog": "^0.1.1-alpha.22",
"@backstage/test-utils": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/catalog-model": "^0.1.1-alpha.23",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/core-api": "^0.1.1-alpha.23",
"@backstage/plugin-catalog": "^0.1.1-alpha.23",
"@backstage/test-utils": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -40,8 +40,8 @@
"sanitize-html": "^1.27.0"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
@@ -21,6 +21,8 @@ import { useAsync } from 'react-use';
import { techdocsStorageApiRef } from '../../api';
import { useParams, useNavigate } from 'react-router-dom';
import { ParsedEntityId } from '../../types';
import { useTheme } from '@material-ui/core';
import { BackstageTheme } from '@backstage/theme';
import transformer, {
addBaseUrl,
@@ -30,6 +32,7 @@ import transformer, {
modifyCss,
onCssReady,
sanitizeDOM,
injectCss,
} from '../transformers';
import { TechDocsNotFound } from './TechDocsNotFound';
@@ -40,6 +43,7 @@ type Props = {
export const Reader = ({ entityId }: Props) => {
const { kind, namespace, name } = entityId;
const { '*': path } = useParams();
const theme = useTheme<BackstageTheme>();
const techdocsStorageApi = useApi(techdocsStorageApiRef);
const [shadowDomRef, shadowRoot] = useShadowDom();
@@ -73,6 +77,18 @@ export const Reader = ({ entityId }: Props) => {
},
}),
removeMkdocsHeader(),
injectCss({
css: `
body {
font-family: ${theme.typography.fontFamily};
--md-text-color: ${theme.palette.text.primary};
--md-text-link-color: ${theme.palette.primary.main};
--md-code-fg-color: ${theme.palette.text.primary};
--md-code-bg-color: ${theme.palette.background.paper};
}
`,
}),
]);
if (!transformedElement) {
@@ -125,6 +141,7 @@ export const Reader = ({ entityId }: Props) => {
entityId,
navigate,
techdocsStorageApi,
theme,
]);
if (error) {
@@ -21,6 +21,7 @@ export * from './removeMkdocsHeader';
export * from './modifyCss';
export * from './onCssReady';
export * from './sanitizeDOM';
export * from './injectCss';
export type Transformer = (dom: Element) => Element;
@@ -0,0 +1,40 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createTestShadowDom } from '../../test-utils';
import { injectCss } from '../transformers';
describe('injectCss', () => {
it('should inject style with passed css in head', () => {
const html = `
<html>
<head></head>
<body></body>
</html>
`;
const injectedCss = '* {background-color: #fff}';
const shadowDom = createTestShadowDom(html, {
preTransformers: [injectCss({ css: injectedCss })],
postTransformers: [],
});
const styleElement = shadowDom.querySelector('head > style');
expect(styleElement).toBeTruthy();
expect(styleElement!.innerHTML).toEqual(injectedCss);
});
});
@@ -0,0 +1,31 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { Transformer } from './index';
type InjectCssOptions = {
css: string;
};
export const injectCss = ({ css }: InjectCssOptions): Transformer => {
return dom => {
dom
.getElementsByTagName('head')[0]
.insertAdjacentHTML('beforeend', `<style>${css}</style>`);
return dom;
};
};
@@ -62,4 +62,42 @@ describe('sanitizeDOM', () => {
shadowDom.querySelector('#test-malicious-link')?.hasAttribute('onclick'),
).toBeFalsy();
});
it('removes style tags', () => {
const html = `
<html>
<head>
<style>* {color: #f0f;}<style>
</head>
<body>
</body>
</html>
`;
const shadowDom = createTestShadowDom(html, {
preTransformers: [sanitizeDOM()],
postTransformers: [],
});
expect(shadowDom.querySelectorAll('style').length).toEqual(0);
});
it('does not remove link tags', () => {
const html = `
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
</body>
</html>
`;
const shadowDom = createTestShadowDom(html, {
preTransformers: [sanitizeDOM()],
postTransformers: [],
});
expect(shadowDom.querySelectorAll('link').length).toEqual(1);
});
});
@@ -101,7 +101,6 @@ export const html = [
'span',
'strike',
'strong',
'style',
'sub',
'summary',
'sup',
@@ -162,7 +161,6 @@ export const svg = [
'radialgradient',
'rect',
'stop',
'style',
'switch',
'symbol',
'text',
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-welcome",
"version": "0.1.1-alpha.22",
"version": "0.1.1-alpha.23",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -21,8 +21,8 @@
"start": "backstage-cli plugin:serve"
},
"dependencies": {
"@backstage/core": "^0.1.1-alpha.22",
"@backstage/theme": "^0.1.1-alpha.22",
"@backstage/core": "^0.1.1-alpha.23",
"@backstage/theme": "^0.1.1-alpha.23",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -32,8 +32,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.22",
"@backstage/dev-utils": "^0.1.1-alpha.22",
"@backstage/cli": "^0.1.1-alpha.23",
"@backstage/dev-utils": "^0.1.1-alpha.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",