Merge branch 'master' of github.com:backstage/backstage into RoadieHQ-identity-api-client-interface-7

This commit is contained in:
Brian Fletcher
2022-08-23 15:28:40 +01:00
955 changed files with 13568 additions and 5271 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': patch
---
Workaround support for `swc` instead of `sucrase`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': minor
---
Add the option for a homepage when using the `github:publish` action
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-kafka': patch
'@backstage/plugin-kafka-backend': patch
'@backstage/plugin-lighthouse': patch
'@backstage/plugin-proxy-backend': patch
---
Minor API signatures cleanup
+16
View File
@@ -0,0 +1,16 @@
---
'@backstage/plugin-scaffolder-backend': minor
---
Fixed a bug in plugin-scaffolder-backend where it ignores the skip migration database options.
To use this new implementation you need to create the instance of `DatabaseTaskStore` using the `PluginDatabaseManager` instead of `Knex`;
```
import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common';
import { DatabaseTaskStore } from '@backstage/plugin-scaffolder-backend';
const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() });
const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } });
const databaseTaskStore = await DatabaseTaskStore.create(databaseManager);
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Fix bug with empty strings in `EntityPicker`
+25
View File
@@ -0,0 +1,25 @@
---
'@backstage/plugin-azure-devops': patch
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-azure-devops-common': patch
'@backstage/plugin-cloudbuild': patch
'@backstage/plugin-explore': patch
'@backstage/plugin-fossa': patch
'@backstage/plugin-git-release-manager': patch
'@backstage/plugin-github-actions': patch
'@backstage/plugin-jenkins': patch
'@backstage/plugin-newrelic-dashboard': patch
'@backstage/plugin-pagerduty': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-search-backend-node': patch
'@backstage/plugin-sentry': patch
'@backstage/plugin-sonarqube': patch
'@backstage/plugin-tech-insights': patch
'@backstage/plugin-tech-insights-node': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-techdocs-module-addons-contrib': patch
'@backstage/plugin-user-settings': patch
'@backstage/plugin-vault-backend': patch
---
Minor API signatures cleanup
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-tasks': patch
'@backstage/plugin-catalog-backend': patch
---
Added support to mysql on some raw queries
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/plugin-dynatrace': minor
---
New features:
- Some visual improvements to the table that displays Problems
- Added support for viewing recent Synthetics results using
- Added some additional linking to the configured Dynatrace instance
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': minor
---
Removed the previously deprecated class `AtlassianAuthProvider`. Please use `providers.atlassian.create(...)` instead.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-github': patch
---
New experimental alpha exports for use with the upcoming backend system.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Fix typo in the documentation
+71
View File
@@ -0,0 +1,71 @@
---
'@backstage/create-app': patch
---
The `packages/backend/Dockerfile` received a couple of updates, it now looks as follows:
```Dockerfile
FROM node:16-bullseye-slim
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
RUN apt-get update && \
apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \
rm -rf /var/lib/apt/lists/* && \
yarn config set python /usr/bin/python3
# From here on we use the least-privileged `node` user to run the backend.
USER node
WORKDIR /app
# This switches many Node.js dependencies to production mode.
ENV NODE_ENV production
# Copy repo skeleton first, to avoid unnecessary docker cache invalidation.
# The skeleton contains the package.json of each package in the monorepo,
# and along with yarn.lock and the root package.json, that's enough to run yarn install.
COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)"
# Then copy the rest of the backend bundle, along with any other files we might want.
COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"]
```
The two notable changes are that a `USER node` instruction has been added and the ordering of instructions has been changed accordingly. This means that the app will now be running using the least-privileged `node` user. In order for this to work we now need to make sure that all app files are owned by the `node` user, which we do by adding the `--chown=node:node` option to the `COPY` instructions.
The second change is the addition of `ENV NODE_ENV production`, which ensured that all Node.js modules run in production mode. If you apply this change to an existing app, note that one of the more significant changes is that this switches the log formatting to use the default production format, JSON. Rather than your log lines looking like this:
```log
2022-08-10T11:36:05.478Z catalog info Performing database migration type=plugin
```
They will now look like this:
```log
{"level":"info","message":"Performing database migration","plugin":"catalog","service":"backstage","type":"plugin"}
```
If you wish to keep the existing format, you can override this change by applying the following change to `packages/backend/src/index.ts`:
```diff
getRootLogger,
+ setRootLogger,
+ createRootLogger,
+ coloredFormat,
useHotMemoize,
...
ServerTokenManager,
} from '@backstage/backend-common';
...
async function main() {
+ setRootLogger(createRootLogger({ format: coloredFormat }));
+
const config = await loadBackendConfig({
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cost-insights': patch
---
The `CostInsightsHeader`component now uses group names if available
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/core-app-api': patch
'@backstage/core-plugin-api': patch
---
Added `getSystemIcons()` function to the `AppContext` available through `useApp` that will pull a list of all the icons that have been registered in the App.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Adds code to generate ids for headers parsed through the MarkdownContent component.
+16
View File
@@ -0,0 +1,16 @@
---
'@backstage/plugin-search-backend-module-pg': minor
---
Fixed a bug in search-backend-module-pg where it ignores the skip migration database options when using the database.
To use this new implementation you need to create the instance of `DatabaseDocumentStore` using the `PluginDatabaseManager` instead of `Knex`;
```
import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common';
import { DatabaseDocumentStore } from '@backstage/plugin-search-backend-module-pg';
const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() });
const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } });
const databaseDocumentStore = await DatabaseDocumentStore.create(databaseManager);
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-org': patch
---
Added an edit button to the `UserProfileCard` that is enabled when the `backstage.io/edit-url` is present, this matches how the `GroupProfileCard` works
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': minor
---
Renamed the `RedirectInfo` type to `OAuthStartResponse`
+63
View File
@@ -0,0 +1,63 @@
---
'@backstage/cli': patch
---
Switch out `sucrase` for `swc` for transpilation.
`sucrase` is a little more relaxed when it comes to supporting the ways of mocking in `jest`. You might have to make some changes to your tests to meet the `jest` standard and spec if your tests seems to start failing.
Mocks that look like this are invalid, and they will throw a reference error in line with the `jest` documentation [here on example 3](https://jestjs.io/docs/es6-class-mocks#calling-jestmock-with-the-module-factory-parameter)
```ts
const mockCommandExists = jest.fn();
jest.mock('command-exists', () => mockCommandExists);
```
You might need to update these mocks to look a little like the following to defer the call to the `jest.fn()` spy until the mock is called.
```ts
const mockCommandExists = jest.fn();
jest.mock(
'command-exists',
() =>
(...args: any[]) =>
commandExists(...args),
);
```
Also, imports are immutable. So it means that you might get some errors when trying to use `jest.spyOn` with starred imports. You might see an error like this:
```log
TypeError: Cannot redefine property: executeFrameHandlerStrategy
at Function.defineProperty (<anonymous>)
20 | import { AuthResolverContext } from '../types';
21 |
> 22 | const mockFrameHandler = jest.spyOn(
| ^
23 | helpers,
24 | 'executeFrameHandlerStrategy',
25 | ) as unknown as jest.MockedFunction<
```
This happens when you try to do `import * as something from './something'` and then `jest.spyOn(something, 'test)`. You will need to add a `jest.mock` call to mock out the required starred import to return `jest.fn()` functions from the start. Something like this fixes the above test:
```ts
jest.mock('../../helpers', () => ({
executeFrameHandlerStrategy: jest.fn(),
}));
```
You can also remove any occurrence of `hot(App)` and any import of `react-hot-loader` if you're using the that package locally, as all this has now been replaced with [React Refresh](https://www.npmjs.com/package/react-refresh) which you will get out of the box with the new CLI.
**Note** If you're experiencing difficulties with running tests after the migration, please reach out to us on Discord to see if we can help, or raise an issue. But in the meantime you can switch back to the existing behaviour by using the following config in your root `package.json`.
```json
"jest": {
"transform": {
"\\.(js|jsx|ts|tsx|mjs|cjs)$": "@backstage/cli/config/jestSucraseTransform.js",
"\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$": "@backstage/cli/config/jestFileTransform.js",
"\\.(yaml)$": "jest-transform-yaml"
}
}
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': patch
---
Simplified the `ServiceFactory` type and removed `AnyServiceFactory`.
+215
View File
@@ -0,0 +1,215 @@
{
"mode": "pre",
"tag": "next",
"initialVersions": {
"example-app": "0.2.74",
"@backstage/app-defaults": "1.0.5",
"example-backend": "0.2.74",
"@backstage/backend-app-api": "0.2.0",
"@backstage/backend-common": "0.15.0",
"@backstage/backend-defaults": "0.1.0",
"example-backend-next": "0.0.2",
"@backstage/backend-plugin-api": "0.1.1",
"@backstage/backend-tasks": "0.3.4",
"@backstage/backend-test-utils": "0.1.27",
"@backstage/catalog-client": "1.0.4",
"@backstage/catalog-model": "1.1.0",
"@backstage/cli": "0.18.1",
"@backstage/cli-common": "0.1.9",
"@backstage/codemods": "0.1.38",
"@backstage/config": "1.0.1",
"@backstage/config-loader": "1.1.3",
"@backstage/core-app-api": "1.0.5",
"@backstage/core-components": "0.11.0",
"@backstage/core-plugin-api": "1.0.5",
"@backstage/create-app": "0.4.30",
"@backstage/dev-utils": "1.0.5",
"e2e-test": "0.2.0",
"@backstage/errors": "1.1.0",
"@backstage/integration": "1.3.0",
"@backstage/integration-react": "1.1.3",
"@backstage/release-manifests": "0.0.5",
"@techdocs/cli": "1.2.0",
"techdocs-cli-embedded-app": "0.2.73",
"@backstage/test-utils": "1.1.3",
"@backstage/theme": "0.2.16",
"@backstage/types": "1.0.0",
"@backstage/version-bridge": "1.0.1",
"@backstage/plugin-adr": "0.2.0",
"@backstage/plugin-adr-backend": "0.2.0",
"@backstage/plugin-adr-common": "0.2.0",
"@backstage/plugin-airbrake": "0.3.8",
"@backstage/plugin-airbrake-backend": "0.2.8",
"@backstage/plugin-allure": "0.1.24",
"@backstage/plugin-analytics-module-ga": "0.1.19",
"@backstage/plugin-apache-airflow": "0.2.1",
"@backstage/plugin-api-docs": "0.8.8",
"@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.0",
"@backstage/plugin-apollo-explorer": "0.1.1",
"@backstage/plugin-app-backend": "0.3.35",
"@backstage/plugin-auth-backend": "0.15.1",
"@backstage/plugin-auth-node": "0.2.4",
"@backstage/plugin-azure-devops": "0.1.24",
"@backstage/plugin-azure-devops-backend": "0.3.14",
"@backstage/plugin-azure-devops-common": "0.2.4",
"@backstage/plugin-badges": "0.2.32",
"@backstage/plugin-badges-backend": "0.1.29",
"@backstage/plugin-bazaar": "0.1.23",
"@backstage/plugin-bazaar-backend": "0.1.19",
"@backstage/plugin-bitbucket-cloud-common": "0.1.2",
"@backstage/plugin-bitrise": "0.1.35",
"@backstage/plugin-catalog": "1.5.0",
"@backstage/plugin-catalog-backend": "1.3.1",
"@backstage/plugin-catalog-backend-module-aws": "0.1.8",
"@backstage/plugin-catalog-backend-module-azure": "0.1.6",
"@backstage/plugin-catalog-backend-module-bitbucket": "0.2.2",
"@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.2",
"@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.0",
"@backstage/plugin-catalog-backend-module-gerrit": "0.1.3",
"@backstage/plugin-catalog-backend-module-github": "0.1.6",
"@backstage/plugin-catalog-backend-module-gitlab": "0.1.6",
"@backstage/plugin-catalog-backend-module-ldap": "0.5.2",
"@backstage/plugin-catalog-backend-module-msgraph": "0.4.1",
"@backstage/plugin-catalog-backend-module-openapi": "0.1.1",
"@backstage/plugin-catalog-common": "1.0.5",
"@internal/plugin-catalog-customized": "0.0.1",
"@backstage/plugin-catalog-graph": "0.2.20",
"@backstage/plugin-catalog-graphql": "0.3.12",
"@backstage/plugin-catalog-import": "0.8.11",
"@backstage/plugin-catalog-node": "1.0.1",
"@backstage/plugin-catalog-react": "1.1.3",
"@backstage/plugin-cicd-statistics": "0.1.10",
"@backstage/plugin-cicd-statistics-module-gitlab": "0.1.4",
"@backstage/plugin-circleci": "0.3.8",
"@backstage/plugin-cloudbuild": "0.3.8",
"@backstage/plugin-code-climate": "0.1.8",
"@backstage/plugin-code-coverage": "0.2.1",
"@backstage/plugin-code-coverage-backend": "0.2.1",
"@backstage/plugin-codescene": "0.1.3",
"@backstage/plugin-config-schema": "0.1.31",
"@backstage/plugin-cost-insights": "0.11.30",
"@backstage/plugin-cost-insights-common": "0.1.1",
"@backstage/plugin-dynatrace": "0.1.2",
"@internal/plugin-todo-list": "1.0.4",
"@internal/plugin-todo-list-backend": "1.0.4",
"@internal/plugin-todo-list-common": "1.0.3",
"@backstage/plugin-explore": "0.3.39",
"@backstage/plugin-explore-react": "0.0.20",
"@backstage/plugin-firehydrant": "0.1.25",
"@backstage/plugin-fossa": "0.2.40",
"@backstage/plugin-gcalendar": "0.3.4",
"@backstage/plugin-gcp-projects": "0.3.27",
"@backstage/plugin-git-release-manager": "0.3.21",
"@backstage/plugin-github-actions": "0.5.8",
"@backstage/plugin-github-deployments": "0.1.39",
"@backstage/plugin-github-issues": "0.1.0",
"@backstage/plugin-github-pull-requests-board": "0.1.2",
"@backstage/plugin-gitops-profiles": "0.3.26",
"@backstage/plugin-gocd": "0.1.14",
"@backstage/plugin-graphiql": "0.2.40",
"@backstage/plugin-graphql-backend": "0.1.25",
"@backstage/plugin-home": "0.4.24",
"@backstage/plugin-ilert": "0.1.34",
"@backstage/plugin-jenkins": "0.7.7",
"@backstage/plugin-jenkins-backend": "0.1.25",
"@backstage/plugin-jenkins-common": "0.1.7",
"@backstage/plugin-kafka": "0.3.8",
"@backstage/plugin-kafka-backend": "0.2.28",
"@backstage/plugin-kubernetes": "0.7.1",
"@backstage/plugin-kubernetes-backend": "0.7.1",
"@backstage/plugin-kubernetes-common": "0.4.1",
"@backstage/plugin-lighthouse": "0.3.8",
"@backstage/plugin-newrelic": "0.3.26",
"@backstage/plugin-newrelic-dashboard": "0.2.1",
"@backstage/plugin-org": "0.5.8",
"@backstage/plugin-pagerduty": "0.5.1",
"@backstage/plugin-periskop": "0.1.6",
"@backstage/plugin-periskop-backend": "0.1.6",
"@backstage/plugin-permission-backend": "0.5.10",
"@backstage/plugin-permission-common": "0.6.3",
"@backstage/plugin-permission-node": "0.6.4",
"@backstage/plugin-permission-react": "0.4.4",
"@backstage/plugin-proxy-backend": "0.2.29",
"@backstage/plugin-rollbar": "0.4.8",
"@backstage/plugin-rollbar-backend": "0.1.32",
"@backstage/plugin-scaffolder": "1.5.0",
"@backstage/plugin-scaffolder-backend": "1.5.0",
"@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.10",
"@backstage/plugin-scaffolder-backend-module-rails": "0.4.3",
"@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.8",
"@backstage/plugin-scaffolder-common": "1.1.2",
"@backstage/plugin-search": "1.0.1",
"@backstage/plugin-search-backend": "1.0.1",
"@backstage/plugin-search-backend-module-elasticsearch": "1.0.1",
"@backstage/plugin-search-backend-module-pg": "0.3.6",
"@backstage/plugin-search-backend-node": "1.0.1",
"@backstage/plugin-search-common": "1.0.0",
"@backstage/plugin-search-react": "1.0.1",
"@backstage/plugin-sentry": "0.4.1",
"@backstage/plugin-shortcuts": "0.3.0",
"@backstage/plugin-sonarqube": "0.4.0",
"@backstage/plugin-sonarqube-backend": "0.1.0",
"@backstage/plugin-splunk-on-call": "0.3.32",
"@backstage/plugin-stack-overflow": "0.1.4",
"@backstage/plugin-stack-overflow-backend": "0.1.4",
"@backstage/plugin-tech-insights": "0.2.4",
"@backstage/plugin-tech-insights-backend": "0.5.1",
"@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.19",
"@backstage/plugin-tech-insights-common": "0.2.6",
"@backstage/plugin-tech-insights-node": "0.3.3",
"@backstage/plugin-tech-radar": "0.5.15",
"@backstage/plugin-techdocs": "1.3.1",
"@backstage/plugin-techdocs-addons-test-utils": "1.0.3",
"@backstage/plugin-techdocs-backend": "1.2.1",
"@backstage/plugin-techdocs-module-addons-contrib": "1.0.3",
"@backstage/plugin-techdocs-node": "1.3.0",
"@backstage/plugin-techdocs-react": "1.0.3",
"@backstage/plugin-todo": "0.2.10",
"@backstage/plugin-todo-backend": "0.1.32",
"@backstage/plugin-user-settings": "0.4.7",
"@backstage/plugin-vault": "0.1.2",
"@backstage/plugin-vault-backend": "0.2.1",
"@backstage/plugin-xcmetrics": "0.2.28"
},
"changesets": [
"beige-monkeys-add",
"beige-pumas-tap",
"clever-beans-turn",
"cold-frogs-kiss",
"dry-games-end",
"eight-spies-protect",
"five-carrots-pay",
"fresh-rabbits-juggle",
"gorgeous-swans-kiss",
"happy-kiwis-look",
"hot-files-begin",
"hot-suits-glow",
"hungry-dogs-agree",
"lazy-snakes-film",
"light-beans-share",
"lucky-points-wash",
"nervous-rivers-sneeze",
"old-tables-joke",
"renovate-7d3b357",
"renovate-c98c336",
"rotten-books-crash",
"rude-books-rush",
"shaggy-chicken-behave",
"sharp-swans-suffer",
"shiny-lobsters-fix",
"silent-kings-live",
"slimy-zebras-reply",
"spicy-cherries-remember",
"strong-games-kiss",
"strong-planes-return",
"tame-papayas-protect",
"techdocs-jeans-wait",
"tiny-oranges-thank",
"tough-dolphins-smile",
"two-planets-provide",
"weak-yaks-learn",
"wild-sheep-roll",
"witty-cats-wink",
"young-trees-rescue"
]
}
+44
View File
@@ -0,0 +1,44 @@
---
'@backstage/plugin-allure': patch
'@backstage/plugin-apache-airflow': patch
'@backstage/plugin-app-backend': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-bitrise': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-catalog-graphql': patch
'@backstage/plugin-cicd-statistics': patch
'@backstage/plugin-circleci': patch
'@backstage/plugin-cloudbuild': patch
'@backstage/plugin-code-climate': patch
'@backstage/plugin-config-schema': patch
'@backstage/plugin-cost-insights': patch
'@backstage/plugin-dynatrace': patch
'@backstage/plugin-explore': patch
'@backstage/plugin-explore-react': patch
'@backstage/plugin-firehydrant': patch
'@backstage/plugin-gcalendar': patch
'@backstage/plugin-gcp-projects': patch
'@backstage/plugin-github-actions': patch
'@backstage/plugin-github-deployments': patch
'@backstage/plugin-github-pull-requests-board': patch
'@backstage/plugin-gitops-profiles': patch
'@backstage/plugin-graphql-backend': patch
'@backstage/plugin-home': patch
'@backstage/plugin-ilert': patch
'@backstage/plugin-jenkins-backend': patch
'@backstage/plugin-kubernetes-common': patch
'@backstage/plugin-newrelic': patch
'@backstage/plugin-newrelic-dashboard': patch
'@backstage/plugin-pagerduty': patch
'@backstage/plugin-rollbar': patch
'@backstage/plugin-rollbar-backend': patch
'@backstage/plugin-search-backend-module-pg': patch
'@backstage/plugin-sentry': patch
'@backstage/plugin-shortcuts': patch
'@backstage/plugin-splunk-on-call': patch
'@backstage/plugin-tech-radar': patch
'@backstage/plugin-user-settings': patch
'@backstage/plugin-xcmetrics': patch
---
Minor API signatures cleanup
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Updated dependency `json-schema-library` to `^7.0.0`.
+108
View File
@@ -0,0 +1,108 @@
---
'@backstage/backend-common': patch
'@backstage/backend-test-utils': patch
'@backstage/catalog-client': patch
'@backstage/cli': patch
'@backstage/config-loader': patch
'@backstage/core-app-api': patch
'@backstage/core-components': patch
'@backstage/core-plugin-api': patch
'@backstage/integration-react': patch
'@backstage/integration': patch
'@backstage/release-manifests': patch
'@backstage/test-utils': patch
'@backstage/plugin-adr-backend': patch
'@backstage/plugin-adr': patch
'@backstage/plugin-airbrake-backend': patch
'@backstage/plugin-airbrake': patch
'@backstage/plugin-allure': patch
'@backstage/plugin-analytics-module-ga': patch
'@backstage/plugin-apache-airflow': patch
'@backstage/plugin-api-docs': patch
'@backstage/plugin-apollo-explorer': patch
'@backstage/plugin-app-backend': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-auth-node': patch
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-azure-devops': patch
'@backstage/plugin-badges': patch
'@backstage/plugin-bitbucket-cloud-common': patch
'@backstage/plugin-bitrise': patch
'@backstage/plugin-catalog-backend-module-azure': patch
'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch
'@backstage/plugin-catalog-backend-module-bitbucket-server': patch
'@backstage/plugin-catalog-backend-module-bitbucket': patch
'@backstage/plugin-catalog-backend-module-gerrit': patch
'@backstage/plugin-catalog-backend-module-github': patch
'@backstage/plugin-catalog-backend-module-gitlab': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-graphql': patch
'@backstage/plugin-catalog-import': patch
'@backstage/plugin-circleci': patch
'@backstage/plugin-cloudbuild': patch
'@backstage/plugin-code-climate': patch
'@backstage/plugin-code-coverage-backend': patch
'@backstage/plugin-code-coverage': patch
'@backstage/plugin-codescene': patch
'@backstage/plugin-config-schema': patch
'@backstage/plugin-cost-insights': patch
'@backstage/plugin-dynatrace': patch
'@backstage/plugin-explore-react': patch
'@backstage/plugin-explore': patch
'@backstage/plugin-firehydrant': patch
'@backstage/plugin-fossa': patch
'@backstage/plugin-gcalendar': patch
'@backstage/plugin-gcp-projects': patch
'@backstage/plugin-git-release-manager': patch
'@backstage/plugin-github-actions': patch
'@backstage/plugin-github-deployments': patch
'@backstage/plugin-github-issues': patch
'@backstage/plugin-github-pull-requests-board': patch
'@backstage/plugin-gitops-profiles': patch
'@backstage/plugin-gocd': patch
'@backstage/plugin-graphiql': patch
'@backstage/plugin-graphql-backend': patch
'@backstage/plugin-home': patch
'@backstage/plugin-ilert': patch
'@backstage/plugin-jenkins-backend': patch
'@backstage/plugin-jenkins': patch
'@backstage/plugin-kafka': patch
'@backstage/plugin-kubernetes': patch
'@backstage/plugin-lighthouse': patch
'@backstage/plugin-newrelic': patch
'@backstage/plugin-org': patch
'@backstage/plugin-pagerduty': patch
'@backstage/plugin-periskop-backend': patch
'@backstage/plugin-periskop': patch
'@backstage/plugin-permission-backend': patch
'@backstage/plugin-permission-common': patch
'@backstage/plugin-permission-node': patch
'@backstage/plugin-proxy-backend': patch
'@backstage/plugin-rollbar-backend': patch
'@backstage/plugin-rollbar': patch
'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-search': patch
'@backstage/plugin-sentry': patch
'@backstage/plugin-shortcuts': patch
'@backstage/plugin-sonarqube-backend': patch
'@backstage/plugin-sonarqube': patch
'@backstage/plugin-splunk-on-call': patch
'@backstage/plugin-stack-overflow': patch
'@backstage/plugin-tech-insights': patch
'@backstage/plugin-tech-radar': patch
'@backstage/plugin-techdocs-addons-test-utils': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/plugin-techdocs-module-addons-contrib': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-todo-backend': patch
'@backstage/plugin-todo': patch
'@backstage/plugin-user-settings': patch
'@backstage/plugin-vault-backend': patch
'@backstage/plugin-vault': patch
'@backstage/plugin-xcmetrics': patch
---
Updated dependency `msw` to `^0.45.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': patch
---
Cloudflare Access Provider: Add JWT to CloudflareAccessResult
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/dev-utils': patch
---
Removed the dependency and setup of `react-hot-loader`, since the `@backstage/cli` now uses `swc` with `React Refresh` instead.
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/backend-tasks': patch
'@backstage/plugin-app-backend': patch
'@backstage/plugin-bazaar-backend': patch
'@backstage/plugin-code-coverage-backend': patch
'@backstage/plugin-tech-insights-backend': patch
---
Fixed a bug where the database option to skip migrations was ignored.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-scaffolder-backend': minor
'@backstage/plugin-scaffolder-common': minor
---
add entity metadata to the template info type
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': minor
---
Added support for `async` validation for the `next` version of the plugin
+39
View File
@@ -0,0 +1,39 @@
---
'@backstage/plugin-azure-devops-backend': patch
---
`createRouter` now requires an additional reader: `UrlReader` argument
```diff
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
return createRouter({
logger: env.logger,
config: env.config,
+ reader: env.reader,
});
}
```
Remember to check if you have already provided these settings previously.
#### [Azure DevOps]
```yaml
# app-config.yaml
azureDevOps:
host: dev.azure.com
token: my-token
organization: my-company
```
#### [Azure Integrations]
```yaml
# app-config.yaml
integrations:
azure:
- host: dev.azure.com
token: ${AZURE_TOKEN}
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Removed the depreacated `publish:file` action, use the template editor to test templates instead.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-ldap': patch
---
Now the `searchStream` method in LDAP client awaits the callbacks
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/backend-app-api': patch
'@backstage/backend-defaults': patch
'@backstage/backend-test-utils': patch
---
Updated usages of `ServiceFactory`.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-node': patch
---
The experimental `CatalogProcessingExtensionPoint` now accepts multiple providers and processors at once.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-tech-insights-backend': patch
'@backstage/plugin-tech-insights-node': patch
---
Support for timeout in FactRetrieverRegistrationOptions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': patch
---
When defining a new `ServiceRef` you can now also include a `defaultFactory`, which will be used to construct instances of the service in case there is no explicit factory defined.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
Always update the title and sub-title when the location changes on a `TechDocs` reader page.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-insights-backend': patch
---
Modify Tech insight initialization to expose FactRetrieverEngine. Enables users to trigger fact retrieval manually or reschedule retrievers on runtime.
+19
View File
@@ -0,0 +1,19 @@
---
'@backstage/catalog-client': patch
'@backstage/core-plugin-api': patch
'@backstage/plugin-api-docs': patch
'@backstage/plugin-apollo-explorer': patch
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-badges': patch
'@backstage/plugin-badges-backend': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-circleci': patch
'@backstage/plugin-cloudbuild': patch
'@backstage/plugin-kubernetes': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-search-backend-module-elasticsearch': patch
'@backstage/plugin-sonarqube-backend': patch
'@backstage/plugin-techdocs': patch
---
Minor API signatures cleanup
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': minor
---
Implementing review step for the scaffolder under `create/next`
+49
View File
@@ -0,0 +1,49 @@
---
'@backstage/plugin-azure-devops': minor
'@backstage/plugin-azure-devops-common': minor
---
Added README card `EntityAzureReadmeCard` for Azure Devops.
To get the README component working you'll need to do the following two steps:
1. First we need to add the @backstage/plugin-azure-devops package to your frontend app:
```bash
# From your Backstage root directory
yarn add --cwd packages/app @backstage/plugin-azure-devops
```
2. Second we need to add the `EntityAzureReadmeCard` extension to the entity page in your app:
```tsx
// In packages/app/src/components/catalog/EntityPage.tsx
import {
EntityAzureReadmeCard,
isAzureDevOpsAvailable,
} from '@backstage/plugin-azure-devops';
// As it is a card, you can customize it the way you prefer
// For example in the Service section
const overviewContent = (
<Grid container spacing={3} alignItems="stretch">
<EntitySwitch>
<EntitySwitch.Case if={isAzureDevOpsAvailable}>
<Grid item md={6}>
...
</Grid>
<Grid item md={6}>
<EntityAzureReadmeCard maxHeight={350} />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
</Grid>
);
```
**Notes:**
- You'll need to add the `EntitySwitch.Case` above from step 2 to all the entity sections you want to see Readme in. For example if you wanted to see Readme when looking at Website entities then you would need to add this to the `websiteEntityPage` section.
- The `if` prop is optional on the `EntitySwitch.Case`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation
- The `maxHeight` property on the `EntityAzureReadmeCard` will set the maximum screen size you would like to see, if not set it will default to 100%
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/core-components': patch
'@backstage/plugin-adr': patch
'@backstage/plugin-apache-airflow': patch
'@backstage/plugin-api-docs': patch
---
Minor cleanup of the public API surface to reduce the number of warnings
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-msgraph': patch
---
Fix typo
+24
View File
@@ -0,0 +1,24 @@
---
'@backstage/create-app': patch
---
Added `EntityLinksCard` to the system `EntityPage`.
For an existing installation where you want to display the links card for entity pages of kind `system` you should make the following adjustment to `packages/app/src/components/catalog/EntityPage.tsx`
```diff
const systemPage = (
...
<Grid item md={6} xs={12}>
<EntityCatalogGraphCard variant="gridItem" height={400} />
</Grid>
+ <Grid item md={4} xs={12}>
+ <EntityLinksCard />
+ </Grid>
- <Grid item md={6}>
+ <Grid item md={8}>
<EntityHasComponentsCard variant="gridItem" />
</Grid>
...
);
```
+1
View File
@@ -313,6 +313,7 @@ Talkdesk
tasklist
techdocs
Telenor
telus
templated
templater
Templater
+3 -3
View File
@@ -28,7 +28,6 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi
| [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. |
| [Trendyol](https://trendyol.com) | [Gamze Senturk](https://github.com/gmzsenturk), [Mert Can Bilgic](https://github.com/mertcb) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. |
| [Peloton](https://www.onepeloton.com/) | [Matt Waldron](https://github.com/daftgopher) | Creating our first developer portal and tech-docs. Exploring Service Catalog, Tech Insights and Cost Insights as well. |
| [TELUS](https://telus.com) | [Seb Barre](https://github.com/sbarre) | The Go-to place to find answers about development and delivery at TELUS. |
| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a teams engineering dependencies. |
| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. |
| [Booz Allen Hamilton](https://www.boozallen.com/) | [Jason Miller](https://github.com/JasonMiller-BAH) | Developer portal for a full-stack software development ecosystem that accelerates consistent and repeatable Modern Software Development practices for internal innovation and investments. |
@@ -201,10 +200,11 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi
| [Intility](https://intility.no/en/) | [@daniwk](https://github.com/daniwk) | We are creating a developer portal powered by Backstage, with software catalog, documentation, templates and integrations to our infrastructure and internal tools. |
| [ImmobiliareLabs](https://labs.immobiliare.it/) | [@JellyBellyDev](https://github.com/JellyBellyDev) | Centralized portal with our internal services, infrastructures, relationships between systems, technical documentation, templates, monitoring and custom integrations with our own DX tools. |
| [Skillz](https://skillz.com/) | [Peiman Jafari](https://github.com/peimanja) | Internal developers portal for technical documentations, components ownership and relationship, software templates and integrations with internal tools |
| [Telus](https://www.telus.com/en/) | [Leo Li](mailto:leo.li@telus.com), [Laurent Robichaud](mailto:laurent.robichaud@telus.com) | Simplifying the developer experience through centralized team member portals. Our current focus includes the adoption of Tech Docs, Software Catalog, Software Templates, the plethora of plugins, and contributing features back to Backstage. 🤖 |
| [Telus](https://www.telus.com/en/) | [Leo Li](mailto:leo.li@telus.com), [Laurent Robichaud](mailto:laurent.robichaud@telus.com), [Seb Barre](https://github.com/sbarre) | Simplifying the developer experience through centralized team member portals. Our current focus includes the adoption of Tech Docs, Software Catalog, Software Templates, the plethora of plugins, and contributing features back to Backstage. 🤖 |
| [Fidelity Investments](https://fidelity.com) | [Ankita Upadhyay](mailto:ankita.upadhyay@fmr.com) | Getting started with the adoption for Monorepo projects |
| [Verisk](https://verisk.com) | [Callen Barton](mailto:cbarton@verisk.com) | Developer portal to quickly create and deploy microservices. |
| [iodigital](https://iodigital.com) | [Jan-Willem Mulder](mailto:jan-willem.mulder@iodigital.com) | Internal developer portal for discovery of applications, projects and teams. Using several plugins like the Software Catalog and Tech Insights for promoting best practices and supporting our SDLC toolchain |
| [Fanatics](https://www.fanaticsinc.com/) | [Rory Scott](mailto:rscott@fanatics.com) | Internal Portal consolidating documentation, making it easier to manage applications, internal developer community platform, and self-service cloud infrastructure + pipelines. |
| [Appfolio](https://appfolio.com) | [Andy Vaughn](mailto:andy.vaughn@appfolio.com) | Internal software catalog, tech radar, documentation portal to disambiguate software and domain ownership, foster exploration of available developer platform services and tools, improve communication, democratize documentation and knowledge sharing, and coordinate the software lifecycle; all in service of a best-in-class developer experience. |
| [isaac](https://isaac.com.br/) | [Leonardo Borges](mailto:leonardo.borges@isaac.com.br), [Ordilei Souza](mailto:ordilei.souza@isaac.com.br) | We're using Backstage as our Internal Developer Portal and main microservices catalog for mapping ownership, health and metrics for each one.
| [isaac](https://isaac.com.br/) | [Leonardo Borges](mailto:leonardo.borges@isaac.com.br), [Ordilei Souza](mailto:ordilei.souza@isaac.com.br) | We're using Backstage as our Internal Developer Portal and main microservices catalog for mapping ownership, health and metrics for each one. |
| [Paraná Banco](https://site.paranabanco.com.br/) | [Joao Antunes](mailto:joaopma@pbtech.net.br) | Internal software catalog, documentation and ownership, improve communication, democratize documentation and knowledge sharing, and coordinate the software lifecycle; all in service of a best-in-class developer experience. |
+1 -3
View File
@@ -2,9 +2,7 @@
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 0.x | :white_check_mark: |
See our [Release & Versioning Policy](https://backstage.io/docs/overview/versioning-policy#release-versioning-policy).
## Reporting a Vulnerability
@@ -1,11 +0,0 @@
FROM alpine:3.16
RUN apk add --update \
git \
python \
python-dev \
py-pip \
g++ && \
pip install cookiecutter jinja2_custom_filters_extension && \
apk del g++ py-pip python-dev && \
rm -rf /var/cache/apk/*
@@ -51,7 +51,7 @@ steps:
imageName: 'foo/custom-built-cookiecutter-image-with-extensions'
```
See for example, the [`Dockerfile`](./Dockerfile) in this directory.
For example, you can `pip install jinja2_custom_filters_extension` as part of your cookiecutter Dockerfile.
### Instructing Cookiecutter to use the extension
@@ -1,33 +0,0 @@
FROM node:14-buster
WORKDIR /usr/src/app
# (workaround) Install cookiecutter and mkdocs to avoid the need to run docker in docker
RUN cd /tmp && curl -O https://www.python.org/ftp/python/3.8.2/Python-3.8.2.tar.xz && \
tar -xvf Python-3.8.2.tar.xz && \
cd Python-3.8.2 && \
./configure --enable-optimizations && \
make -j 4 && \
make altinstall
RUN apt update
RUN apt install -y mkdocs
RUN pip3.8 install mkdocs-techdocs-core
RUN pip3.8 install cookiecutter && \
apt remove -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libsqlite3-dev libreadline-dev libffi-dev libbz2-dev g++ python-pip python-dev && \
rm -rf /var/cache/apt/* /tmp/Python-3.8.2
# Copy repo skeleton first, to avoid unnecessary docker cache invalidation.
# The skeleton contains the package.json of each package in the monorepo,
# and along with yarn.lock and the root package.json, that's enough to run yarn install.
ADD yarn.lock package.json skeleton.tar ./
RUN yarn install --frozen-lockfile --production
# This will copy the contents of the dist-workspace when running the build-image command.
# Do not use this Dockerfile outside of that command, as it will copy in the source code instead.
COPY . .
CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.development.yaml"]
@@ -1,13 +0,0 @@
# Example backend Dockerfile
This Dockerfile will build the example backend with certain additional binaries needed to workaround
the docker requirement in the scaffolder and techdocs.
# Usage
```bash
yarn docker-build -f <absolute_path_to_the_dockerfile> --tag <your_tag>
```
> The absolute path is necessary as this directory is not copied to the build workspace when building
> the docker image.
+12 -12
View File
@@ -40,14 +40,14 @@
lodash.once "^4.1.1"
"@types/node@*":
version "18.6.3"
resolved "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz#4e4a95b6fe44014563ceb514b2598b3e623d1c98"
integrity sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg==
version "18.7.6"
resolved "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz#31743bc5772b6ac223845e18c3fc26f042713c83"
integrity sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==
"@types/node@^14.14.31":
version "14.18.23"
resolved "https://registry.npmjs.org/@types/node/-/node-14.18.23.tgz#70f5f20b0b1b38f696848c1d3647bb95694e615e"
integrity sha512-MhbCWN18R4GhO8ewQWAFK4TGQdBpXWByukz7cWyJmXhvRuCIaM/oWytGPqVmDzgEnnaIc9ss6HbU5mUi+vyZPA==
version "14.18.24"
resolved "https://registry.npmjs.org/@types/node/-/node-14.18.24.tgz#406b220dc748947e1959d8a38a75979e87166704"
integrity sha512-aJdn8XErcSrfr7k8ZDDfU6/2OgjZcB2Fu9d+ESK8D7Oa5mtsv8Fa8GpcwTA0v60kuZBaalKPzuzun4Ov1YWO/w==
"@types/sinonjs__fake-timers@8.1.1":
version "8.1.1"
@@ -304,9 +304,9 @@ cross-spawn@^7.0.0:
which "^2.0.1"
cypress@^10.0.0:
version "10.4.0"
resolved "https://registry.npmjs.org/cypress/-/cypress-10.4.0.tgz#bb5b3b6588ad49eff172fecf5778cc0da2980e4e"
integrity sha512-OM7F8MRE01SHQRVVzunid1ZK1m90XTxYnl+7uZfIrB4CYqUDCrZEeSyCXzIbsS6qcaijVCAhqDL60SxG8N6hew==
version "10.6.0"
resolved "https://registry.npmjs.org/cypress/-/cypress-10.6.0.tgz#13f46867febf2c3715874ed5dce9c2e946b175fe"
integrity sha512-6sOpHjostp8gcLO34p6r/Ci342lBs8S5z9/eb3ZCQ22w2cIhMWGUoGKkosabPBfKcvRS9BE4UxybBtlIs8gTQA==
dependencies:
"@cypress/request" "^2.88.10"
"@cypress/xvfb" "^1.2.4"
@@ -359,9 +359,9 @@ dashdash@^1.12.0:
assert-plus "^1.0.0"
dayjs@^1.10.4:
version "1.11.4"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.4.tgz#3b3c10ca378140d8917e06ebc13a4922af4f433e"
integrity sha512-Zj/lPM5hOvQ1Bf7uAvewDaUcsJoI6JmNqmHhHl3nyumwe0XHwt8sWdOVAPACJzCebL8gQCi+K49w7iKWnGwX9g==
version "1.11.5"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz#00e8cc627f231f9499c19b38af49f56dc0ac5e93"
integrity sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==
debug@^3.1.0:
version "3.2.7"
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

+19 -9
View File
@@ -58,8 +58,6 @@ Once the host build is complete, we are ready to build our image. The following
```Dockerfile
FROM node:16-bullseye-slim
WORKDIR /app
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
RUN apt-get update && \
@@ -67,16 +65,23 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/* && \
yarn config set python /usr/bin/python3
# From here on we use the least-privileged `node` user to run the backend.
USER node
WORKDIR /app
# This switches many Node.js dependencies to production mode.
ENV NODE_ENV production
# Copy repo skeleton first, to avoid unnecessary docker cache invalidation.
# The skeleton contains the package.json of each package in the monorepo,
# and along with yarn.lock and the root package.json, that's enough to run yarn install.
COPY yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)"
# Then copy the rest of the backend bundle, along with any other files we might want.
COPY packages/backend/dist/bundle.tar.gz app-config.yaml ./
COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
@@ -177,8 +182,6 @@ RUN yarn --cwd packages/backend build
# Stage 3 - Build the actual backend image and install production dependencies
FROM node:16-bullseye-slim
WORKDIR /app
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
RUN apt-get update && \
@@ -186,18 +189,25 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/* && \
yarn config set python /usr/bin/python3
# From here on we use the least-privileged `node` user to run the backend.
USER node
WORKDIR /app
# This switches many Node.js dependencies to production mode.
ENV NODE_ENV production
# Copy the install dependencies from the build stage and context
COPY --from=build /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton.tar.gz ./
COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton.tar.gz ./
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
RUN yarn install --frozen-lockfile --production --network-timeout 600000 && rm -rf "$(yarn cache dir)"
# Copy the built packages from the build stage
COPY --from=build /app/packages/backend/dist/bundle.tar.gz .
COPY --from=build --chown=node:node /app/packages/backend/dist/bundle.tar.gz .
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
# Copy any other files that we need at runtime
COPY app-config.yaml ./
COPY --chown=node:node app-config.yaml ./
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
```
+59 -4
View File
@@ -273,18 +273,22 @@ const LogoFull = () => {
};
```
## Custom Icons
## Icons
So far you've seen how to create your own theme and add your own logo, in the following sections you'll be shown how to override the existing icons and how to add more icons
### Custom Icons
You can also customize the Project's _default_ icons.
You can change the following [icons](https://github.com/backstage/backstage/blob/master/packages/app-defaults/src/defaults/icons.tsx).
### Requirements
#### Requirements
- Files in `.svg` format
- React components created for the icons
### Create React Component
#### Create React Component
In your front-end application, locate the `src` folder. We suggest creating the `assets/icons` directory and `CustomIcons.tsx` file.
@@ -309,7 +313,7 @@ export const ExampleIcon = (props: SvgIconProps) => (
);
```
### Using the custom icon
#### Using the custom icon
Supply your custom icon in `packages/app/src/App.tsx`
@@ -338,6 +342,57 @@ const app = createApp({
[...]
```
### Adding Icons
You can add more icons, if the [default icons](https://github.com/backstage/backstage/blob/master/packages/app-defaults/src/defaults/icons.tsx) do not fit your needs, so that they can be used in other places like for Links in your entities. For this example we'll be using icons from[Material UI](https://v4.mui.com/components/material-icons/) and specifically the `AlarmIcon`. Here's how to do that:
1. First you will want to open your `App.tsx` in `/packages/app/src`
2. Then you want to import your icon, add this to the rest of your imports: `import AlarmIcon from '@material-ui/icons/Alarm';`
3. Next you want to add the icon like this to your `createApp`:
```diff
const app = createApp({
apis: ...,
plugins: ...,
+ icons: {
+ alert: AlarmIcon,
+ },
themes: ...,
components: ...,
});
```
4. Now we can reference `alert` for our icon in our entity links like this:
```yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: artist-lookup
description: Artist Lookup
links:
- url: https://example.com/alert
title: Alerts
icon: alert
```
And this is the result:
![Example Link with Alert icon](../assets/getting-started/add-icons-links-example.png)
Another way you can use these icons is from the `AppContext` like this:
```ts
import { useApp } from '@backstage/core-plugin-api';
const app = useApp();
const alertIcon = app.getSystemIcon('alert');
```
You might want to use this method if you have an icon you want to use in several locations.
Note: If the icon is not available as one of the default icons or one you've added then it will fall back to Material UI's `LanguageIcon`
## Custom Homepage
In addition to a custom theme, a custom logo, you can also customize the
@@ -36,6 +36,13 @@ Then make sure the environment variables `GCS_CLIENT_EMAIL` and
Since this integration uses the Google Storage SDK, you can also choose to not
provide any explicit credentials and let the SDK discover them automatically.
Please note that for this method to work you must add an empty `googleGcs` object to the `integrations` section in `app-config.yaml`.
```yaml
integrations:
googleGcs: {}
```
One of these discovery methods is to provide an environment variable called
`GOOGLE_APPLICATION_CREDENTIALS` and set it to the file path of your JSON
service account key.
+89
View File
@@ -0,0 +1,89 @@
---
id: threat-model
title: Backstage Threat Model
description: A document describing the threat model for Backstage.
---
The threat model outlines key security considerations of Backstage for operators, developers and security researchers. This is a living document and will evolve and be expanded alongside the Backstage project as relevant.
See [Security Policy and Advisories](https://github.com/backstage/backstage/security) in the Backstage GitHub repository for details on reporting security vulnerabilities and advisories on fixed security flaws.
## Trust Model
The Backstage trust model is divided into three groups with different trust levels.
An **internal user** is an authenticated user that generally belongs to the organization of a particular Backstage deployment. These users are trusted to the extent that they are not expected to compromise the availability of Backstage, but they are not trusted to not compromise data confidentiality or integrity.
An **integrator** is a user responsible for configuring and maintaining an instance of Backstage. Integrators are fully trusted, since they operate the system and database and therefore have root access to the host system. Additional measures can be taken by adopters of Backstage in order to restrict or observe the access of this group, but that falls outside of the current scope of Backstage.
Another group of de facto integrators is internal and external code contributors. When installing Backstage plugins you should vet them just like any other package from an external source. While its possible to limit the impact of for example a supply chain attack by splitting the deployment into separate services with different plugins, the Backstage project itself does not aim to prevent these kinds of attacks or in any other way sandbox or limit the access of plugins.
An **external user** is a user that does not belong to the other two groups, for example a malicious actor outside of the organization. The security model of Backstage currently assumes that this group does not have any direct access to Backstage, and it is the responsibility of each adopter of Backstage to make sure this is the case.
## Integrator Responsibilities
As an integrator of Backstage you yourself are responsible for protecting your Backstage installation from external and unauthorized access. The sign-in system in Backstage does not exist to limit access, only to inform the system of the identity of the user. There are some plugins that have more fine-grained access control through the permissions system, but the primary purpose of that system is to restrict access to resources for internal users rather than Backstage as a whole. A common and recommended way to protect a Backstage deployment from unauthorized access is to deploy it behind an authenticating proxy such as AWSs ALB, GCPs IAP, or Cloudflare Access.
Other responsibilities include protecting the integrity of configuration files as it may otherwise be possible to introduce vulnerable configurations, as well as the confidentiality of configured secrets related to Backstage as these typically include authentication details to third party systems.
The integrator is ultimately responsible for auditing usage of internal and external plugins as these run on the host system and have access to configuration and secrets. When installing plugins from sources like NPM, you should vet these in the same way that you would vet any other package installed from that source.
## Common Backend Configuration
There are many common facilities that are configured centrally and available to all Backstage backend plugins. For example there is a `DatabaseManager` that provides access to a SQL database, `TaskScheduler` for scheduling long-running tasks, `Logger` as a general logging facility, and `UrlReader` for reading content from external sources. These are all configured either directly in code, or within the `backend` block of the static configuration. The appropriate care needs to be taken to ensure that any secrets remain confidential and no malicious configuration is injected.
In a typical Backstage setup, there is no boundary between plugins that run on the same host. Likewise, there is no boundary between plugins that share the same database access. Any plugin that is running on a host that has access to the logical database of any other plugin should be considered to have full access to that other plugin. For example, if you deploy the `auth` and `catalog` plugins on separate hosts with separate configuration and credentials, the `catalog` plugin is still considered to have full access to the `auth` plugin if the `catalog` plugin has access to the `auth` plugin's logical database. The only way to create a boundary between the two plugins is to deploy them in such a way that they do not have access to each others database. This applies to the database facility as well as any other shared resources, such as the cache.
The `UrlReader` facility is of particular interest for a secure Backstage configuration. In particular the `backend.reading.allow` configuration lists the hosts that you trust the backend to be able to read content from on behalf of users. It is extremely important that this list does not, for example, allow access to instance metadata endpoints of cloud providers, or other endpoints that your Backstage instance may have access to which contain sensitive information. In general it is recommended to keep the list minimal and only allow reading from required endpoints. The same concerns apply to custom implementations of the `UrlReader` interface, if you need to implement these through code.
## Authentication
Backstage provides authentication of users through the `auth` plugin, which primarily acts as an authorization server for different OAuth 2.0 provider integrations. These integrations can both serve the purpose of signing users into Backstage, as well as providing delegated access to external resources, and are all subject to the common concerns of implementing secure OAuth 2.0 authorization servers. All auth provider integrations are disabled by default, and need to be enabled through configuration in order to be used. For each Backstage installation it is recommended to only enable the minimal set of providers that are in use by that instance.
It is not within scope of the `auth` backend to protect against unauthorized access, that is something that needs to be handled at a deployment level. See the [Integrator Responsibilities](#integrator-responsibilities) section for more information.
In order to use an auth provider to sign in users into Backstage, it needs to be configured with an [Identity resolver](https://backstage.io/docs/auth/identity-resolver), which is a custom callback implemented in code. The identity resolver is a sensitive part of configuring Backstage and it is important that it always resolves user identities correctly, based on information provided by the authentication provider. There are a number of built-in identity resolvers that can simplify configuration, and it is important that these all resolve users in a secure way, regardless of how they are used.
As part of signing in with an identity resolver, a Backstage Token is issued containing the resolved user identity. The tokens are asymmetrically signed JSON Web Tokens, with the public keys available to any service that wishes to verify a token. The signing keys are rotated continuously and are unique to each installation of Backstage, meaning that Backstage Tokens are not shared across installations. The token contains claims for the user identity and ownership information, which can be used to determine what Backstage resources are owned by that user or group. It is important that this token can not be forged outside of the `auth` plugin, with the exception of other plugins deployed in the same backend service or sharing the same database. For a high-security deployment, the `auth` backend should therefore be deployed in a separate service with its own database.
The token is used to prove the identity of the user within the Backstage system, and is used throughout Backstage plugins to control access. It is important that the ownership resolution logic is consistent across the entire Backstage ecosystem, with no possibility of misinterpreting the ownership information.
For cross backend communication the Backstage Token is typically forwarded or in strict backend to backend communication without a user party the backend itself issues a service token based on a pre-shared secret which is then validated on the receiving end. There are no unique service identities tied to these tokens at this point, meaning the tokens can be used across all services in a Backstage installation, this is something that we aim to improve in the future.
Backstage also supports authentication through a proxy where the user identity is read from the incoming request from the proxy, which has been decorated by an authenticating reverse proxy such as [AWS ALB](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/). The following proxy auth providers verify the signature of incoming requests, and are therefore safe to deploy with direct access by users: `awsAlb`, `cfAccess`, and `gcpIap`. Providers like `oauth2Proxy` does not verify the incoming request and can therefore be spoofed by a malicious internal user to supply the `auth` backend with forged identity information. Its therefore highly recommended to restrict access to the `oauth2Proxy` endpoints, or use a different provider.
## Catalog
Integrators should configure `catalog.rules` and `catalog.locations[].rules` to limit the allowed entity kinds that users can define. In general it is best to restrict definition of User, Group, and Template entities so that internal users cannot register additional ones. Template entities define actions that are executed on the backend hosts, and while the goal is for these actions to be secure regardless of input, it is still a more sensitive context and it is recommended that you protect it with additional checks. It is very important to not allow registration of User and Group entities if you ingest and rely on these as organizational data in your catalog. Doing so could otherwise open up for the ability to impersonate users and confuse group membership information. You should always ingest organizational data using a statically configured catalog location or an entity provider reading from a trusted source. The entities emitted directly by an entity provider are always trusted and rules are not applied to them, but any entities produced further down the chain are still subject to the rules.
The Catalog does not aim to protect against resource exhaustion attacks in its default setup. If you need to prevent your internal users from being able to register large amounts of entities, then it is recommended to disable entity registration and use a different approach for discovering entities. One way to mitigate any resource exhaustion attacks is to only allow the catalog to read from trusted SCM sources that have an audit trail. Catalog currently lacks limits for entity hierarchy depth and entity size, which we hope to address in the future.
By default all internal users are allowed to create and delete entities. If this does not fit your organization's needs it is recommended to enable and configure the [permission](https://backstage.io/docs/permissions/overview) system to restrict these operations.
## Scaffolder
By default, Scaffolding jobs execute directly on the host machine, including any actions defined in the template. Because the Scaffolder templates are considered a more sensitive area it is recommended to control access to create and update templates to trusted parties. Template execution is intended to be secure regardless of input, but we still recommend this additional layer of protection. The string templating is executed in a [node VM sandbox](https://github.com/patriksimek/vm2) to mitigate the possibility of remote code execution attacks.
The Scaffolder often has elevated permissions to for example create repositories in a Github organization. The integrator should therefore be cautious of Scaffolder Templates that for example delete or update existing resources as the user input is typically user defined and can therefore delete or modify resources maliciously or by mistake.
One strategy that allows you to reduce the access that the Scaffolder service has is to rely on user credentials when executing actions. For example, a GitHub App integration could be configured with read-only permissions, with a separate user OAuth token used to create repositories. This requires that your users have access to create repositories in the first place.
The integrator should audit installed scaffolding actions just like any other plugin package. It is also important to verify that installed actions fall in line with your own security requirements, as some actions might be intended for more relaxed environments.
By default all internal users are allowed to execute templates in the scaffolder. If this does not fit your organization's needs it is recommended to enable and configure the [permission](https://backstage.io/docs/permissions/overview) system to restrict these operations.
## TechDocs
TechDocs' backend can be broadly configured in two ways. The default is when `techdocs.builder` is set to `local`, in which documentation is generated on-demand and stored locally by the TechDocs backend. When `techdocs.builder` is set to `external` instead, documentation is assumed to be generated by an external process (e.g. in a CI/CD pipeline), and merely read from a configured external storage provider.
When documentation is generated locally, integrators are responsible for ensuring secure configuration of file system permissions in the location where generated assets are stored. When documentation is generated externally, integrators are responsible for access control and permissioning between the external process that generates the documentation, the storage provider where documentation assets are published, and the TechDocs backend.
Regardless of backend configuration, the TechDocs frontend does not trust the generated HTML of any documentation sites and therefore applies a strict sanitization process before rendering out any content to users.
By default, all TechDocs documentation is visible to all Backstage users. Access can be restricted to TechDocs sites by configuring view permissions for the Catalog.
## Proxy
The proxy backend acts as a utility for frontend plugins to access remote services that may not be set up to receive traffic directly from the Backstage frontend. Typical reasons for this would be that the upstream service does not provide the appropriate CORS headers or does not serve its content over HTTPS.
The proxy entries are configured through static configuration. Each entry has a mount path and an upstream target, and also supports other options such as limiting the allowed methods, or injecting additional headers. It is recommended to avoid injecting authentication headers for upstream services, as this is a risky way to decorate requests with credentials. Anyone with access to your Backstage deployment will be able to make requests to the upstream service using the injected credentials. It is recommended that you instead create a backend plugin that forwards individual requests to the upstream service in a secure way. In case you do end up injecting credentials into upstream requests, be sure that you are not exposing any sensitive information or actions. You should also restrict the access as much as possible, for example using the `allowedMethods` option to limit the methods that can be used, and using tokens with the minimum required authorization scope.
+60
View File
@@ -0,0 +1,60 @@
---
id: v1.5.0
title: v1.5.0
description: Backstage Release v1.5.0
---
These are the release notes for the v1.5.0 release of [Backstage](https://backstage.io/).
A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done.
## Highlights
### GitHub Entity Provider
Added a new `GitHubEntityProvider` ([documentation](https://backstage.io/docs/integrations/github/discovery)), which allows for automatic discovery of catalog entity definition files out of your GitHub projects. This is an improvement upon the `GithubDiscoveryProcessor` that existed before, and we recommend using entity providers rather than processors for discovery and ingestion when possible. Contributed by [@brentg-telus](https://github.com/brentg-telus) [#12822](https://github.com/backstage/backstage/pull/12822)
### Experimental Plugin Reconfiguration
This release adds an experimental API that allows plugin authors to define plugin wide options. These options can then be used by adopters of the plugin to reconfigure it to fit their app. Check out the [plugin customization](https://backstage.io/docs/plugins/customization) docs for more information on how to get started. Feedback is welcome on this new feature! Contributed by [@acierto](https://github.com/acierto) [#11404](https://github.com/backstage/backstage/pull/11404)
### Experimental Backend System Evolution
This release adds the new `@backstage/backend-defaults` package, part of the [evolution of the backend system](https://github.com/backstage/backstage/issues/11611). This package is highly experimental and we do not recommend using it for any purpose, yet.
### New plugin: `@aws/aws-proton-plugin-for-backstage`
Interact with AWS Proton in Backstage. Contributed by [@clareliguori](https://github.com/clareliguori) [#12193](https://github.com/backstage/backstage/pull/12193)
### New plugin: `@backstage/plugin-github-issues`
This new plugin can be used to display GitHub issues for your entities. Contributed by [@mrwolny](https://github.com/mrwolny) [#12875](https://github.com/backstage/backstage/pull/12875)
### New plugin: `@backstage/plugin-sonarqube-backend`
This new backend for `@backstage/plugin-sonarqube` replaces the Sonarqube proxy configuration; once it is installed, you can remove the `/sonarqube` proxy entry. For more information, see the plugin [README.md](https://github.com/backstage/backstage/blob/master/plugins/sonarqube-backend/README.md). Contributed by [@Neemys](https://github.com/Neemys) [#11925](https://github.com/backstage/backstage/pull/11925)
### New module: `@backstage/plugin-catalog-backend-module-bitbucket-server`
This new module for the catalog backend adds the `BitbucketServerEntityProvider`, which allows discovery of entities out of Bitbucket Server installations. Contributed by [@ONordander](https://github.com/ONordander) [#12835](https://github.com/backstage/backstage/pull/12835)
## Security Fixes
This release does not contain any security fixes.
## Upgrade path
We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated).
## Links and References
Below you can find a list of links and references to help you learn about and start using this new release.
- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/)
- [GitHub repository](https://github.com/backstage/backstage)
- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy)
- [Community Discord](https://discord.gg/bFESRKVt) for discussions and support
- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.5.0-changelog.md)
- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins)
Sign up for our [newsletter](https://mailchi.mp/spotify/backstage-community) if you want to be informed about what is happening in the world of Backstage.
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -3,7 +3,7 @@ title: Dynatrace
author: TELUS
authorUrl: https://github.com/telus
category: Monitoring
description: View monitoring info from dynatrace for services in your software catalog.
description: View monitoring info from Dynatrace for services in your software catalog.
documentation: https://github.com/backstage/backstage/tree/master/plugins/dynatrace
iconUrl: img/dynatrace.svg
npmPackageName: '@backstage/plugin-dynatrace'
+2
View File
@@ -1,6 +1,7 @@
{
"releases": {
"Release Notes": [
"releases/v1.5.0",
"releases/v1.4.0",
"releases/v1.3.0",
"releases/v1.2.0",
@@ -17,6 +18,7 @@
"overview/background",
"overview/adopting",
"overview/versioning-policy",
"overview/threat-model",
"overview/support",
"overview/glossary",
"overview/logos"
+1
View File
@@ -15,6 +15,7 @@ nav:
- The Spotify Story: 'overview/background.md'
- Strategies for adopting: 'overview/adopting.md'
- Release & Versioning Policy: 'overview/versioning-policy.md'
- Backstage Threat Model: 'overview/threat-model.md'
- Support and community: 'overview/support.md'
- Glossary: 'overview/glossary.md'
- Logo assets: 'overview/logos.md'
+1 -2
View File
@@ -45,11 +45,10 @@
]
},
"resolutions": {
"**/@graphql-codegen/cli/**/ws": "^8.0.0",
"@types/react": "^17",
"@types/react-dom": "^17"
},
"version": "1.5.0",
"version": "1.6.0-next.0",
"dependencies": {
"@manypkg/get-packages": "^1.1.3",
"@microsoft/api-documenter": "^7.17.11",
+10
View File
@@ -1,5 +1,15 @@
# @backstage/app-defaults
## 1.0.6-next.0
### Patch Changes
- Updated dependencies
- @backstage/core-app-api@1.0.6-next.0
- @backstage/core-plugin-api@1.0.6-next.0
- @backstage/core-components@0.11.1-next.0
- @backstage/plugin-permission-react@0.4.5-next.0
## 1.0.5
### Patch Changes
+7 -7
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/app-defaults",
"description": "Provides the default wiring of a Backstage App",
"version": "1.0.5",
"version": "1.0.6-next.0",
"private": false,
"publishConfig": {
"access": "public",
@@ -33,10 +33,10 @@
"start": "backstage-cli package start"
},
"dependencies": {
"@backstage/core-components": "^0.11.0",
"@backstage/core-app-api": "^1.0.5",
"@backstage/core-plugin-api": "^1.0.5",
"@backstage/plugin-permission-react": "^0.4.4",
"@backstage/core-components": "^0.11.1-next.0",
"@backstage/core-app-api": "^1.0.6-next.0",
"@backstage/core-plugin-api": "^1.0.6-next.0",
"@backstage/plugin-permission-react": "^0.4.5-next.0",
"@backstage/theme": "^0.2.16",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -46,8 +46,8 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.18.1",
"@backstage/test-utils": "^1.1.3",
"@backstage/cli": "^0.18.2-next.0",
"@backstage/test-utils": "^1.1.4-next.0",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^12.1.3",
"@types/jest": "^26.0.7",
+58
View File
@@ -1,5 +1,63 @@
# example-app
## 0.2.75-next.0
### Patch Changes
- Updated dependencies
- @backstage/plugin-kafka@0.3.9-next.0
- @backstage/plugin-lighthouse@0.3.9-next.0
- @backstage/plugin-scaffolder@1.6.0-next.0
- @backstage/plugin-azure-devops@0.2.0-next.0
- @backstage/plugin-cloudbuild@0.3.9-next.0
- @backstage/plugin-explore@0.3.40-next.0
- @backstage/plugin-github-actions@0.5.9-next.0
- @backstage/plugin-jenkins@0.7.8-next.0
- @backstage/plugin-newrelic-dashboard@0.2.2-next.0
- @backstage/plugin-pagerduty@0.5.2-next.0
- @backstage/plugin-sentry@0.4.2-next.0
- @backstage/plugin-tech-insights@0.2.5-next.0
- @backstage/plugin-techdocs@1.3.2-next.0
- @backstage/plugin-techdocs-module-addons-contrib@1.0.4-next.0
- @backstage/plugin-user-settings@0.4.8-next.0
- @backstage/plugin-dynatrace@0.2.0-next.0
- @backstage/plugin-cost-insights@0.11.31-next.0
- @backstage/core-app-api@1.0.6-next.0
- @backstage/core-plugin-api@1.0.6-next.0
- @backstage/core-components@0.11.1-next.0
- @backstage/plugin-org@0.5.9-next.0
- @backstage/cli@0.18.2-next.0
- @backstage/integration-react@1.1.4-next.0
- @backstage/plugin-airbrake@0.3.9-next.0
- @backstage/plugin-apache-airflow@0.2.2-next.0
- @backstage/plugin-api-docs@0.8.9-next.0
- @backstage/plugin-badges@0.2.33-next.0
- @backstage/plugin-catalog-import@0.8.12-next.0
- @backstage/plugin-circleci@0.3.9-next.0
- @backstage/plugin-code-coverage@0.2.2-next.0
- @backstage/plugin-gcalendar@0.3.5-next.0
- @backstage/plugin-gcp-projects@0.3.28-next.0
- @backstage/plugin-gocd@0.1.15-next.0
- @backstage/plugin-graphiql@0.2.41-next.0
- @backstage/plugin-home@0.4.25-next.0
- @backstage/plugin-kubernetes@0.7.2-next.0
- @backstage/plugin-newrelic@0.3.27-next.0
- @backstage/plugin-rollbar@0.4.9-next.0
- @backstage/plugin-search@1.0.2-next.0
- @backstage/plugin-shortcuts@0.3.1-next.0
- @backstage/plugin-stack-overflow@0.1.5-next.0
- @backstage/plugin-tech-radar@0.5.16-next.0
- @backstage/plugin-todo@0.2.11-next.0
- @backstage/plugin-catalog-react@1.1.4-next.0
- @backstage/app-defaults@1.0.6-next.0
- @backstage/plugin-catalog-graph@0.2.21-next.0
- @backstage/plugin-search-react@1.0.2-next.0
- @backstage/plugin-permission-react@0.4.5-next.0
- @backstage/plugin-techdocs-react@1.0.4-next.0
- @backstage/plugin-catalog-common@1.0.6-next.0
- @backstage/plugin-search-common@1.0.1-next.0
- @internal/plugin-catalog-customized@0.0.2-next.0
## 0.2.74
### Patch Changes
+54 -55
View File
@@ -1,65 +1,65 @@
{
"name": "example-app",
"version": "0.2.74",
"version": "0.2.75-next.0",
"private": true,
"backstage": {
"role": "frontend"
},
"bundled": true,
"dependencies": {
"@backstage/app-defaults": "^1.0.5",
"@backstage/app-defaults": "^1.0.6-next.0",
"@backstage/catalog-model": "^1.1.0",
"@backstage/cli": "^0.18.1",
"@backstage/cli": "^0.18.2-next.0",
"@backstage/config": "^1.0.1",
"@backstage/core-app-api": "^1.0.5",
"@backstage/core-components": "^0.11.0",
"@backstage/core-plugin-api": "^1.0.5",
"@backstage/integration-react": "^1.1.3",
"@backstage/plugin-airbrake": "^0.3.8",
"@backstage/plugin-api-docs": "^0.8.8",
"@backstage/plugin-azure-devops": "^0.1.24",
"@backstage/plugin-apache-airflow": "^0.2.1",
"@backstage/plugin-badges": "^0.2.32",
"@backstage/plugin-catalog-common": "^1.0.5",
"@backstage/plugin-catalog-graph": "^0.2.20",
"@backstage/plugin-catalog-import": "^0.8.11",
"@backstage/plugin-catalog-react": "^1.1.3",
"@backstage/plugin-circleci": "^0.3.8",
"@backstage/plugin-cloudbuild": "^0.3.8",
"@backstage/plugin-code-coverage": "^0.2.1",
"@backstage/plugin-cost-insights": "^0.11.30",
"@backstage/plugin-dynatrace": "^0.1.2",
"@backstage/plugin-explore": "^0.3.39",
"@backstage/plugin-gcalendar": "^0.3.4",
"@backstage/plugin-gcp-projects": "^0.3.27",
"@backstage/plugin-github-actions": "^0.5.8",
"@backstage/plugin-gocd": "^0.1.14",
"@backstage/plugin-graphiql": "^0.2.40",
"@backstage/plugin-home": "^0.4.24",
"@backstage/plugin-jenkins": "^0.7.7",
"@backstage/plugin-kafka": "^0.3.8",
"@backstage/plugin-kubernetes": "^0.7.1",
"@backstage/plugin-lighthouse": "^0.3.8",
"@backstage/plugin-newrelic": "^0.3.26",
"@backstage/plugin-newrelic-dashboard": "^0.2.1",
"@backstage/plugin-org": "^0.5.8",
"@backstage/plugin-pagerduty": "0.5.1",
"@backstage/plugin-permission-react": "^0.4.4",
"@backstage/plugin-rollbar": "^0.4.8",
"@backstage/plugin-scaffolder": "^1.5.0",
"@backstage/plugin-search": "^1.0.1",
"@backstage/plugin-search-common": "^1.0.0",
"@backstage/plugin-search-react": "^1.0.1",
"@backstage/plugin-sentry": "^0.4.1",
"@backstage/plugin-shortcuts": "^0.3.0",
"@backstage/plugin-stack-overflow": "^0.1.4",
"@backstage/plugin-tech-insights": "^0.2.4",
"@backstage/plugin-tech-radar": "^0.5.15",
"@backstage/plugin-techdocs": "^1.3.1",
"@backstage/plugin-techdocs-module-addons-contrib": "^1.0.3",
"@backstage/plugin-techdocs-react": "^1.0.3",
"@backstage/plugin-todo": "^0.2.10",
"@backstage/plugin-user-settings": "^0.4.7",
"@backstage/core-app-api": "^1.0.6-next.0",
"@backstage/core-components": "^0.11.1-next.0",
"@backstage/core-plugin-api": "^1.0.6-next.0",
"@backstage/integration-react": "^1.1.4-next.0",
"@backstage/plugin-airbrake": "^0.3.9-next.0",
"@backstage/plugin-api-docs": "^0.8.9-next.0",
"@backstage/plugin-azure-devops": "^0.2.0-next.0",
"@backstage/plugin-apache-airflow": "^0.2.2-next.0",
"@backstage/plugin-badges": "^0.2.33-next.0",
"@backstage/plugin-catalog-common": "^1.0.6-next.0",
"@backstage/plugin-catalog-graph": "^0.2.21-next.0",
"@backstage/plugin-catalog-import": "^0.8.12-next.0",
"@backstage/plugin-catalog-react": "^1.1.4-next.0",
"@backstage/plugin-circleci": "^0.3.9-next.0",
"@backstage/plugin-cloudbuild": "^0.3.9-next.0",
"@backstage/plugin-code-coverage": "^0.2.2-next.0",
"@backstage/plugin-cost-insights": "^0.11.31-next.0",
"@backstage/plugin-dynatrace": "^0.2.0-next.0",
"@backstage/plugin-explore": "^0.3.40-next.0",
"@backstage/plugin-gcalendar": "^0.3.5-next.0",
"@backstage/plugin-gcp-projects": "^0.3.28-next.0",
"@backstage/plugin-github-actions": "^0.5.9-next.0",
"@backstage/plugin-gocd": "^0.1.15-next.0",
"@backstage/plugin-graphiql": "^0.2.41-next.0",
"@backstage/plugin-home": "^0.4.25-next.0",
"@backstage/plugin-jenkins": "^0.7.8-next.0",
"@backstage/plugin-kafka": "^0.3.9-next.0",
"@backstage/plugin-kubernetes": "^0.7.2-next.0",
"@backstage/plugin-lighthouse": "^0.3.9-next.0",
"@backstage/plugin-newrelic": "^0.3.27-next.0",
"@backstage/plugin-newrelic-dashboard": "^0.2.2-next.0",
"@backstage/plugin-org": "^0.5.9-next.0",
"@backstage/plugin-pagerduty": "0.5.2-next.0",
"@backstage/plugin-permission-react": "^0.4.5-next.0",
"@backstage/plugin-rollbar": "^0.4.9-next.0",
"@backstage/plugin-scaffolder": "^1.6.0-next.0",
"@backstage/plugin-search": "^1.0.2-next.0",
"@backstage/plugin-search-common": "^1.0.1-next.0",
"@backstage/plugin-search-react": "^1.0.2-next.0",
"@backstage/plugin-sentry": "^0.4.2-next.0",
"@backstage/plugin-shortcuts": "^0.3.1-next.0",
"@backstage/plugin-stack-overflow": "^0.1.5-next.0",
"@backstage/plugin-tech-insights": "^0.2.5-next.0",
"@backstage/plugin-tech-radar": "^0.5.16-next.0",
"@backstage/plugin-techdocs": "^1.3.2-next.0",
"@backstage/plugin-techdocs-module-addons-contrib": "^1.0.4-next.0",
"@backstage/plugin-techdocs-react": "^1.0.4-next.0",
"@backstage/plugin-todo": "^0.2.11-next.0",
"@backstage/plugin-user-settings": "^0.4.8-next.0",
"@backstage/theme": "^0.2.16",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -69,19 +69,18 @@
"@roadiehq/backstage-plugin-github-insights": "^2.0.0",
"@roadiehq/backstage-plugin-github-pull-requests": "^2.0.0",
"@roadiehq/backstage-plugin-travis-ci": "^2.0.0",
"@internal/plugin-catalog-customized": "0.0.1",
"@internal/plugin-catalog-customized": "0.0.2-next.0",
"history": "^5.0.0",
"prop-types": "^15.7.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-hot-loader": "^4.13.0",
"react-router": "6.0.0-beta.0",
"react-router-dom": "6.0.0-beta.0",
"react-use": "^17.2.4",
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/test-utils": "^1.1.3",
"@backstage/test-utils": "^1.1.4-next.0",
"@rjsf/core": "^3.2.1",
"@testing-library/cypress": "^8.0.2",
"@testing-library/jest-dom": "^5.10.1",
+6 -4
View File
@@ -85,13 +85,15 @@ import {
import { AdvancedSettings } from './components/advancedSettings';
import AlarmIcon from '@material-ui/icons/Alarm';
import React from 'react';
import { hot } from 'react-hot-loader/root';
import { Navigate, Route } from 'react-router';
import { apis } from './apis';
import { entityPage } from './components/catalog/EntityPage';
import { homePage } from './components/home/HomePage';
import { Root } from './components/Root';
import { LowerCaseValuePickerFieldExtension } from './components/scaffolder/customScaffolderExtensions';
import {
DelayingComponentFieldExtension,
LowerCaseValuePickerFieldExtension,
} from './components/scaffolder/customScaffolderExtensions';
import { defaultPreviewTemplate } from './components/scaffolder/defaultPreviewTemplate';
import { searchPage } from './components/search/SearchPage';
import { providers } from './identityProviders';
@@ -228,7 +230,7 @@ const routes = (
}
>
<ScaffolderFieldExtensions>
<LowerCaseValuePickerFieldExtension />
<DelayingComponentFieldExtension />
</ScaffolderFieldExtensions>
</Route>
<Route path="/explore" element={<ExplorePage />} />
@@ -273,4 +275,4 @@ const App = () => (
</AppProvider>
);
export default hot(App);
export default App;
@@ -62,3 +62,37 @@ export const LowerCaseValuePickerFieldExtension = scaffolderPlugin.provide(
},
}),
);
const MockDelayComponent = (
props: FieldExtensionComponentProps<{ test?: string }>,
) => {
const { onChange, formData, rawErrors } = props;
return (
<TextField
label="test"
helperText="description"
value={formData?.test ?? ''}
onChange={({ target: { value } }) => onChange({ test: value })}
margin="normal"
error={rawErrors?.length > 0 && !formData}
/>
);
};
export const DelayingComponentFieldExtension = scaffolderPlugin.provide(
createScaffolderFieldExtension({
name: 'DelayingComponent',
component: MockDelayComponent,
validation: async (
value: { test?: string },
validation: FieldValidation,
) => {
// delay 2 seconds
await new Promise(resolve => setTimeout(resolve, 2000));
if (value.test !== 'pass') {
validation.addError('value was not equal to pass');
}
},
}),
);
+11
View File
@@ -1,5 +1,16 @@
# @backstage/backend-app-api
## 0.2.1-next.0
### Patch Changes
- de3347ca74: Updated usages of `ServiceFactory`.
- Updated dependencies
- @backstage/backend-common@0.15.1-next.0
- @backstage/backend-tasks@0.3.5-next.0
- @backstage/backend-plugin-api@0.1.2-next.0
- @backstage/plugin-permission-node@0.6.5-next.0
## 0.2.0
### Minor Changes
+11 -38
View File
@@ -3,7 +3,6 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { AnyServiceFactory } from '@backstage/backend-plugin-api';
import { BackendFeature } from '@backstage/backend-plugin-api';
import { Config } from '@backstage/config';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
@@ -29,14 +28,10 @@ export interface Backend {
}
// @public (undocumented)
export const cacheFactory: ServiceFactory<
PluginCacheManager,
PluginCacheManager,
{}
>;
export const cacheFactory: ServiceFactory<PluginCacheManager>;
// @public (undocumented)
export const configFactory: ServiceFactory<Config, Config, {}>;
export const configFactory: ServiceFactory<Config>;
// @public (undocumented)
export function createSpecializedBackend(
@@ -46,46 +41,28 @@ export function createSpecializedBackend(
// @public (undocumented)
export interface CreateSpecializedBackendOptions {
// (undocumented)
services: AnyServiceFactory[];
services: ServiceFactory[];
}
// @public (undocumented)
export const databaseFactory: ServiceFactory<
PluginDatabaseManager,
PluginDatabaseManager,
{}
>;
export const databaseFactory: ServiceFactory<PluginDatabaseManager>;
// @public (undocumented)
export const discoveryFactory: ServiceFactory<
PluginEndpointDiscovery,
PluginEndpointDiscovery,
{}
>;
export const discoveryFactory: ServiceFactory<PluginEndpointDiscovery>;
// @public (undocumented)
export const httpRouterFactory: ServiceFactory<
HttpRouterService,
HttpRouterService,
{}
>;
export const httpRouterFactory: ServiceFactory<HttpRouterService>;
// @public (undocumented)
export const loggerFactory: ServiceFactory<Logger, Logger, {}>;
export const loggerFactory: ServiceFactory<Logger>;
// @public (undocumented)
export const permissionsFactory: ServiceFactory<
PermissionAuthorizer | PermissionEvaluator,
PermissionAuthorizer | PermissionEvaluator,
{}
PermissionAuthorizer | PermissionEvaluator
>;
// @public (undocumented)
export const schedulerFactory: ServiceFactory<
PluginTaskScheduler,
PluginTaskScheduler,
{}
>;
export const schedulerFactory: ServiceFactory<PluginTaskScheduler>;
// @public (undocumented)
export type ServiceOrExtensionPoint<T = unknown> =
@@ -93,12 +70,8 @@ export type ServiceOrExtensionPoint<T = unknown> =
| ServiceRef<T>;
// @public (undocumented)
export const tokenManagerFactory: ServiceFactory<
TokenManager,
TokenManager,
{}
>;
export const tokenManagerFactory: ServiceFactory<TokenManager>;
// @public (undocumented)
export const urlReaderFactory: ServiceFactory<UrlReader, UrlReader, {}>;
export const urlReaderFactory: ServiceFactory<UrlReader>;
```
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-app-api",
"description": "Core API used by Backstage backend apps",
"version": "0.2.0",
"version": "0.2.1-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -34,16 +34,16 @@
"start": "backstage-cli package start"
},
"dependencies": {
"@backstage/backend-plugin-api": "^0.1.1",
"@backstage/backend-common": "^0.15.0",
"@backstage/backend-tasks": "^0.3.4",
"@backstage/plugin-permission-node": "^0.6.4",
"@backstage/backend-plugin-api": "^0.1.2-next.0",
"@backstage/backend-common": "^0.15.1-next.0",
"@backstage/backend-tasks": "^0.3.5-next.0",
"@backstage/plugin-permission-node": "^0.6.5-next.0",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.18.1"
"@backstage/cli": "^0.18.2-next.0"
},
"files": [
"dist",
@@ -108,7 +108,9 @@ export class BackendInitializer {
id: feature.id,
provides,
consumes: new Set(Object.values(registerOptions.deps)),
deps: registerOptions.deps,
deps: registerOptions.deps as {
[name: string]: ServiceOrExtensionPoint;
},
init: registerOptions.init as BackendRegisterInit['init'],
};
},
@@ -14,10 +14,7 @@
* limitations under the License.
*/
import {
AnyServiceFactory,
BackendFeature,
} from '@backstage/backend-plugin-api';
import { ServiceFactory, BackendFeature } from '@backstage/backend-plugin-api';
import { BackendInitializer } from './BackendInitializer';
import { ServiceRegistry } from './ServiceRegistry';
import { Backend } from './types';
@@ -26,7 +23,7 @@ export class BackstageBackend implements Backend {
#services: ServiceRegistry;
#initializer: BackendInitializer;
constructor(apiFactories: AnyServiceFactory[]) {
constructor(apiFactories: ServiceFactory[]) {
this.#services = new ServiceRegistry(apiFactories);
this.#initializer = new BackendInitializer(this.#services);
}
@@ -0,0 +1,173 @@
/*
* 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 {
createServiceRef,
createServiceFactory,
} from '@backstage/backend-plugin-api';
import { ServiceRegistry } from './ServiceRegistry';
const ref1 = createServiceRef<{ x: number; pluginId: string }>({
id: '1',
});
const sf1 = createServiceFactory({
service: ref1,
deps: {},
factory: async () => {
return async pluginId => {
return { x: 1, pluginId };
};
},
});
const ref2 = createServiceRef<{ x: number; pluginId: string }>({
id: '2',
});
const sf2 = createServiceFactory({
service: ref2,
deps: {},
factory: async () => {
return async pluginId => {
return { x: 2, pluginId };
};
},
});
const sf2b = createServiceFactory({
service: ref2,
deps: {},
factory: async () => {
return async pluginId => {
return { x: 22, pluginId };
};
},
});
const refDefault1 = createServiceRef<{ x: number; pluginId: string }>({
id: '1',
defaultFactory: async service =>
createServiceFactory({
service,
deps: {},
factory: async () => async pluginId => ({ x: 10, pluginId }),
}),
});
const refDefault2a = createServiceRef<{ x: number; pluginId: string }>({
id: '2a',
defaultFactory: async service =>
createServiceFactory({
service,
deps: {},
factory: async () => async pluginId => ({ x: 20, pluginId }),
}),
});
const refDefault2b = createServiceRef<{ x: number; pluginId: string }>({
id: '2b',
defaultFactory: async service =>
createServiceFactory({
service,
deps: {},
factory: async () => async pluginId => ({ x: 220, pluginId }),
}),
});
describe('ServiceRegistry', () => {
it('should return undefined if there is no factory defined', async () => {
const registry = new ServiceRegistry([]);
expect(registry.get(ref1)).toBe(undefined);
});
it('should return a factory for a registered ref', async () => {
const registry = new ServiceRegistry([sf1]);
const factory = registry.get(ref1)!;
expect(factory).toEqual(expect.any(Function));
await expect(factory('catalog')).resolves.toEqual({
x: 1,
pluginId: 'catalog',
});
await expect(factory('scaffolder')).resolves.toEqual({
x: 1,
pluginId: 'scaffolder',
});
expect(await factory('catalog')).toBe(await factory('catalog'));
});
it('should handle multiple factories with different serviceRefs', async () => {
const registry = new ServiceRegistry([sf1, sf2]);
const factory1 = registry.get(ref1)!;
const factory2 = registry.get(ref2)!;
expect(factory1).toEqual(expect.any(Function));
expect(factory2).toEqual(expect.any(Function));
await expect(factory1('catalog')).resolves.toEqual({
x: 1,
pluginId: 'catalog',
});
await expect(factory2('catalog')).resolves.toEqual({
x: 2,
pluginId: 'catalog',
});
expect(await factory1('catalog')).not.toBe(await factory2('catalog'));
});
it('should use the last factory for each ref', async () => {
const registry = new ServiceRegistry([sf2, sf2b]);
const factory2 = registry.get(ref2)!;
await expect(factory2('catalog')).resolves.toEqual({
x: 22,
pluginId: 'catalog',
});
});
it('should return the defaultFactory from the ref if not provided to the registry', async () => {
const registry = new ServiceRegistry([]);
const factory = registry.get(refDefault1)!;
expect(factory).toEqual(expect.any(Function));
await expect(factory('catalog')).resolves.toEqual({
x: 10,
pluginId: 'catalog',
});
});
it('should not return the defaultFactory from the ref if provided to the registry', async () => {
const registry = new ServiceRegistry([sf1]);
const factory = registry.get(refDefault1)!;
expect(factory).toEqual(expect.any(Function));
await expect(factory('catalog')).resolves.toEqual({
x: 1,
pluginId: 'catalog',
});
});
it('should handle duplicate defaultFactories by duplicating the implementations', async () => {
const registry = new ServiceRegistry([]);
const factoryA = registry.get(refDefault2a)!;
const factoryB = registry.get(refDefault2b)!;
expect(factoryA).toEqual(expect.any(Function));
expect(factoryB).toEqual(expect.any(Function));
await expect(factoryA('catalog')).resolves.toEqual({
x: 20,
pluginId: 'catalog',
});
await expect(factoryB('catalog')).resolves.toEqual({
x: 220,
pluginId: 'catalog',
});
expect(await factoryA('catalog')).toBe(await factoryA('catalog'));
expect(await factoryB('catalog')).toBe(await factoryB('catalog'));
expect(await factoryA('catalog')).not.toBe(await factoryB('catalog'));
});
});
@@ -14,35 +14,47 @@
* limitations under the License.
*/
import {
AnyServiceFactory,
ServiceFactory,
FactoryFunc,
ServiceRef,
} from '@backstage/backend-plugin-api';
export class ServiceRegistry {
readonly #implementations: Map<string, Map<string, unknown>>;
readonly #factories: Map<string, AnyServiceFactory>;
readonly #providedFactories: Map<string, ServiceFactory>;
readonly #loadedDefaultFactories: Map<Function, ServiceFactory>;
readonly #implementations: Map<ServiceFactory, Map<string, unknown>>;
constructor(factories: AnyServiceFactory[]) {
this.#factories = new Map(factories.map(f => [f.service.id, f]));
constructor(factories: ServiceFactory<any>[]) {
this.#providedFactories = new Map(factories.map(f => [f.service.id, f]));
this.#loadedDefaultFactories = new Map();
this.#implementations = new Map();
}
get<T>(ref: ServiceRef<T>): FactoryFunc<T> | undefined {
const factory = this.#factories.get(ref.id);
if (!factory) {
let factory = this.#providedFactories.get(ref.id);
const { defaultFactory } = ref;
if (!factory && !defaultFactory) {
return undefined;
}
return async (pluginId: string): Promise<T> => {
let implementations = this.#implementations.get(ref.id);
if (!factory) {
let loadedFactory = this.#loadedDefaultFactories.get(defaultFactory!);
if (!loadedFactory) {
loadedFactory = (await defaultFactory!(ref)) as ServiceFactory;
this.#loadedDefaultFactories.set(defaultFactory!, loadedFactory);
}
factory = loadedFactory;
}
let implementations = this.#implementations.get(factory);
if (implementations) {
if (implementations.has(pluginId)) {
return implementations.get(pluginId) as T;
}
} else {
implementations = new Map();
this.#implementations.set(ref.id, implementations);
this.#implementations.set(factory, implementations);
}
const factoryDeps = Object.fromEntries(
+2 -2
View File
@@ -15,7 +15,7 @@
*/
import {
AnyServiceFactory,
ServiceFactory,
BackendFeature,
ExtensionPoint,
FactoryFunc,
@@ -43,7 +43,7 @@ export interface BackendRegisterInit {
* @public
*/
export interface CreateSpecializedBackendOptions {
services: AnyServiceFactory[];
services: ServiceFactory[];
}
export type ServiceHolder = {
+10
View File
@@ -1,5 +1,15 @@
# @backstage/backend-common
## 0.15.1-next.0
### Patch Changes
- 399286d7dd: Workaround support for `swc` instead of `sucrase`
- bf5e9030eb: Updated dependency `msw` to `^0.45.0`.
- Updated dependencies
- @backstage/config-loader@1.1.4-next.0
- @backstage/integration@1.3.1-next.0
## 0.15.0
### Minor Changes
+2 -2
View File
@@ -8,6 +8,7 @@
import { AbortController as AbortController_2 } from 'node-abort-controller';
import { AbortSignal as AbortSignal_2 } from 'node-abort-controller';
import aws from 'aws-sdk';
import { AwsS3Integration } from '@backstage/integration';
import { AzureIntegration } from '@backstage/integration';
import { BitbucketCloudIntegration } from '@backstage/integration';
@@ -34,7 +35,6 @@ import { Readable } from 'stream';
import { ReadCommitResult } from 'isomorphic-git';
import { RequestHandler } from 'express';
import { Router } from 'express';
import { S3 } from 'aws-sdk';
import { Server } from 'http';
import * as winston from 'winston';
import { Writable } from 'stream';
@@ -44,7 +44,7 @@ export class AwsS3UrlReader implements UrlReader {
constructor(
integration: AwsS3Integration,
deps: {
s3: S3;
s3: aws.S3;
treeResponseFactory: ReadTreeResponseFactory;
},
);
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.15.0",
"version": "0.15.1-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -36,9 +36,9 @@
"dependencies": {
"@backstage/cli-common": "^0.1.9",
"@backstage/config": "^1.0.1",
"@backstage/config-loader": "^1.1.3",
"@backstage/config-loader": "^1.1.4-next.0",
"@backstage/errors": "^1.1.0",
"@backstage/integration": "^1.3.0",
"@backstage/integration": "^1.3.1-next.0",
"@backstage/types": "^1.0.0",
"@google-cloud/storage": "^6.0.0",
"@keyv/redis": "^2.2.3",
@@ -91,8 +91,8 @@
}
},
"devDependencies": {
"@backstage/backend-test-utils": "^0.1.27",
"@backstage/cli": "^0.18.1",
"@backstage/backend-test-utils": "^0.1.28-next.0",
"@backstage/cli": "^0.18.2-next.0",
"@types/archiver": "^5.1.0",
"@types/base64-stream": "^1.0.2",
"@types/compression": "^1.7.0",
@@ -112,7 +112,7 @@
"better-sqlite3": "^7.5.0",
"http-errors": "^2.0.0",
"mock-fs": "^5.1.0",
"msw": "^0.44.0",
"msw": "^0.45.0",
"mysql2": "^2.2.5",
"recursive-readdir": "^2.2.2",
"supertest": "^6.1.3"
@@ -14,7 +14,9 @@
* limitations under the License.
*/
import aws, { Credentials, S3 } from 'aws-sdk';
// note: We do the import like this so that we don't get issues destructuring
// and it not being mocked by the aws-sdk-mock package which is unfortunate.
import aws from 'aws-sdk';
import { CredentialsOptions } from 'aws-sdk/lib/credentials';
import {
ReaderFactory,
@@ -126,7 +128,7 @@ export class AwsS3UrlReader implements UrlReader {
return integrations.awsS3.list().map(integration => {
const credentials = AwsS3UrlReader.buildCredentials(integration);
const s3 = new S3({
const s3 = new aws.S3({
apiVersion: '2006-03-01',
credentials,
endpoint: integration.config.endpoint,
@@ -145,7 +147,7 @@ export class AwsS3UrlReader implements UrlReader {
constructor(
private readonly integration: AwsS3Integration,
private readonly deps: {
s3: S3;
s3: aws.S3;
treeResponseFactory: ReadTreeResponseFactory;
},
) {}
@@ -156,17 +158,17 @@ export class AwsS3UrlReader implements UrlReader {
*/
private static buildCredentials(
integration?: AwsS3Integration,
): Credentials | CredentialsOptions | undefined {
): aws.Credentials | CredentialsOptions | undefined {
if (!integration) {
return undefined;
}
const accessKeyId = integration.config.accessKeyId;
const secretAccessKey = integration.config.secretAccessKey;
let explicitCredentials: Credentials | undefined;
let explicitCredentials: aws.Credentials | undefined;
if (accessKeyId && secretAccessKey) {
explicitCredentials = new Credentials({
explicitCredentials = new aws.Credentials({
accessKeyId,
secretAccessKey,
});
+9
View File
@@ -1,5 +1,14 @@
# @backstage/backend-defaults
## 0.1.1-next.0
### Patch Changes
- de3347ca74: Updated usages of `ServiceFactory`.
- Updated dependencies
- @backstage/backend-plugin-api@0.1.2-next.0
- @backstage/backend-app-api@0.2.1-next.0
## 0.1.0
### Minor Changes
+2 -2
View File
@@ -3,8 +3,8 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { AnyServiceFactory } from '@backstage/backend-plugin-api';
import { Backend } from '@backstage/backend-app-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
// @public (undocumented)
export function createBackend(options?: CreateBackendOptions): Backend;
@@ -12,6 +12,6 @@ export function createBackend(options?: CreateBackendOptions): Backend;
// @public (undocumented)
export interface CreateBackendOptions {
// (undocumented)
services?: AnyServiceFactory[];
services?: ServiceFactory[];
}
```
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-defaults",
"description": "Backend defaults used by Backstage backend apps",
"version": "0.1.0",
"version": "0.1.1-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -33,11 +33,11 @@
"start": "backstage-cli package start"
},
"dependencies": {
"@backstage/backend-app-api": "^0.2.0",
"@backstage/backend-plugin-api": "^0.1.1"
"@backstage/backend-app-api": "^0.2.1-next.0",
"@backstage/backend-plugin-api": "^0.1.2-next.0"
},
"devDependencies": {
"@backstage/cli": "^0.18.1"
"@backstage/cli": "^0.18.2-next.0"
},
"files": [
"dist"
@@ -28,7 +28,7 @@ import {
tokenManagerFactory,
urlReaderFactory,
} from '@backstage/backend-app-api';
import { AnyServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
export const defaultServiceFactories = [
cacheFactory,
@@ -47,15 +47,15 @@ export const defaultServiceFactories = [
* @public
*/
export interface CreateBackendOptions {
services?: AnyServiceFactory[];
services?: ServiceFactory[];
}
/**
* @public
*/
export function createBackend(options?: CreateBackendOptions): Backend {
const services = new Map<string, AnyServiceFactory>(
defaultServiceFactories.map(sf => [sf.service.id, sf]),
const services = new Map<string, ServiceFactory>(
defaultServiceFactories.map(sf => [sf.service.id, sf as ServiceFactory]),
);
if (options?.services) {
+9
View File
@@ -1,5 +1,14 @@
# example-backend-next
## 0.0.3-next.0
### Patch Changes
- Updated dependencies
- @backstage/plugin-scaffolder-backend@1.6.0-next.0
- @backstage/plugin-catalog-backend@1.3.2-next.0
- @backstage/backend-defaults@0.1.1-next.0
## 0.0.2
### Patch Changes
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend-next",
"version": "0.0.2",
"version": "0.0.3-next.0",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -25,12 +25,12 @@
"clean": "backstage-cli package clean"
},
"dependencies": {
"@backstage/backend-defaults": "^0.1.0",
"@backstage/plugin-catalog-backend": "^1.3.1",
"@backstage/plugin-scaffolder-backend": "^1.5.0"
"@backstage/backend-defaults": "^0.1.1-next.0",
"@backstage/plugin-catalog-backend": "^1.3.2-next.0",
"@backstage/plugin-scaffolder-backend": "^1.6.0-next.0"
},
"devDependencies": {
"@backstage/cli": "^0.18.1"
"@backstage/cli": "^0.18.2-next.0"
},
"files": [
"dist"
+11
View File
@@ -1,5 +1,16 @@
# @backstage/backend-plugin-api
## 0.1.2-next.0
### Patch Changes
- eef91a2558: Simplified the `ServiceFactory` type and removed `AnyServiceFactory`.
- 68513f169a: When defining a new `ServiceRef` you can now also include a `defaultFactory`, which will be used to construct instances of the service in case there is no explicit factory defined.
- Updated dependencies
- @backstage/backend-common@0.15.1-next.0
- @backstage/backend-tasks@0.3.5-next.0
- @backstage/plugin-permission-common@0.6.4-next.0
## 0.1.1
### Patch Changes
+21 -24
View File
@@ -16,15 +16,6 @@ import { TokenManager } from '@backstage/backend-common';
import { TransportStreamOptions } from 'winston-transport';
import { UrlReader } from '@backstage/backend-common';
// @public (undocumented)
export type AnyServiceFactory = ServiceFactory<
unknown,
unknown,
{
[key in string]: unknown;
}
>;
// @public (undocumented)
export interface BackendFeature {
// (undocumented)
@@ -101,15 +92,22 @@ export function createExtensionPoint<T>(options: {
// @public (undocumented)
export function createServiceFactory<
Api,
Impl extends Api,
Deps extends {
TService,
TImpl extends TService,
TDeps extends {
[name in string]: unknown;
},
>(factory: ServiceFactory<Api, Impl, Deps>): ServiceFactory<Api, Api, {}>;
>(factory: {
service: ServiceRef<TService>;
deps: TypesToServiceRef<TDeps>;
factory(deps: DepsToDepFactories<TDeps>): Promise<FactoryFunc<TImpl>>;
}): ServiceFactory<TService>;
// @public (undocumented)
export function createServiceRef<T>(options: { id: string }): ServiceRef<T>;
export function createServiceRef<T>(options: {
id: string;
defaultFactory?: (service: ServiceRef<T>) => Promise<ServiceFactory<T>>;
}): ServiceRef<T>;
// @public (undocumented)
export const databaseServiceRef: ServiceRef<PluginDatabaseManager>;
@@ -168,22 +166,21 @@ export const permissionsServiceRef: ServiceRef<
export const schedulerServiceRef: ServiceRef<PluginTaskScheduler>;
// @public (undocumented)
export type ServiceFactory<
TApi,
TImpl extends TApi,
TDeps extends {
[name in string]: unknown;
},
> = {
service: ServiceRef<TApi>;
deps: TypesToServiceRef<TDeps>;
factory(deps: DepsToDepFactories<TDeps>): Promise<FactoryFunc<TImpl>>;
export type ServiceFactory<TService = unknown> = {
service: ServiceRef<TService>;
deps: {
[key in string]: ServiceRef<unknown>;
};
factory(deps: {
[key in string]: unknown;
}): Promise<FactoryFunc<TService>>;
};
// @public
export type ServiceRef<T> = {
id: string;
T: T;
defaultFactory?: (service: ServiceRef<T>) => Promise<ServiceFactory<T>>;
toString(): string;
$$ref: 'service';
};
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-plugin-api",
"description": "Core API used by Backstage backend plugins",
"version": "0.1.1",
"version": "0.1.2-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -35,16 +35,16 @@
},
"dependencies": {
"@backstage/config": "^1.0.1",
"@backstage/backend-common": "^0.15.0",
"@backstage/plugin-permission-common": "^0.6.3",
"@backstage/backend-tasks": "^0.3.4",
"@backstage/backend-common": "^0.15.1-next.0",
"@backstage/plugin-permission-common": "^0.6.4-next.0",
"@backstage/backend-tasks": "^0.3.5-next.0",
"@types/express": "^4.17.6",
"express": "^4.17.1",
"winston": "^3.2.1",
"winston-transport": "^4.5.0"
},
"devDependencies": {
"@backstage/cli": "^0.18.1"
"@backstage/cli": "^0.18.2-next.0"
},
"files": [
"dist",
@@ -20,6 +20,5 @@ export type {
DepsToDepFactories,
FactoryFunc,
ServiceFactory,
AnyServiceFactory,
} from './types';
export { createServiceRef, createServiceFactory } from './types';
@@ -28,6 +28,12 @@ export type ServiceRef<T> = {
*/
T: T;
/**
* The default factory that will be used to create service
* instances if no other factory is provided.
*/
defaultFactory?: (service: ServiceRef<T>) => Promise<ServiceFactory<T>>;
toString(): string;
$$ref: 'service';
@@ -45,32 +51,26 @@ export type DepsToDepFactories<T> = {
export type FactoryFunc<Impl> = (pluginId: string) => Promise<Impl>;
/** @public */
export type ServiceFactory<
TApi,
TImpl extends TApi,
TDeps extends { [name in string]: unknown },
> = {
service: ServiceRef<TApi>;
deps: TypesToServiceRef<TDeps>;
factory(deps: DepsToDepFactories<TDeps>): Promise<FactoryFunc<TImpl>>;
export type ServiceFactory<TService = unknown> = {
service: ServiceRef<TService>;
deps: { [key in string]: ServiceRef<unknown> };
factory(deps: { [key in string]: unknown }): Promise<FactoryFunc<TService>>;
};
/** @public */
export type AnyServiceFactory = ServiceFactory<
unknown,
unknown,
{ [key in string]: unknown }
>;
/**
* @public
*/
export function createServiceRef<T>(options: { id: string }): ServiceRef<T> {
export function createServiceRef<T>(options: {
id: string;
defaultFactory?: (service: ServiceRef<T>) => Promise<ServiceFactory<T>>;
}): ServiceRef<T> {
const { id, defaultFactory } = options;
return {
id: options.id,
id,
get T(): T {
throw new Error(`tried to read ServiceRef.T of ${this}`);
},
defaultFactory,
toString() {
return `serviceRef{${options.id}}`;
},
@@ -82,9 +82,13 @@ export function createServiceRef<T>(options: { id: string }): ServiceRef<T> {
* @public
*/
export function createServiceFactory<
Api,
Impl extends Api,
Deps extends { [name in string]: unknown },
>(factory: ServiceFactory<Api, Impl, Deps>): ServiceFactory<Api, Api, {}> {
return factory;
TService,
TImpl extends TService,
TDeps extends { [name in string]: unknown },
>(factory: {
service: ServiceRef<TService>;
deps: TypesToServiceRef<TDeps>;
factory(deps: DepsToDepFactories<TDeps>): Promise<FactoryFunc<TImpl>>;
}): ServiceFactory<TService> {
return factory as ServiceFactory<TService>;
}
+9
View File
@@ -1,5 +1,14 @@
# @backstage/backend-tasks
## 0.3.5-next.0
### Patch Changes
- 243533ecdc: Added support to mysql on some raw queries
- 8872cc735d: Fixed a bug where the database option to skip migrations was ignored.
- Updated dependencies
- @backstage/backend-common@0.15.1-next.0
## 0.3.4
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-tasks",
"description": "Common distributed task management library for Backstage backends",
"version": "0.3.4",
"version": "0.3.5-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -33,7 +33,7 @@
"start": "backstage-cli package start"
},
"dependencies": {
"@backstage/backend-common": "^0.15.0",
"@backstage/backend-common": "^0.15.1-next.0",
"@backstage/config": "^1.0.1",
"@backstage/errors": "^1.1.0",
"@backstage/types": "^1.0.0",
@@ -48,8 +48,8 @@
"zod": "^3.9.5"
},
"devDependencies": {
"@backstage/backend-test-utils": "^0.1.27",
"@backstage/cli": "^0.18.1",
"@backstage/backend-test-utils": "^0.1.28-next.0",
"@backstage/cli": "^0.18.2-next.0",
"@types/cron": "^2.0.0",
"wait-for-expect": "^3.0.2"
},
@@ -58,9 +58,12 @@ export class TaskScheduler {
*/
forPlugin(pluginId: string): PluginTaskScheduler {
const databaseFactory = once(async () => {
const knex = await this.databaseManager.forPlugin(pluginId).getClient();
const databaseManager = this.databaseManager.forPlugin(pluginId);
const knex = await databaseManager.getClient();
await migrateBackendTasks(knex);
if (!databaseManager.migrations?.skip) {
await migrateBackendTasks(knex);
}
const janitor = new PluginTaskSchedulerJanitor({
knex,
+15 -8
View File
@@ -292,14 +292,21 @@ export class TaskWorker {
seconds: dt,
})}`,
);
nextRun = this.knex.client.config.client.includes('sqlite3')
? this.knex.raw(
`max(datetime(next_run_start_at, ?), datetime('now'))`,
[`+${dt} seconds`],
)
: this.knex.raw(
`greatest(next_run_start_at + interval '${dt} seconds', now())`,
);
if (this.knex.client.config.client.includes('sqlite3')) {
nextRun = this.knex.raw(
`max(datetime(next_run_start_at, ?), datetime('now'))`,
[`+${dt} seconds`],
);
} else if (this.knex.client.config.client.includes('mysql')) {
nextRun = this.knex.raw(
`greatest(next_run_start_at + interval ${dt} second, now())`,
);
} else {
nextRun = this.knex.raw(
`greatest(next_run_start_at + interval '${dt} seconds', now())`,
);
}
}
const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)
+39 -1
View File
@@ -14,9 +14,16 @@
* limitations under the License.
*/
import knexFactory, { Knex } from 'knex';
import { Duration } from 'luxon';
import { AbortController } from 'node-abort-controller';
import { delegateAbortController, sleep, validateId } from './util';
import { delegateAbortController, nowPlus, sleep, validateId } from './util';
class KnexBuilder {
public build(client: string): Knex {
return knexFactory({ client });
}
}
describe('util', () => {
describe('validateId', () => {
@@ -73,4 +80,35 @@ describe('util', () => {
expect(child.signal.aborted).toBe(true);
});
});
describe('nowPlus', () => {
describe('without duration', () => {
const databases = [
{ client: 'sqlite3', expected: 'CURRENT_TIMESTAMP' },
{ client: 'mysql2', expected: 'CURRENT_TIMESTAMP' },
{ client: 'pg', expected: 'CURRENT_TIMESTAMP' },
];
it.each(databases)('for client $client', ({ client, expected }) => {
const knex = new KnexBuilder().build(client);
const result = nowPlus(undefined, knex);
expect(result.toString()).toBe(expected);
});
});
describe('With duration', () => {
const databases = [
{ client: 'sqlite3', expected: "datetime('now', '20 seconds')" },
{ client: 'mysql2', expected: 'now() + interval 20 second' },
{ client: 'pg', expected: "now() + interval '20 seconds'" },
];
it.each(databases)('for client $client', ({ client, expected }) => {
const duration = Duration.fromObject({ seconds: 20 });
const knex = new KnexBuilder().build(client);
const result = nowPlus(duration, knex);
expect(result.toString()).toBe(expected);
});
});
});
});
+10 -3
View File
@@ -38,9 +38,16 @@ export function nowPlus(duration: Duration | undefined, knex: Knex) {
if (!seconds) {
return knex.fn.now();
}
return knex.client.config.client.includes('sqlite3')
? knex.raw(`datetime('now', ?)`, [`${seconds} seconds`])
: knex.raw(`now() + interval '${seconds} seconds'`);
if (knex.client.config.client.includes('sqlite3')) {
return knex.raw(`datetime('now', ?)`, [`${seconds} seconds`]);
}
if (knex.client.config.client.includes('mysql')) {
return knex.raw(`now() + interval ${seconds} second`);
}
return knex.raw(`now() + interval '${seconds} seconds'`);
}
/**
+12
View File
@@ -1,5 +1,17 @@
# @backstage/backend-test-utils
## 0.1.28-next.0
### Patch Changes
- bf5e9030eb: Updated dependency `msw` to `^0.45.0`.
- de3347ca74: Updated usages of `ServiceFactory`.
- Updated dependencies
- @backstage/backend-common@0.15.1-next.0
- @backstage/cli@0.18.2-next.0
- @backstage/backend-plugin-api@0.1.2-next.0
- @backstage/backend-app-api@0.2.1-next.0
## 0.1.27
### Patch Changes
+2 -2
View File
@@ -3,10 +3,10 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { AnyServiceFactory } from '@backstage/backend-plugin-api';
import { BackendFeature } from '@backstage/backend-plugin-api';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
import { Knex } from 'knex';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceRef } from '@backstage/backend-plugin-api';
// @public (undocumented)
@@ -45,7 +45,7 @@ export interface TestBackendOptions<
services?: readonly [
...{
[index in keyof TServices]:
| AnyServiceFactory
| ServiceFactory<TServices[index]>
| [ServiceRef<TServices[index]>, Partial<TServices[index]>];
},
];

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