Merge remote-tracking branch 'upstream/master' into improvemsgraphperf

This commit is contained in:
Alex Crome
2023-01-31 19:03:46 +00:00
542 changed files with 9566 additions and 1811 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-sonarqube': patch
---
Additional export added in order to bind SonarQubeClient to its apiref
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-scaffolder': patch
---
`scaffolder/next`: bump `react-jsonschema-form` libraries to `v5-stable`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
The `backstage-cli repo test` command now sets a default Jest `--workerIdleMemoryLimit` of 1GB. If needed to ensure that tests are not run in band, `--maxWorkers=2` is set as well. This is the recommended workaround for dealing with Jest workers leaking memory and eventually hitting the heap limit.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': minor
---
Update DocsTable and EntityListDocsTable to accept overrides for Material Table options.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Added a check to ensure that Yarn v1 is used when creating new projects.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
The previous migration that adds the `search.original_value` column may leave some of the entities not updated. Add a migration script to trigger a reprocessing of the entities.
+18
View File
@@ -0,0 +1,18 @@
---
'@backstage/plugin-tech-insights-backend': patch
'@backstage/plugin-tech-insights-common': patch
'@backstage/plugin-tech-insights-node': minor
'@backstage/plugin-tech-insights': patch
---
TechInsightsApi interface now has getFactSchemas() method.
TechInsightsClient now implements method getFactSchemas().
**BREAKING** FactSchema type moved from @backstage/plugin-tech-insights-node into @backstage/plugin-tech-insights-common
These changes are **required** if you were importing this type directly.
```diff
- import { FactSchema } from '@backstage/plugin-tech-insights-node';
+ import { FactSchema } from '@backstage/plugin-tech-insights-common';
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-msgraph': patch
---
Fix MS Graph provider to use target URL for fetching access token
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search': minor
---
Update `SearchModal` component to use `SearchResult` extensions.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-azure-devops-backend': patch
---
Fixed a bug where the azure devops host in URLs on the readme card was being URL encoded, breaking hosts with ports.
+12
View File
@@ -0,0 +1,12 @@
---
'@backstage/plugin-techdocs-module-addons-contrib': patch
'@backstage/plugin-techdocs-addons-test-utils': patch
'@backstage/plugin-apollo-explorer': patch
'@backstage/plugin-cicd-statistics': patch
'@backstage/plugin-codescene': patch
'@backstage/plugin-dynatrace': patch
'@backstage/plugin-org-react': patch
'@backstage/plugin-playlist': patch
---
Depend on `@material-ui/core` version `^4.12.2` like all other in-repo packages
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-github': patch
---
Add support for filtering out forks
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-sentry': patch
---
Fix broken module exports and dependencies to match a backend module, rather than a frontend plugin.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-home': patch
---
Fixed regression that caused the `WelcomeTitle` to not be the right size when passed to the `title` property of the `<Header>` component. A Storybook entry was also added for the `WelcomeTitle`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': minor
---
Added Markdown support in the `AboutCard` description section
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Switched the order of reprocessing statements retroactively in migrations. This only improves the experience for those who at a later time perform a large upgrade of an old Backstage installation.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Update `SearchPage` template to use `SearchResult` extensions.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-app-api': patch
---
Fixed an issue where an explicit port the frontend base URL could break the app.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-home': patch
---
remove unused plugin-stack-overflow dependency
+30
View File
@@ -0,0 +1,30 @@
---
'@backstage/plugin-catalog-backend-module-azure': patch
---
This will add the ability to use Azure DevOps with multi project with a single value which is a new feature as previously this had to be done manually for each project that you wanted to add.
Right now you would have to fill in multiple values in the config to use multiple projects:
```
yourFirstProviderId: # identifies your dataset / provider independent of config changes
organization: myorg
project: 'firstProject' # this will match the firstProject project
repository: '*' # this will match all repos
path: /catalog-info.yaml
yourSecondProviderId: # identifies your dataset / provider independent of config changes
organization: myorg
project: 'secondProject' # this will match the secondProject project
repository: '*' # this will match all repos
path: /catalog-info.yaml
```
With this change you can actually have all projects available where your PAT determines which you have access to, so that includes multiple projects:
```
yourFirstProviderId: # identifies your dataset / provider independent of config changes
organization: myorg
project: '*' # this will match all projects where your PAT has access to
repository: '*' # this will match all repos
path: /catalog-info.yaml
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': minor
---
The `CatalogSearchResultListItem` component is now a search result extension. This means that when rendered as a child of components that render search extensions, the `result`, `rank`, and `highlight` properties are optional. See the [documentation](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions) for more details.
+2 -2
View File
@@ -1,5 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-incremental-ingestion': minor
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
---
Return EventSubscriber from addIncrementalEntityProvider to hook up to EventsBackend
Return `EventSubscriber` from `addIncrementalEntityProvider` to hook up to `EventsBackend`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
The Button component has been deprecated in favor of the LinkButton component
+43
View File
@@ -198,36 +198,79 @@
"@backstage/plugin-scaffolder-node": "0.0.0"
},
"changesets": [
"afraid-foxes-provide",
"brave-cougars-burn",
"bright-eagles-love",
"brown-islands-own",
"calm-avocados-exercise",
"chatty-owls-care",
"clean-queens-judge",
"cold-cycles-switch",
"create-app-1674561612",
"cuddly-boxes-agree",
"cyan-deers-walk",
"dry-donkeys-cheer",
"dull-gorillas-sing",
"eight-falcons-explode",
"eight-hotels-sparkle",
"flat-cups-itch",
"four-candles-add",
"four-rivers-enjoy",
"friendly-scissors-shop",
"gold-bulldogs-talk",
"gold-lemons-eat",
"gold-masks-sleep",
"grumpy-bottles-stare",
"happy-cows-moo",
"hip-pugs-teach",
"hot-lions-cover",
"hungry-news-fix",
"itchy-goats-melt",
"khaki-toes-care",
"late-rice-crash",
"lazy-badgers-rule",
"lazy-badgers-try",
"lemon-tables-train",
"lovely-ladybugs-taste",
"many-nails-joke",
"modern-cats-worry",
"nasty-beans-accept",
"neat-zebras-run",
"nervous-apricots-whisper",
"nervous-mangos-rhyme",
"nine-glasses-invent",
"nine-guests-compete",
"ninety-hats-serve",
"old-knives-wonder",
"perfect-cheetahs-serve",
"pink-falcons-serve",
"poor-moons-confess",
"popular-dancers-join",
"pretty-ladybugs-taste",
"purple-feet-smile",
"quick-ladybugs-reply",
"rare-melons-battle",
"renovate-0b349f9",
"renovate-0c3644c",
"rich-snakes-rest",
"rotten-mayflies-love",
"sharp-lobsters-build",
"shiny-years-tap",
"shy-steaks-invite",
"silly-turkeys-hang",
"smart-dingos-raise",
"soft-boxes-buy",
"soft-snails-notice",
"spotty-coats-clean",
"stale-dots-smile",
"stupid-ladybugs-brake",
"swift-fishes-smash",
"tall-years-relate",
"thick-clocks-pump",
"twenty-islands-wonder",
"twenty-parents-relate",
"two-melons-lie",
"witty-moose-itch",
"young-singers-learn"
]
}
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Adds new type, TableOptions, extending Material Table Options.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-radar': patch
---
Allow to set additional links to the entry description.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/cli': patch
'@backstage/plugin-scaffolder-backend': patch
---
Updated dependency `esbuild` to `^0.17.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-explore': minor
---
The `ToolSearchResultListItem` component is now a search result extension. This means that when rendered as a child of components that render search extensions, the `result`, `rank`, and `highlight` properties are optional. See the [documentation](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions) for more details.
+10
View File
@@ -0,0 +1,10 @@
---
'@backstage/backend-plugin-api': patch
---
The `register` methods passed to `createBackendPlugin` and `createBackendModule`
now have dedicated `BackendPluginRegistrationPoints` and
`BackendModuleRegistrationPoints` arguments, respectively. This lets us make it
clear on a type level that it's not possible to pass in extension points as
dependencies to plugins (should only ever be done for modules). This has no
practical effect on code that was already well behaved.
+16
View File
@@ -0,0 +1,16 @@
---
'@backstage/plugin-catalog-backend-module-bitbucket': patch
'@backstage/plugin-catalog-backend-module-github': patch
'@backstage/plugin-catalog-backend-module-gitlab': patch
'@backstage/plugin-catalog-backend-module-azure': patch
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-git-release-manager': patch
'@backstage/core-components': patch
'@backstage/plugin-playlist-backend': patch
'@backstage/plugin-apache-airflow': patch
'@backstage/plugin-circleci': patch
'@backstage/plugin-bitrise': patch
'@backstage/plugin-sentry': patch
---
Internal refactor to not use deprecated `substr`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-gitlab': patch
---
Implement Group and User Catalog Provider
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Prefer schema ordering of template properties during review content generation.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-search-react': minor
---
- Create the search results extensions, for more details see the documentation [here](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions);
- Update the `SearchResult`, `SearchResultList` and `SearchResultGroup` components to use extensions and default their props to optionally accept a query, when the query is not passed, the component tries to get it from the search context.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-airbrake': patch
---
Adds a boolean helper function to airbrake plugin for use on the EntityPage to show/hide airbrake tab depending on whether the entity's catalog-info.yml has an airbrake id set in the metadata
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Fixed bug in review step refactor that caused schema-based display settings for individual property values to be discarded.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': minor
---
Aligned buttons on "Unregister entity" dialog to keep them on the same line
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Switch to inline source maps for test transpilation, simplifying editor setups.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': minor
---
The `TechDocsSearchResultListItem` component is now a search result extension. This means that when rendered as a child of components that render search extensions, the `result`, `rank`, and `highlight` properties are optional. See the [documentation](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions) for more details.
+1 -1
View File
@@ -1,6 +1,6 @@
name: '🐛 Bug Report'
description: 'Submit a bug report to help us improve'
title: '🐛 Bug Report: '
title: '🐛 Bug Report: <title>'
labels:
- bug
body:
+1 -1
View File
@@ -1,6 +1,6 @@
name: 🚀 Feature
description: 'Submit a proposal for a new feature'
title: '🚀 Feature: '
title: '🚀 Feature: <title>'
labels: [enhancement]
body:
- type: markdown
+1 -1
View File
@@ -1,6 +1,6 @@
name: 🔌 Plugin
description: 'Submit a proposal for a new Plugin'
title: '🔌 Plugin: '
title: '🔌 Plugin: <title>'
labels: [plugin]
body:
- type: markdown
+1 -1
View File
@@ -1,6 +1,6 @@
name: 💬 RFC
description: 'Request For Comments (RFC) from the community'
title: '💬 RFC: '
title: '💬 RFC: <title>'
labels: [rfc]
body:
- type: markdown
+1 -1
View File
@@ -1,6 +1,6 @@
name: 🦄 UX Component
description: 'For designers to request UX components to be added to the Backstage Storybook'
title: '🦄 UX Component: '
title: '🦄 UX Component: <title>'
labels: [design]
body:
- type: markdown
+1 -5
View File
@@ -53,10 +53,6 @@ jobs:
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
# TODO(Rugvip): Remove the create-app dispatch once we've been on the release version for a while
script: |
const releaseVersion = require('./backstage/package.json').version;
if(releaseVersion.includes('next')) {
return;
}
console.log('Dispatching upgrade helper sync');
await github.rest.actions.createWorkflowDispatch({
owner: 'backstage',
@@ -65,6 +61,6 @@ jobs:
ref: 'master',
inputs: {
version: require('./backstage/packages/create-app/package.json').version,
releaseVersion
releaseVersion: require('./backstage/package.json').version
},
});
+2 -12
View File
@@ -89,16 +89,11 @@ jobs:
name: preview-spec
path: docker-compose.rendered.yml
retention-days: 2
- name: Serialize PR Event to File
run: |
cat << EOF > event.json
${{ toJSON(github.event) }}
EOF
- name: Upload PR Event as Artifact
uses: actions/upload-artifact@v3
with:
name: preview-spec
path: event.json
path: ${{ github.event_path }}
retention-days: 2
delete-preview:
@@ -107,14 +102,9 @@ jobs:
if: ${{ github.event.action == 'closed' }}
steps:
# If this PR is closing, we will not render a compose file nor pass it to the next workflow.
- name: Serialize PR Event to File
run: |
cat << EOF > event.json
${{ toJSON(github.event) }}
EOF
- name: Upload PR Event as Artifact
uses: actions/upload-artifact@v3
with:
name: preview-spec
path: event.json
path: ${{ github.event_path }}
retention-days: 2
+3 -1
View File
@@ -11,6 +11,7 @@ jobs:
cache-compose-file:
name: Cache Compose File
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
outputs:
compose-file-cache-key: ${{ env.COMPOSE_FILE_HASH }}
pr-number: ${{ env.PR_NUMBER }}
@@ -47,7 +48,7 @@ jobs:
run: |
echo 'EVENT_JSON<<EOF' >> $GITHUB_ENV
cat event.json >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
echo -e '\nEOF' >> $GITHUB_ENV
- name: Hash Rendered Compose File
id: hash
@@ -77,6 +78,7 @@ jobs:
name: Use Remote Workflow to Preview on Uffizzi
needs:
- cache-compose-file
if: ${{ github.event.workflow_run.conclusion == 'success' }}
uses: UffizziCloud/preview-action/.github/workflows/reusable.yaml@v2
with:
# If this workflow was triggered by a PR close event, cache-key will be an empty string
+7
View File
@@ -94,6 +94,13 @@ This section describes guidelines for designing public APIs. It can also be appl
/* ... */
}
// In order to make a private constructor available for testing you can use a
// static factory marked as `@internal`, which will not show up in the public API.
/** @internal */
static forTesting(internalOptions?: { ... }) {
return new DefaultImageLoader(internalOptions);
}
private constructor(/* ... */) {
/* ... */
}
@@ -1,32 +1,28 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="522px" height="282px" viewBox="-0.5 -0.5 522 282" content="&lt;mxfile scale=&quot;1.5&quot; border=&quot;20&quot;&gt;&lt;diagram id=&quot;gKBvn7eBFHudv9VMIRD-&quot; name=&quot;Page-1&quot;&gt;3VhBc6IwGP01XDtAAPW4tbZ76Ywz7sx2jylEyBgTJwTF/fUbSJBErKtsq654kPfyhYT3Mg+CA8bL8oXDVfbKEkQc301KBzw5vu95wJd/FbNVTDgaKCLlONFFLTHDv5EmXc0WOEG5VSgYIwKvbDJmlKJYWBzknG3ssjkj9qgrmKIOMYsh6bI/cSIyxYLAbfnvCKdZM/JQN7zDeJFyVlA9nOODeX2o5iVsLqXr8wwmbGNQYOKAMWdMqLNlOUakkrZRTfV7/qB1N22OqDilg3YlF9vmzlEihdCQMir/HjOxJBJ58hTR5Fslr4TvhMWLHxmmin7GxCjSjgYS5QJyYeBaHVSN70rUnXBjN+Qp0lSgqGpqRo2+oxfElkjwrSzgiECB17aHUC+FdFe36zplWI7qu3rZhtqUrQ2bC+Ss4DHSfVpN5YkxiZaqlT6s+vBc1Uss3irBHoaDUONfRttTqdWswdYAU8SxnBjiDXcx/5RaivK7lkaXsRSMbE8HX+apvsc1JIWe7KPMAillx2tbwE2GBZqtYK3VRqapbf1c2jJmhPG6L5hE1a92hbMFMlqi+qh6MCoMXh3HnFojLlB51IWm1RazgRsjIZtgy4x0DNyPbbMUPyIv6Mg7Q3yNY/mQuCN9weHVagg8/CJ9Rz0jyTPiyH0IjwfSVcIn6IZP+Nnhc6rKnt87+a3gd/+is5zWmwkMdyrYdqvRzfkDruVP0EmZKSlSTO8qZPZCHFwuZMKOvJNSIJpjRiVdP4XvSmlwPakbl89PmpsP9OiWAh30DnS/R6B7/0OgH/DnaoEedRLnlSUFuau3xv1960Vj5uz3xs9ekgnMsxp4GkyhkPtdWjO+6+003lt8fTat4B9X7eE9qheNHkLLwRO/PHSutL8S9ne76l567HYlbL9JqfL2ux+Y/AE=&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);">
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="642px" height="327px" viewBox="-0.5 -0.5 642 327" content="&lt;mxfile scale=&quot;1.5&quot; border=&quot;20&quot;&gt;&lt;diagram id=&quot;gKBvn7eBFHudv9VMIRD-&quot; name=&quot;Page-1&quot;&gt;3VnbTuMwEP2aPFLl1tsjlMLuw0pI3dXCo0ncxMK1K8dtU75+7dhJnBhKFMJlGySUGV/nnDNjE5xgsclvGdimv2gMseO7ce4E147vz1xX/JaOo3JMZ9qRMBQrl1c7VugZamfZbYdimDU6ckoxR9umM6KEwIg3fIAxemh2W1PcXHULEmg5VhHAtvcvinmqvEHo1v4fECVpuXIZ3iOInhJGd0Qv5/jBunhU8waUU+n+WQpiejBcwdIJFoxSrt42+QJiiWyJmhp380prtW0GCe8ywFcD9gDvdORXIgJI4kzvjx9LSIqooBznOsHVIUUcrrYgkq0HoQHhS/kGC8sTr2uE8YJiyoqxwXIif4Q/44w+QaNlUjxyBCXc8KtH+O2IdJB7yDjMDZeO8BbSDeTsKLro1otAo63FeFGif6ipDUvFpgatJd1Aqymppq4hFS8a1ZcRDiyEV5DtUQTPCWGvhfDUBnj2QfjOLXzvGN2L6mHBC2OR4toklMAmnjBH/N54f5A0jMbaus41K4VxLA0SX8piI8xHTKOn3ykiyn2DcDUxKetbWNADGDfsJueSIt04P8VMRncs0mGFujwClkDda6xcMuCT7DGIAUf7Zs17iQw99I4isZG6C12vM7Fmm61qhU4EenYN+pP1Zc8dTccmgW/QJzZ5bxoG6dKshxXWh9EuEw2Jw+cSo0TMdL1BcYyLCClDz0IToMr6YQQSdBSITm935Lr+TI35FpoJ7aTHuwSRc6qp7VOrqrGfUFTHFr7LnEOSIUqEu6D0nKBuH1+fCXV54zWwXgDZo1/9+99Or8knnF6dqbDvau85ifweJ5H3xSfRQBR2PV8Gp3BiMSj+NN3hs7ps+/Ovq1bVbmuAfxIhqf4Fa+TO50aeeCM37Hhpq7PjwWz79pc2Gc4dZEiAD5merFOi+XaihUMnWudbW90nb8qrVGVbbioSPejEPF57Irc1kYrfmqjHNfKFzx891XwWolQBtLLRP52NA2p58n20HLQuhH217L+REwNK2b679PwOckZSNi9g3kkdxyBLi5W9dwh48FvPOwTcKqKBO5rOjWc87ifo9rzDKVqY9Wdv1b3+z0Kw/Ac=&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);">
<defs/>
<g>
<path d="M 79.5 79.5 L 79.5 190.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 79.5 197.82 L 77 190.32 L 82 190.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 439.5 79.5 L 439.5 190.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 439.5 197.82 L 437 190.32 L 442 190.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="19.5" y="19.5" width="480" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<rect x="19.5" y="19.5" width="600" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 318px; height: 1px; padding-top: 33px; margin-left: 14px;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 398px; height: 1px; padding-top: 33px; margin-left: 14px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Backend
Backends
</div>
</div>
</div>
</foreignObject>
<text x="173" y="37" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Backend
<text x="213" y="37" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Backends
</text>
</switch>
</g>
<rect x="199.5" y="109.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<rect x="259.5" y="154.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 93px; margin-left: 134px;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 123px; margin-left: 174px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Services
@@ -34,20 +30,52 @@
</div>
</div>
</foreignObject>
<text x="173" y="97" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
<text x="213" y="127" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Services
</text>
</switch>
</g>
<path d="M 139.5 229.5 L 190.32 229.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 197.82 229.5 L 190.32 232 L 190.32 227 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 109.5 199.5 L 191.86 144.59" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 198.1 140.43 L 193.25 146.67 L 190.48 142.51 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="19.5" y="199.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<path d="M 139.5 274.5 L 250.32 274.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 257.82 274.5 L 250.32 277 L 250.32 272 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 153px; margin-left: 14px;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 183px; margin-left: 133px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Provide
</div>
</div>
</div>
</foreignObject>
<text x="133" y="186" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
Provide
</text>
</switch>
</g>
<path d="M 109.5 244.5 L 250.98 187.91" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 257.94 185.12 L 251.91 190.23 L 250.05 185.59 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 143px; margin-left: 123px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Use
</div>
</div>
</div>
</foreignObject>
<text x="123" y="146" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
Use
</text>
</switch>
</g>
<rect x="19.5" y="244.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 183px; margin-left: 14px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Plugins
@@ -55,16 +83,16 @@
</div>
</div>
</foreignObject>
<text x="53" y="157" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
<text x="53" y="187" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Plugins
</text>
</switch>
</g>
<rect x="199.5" y="199.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<rect x="259.5" y="244.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 153px; margin-left: 134px;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 183px; margin-left: 174px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Extension Points
@@ -72,20 +100,52 @@
</div>
</div>
</foreignObject>
<text x="173" y="157" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
<text x="213" y="187" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Extension Poi...
</text>
</switch>
</g>
<path d="M 379.5 229.5 L 328.68 229.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 321.18 229.5 L 328.68 227 L 328.68 232 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 409.5 199.5 L 327.14 144.59" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 320.9 140.43 L 328.52 142.51 L 325.75 146.67 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<rect x="379.5" y="199.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<path d="M 499.5 274.5 L 388.68 274.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 381.18 274.5 L 388.68 272 L 388.68 277 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 153px; margin-left: 254px;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 183px; margin-left: 293px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Call
</div>
</div>
</div>
</foreignObject>
<text x="293" y="186" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
Call
</text>
</switch>
</g>
<path d="M 529.5 244.5 L 388.02 187.91" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 381.06 185.12 L 388.95 185.59 L 387.09 190.23 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 143px; margin-left: 303px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Use
</div>
</div>
</div>
</foreignObject>
<text x="303" y="146" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
Use
</text>
</switch>
</g>
<rect x="499.5" y="244.5" width="120" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 183px; margin-left: 334px;">
<div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
Modules
@@ -93,19 +153,71 @@
</div>
</div>
</foreignObject>
<text x="293" y="157" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
<text x="373" y="187" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">
Modules
</text>
</switch>
</g>
<path d="M 259.5 79.5 L 259.5 100.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="1.5 1.5" pointer-events="stroke"/>
<path d="M 259.5 107.82 L 257 100.32 L 262 100.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 78.9 81.9 L 79.47 235.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 79.49 242.82 L 76.97 235.33 L 81.97 235.31 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 109px; margin-left: 53px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Install
</div>
</div>
</div>
</foreignObject>
<text x="53" y="112" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
Install
</text>
</switch>
</g>
<path d="M 559.5 80.7 L 559.5 235.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 559.5 242.82 L 557 235.32 L 562 235.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 108px; margin-left: 373px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Install
</div>
</div>
</div>
</foreignObject>
<text x="373" y="111" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
Install
</text>
</switch>
</g>
<path d="M 319.5 79.5 L 319.5 145.32" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" stroke-dasharray="4.5 4.5" pointer-events="stroke"/>
<path d="M 319.5 152.82 L 317 145.32 L 322 145.32 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)scale(1.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 78px; margin-left: 213px;">
<div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 9px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">
Provide
</div>
</div>
</div>
</foreignObject>
<text x="213" y="81" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
Provide
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Viewer does not support full SVG 1.1
Text is not SVG - cannot display
</text>
</a>
</switch>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 19 KiB

+10 -14
View File
@@ -6,16 +6,14 @@ sidebar_label: System Architecture
description: The structure and architecture of the new Backend System and its component parts
---
# Overview
## Building Blocks
This section introduces the high-level building blocks upon which this new
system is built. These are all concepts that exist in our current system in one
way or another, but they have all been lifted up to be first class concerns in
the new system.
## Building Blocks
This section introduces the high-level building blocks upon which this new system is built. Regardless of whether you are setting up your own backstage instance, developing plugins, or extending plugins with new features, it is important to understand these concepts.
the new system. Regardless of whether you are setting up your own backstage
instance, developing plugins, or extending plugins with new features, it is
important to understand these concepts.
The diagram below provides an overview of the different building blocks, and the other blocks that each of them interact with.
@@ -37,7 +35,7 @@ Plugins provide the actual features, just like in our existing system. They oper
Services provide utilities to help make it simpler to implement plugins, so that each plugin doesn't need to implement everything from scratch. There are both many built-in services, like the ones for logging, database access, and reading configuration, but you can also import third-party services, or create your own.
Services are also a customization point for individual backend installations. You can both override services with your own implementations, as well as make smaller customizations to existing services.
Services are also a customization point for individual backend installations. You can override services with your own implementations, as well as make smaller customizations to existing services.
### Extension Points
@@ -45,7 +43,7 @@ Many plugins have ways in which you can extend them, for example entity provider
Extension Points look a little bit like services, since you depended on them just like you would a service. A key difference is that extension points are registered and provided by plugins themselves, based on what customizations each individual plugin wants to expose.
Extension Points are also exported separately from the plugin instance itself, and a single plugin can also expose multiple different extension points at once. This makes it easier to evolve and deprecated individual Extension Points over time, rather than dealing with a single large API surface.
Extension Points are also exported separately from the plugin instance itself, and a single plugin can also expose multiple different extension points at once. This makes it easier to evolve and deprecate individual Extension Points over time, rather than dealing with a single large API surface.
### Modules
@@ -53,22 +51,20 @@ Modules use the plugin Extension Points to add new features for plugins. They mi
Each module may only extend a single plugin, and the module must be deployed together with that plugin in the same backend instance. Modules may however only communicate with their plugin through its registered extension points.
Just like plugins, modules also have access to services and can depend on their own service implementations. They will however share services with the plugin that they extend, there are no module-specific service implementations.
Just like plugins, modules also have access to services and can depend on their own service implementations. They will however share services with the plugin that they extend - there are no module-specific service implementations.
## Package structure
A detailed explanation of the package architecture can be found in the
[Backstage Architecture
Overview](../../overview/architecture-overview.md#package-architecture). The
most important packages to consider for this system are `backend`,
`plugin-<pluginId>-backend`, `plugin-<pluginId>-node`, and
`plugin-<pluginId>-backend-module-<moduleId>`.
most important packages to consider for this system are the following:
- `plugin-<pluginId>-backend` houses the implementation of the backend plugins
themselves.
- `plugin-<pluginId>-node` houses the extension points and any other utilities
- `plugin-<pluginId>-node` houses the backend plugin's extension points and any other utilities
that modules or other plugins might need.
- `plugin-<pluginId>-backend-module-<moduleId>` houses the modules that extend
the plugins via the extension points.
the plugin via its extension points.
- `backend` is the backend itself that wires everything together to something
that you can deploy.
+201 -77
View File
@@ -1,103 +1,227 @@
---
id: services
title: Backend Service APIs
sidebar_label: Service APIs
title: Backend Services
sidebar_label: Services
# prettier-ignore
description: Service APIs for backend plugins
description: Services for backend plugins
---
## Backend Services
Backend services provide shared functionality available to all backend plugins and modules. They are made available through service references that embed a type that represents the service interface, similar to how [Utility APIs](../../api/utility-apis.md) work in the Backstage frontend system. To use a service in your plugin or module you request an implementation of that service using the service reference.
The default backend provides several [core services](https://github.com/backstage/backstage/blob/master/packages/backend-plugin-api/src/services/definitions/coreServices.ts) out of the box which includes access to configuration, logging, databases and more.
Service dependencies are declared using their `ServiceRef`s in the `deps` section of the plugin or module, and the implementations are then forwarded to the `init` method of the plugin or module.
The system surrounding services exists to provide a level of indirection between the service interfaces and their implementation. It is an implementation of dependency injection, where each backend instance is the dependency injection container. The implementation for each service is provided by a service factory, which encapsulates the logic for how each service instance is created.
### Service References
## Service Interfaces
A `ServiceRef` is a named reference to an interface which are later used to resolve the concrete service implementation. Conceptually this is very similar to `ApiRef`s in the frontend.
Services is what provides common utilities that previously resided in the `PluginEnvironment` such as Config, Logging and Database.
Service interfaces can be any TypeScript type, but it is best to make it an object interface with a number of methods. General guidelines for interface design apply: keep them simple and lean, with few but powerful methods. Take care to avoid locking down the ways in which individual methods can evolve. Often you want to stick to a method with an options object as its only parameter, and return a result object. If there is any reason for uncertainty about whether the method should be async or not, always make it async. For example, a minimal interface should often use the following pattern:
On startup the backend will make sure that the services are initialized before being passed to the plugin/module that depend on them.
ServiceRefs contain a scope which is used to determine if the serviceFactory creating the service will create a new instance scoped per plugin/module or if it will be shared. `plugin` scoped services will be created once per plugin/module and `root` scoped services will be created once per backend instance.
```ts
export interface FooService {
foo(options: FooOptions): Promise<FooResult>;
}
```
#### Defining a Service
## Service References
Once you have defined a service interface, you need to create a service reference using the `createServiceRef` function. This will create a `ServiceRef` instance, which is a reference that you export in order to allow users to interact with your service. Conceptually this is very similar to `ApiRef`s in the frontend system. For example:
```ts
import { createServiceRef } from '@backstage/backend-plugin-api';
export interface FooService {
foo(options: FooOptions): Promise<FooResult>;
}
export const fooServiceRef = createServiceRef<FooService>({
id: 'example.foo', // the owner of this service is in this case the 'example' plugin
});
```
The `fooServiceRef` that we create above should be exported, and can then be used to declare a dependency on the `FooService` interface and receive an implementation of it at runtime.
When creating a service reference you need to give it an ID. This ID needs to be globally unique, and should generally be of the format `'<pluginId>.<serviceName>'`. For more naming patters surrounding services, see the [naming patterns](./07-naming-patterns.md#services) page.
A note on naming: the frontend and backend systems intentionally use the separate names "APIs" and "Services" for concepts that are quite similar. This is to avoid confusion between the two, both in documentation and discussion, but also in code. While the two systems are quite similar, they are not identical, and they can't be used interchangeably.
## Service Factories
In order to be able to depend on a service interface through a service reference, we of course also need to have some way of creating the concrete implementation of it. To encapsulate that logic we use service factories, which define both how service instances are created, as well as what other services they depend on for their implementation.
Service factories can come from many different sources. There are built-in service factories, external ones that you can import from other packages, and you can also create your own. Specific service factories are installed within each backend instance, which acts as the dependency injection container. For any given backend instance there can only be a single designated service factory for each service.
To define a service factory, we use `createServiceFactory`:
```ts
import { createServiceFactory } from '@backstage/backend-plugin-api';
class DefaultFooService implements FooService {
async foo(options: FooOptions): Promise<FooResult> {
// ...
}
}
export const fooFactory = createServiceFactory({
service: fooServiceRef,
deps: { bar: barServiceRef },
factory({ bar }) {
return new DefaultFooService(bar);
},
});
```
To create a service factory we need to provide a reference to the `service` for which the factory will create instances, a `deps` object which lists the other services that the factory depends on, and a `factory` function which will be called to create the service instance. The backend system will call the `factory` function with an object that contains the service instances for each of the dependencies listed in the `deps` object. If a service implementation does not depend on any other services, the `deps` are left as an empty object (`{}`). The `factory` function must return a value that implements the service interface.
If you need the creation of the service instance to be asynchronous, you can make the `factory` function async. For example:
```ts
export const fooFactory = createServiceFactory({
service: fooServiceRef,
deps: {},
async factory() {
const foo = new DefaultFooService();
await foo.init();
return foo;
},
});
```
Note that circular dependencies among service factories are not allowed. This is verified at runtime, and your backend instance will refuse to start up if it detects any conflicts. Likewise, the backend will also fail to start up if a service factory depends on a service that is not provided by any registered service factory.
## Service Factory Options
To install a service factory in a backend instance, we pass it in through the `services` option to `createBackend`:
```ts
const backend = createBackend({
services: [fooFactory()],
});
```
Note that we call `fooFactory` to create the service factory instance. This is because `createServiceFactory` always returns a factory function that creates the actual service factory. This is done to always allow for options to be added to the service factory in the future, without breaking existing code. To add options to your service factory, you wrap the object passed to `createServiceFactory` in a callback that accepts the desired options. For example:
```ts
export interface FooFactoryOptions {
mode: 'eager' | 'lazy';
}
export const fooFactory = createServiceFactory(
(options?: FooFactoryOptions) => ({
service: fooServiceRef,
deps: { bar: barServiceRef },
factory({ bar }) {
return new DefaultFooService(bar, options?.mode);
},
}),
);
```
This lets us use the options to customize the factory implementation in any way we want. From the outside the service factory looks just like before, except that we're now also able to pass options when installing the factory:
```ts
const backend = createBackend({
services: [fooFactory({ mode: 'eager' })],
});
```
## Core Services
The backend system provides a number of core service definitions that both help implement the main functionality of the backend, but also provide a set of utilities for common concerns, such as logging, database access, job scheduling, and so on. These core services will always be present in a backend instance created with `createBackend`, and they can all be overridden with custom implementations if needed.
The service references for all core services are exported via their own `coreServices` object, available from the `@backstage/backend-plugin-api` package. For example, the logging service is accessible via `coreServices.logger`.
You can read more about what core services there are and how to use them in the [core services](../core-services/01-index.md) section.
## Service Scope
By default services are scoped to individual plugins, meaning that separate instances of the service will be created for each plugin. For example, in our `fooFactory` above, a separate instance of `DefaultFooService` will be created for every plugin that depends on the service. This both makes it possible to tailor the service implementations for the individual plugins, and also ensures some level of separation between plugins.
The service scope is defined during the call to `createServiceRef`, with plugin scope being the default. Our above definition of the `fooServiceRef` is therefore equivalent to the following:
```ts
export const fooServiceRef = createServiceRef<FooService>({
scope: 'plugin',
id: 'example.foo',
});
```
There are only two possible scopes for services, `'plugin'` and `'root'`.
## Root Scoped Services
If a service is defined as a root scoped service, the implementation created by the factory will be shared across all plugins and services. One other differentiating factory for root scoped services is that they are always initialized, regardless of whether any plugins depend on them or not. This makes them suitable for implementing backend-wide concerns that are not specific to any individual plugin.
There is a limitation in the usage of root scoped services, which is that their implementation can only depend on other root scoped services. Plugin scoped services on the other hand can depend on both root and plugin scoped services. Because of this limitation, one of the main reasons to define a root scoped services is to make it possible for other root scoped services to depend on it.
Because of these limitations and particular use-cases for root scoped services, they tend to be more rare than plugin scoped services. In general, you should prefer defining a service as plugin scoped, unless you are implementing either of the two mentioned use-cases.
Some services come in pairs of a plugin and a root scoped service definition. For example, the `rootLogger` service is a root scoped service, while the `logger` service is a plugin scoped service. The `rootLogger` service houses the main logging implementation, while the `logger` service simply builds upon the `rootLogger` to add plugin specific labels. This division exists so that other root scoped services also have access to a logging service, but it is always preferable if the split can be avoided. If you do end up implementing this pattern, the root scoped service should be prefixed with `root`, this is to encourage use of the plugin scoped service instead.
## Plugin Metadata
Plugin scoped services have access to a plugin metadata service, which is a special service provided by the backend system that is not possible to override. The plugin metadata service provides information about the plugin that a service instance is being created for. It is itself a plugin scoped service, and can be depended on like any other service through the `coreServices.pluginMetadata` reference.
The plugin metadata service is the base for all plugin specific customizations for services. For example, the default implementation of the plugin scoped logger service uses the plugin metadata service to attach the plugin ID as a field in all log messages:
```ts
export const loggerFactory = createServiceFactory({
service: coreServices.logger,
deps: {
rootLogger: coreServices.rootLogger,
pluginMetadata: coreServices.pluginMetadata,
},
factory({ rootLogger, pluginMetadata }) {
return rootLogger.child({ plugin: pluginMetadata.getId() });
},
});
```
## Root Context for Service Factories
Some services may benefit from having a context that is shared across all instances of a service. This of course only applies to plugin scoped services, as root scoped services only ever have a single instance. The root context could for example be used for sharing a common connection pool for database access, generated secrets for development, or any other kind of shared facility. Note that you should not use this to share state between plugins in production, as that would be a violation of the [plugin isolation rule](./04-plugins.md#rules-of-plugins).
The root context is defined as part of the service factory by passing the `createRootContext` option:
```ts
export const fooFactory = createServiceFactory({
service: fooServiceRef,
deps: { rootLogger: coreServices.rootLogger, bar: barServiceRef },
createRootContext({ rootLogger }) {
return new FooRootContext(rootLogger);
}
factory({ bar }, ctx) {
return ctx.forPlugin(bar)
},
});
```
Whatever value is returned by the `createRootContext` function will shared and passed as the second argument to each invocation of the `factory` function. That way you can create a shared context that is used in the creation of each plugin instance. Unlike the `factory` function, the `createRootContext` function will only receive root scoped services as its dependencies, but just like the `factory` function, it can also be `async`.
## Default Service Factories
There are a lot of services that are installed in any standard Backstage backend instance by default. You can expect these services to always exist, and do not need to take any additional steps to make them available. This is not necessarily true for services that you import from external packages, as the user of your plugin or module might not have installed a factory for that service in their backend. In order to avoid having to ask integrators of your plugin to install a service factory for a service that you depend on, it is possible to define a default factory for a service.
Default service factories are defined as part of the service reference by passing the `defaultFactory` option to `createServiceRef`:
```ts
import {
createServiceFactory,
coreServices,
createServiceRef,
} from '@backstage/backend-plugin-api';
import { ExampleImpl } from './ExampleImpl';
export interface ExampleApi {
doSomething(): Promise<void>;
}
export const exampleServiceRef = createServiceRef<ExampleApi>({
id: 'example',
scope: 'plugin', // can be 'root' or 'plugin'
// The defaultFactory is optional to implement but it will be used if no
// other factory is provided to the backend. This allows for the backend
// to provide a default implementation of the service without having to wire
// it beforehand.
export const fooServiceRef = createServiceRef<FooService>({
id: 'example.foo',
defaultFactory: async service =>
createServiceFactory({
service,
deps: {
logger: coreServices.logger,
plugin: coreServices.pluginMetadata,
},
// This root context method is only available for plugin scoped services.
// It's only called once per backend instance.
// Logger is available at the root context level as it's also a root
// scoped service.
createRootContext({ logger }) {
return new ExampleImplFactory({ logger });
},
// Plugin is available as it's a plugin scoped service and will be
// created once per plugin. The logger can be had here too if needed.
// Both this anc the root context can also be async.
factory({ logger, plugin }, rootContext) {
// This block will be executed once for every plugin that depends on
// this service
logger.info('Initializing example service plugin instance');
return rootContext.forPlugin(plugin.getId());
deps: {},
factory() {
return new DefaultFooService();
},
}),
});
```
### Overriding Services
Note that we don't use the `fooServiceRef` when creating our service factory, but instead use the `service` parameter in the default factory callback. This is because attempting to use `fooServiceRef` directly would result in a circular reference.
In this example we replace the default root logger service implementation with a custom one that streams logs to GCP. The `rootLoggerServiceRef` has a `'root'` scope, meaning there are no plugin-specific instances of this service.
If a service defines a default factory, that factory will be used if there is no explicit factory registered in the backend for that service. This allows users of your service to directly import and use a service, without worrying about whether it is installed or not. It is recommended to always define a default factory for any service that you are exporting for use in other plugins or modules.
```ts
import {
createServiceFactory,
rootLoggerServiceRef,
LoggerService,
} from '@backstage/backend-plugin-api';
// This custom implementation would typically live separately from
// the backend setup code, either nearby such as in
// packages/backend/src/services/logger/GoogleCloudLogger.ts
// Or you can let it live in its own library package.
class GoogleCloudLogger implements LoggerService {
static factory = createServiceFactory({
service: rootLoggerServiceRef,
deps: {},
factory() {
return new GoogleCloudLogger();
},
});
// custom implementation here ...
}
// packages/backend/src/index.ts
const backend = createBackend({
services: [
// supplies additional or replacement services to the backend
GoogleCloudLogger.factory(),
],
});
```
When defining a default factory for a service, it is possible for it to end up with duplicate implementations at runtime. This applies both to any shared root context in your factory, as well as plugin specific instances of your service. This is because package dependency version ranges may not line up perfectly, causing duplicate installations of the same package. This can happen both for two different plugins using the same service, but also across a plugin and its modules. If your service would break in this scenario, you should not define a default factory for it, but instead require that users of your service explicitly install a factory in their backend instance.
@@ -16,6 +16,12 @@ Backend [plugins](../architecture/04-plugins.md) and
backend _features_, are the building blocks that adopters add to their
[backends](../architecture/02-backends.md).
## Creating a new Plugin
This guide assumes that you already have a Backend project set up. Even if you only want to develop a single plugin for publishing, we still recommend that you do so in a standard Backstage monorepo project, as you often end up needing multiple packages. For instructions on how to set up a new project, see our [getting started](../../getting-started/index.md#prerequisites) documentation.
To create a Backend plugin, run `yarn new`, select `backend-plugin`, and fill out the rest of the prompts. This will create a new package at `plugins/<pluginId>-backend`, which will be the main entrypoint for your plugin.
## Plugins
A basic backend plugin might look as follows:
+2 -2
View File
@@ -3,7 +3,7 @@ id: index
title: The Backend System
sidebar_label: Overview
# prettier-ignore
description: The backend system
description: The Backend System
---
> **DISCLAIMER: The new backend system is under active development and is not considered stable**
@@ -12,4 +12,4 @@ description: The backend system
The new backend system is under active development, and only a small number of plugins have been migrated so far. It is possible to try it out, but it is not recommended to use this new system in production yet.
You can find an example backend setup in [the backend-next package](https://github.com/backstage/backstage/tree/master/packages/backend-next).
You can find an example backend setup in [the `backend-next` package](https://github.com/backstage/backstage/tree/master/packages/backend-next).
+153
View File
@@ -210,3 +210,156 @@ const highlightOverride = {
[obj-mode]: https://nodejs.org/dist/latest-v16.x/docs/api/stream.html#stream_object_mode
[read-stream]: https://nodejs.org/dist/latest-v16.x/docs/api/stream.html#readable-streams
[async-gen]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of#iterating_over_async_generators
## How to render search results using extensions
Extensions for search results let you customize components used to render search result items, It is possible to provide your own search result item extensions or use the ones provided by plugin packages:
### 1. Providing an extension in your plugin package
Using the example below, you can provide an extension to be used as a default result item:
```tsx
// plugins/your-plugin/src/plugin.ts
import { createPlugin } from '@backstage/core-plugin-api';
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react';
const plugin = createPlugin({ id: 'YOUR_PLUGIN_ID' });
export const YourSearchResultListItemExtension = plugin.provide(
createSearchResultListItemExtension({
name: 'YourSearchResultListItem',
component: () =>
import('./components').then(m => m.YourSearchResultListItem),
}),
);
```
Additionally, you can define a predicate function that receives a result and returns whether your extension should be used to render it or not:
```tsx
// plugins/your-plugin/src/plugin.ts
import { createPlugin } from '@backstage/core-plugin-api';
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react';
const plugin = createPlugin({ id: 'YOUR_PLUGIN_ID' });
export const YourSearchResultListItemExtension = plugin.provide(
createSearchResultListItemExtension({
name: 'YourSearchResultListItem',
component: () =>
import('./components').then(m => m.YourSearchResultListItem),
// Only results matching your type will be rendered by this extension
predicate: result => result.type === 'YOUR_RESULT_TYPE',
}),
);
```
Remember to export your new extension:
```tsx
// plugins/your-plugin/src/index.ts
export { YourSearchResultListItem } from './plugin.ts';
```
For more details, see the [createSearchResultListItemExtension](https://backstage.io/docs/reference/plugin-search-react.createsearchresultlistitemextension) API reference.
### 2. Using an extension in your Backstage app
Now that you know how a search result item is provided, let's finally see how they can be used, for example, to compose a page in your application:
```tsx
// packages/app/src/components/searchPage.tsx
import React from 'react';
import { Grid, Paper } from '@material-ui/core';
import BuildIcon from '@material-ui/icons/Build';
import {
Page,
Header,
Content,
DocsIcon,
CatalogIcon,
} from '@backstage/core-components';
import { SearchBar, SearchResult } from '@backstage/plugin-search-react';
// Your search result item extension
import { YourSearchResultListItem } from '@backstage/your-plugin';
// Extensions provided by other plugin developers
import { ToolSearchResultListItem } from '@backstage/plugin-explore';
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
import { CatalogSearchResultListItem } from '@internal/plugin-catalog-customized';
// This example omits other components, like filter and pagination
const SearchPage = () => (
<Page themeId="home">
<Header title="Search" />
<Content>
<Grid container direction="row">
<Grid item xs={12}>
<Paper>
<SearchBar />
</Paper>
</Grid>
<Grid item xs={12}>
<SearchResult>
<YourSearchResultListItem />
<CatalogSearchResultListItem icon={<CatalogIcon />} />
<TechDocsSearchResultListItem icon={<DocsIcon />} />
<ToolSearchResultListItem icon={<BuildIcon />} />
</SearchResult>
</Grid>
</Grid>
</Content>
</Page>
);
export const searchPage = <SearchPage />;
```
> **Important**: A default result item extension should be placed as the last child, so it can be used only when no other extensions match the result being rendered. If a non-default extension is specified, the `DefaultResultListItem` component will be used.
As another example, here's a search modal that renders results with extensions:
```tsx
// packages/app/src/components/searchModal.tsx
import React from 'react';
import { DialogContent, DialogTitle, Paper } from '@material-ui/core';
import BuildIcon from '@material-ui/icons/Build';
import { DocsIcon, CatalogIcon } from '@backstage/core-components';
import { SearchBar, SearchResult } from '@backstage/plugin-search-react';
// Your search result item extension
import { YourSearchResultListItem } from '@backstage/your-plugin';
// Extensions provided by other plugin developers
import { ToolSearchResultListItem } from '@backstage/plugin-explore';
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
import { CatalogSearchResultListItem } from '@internal/plugin-catalog-customized';
export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => (
<>
<DialogTitle>
<Paper>
<SearchBar />
</Paper>
</DialogTitle>
<DialogContent>
<SearchResult onClick={toggleModal}>
<CatalogSearchResultListItem icon={<CatalogIcon />} />
<TechDocsSearchResultListItem icon={<DocsIcon />} />
<ToolSearchResultListItem icon={<BuildIcon />} />
{/* As a "default" extension, it does not define a predicate function,
so it must be the last child to render results that do not match the above extensions */}
<YourSearchResultListItem />
</SearchResult>
</DialogContent>
</>
);
```
There are other more specific search results layout components that also accept result item extensions, check their documentation: [SearchResultList](https://backstage.io/storybook/?path=/story/plugins-search-searchresultlist--with-result-item-extensions) and [SearchResultGroup](https://backstage.io/storybook/?path=/story/plugins-search-searchresultgroup--with-result-item-extensions).
@@ -35,7 +35,7 @@ import FormControl from '@material-ui/core/FormControl';
/*
This is the actual component that will get rendered in the form
*/
export const ValidateKebabCaseExtension = ({
export const ValidateKebabCase = ({
onChange,
rawErrors,
required,
@@ -96,7 +96,7 @@ import {
import {
ValidateKebabCase,
validateKebabCaseValidation,
} from './ValidateKebabCase';
} from './ValidateKebabCase/ValidateKebabCaseExtension';
export const ValidateKebabCaseFieldExtension = scaffolderPlugin.provide(
createScaffolderFieldExtension({
@@ -173,7 +173,7 @@ spec:
title: Name
type: string
description: My custom name for the component
ui:field: ValidateKebabCaseExtension
ui:field: ValidateKebabCase
steps:
[...]
```
+1 -1
View File
@@ -49,7 +49,7 @@ techdocs:
# will be broken in these scenarios.
legacyCopyReadmeMdToIndexMd: false
# techdocs.builder can be either 'local' or 'external.
# techdocs.builder can be either 'local' or 'external'.
# Using the default build strategy, if builder is set to 'local' and you open a TechDocs page,
# techdocs-backend will try to generate the docs, publish to storage and show the generated docs afterwords.
# This is the "Basic" setup of the TechDocs Architecture.
@@ -230,7 +230,7 @@ If you are deploying Backstage to Amazon EC2, Amazon ECS, or Amazon EKS, you do
not need to obtain the access keys separately. They can be made available in the
environment automatically by defining appropriate IAM role with access to the
bucket. Read more in the
[official AWS documentation for using IAM roles.](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html#use-roles).
[official AWS documentation for using IAM roles](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html#use-roles).
**4b. Authentication using app-config.yaml**
+7 -2
View File
@@ -47,6 +47,11 @@ catalog:
frequency: { minutes: 30 }
# supports ISO duration, "human duration" as used in code
timeout: { minutes: 3 }
yourSecondProviderId: # identifies your dataset / provider independent of config changes
organization: myorg
project: '*' # this will match all projects
repository: '*' # this will match all repos
path: /catalog-info.yaml
anotherProviderId: # another identifier
organization: myorg
project: myproject
@@ -62,7 +67,7 @@ The parameters available are:
- **`host:`** _(optional)_ Leave empty for Cloud hosted, otherwise set to your self-hosted instance host.
- **`organization:`** Your Organization slug (or Collection for on-premise users). Required.
- **`project:`** Your project slug. Required.
- **`project:`** _(optional)_ Your project slug. Wildcards are supported as show on the examples above. If not set, all projects will be searched.
- **`repository:`** _(optional)_ The repository name. Wildcards are supported as show on the examples above. If not set, all repositories will be searched.
- **`path:`** _(optional)_ Where to find catalog-info.yaml files. Defaults to /catalog-info.yaml.
- **`schedule`** _(optional)_:
@@ -144,7 +149,7 @@ When using a custom pattern, the target is composed of five parts:
- The base instance URL, `https://dev.azure.com` in this case
- The organization name which is required, `myorg` in this case
- The project name which is required, `myproject` in this case
- The project name which is optional, `myproject` in this case. This defaults to \*, which scans all the projects where the token has access to.
- The repository blob to scan, which accepts \* wildcard tokens and must be
added after `_git/`. This can simply be `*` to scan all repositories in the
project.
+34
View File
@@ -0,0 +1,34 @@
---
id: org
title: GitLab Organizational Data
sidebar_label: Org Data
description: Importing users and groups from a GitLab organization into Backstage
---
The Backstage catalog can be set up to ingest organizational data - users and
teams - directly from an organization in GitLab. The result
is a hierarchy of
[`User`](../../features/software-catalog/descriptor-format.md#kind-user) and
[`Group`](../../features/software-catalog/descriptor-format.md#kind-group) kind
entities that mirror your org setup.
```yaml
integrations:
gitlab:
- host: gitlab.com
token: ${GITLAB_TOKEN}
```
This will query all users and groups from your gitlab installation. Depending on the size
of the Gitlab Instance, this can take some time our resources.
The token that is used for the Organization Integration, has to be an Admin PAT.
```yaml
catalog:
providers:
gitlab:
yourProviderId:
host: gitlab.com
orgEnabled: true
```
-1
View File
@@ -37,7 +37,6 @@ schedule it:
```diff
// packages/backend/src/plugins/catalog.ts
+import { Duration } from 'luxon';
+import { LdapOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-ldap';
export default async function createPlugin(
+2
View File
@@ -28,6 +28,8 @@ Other responsibilities include protecting the integrity of configuration files a
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.
The integrator is also responsible for maintaining the resolved NPM dependencies of their Backstage project. This involves ensuring that `yarn.lock` receives updated versions of packages that have vulnerabilities, when those fixed versions are in range of what the Backstage packages request in their respective `package.json` files. This is commonly done by employing automated tooling such as [Dependabot](https://dependabot.com/), [Snyk](https://snyk.io/), and/or [Renovate](https://docs.renovatebot.com/) on your own repository. When fixed versions exist that are _not_ in range of what Backstage packages request, or when larger operations such as switching out an entire dependency for another one is required, maintainers collaborate with contributors to try to address those dependency declarations in the main project as soon as possible.
## 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.
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
---
title: S3 Viewer
author: Spreadgroup
authorUrl: https://github.com/spreadshirt
category: AWS
description: Visualization of S3 buckets and their contents in file explorer style.
documentation: https://github.com/spreadshirt/backstage-plugin-s3/
iconUrl: img/s3-bucket.svg
npmPackageName: '@spreadshirt/backstage-plugin-s3-viewer'
tags:
- s3
addedDate: '2023-01-18'
+12
View File
@@ -0,0 +1,12 @@
---
title: Torque
author: Quali
authorUrl: 'https://www.qtorque.io/'
category: Orchestration
description: |
Deploy the environments you need to keep building, testing and delivering incredible code.
Plugin includes an Entity ComponentCard, Backend API route and scaffolder actions.
documentation: https://github.com/QualiTorque/torque-backstage-plugin/tree/main/packages/torque#readme
iconUrl: https://user-images.githubusercontent.com/8643801/214640977-751bc338-6b77-40a0-a897-cba41b6f006a.png
npmPackageName: '@qtorque/backstage-plugin-torque'
addedDate: '2023-01-25'
+1 -1
View File
@@ -20,7 +20,7 @@ const ondemandMetadata = fs
.reverse()
.map(file => yaml.load(fs.readFileSync(`./data/on-demand/${file}`, 'utf8')));
const truncate = text =>
text.length > 170 ? text.substr(0, 170) + '...' : text;
text.length > 170 ? text.slice(0, 170) + '...' : text;
const addVideoDocsLink = '/docs/overview/support';
const defaultIconUrl = 'img/logo-gradient-on-dark.svg';
+1 -1
View File
@@ -19,7 +19,7 @@ const pluginMetadata = fs
.map(file => yaml.load(fs.readFileSync(`./data/plugins/${file}`, 'utf8')))
.sort((a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase()));
const truncate = text =>
text.length > 170 ? text.substr(0, 170) + '...' : text;
text.length > 170 ? text.slice(0, 170) + '...' : text;
const newForDays = 100;
+2 -1
View File
@@ -201,7 +201,8 @@
"label": "GitLab",
"ids": [
"integrations/gitlab/locations",
"integrations/gitlab/discovery"
"integrations/gitlab/discovery",
"integrations/gitlab/org"
]
},
{
+3 -2
View File
@@ -138,8 +138,9 @@ const siteConfig = {
],
algolia: {
apiKey: '8d115c9875ba0f4feaee95bab55a1645',
indexName: 'backstage',
apiKey: '10b9e6c92a4513c1cf390f50e53aad1f',
indexName: 'backstage_io',
appId: 'JCMFNHCHI8',
searchParameters: {}, // Optional (if provided by Algolia)
},
};
+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 100 100" height="100px" version="1.1" viewBox="0 0 100 100" width="100px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Layer_1"><g><g><g enable-background="new "><g enable-background="new "><defs><path d="M77.586,28.061v2.772c0,3.559-12.344,6.433-27.578,6.433 c-15.25,0-27.594-2.874-27.594-6.433v-2.772c0,3.559,12.344,6.432,27.594,6.432C65.242,34.492,77.586,31.619,77.586,28.061z" enable-background="new " id="SVGID_5_"/></defs><clipPath id="SVGID_2_"/><g clip-path="url(#SVGID_2_)" enable-background="new "><path d="M77.586,28.061v2.772c0,0.084-0.006,0.168-0.02,0.25v-2.771C77.58,28.228,77.586,28.145,77.586,28.061 " fill="#8C3323"/><path d="M77.566,28.312v2.771c-0.018,0.098-0.039,0.193-0.074,0.289v-2.773 C77.527,28.503,77.549,28.407,77.566,28.312" fill="#8C3323"/><path d="M77.492,28.599v2.773c-0.049,0.135-0.113,0.268-0.195,0.4v-2.773 C77.379,28.866,77.443,28.734,77.492,28.599" fill="#8C3323"/><path d="M77.297,28.999v2.773c-1.945,3.111-13.42,5.493-27.289,5.493c-15.25,0-27.594-2.874-27.594-6.433 v-2.772c0,3.559,12.344,6.432,27.594,6.432C63.877,34.492,75.352,32.11,77.297,28.999" fill="#8C3323"/></g></g><g><path d="M50.008,21.628c15.234,0,27.578,2.875,27.578,6.433c0,3.559-12.344,6.432-27.578,6.432 c-15.25,0-27.594-2.873-27.594-6.432C22.414,24.503,34.758,21.628,50.008,21.628z" fill="#E15343"/></g><g><polygon fill="#8C3323" points="77.428,33.006 77.428,35.779 68.387,74.069 67.67,72.257 "/></g><g><polygon fill="#8C3323" points="31.613,71.296 31.613,74.069 22.572,35.779 22.572,33.006 "/></g><g enable-background="new "><defs><path d="M68.387,71.296v2.773c0,2.387-8.217,4.303-18.379,4.303 s-18.395-1.916-18.395-4.303v-2.773c0,2.389,8.232,4.303,18.395,4.303S68.387,73.685,68.387,71.296z" enable-background="new " id="SVGID_7_"/></defs><clipPath id="SVGID_4_"/><g clip-path="url(#SVGID_4_)" enable-background="new "><path d="M68.387,71.296v2.773c0,0.057-0.004,0.112-0.012,0.168v-2.771 C68.383,71.409,68.387,71.353,68.387,71.296" fill="#8C3323"/><path d="M68.375,71.466v2.771c-0.012,0.066-0.027,0.131-0.051,0.196v-2.772 C68.348,71.596,68.363,71.53,68.375,71.466" fill="#8C3323"/><path d="M68.324,71.661v2.772c-0.033,0.091-0.076,0.18-0.131,0.268v-2.772 C68.248,71.839,68.291,71.751,68.324,71.661" fill="#8C3323"/><path d="M68.67,71.007l-0.477,3.694c-1.301,2.084-8.939,3.671-18.186,3.671 c-10.162,0-18.395-1.916-18.395-4.303v-2.773c0,2.389,8.232,4.303,18.395,4.303c9.246,0,16.885-1.585,18.186-3.67" fill="#8C3323"/></g></g><g><path d="M50.008,38.752c14.24,0,25.951-2.515,27.42-5.746l-9.041,38.29c0,2.389-8.217,4.303-18.379,4.303 s-18.395-1.914-18.395-4.303l-9.041-38.29C24.043,36.237,35.77,38.752,50.008,38.752z" fill="#E15343"/></g></g></g><rect clip-rule="evenodd" fill="#FFFFFF" fill-rule="evenodd" height="11.398" width="11.477" x="43.762" y="42.854"/><ellipse clip-rule="evenodd" cx="40.287" cy="63.9" fill="#FFFFFF" fill-rule="evenodd" rx="5.658" ry="5.62"/><polygon clip-rule="evenodd" fill="#FFFFFF" fill-rule="evenodd" points="64.09,69.257 52.748,69.257 58.42,58.784 "/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

+1 -1
View File
@@ -46,7 +46,7 @@
"@types/react": "^17",
"@types/react-dom": "^17"
},
"version": "1.11.0-next.0",
"version": "1.11.0-next.1",
"dependencies": {
"@backstage/errors": "workspace:^",
"@manypkg/get-packages": "^1.1.3"
+11
View File
@@ -1,5 +1,16 @@
# @backstage/app-defaults
## 1.1.1-next.0
### Patch Changes
- Updated dependencies
- @backstage/core-app-api@1.4.1-next.0
- @backstage/core-components@0.12.4-next.0
- @backstage/core-plugin-api@1.3.0
- @backstage/theme@0.2.16
- @backstage/plugin-permission-react@0.4.9
## 1.1.0
### Minor Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/app-defaults",
"description": "Provides the default wiring of a Backstage App",
"version": "1.1.0",
"version": "1.1.1-next.0",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
+64
View File
@@ -1,5 +1,69 @@
# example-app
## 0.2.80-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-scaffolder-react@1.1.0-next.1
- @backstage/plugin-scaffolder@1.11.0-next.1
- @backstage/cli@0.22.2-next.0
- @backstage/plugin-techdocs@1.5.0-next.1
- @backstage/plugin-tech-insights@0.3.7-next.1
- @backstage/plugin-search@1.1.0-next.1
- @backstage/plugin-techdocs-module-addons-contrib@1.0.10-next.1
- @backstage/plugin-dynatrace@2.0.0-next.1
- @backstage/plugin-playlist@0.1.6-next.1
- @backstage/plugin-home@0.4.31-next.1
- @backstage/core-app-api@1.4.1-next.0
- @backstage/plugin-kubernetes@0.7.8-next.1
- @backstage/core-components@0.12.4-next.0
- @backstage/plugin-tech-radar@0.6.1-next.0
- @backstage/plugin-explore@0.4.0-next.1
- @backstage/plugin-apache-airflow@0.2.8-next.0
- @backstage/plugin-circleci@0.3.15-next.1
- @backstage/plugin-sentry@0.4.8-next.1
- @backstage/plugin-search-react@1.5.0-next.0
- @backstage/plugin-airbrake@0.3.15-next.1
- @backstage/plugin-catalog-react@1.3.0-next.1
- @backstage/app-defaults@1.1.1-next.0
- @backstage/catalog-model@1.1.6-next.0
- @backstage/config@1.0.6
- @backstage/core-plugin-api@1.3.0
- @backstage/integration-react@1.1.10-next.0
- @backstage/theme@0.2.16
- @backstage/plugin-api-docs@0.8.15-next.1
- @backstage/plugin-azure-devops@0.2.6-next.1
- @backstage/plugin-azure-sites@0.1.4-next.1
- @backstage/plugin-badges@0.2.39-next.1
- @backstage/plugin-catalog-common@1.0.11-next.0
- @backstage/plugin-catalog-graph@0.2.27-next.1
- @backstage/plugin-catalog-import@0.9.5-next.1
- @backstage/plugin-cloudbuild@0.3.15-next.1
- @backstage/plugin-code-coverage@0.2.8-next.1
- @backstage/plugin-cost-insights@0.12.4-next.1
- @backstage/plugin-gcalendar@0.3.11-next.0
- @backstage/plugin-gcp-projects@0.3.34-next.0
- @backstage/plugin-github-actions@0.5.15-next.1
- @backstage/plugin-gocd@0.1.21-next.1
- @backstage/plugin-graphiql@0.2.47-next.0
- @backstage/plugin-jenkins@0.7.14-next.1
- @backstage/plugin-kafka@0.3.15-next.1
- @backstage/plugin-lighthouse@0.3.15-next.1
- @backstage/plugin-newrelic@0.3.33-next.0
- @backstage/plugin-newrelic-dashboard@0.2.8-next.1
- @backstage/plugin-org@0.6.5-next.1
- @backstage/plugin-pagerduty@0.5.8-next.1
- @backstage/plugin-permission-react@0.4.9
- @backstage/plugin-rollbar@0.4.15-next.1
- @backstage/plugin-search-common@1.2.1
- @backstage/plugin-shortcuts@0.3.7-next.0
- @backstage/plugin-stack-overflow@0.1.11-next.1
- @backstage/plugin-techdocs-react@1.1.3-next.1
- @backstage/plugin-todo@0.2.17-next.1
- @backstage/plugin-user-settings@0.6.3-next.1
- @internal/plugin-catalog-customized@0.0.7-next.1
## 0.2.80-next.0
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-app",
"version": "0.2.80-next.0",
"version": "0.2.80-next.1",
"private": true,
"backstage": {
"role": "frontend"
@@ -21,7 +21,6 @@ import {
DialogContent,
DialogTitle,
Grid,
List,
makeStyles,
Paper,
useTheme,
@@ -44,9 +43,8 @@ import {
import { ToolSearchResultListItem } from '@backstage/plugin-explore';
import { searchPlugin, SearchType } from '@backstage/plugin-search';
import {
DefaultResultListItem,
SearchFilter,
SearchBar,
SearchFilter,
SearchResult,
SearchResultPager,
useSearch,
@@ -93,7 +91,7 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => {
searchBarRef?.current?.focus();
});
const handleSearchResulClick = useCallback(() => {
const handleSearchResultClick = useCallback(() => {
toggleModal();
setTimeout(focusContent, transitions.duration.leavingScreen);
}, [toggleModal, focusContent, transitions]);
@@ -101,11 +99,11 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => {
const handleSearchBarKeyDown = useCallback(
(e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
if (e.key === 'Enter') {
handleSearchResultClick();
navigate(searchPagePath);
toggleModal();
}
},
[navigate, toggleModal, searchPagePath],
[navigate, searchPagePath, handleSearchResultClick],
);
return (
@@ -189,7 +187,7 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => {
alignItems="center"
>
<Grid item>
<Link to={searchPagePath} onClick={handleSearchResulClick}>
<Link to={searchPagePath} onClick={handleSearchResultClick}>
<Typography
component="span"
className={classes.viewResultsLink}
@@ -202,69 +200,13 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => {
</Grid>
</Grid>
<Grid item xs>
<SearchResult>
{({ results }) => (
<List>
{results.map(({ type, document, highlight, rank }) => {
let resultItem;
switch (type) {
case 'software-catalog':
resultItem = (
<CatalogSearchResultListItem
icon={<CatalogIcon />}
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
);
break;
case 'techdocs':
resultItem = (
<TechDocsSearchResultListItem
icon={<DocsIcon />}
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
);
break;
case 'tools':
resultItem = (
<ToolSearchResultListItem
icon={<BuildIcon />}
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
);
break;
default:
resultItem = (
<DefaultResultListItem
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
);
}
return (
<div
role="button"
tabIndex={0}
key={`${document.location}-btn`}
onClick={handleSearchResulClick}
onKeyDown={handleSearchResulClick}
>
{resultItem}
</div>
);
})}
</List>
)}
<SearchResult
onClick={handleSearchResultClick}
onKeyDown={handleSearchResultClick}
>
<CatalogSearchResultListItem icon={<CatalogIcon />} />
<TechDocsSearchResultListItem icon={<DocsIcon />} />
<ToolSearchResultListItem icon={<BuildIcon />} />
</SearchResult>
</Grid>
</Grid>
@@ -30,16 +30,15 @@ import {
} from '@backstage/plugin-catalog-react';
import { SearchType } from '@backstage/plugin-search';
import {
DefaultResultListItem,
SearchBar,
SearchFilter,
SearchResult,
SearchPagination,
SearchResult,
SearchResultPager,
useSearch,
} from '@backstage/plugin-search-react';
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
import { Grid, List, makeStyles, Paper, Theme } from '@material-ui/core';
import { Grid, makeStyles, Paper, Theme } from '@material-ui/core';
import React from 'react';
import { ToolSearchResultListItem } from '@backstage/plugin-explore';
import BuildIcon from '@material-ui/icons/Build';
@@ -133,53 +132,9 @@ const SearchPage = () => {
<Grid item xs>
<SearchPagination />
<SearchResult>
{({ results }) => (
<List>
{results.map(({ type, document, highlight, rank }) => {
switch (type) {
case 'software-catalog':
return (
<CatalogSearchResultListItem
icon={<CatalogIcon />}
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
);
case 'techdocs':
return (
<TechDocsSearchResultListItem
icon={<DocsIcon />}
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
);
case 'tools':
return (
<ToolSearchResultListItem
icon={<BuildIcon />}
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
);
default:
return (
<DefaultResultListItem
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
);
}
})}
</List>
)}
<CatalogSearchResultListItem icon={<CatalogIcon />} />
<TechDocsSearchResultListItem icon={<DocsIcon />} />
<ToolSearchResultListItem icon={<BuildIcon />} />
</SearchResult>
<SearchResultPager />
</Grid>
+16
View File
@@ -1,5 +1,21 @@
# @backstage/backend-app-api
## 0.3.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/backend-common@0.18.2-next.1
- @backstage/backend-plugin-api@0.3.2-next.1
- @backstage/backend-tasks@0.4.3-next.1
- @backstage/cli-common@0.1.11
- @backstage/config@1.0.6
- @backstage/config-loader@1.1.8
- @backstage/errors@1.1.4
- @backstage/types@1.0.2
- @backstage/plugin-auth-node@0.2.11-next.1
- @backstage/plugin-permission-node@0.7.5-next.1
## 0.3.2-next.0
### Patch Changes
+2 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-app-api",
"description": "Core API used by Backstage backend apps",
"version": "0.3.2-next.0",
"version": "0.3.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -64,6 +64,7 @@
"winston-transport": "^4.5.0"
},
"devDependencies": {
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"@types/compression": "^1.7.0",
"@types/fs-extra": "^9.0.3",
@@ -0,0 +1,68 @@
/*
* Copyright 2023 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 {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { startTestBackend } from '@backstage/backend-test-utils';
import { schedulerFactory } from './schedulerFactory';
describe('schedulerFactory', () => {
it('creates sidecar database features', async () => {
expect.assertions(3);
const subject = schedulerFactory();
const plugin = createBackendPlugin({
id: 'example',
register(reg) {
reg.registerInit({
deps: {
scheduler: subject.service,
database: coreServices.database,
},
init: async ({ scheduler, database }) => {
await scheduler.scheduleTask({
id: 'task1',
timeout: { seconds: 1 },
frequency: { seconds: 1 },
fn: async () => {},
});
const client = await database.getClient();
await expect(
client.from('backstage_backend_tasks__tasks').count(),
).resolves.toEqual([{ 'count(*)': 1 }]);
await expect(
client.from('backstage_backend_tasks__knex_migrations').count(),
).resolves.toEqual([{ 'count(*)': expect.any(Number) }]);
await expect(
client
.from('backstage_backend_tasks__knex_migrations_lock')
.count(),
).resolves.toEqual([{ 'count(*)': expect.any(Number) }]);
},
});
},
});
await startTestBackend({
features: [plugin()],
services: [subject],
});
});
});
+15
View File
@@ -1,5 +1,20 @@
# @backstage/backend-common
## 0.18.2-next.1
### Patch Changes
- 628e2bd89a: Updated dependency `@kubernetes/client-node` to `0.18.1`.
- Updated dependencies
- @backstage/backend-plugin-api@0.3.2-next.1
- @backstage/backend-app-api@0.3.2-next.1
- @backstage/cli-common@0.1.11
- @backstage/config@1.0.6
- @backstage/config-loader@1.1.8
- @backstage/errors@1.1.4
- @backstage/integration@1.4.2
- @backstage/types@1.0.2
## 0.18.2-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.18.2-next.0",
"version": "0.18.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+8
View File
@@ -1,5 +1,13 @@
# @backstage/backend-defaults
## 0.1.7-next.1
### Patch Changes
- Updated dependencies
- @backstage/backend-plugin-api@0.3.2-next.1
- @backstage/backend-app-api@0.3.2-next.1
## 0.1.7-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-defaults",
"description": "Backend defaults used by Backstage backend apps",
"version": "0.1.7-next.0",
"version": "0.1.7-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+10
View File
@@ -1,5 +1,15 @@
# example-backend-next
## 0.0.8-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog-backend@1.7.2-next.1
- @backstage/plugin-scaffolder-backend@1.11.0-next.1
- @backstage/backend-defaults@0.1.7-next.1
- @backstage/plugin-app-backend@0.3.42-next.1
## 0.0.8-next.0
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend-next",
"version": "0.0.8-next.0",
"version": "0.0.8-next.1",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
+17
View File
@@ -1,5 +1,22 @@
# @backstage/backend-plugin-api
## 0.3.2-next.1
### Patch Changes
- ae88f61e00: The `register` methods passed to `createBackendPlugin` and `createBackendModule`
now have dedicated `BackendPluginRegistrationPoints` and
`BackendModuleRegistrationPoints` arguments, respectively. This lets us make it
clear on a type level that it's not possible to pass in extension points as
dependencies to plugins (should only ever be done for modules). This has no
practical effect on code that was already well behaved.
- Updated dependencies
- @backstage/backend-tasks@0.4.3-next.1
- @backstage/config@1.0.6
- @backstage/types@1.0.2
- @backstage/plugin-auth-node@0.2.11-next.1
- @backstage/plugin-permission-common@0.7.3
## 0.3.2-next.0
### Patch Changes
+45 -16
View File
@@ -22,27 +22,57 @@ export interface BackendFeature {
register(reg: BackendRegistrationPoints): void;
}
// @public (undocumented)
// @public
export interface BackendModuleConfig {
// (undocumented)
moduleId: string;
// (undocumented)
pluginId: string;
// (undocumented)
register(
reg: Omit<BackendRegistrationPoints, 'registerExtensionPoint'>,
): void;
register(reg: BackendModuleRegistrationPoints): void;
}
// @public (undocumented)
export interface BackendPluginConfig {
// @public
export interface BackendModuleRegistrationPoints {
// (undocumented)
registerInit<
Deps extends {
[name in string]: unknown;
},
>(options: {
deps: {
[name in keyof Deps]: ServiceRef<Deps[name]> | ExtensionPoint<Deps[name]>;
};
init(deps: Deps): Promise<void>;
}): void;
}
// @public
export interface BackendPluginConfig {
id: string;
// (undocumented)
register(reg: BackendRegistrationPoints): void;
register(reg: BackendPluginRegistrationPoints): void;
}
// @public (undocumented)
// @public
export interface BackendPluginRegistrationPoints {
// (undocumented)
registerExtensionPoint<TExtensionPoint>(
ref: ExtensionPoint<TExtensionPoint>,
impl: TExtensionPoint,
): void;
// (undocumented)
registerInit<
Deps extends {
[name in string]: unknown;
},
>(options: {
deps: {
[name in keyof Deps]: ServiceRef<Deps[name]>;
};
init(deps: Deps): Promise<void>;
}): void;
}
// @public
export interface BackendRegistrationPoints {
// (undocumented)
registerExtensionPoint<TExtensionPoint>(
@@ -116,12 +146,12 @@ export function createBackendModule<TOptions extends [options?: object] = []>(
config: BackendModuleConfig | ((...params: TOptions) => BackendModuleConfig),
): (...params: TOptions) => BackendFeature;
// @public (undocumented)
// @public
export function createBackendPlugin<TOptions extends [options?: object] = []>(
config: BackendPluginConfig | ((...params: TOptions) => BackendPluginConfig),
): (...params: TOptions) => BackendFeature;
// @public (undocumented)
// @public
export function createExtensionPoint<T>(
config: ExtensionPointConfig,
): ExtensionPoint<T>;
@@ -248,9 +278,8 @@ export type ExtensionPoint<T> = {
$$ref: 'extension-point';
};
// @public (undocumented)
// @public
export interface ExtensionPointConfig {
// (undocumented)
id: string;
}
@@ -476,13 +505,13 @@ export interface ServiceRefConfig<TService, TScope extends 'root' | 'plugin'> {
scope?: TScope;
}
// @public (undocumented)
// @public
export interface SharedBackendEnvironment {
// (undocumented)
$$type: 'SharedBackendEnvironment';
}
// @public (undocumented)
// @public
export interface SharedBackendEnvironmentConfig {
// (undocumented)
services?: ServiceFactoryOrFunction[];
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-plugin-api",
"description": "Core API used by Backstage backend plugins",
"version": "0.3.2-next.0",
"version": "0.3.2-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -16,35 +16,47 @@
import { ServiceFactory, ServiceFactoryOrFunction } from '../services';
/** @public */
/**
* The configuration options passed to {@link createSharedEnvironment}.
*
* @public
*/
export interface SharedBackendEnvironmentConfig {
services?: ServiceFactoryOrFunction[];
}
// This type is opaque in order to allow for future API evolution without
// cluttering the external API. For example we might want to add support
// for more powerful callback based backend modifications.
//
// By making this opaque we also ensure that the type doesn't become an input
// type that we need to care about, as it would otherwise be possible to pass
// a custom environment definition to `createBackend`, which we don't want.
/**
* An opaque type that represents the contents of a shared backend environment.
*
* @public
*/
export interface SharedBackendEnvironment {
$$type: 'SharedBackendEnvironment';
// NOTE: This type is opaque in order to allow for future API evolution without
// cluttering the external API. For example we might want to add support
// for more powerful callback based backend modifications.
//
// By making this opaque we also ensure that the type doesn't become an input
// type that we need to care about, as it would otherwise be possible to pass
// a custom environment definition to `createBackend`, which we don't want.
}
/**
* This type is NOT supposed to be used by anyone except internally by the backend-app-api package.
* @internal */
* This type is NOT supposed to be used by anyone except internally by the
* backend-app-api package.
*
* @internal
*/
export interface InternalSharedBackendEnvironment {
version: 'v1';
services?: ServiceFactory[];
}
/**
* Creates a shared backend environment which can be used to create multiple backends
* Creates a shared backend environment which can be used to create multiple
* backends.
*
* @public
*/
export function createSharedEnvironment<
@@ -15,17 +15,35 @@
*/
import {
BackendModuleRegistrationPoints,
BackendPluginRegistrationPoints,
BackendRegistrationPoints,
BackendFeature,
ExtensionPoint,
} from './types';
/** @public */
/**
* The configuration options passed to {@link createExtensionPoint}.
*
* @public
* @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points}
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
*/
export interface ExtensionPointConfig {
/**
* The ID of this extension point.
*
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
*/
id: string;
}
/** @public */
/**
* Creates a new backend extension point.
*
* @public
* @see {@link https://backstage.io/docs/backend-system/architecture/extension-points | The architecture of extension points}
*/
export function createExtensionPoint<T>(
config: ExtensionPointConfig,
): ExtensionPoint<T> {
@@ -41,13 +59,30 @@ export function createExtensionPoint<T>(
};
}
/** @public */
/**
* The configuration options passed to {@link createBackendPlugin}.
*
* @public
* @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins}
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
*/
export interface BackendPluginConfig {
/**
* The ID of this plugin.
*
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
*/
id: string;
register(reg: BackendRegistrationPoints): void;
register(reg: BackendPluginRegistrationPoints): void;
}
/** @public */
/**
* Creates a new backend plugin.
*
* @public
* @see {@link https://backstage.io/docs/backend-system/architecture/plugins | The architecture of plugins}
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
*/
export function createBackendPlugin<TOptions extends [options?: object] = []>(
config: BackendPluginConfig | ((...params: TOptions) => BackendPluginConfig),
): (...params: TOptions) => BackendFeature {
@@ -58,28 +93,33 @@ export function createBackendPlugin<TOptions extends [options?: object] = []>(
return () => config;
}
/** @public */
/**
* The configuration options passed to {@link createBackendModule}.
*
* @public
* @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules}
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
*/
export interface BackendModuleConfig {
/**
* The ID of this plugin.
*
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
*/
pluginId: string;
/**
* Should exactly match the `id` of the plugin that the module extends.
*/
moduleId: string;
register(
reg: Omit<BackendRegistrationPoints, 'registerExtensionPoint'>,
): void;
register(reg: BackendModuleRegistrationPoints): void;
}
/**
* Creates a new backend module for a given plugin.
*
* @public
*
* @remarks
*
* The `moduleId` should be equal to the module-specific suffix of the exported name, such
* that the full name is `pluginId + "Module" + ModuleId`. For example, a GitHub entity
* provider module for the `catalog` plugin might have the module ID `'githubEntityProvider'`,
* and the full exported name would be `catalogModuleGithubEntityProvider`.
*
* The `pluginId` should exactly match the `id` of the plugin that the module extends.
* @see {@link https://backstage.io/docs/backend-system/architecture/modules | The architecture of modules}
* @see {@link https://backstage.io/docs/backend-system/architecture/naming-patterns | Recommended naming patterns}
*/
export function createBackendModule<TOptions extends [options?: object] = []>(
config: BackendModuleConfig | ((...params: TOptions) => BackendModuleConfig),
@@ -96,8 +136,9 @@ export function createBackendModule<TOptions extends [options?: object] = []>(
return () => ({
id: `${config.pluginId}.${config.moduleId}`,
register(register: BackendRegistrationPoints) {
// TODO: Hide registerExtensionPoint
return config.register(register);
return config.register({
registerInit: register.registerInit.bind(register),
});
},
});
}
@@ -30,6 +30,8 @@ export {
createExtensionPoint,
} from './factories';
export type {
BackendModuleRegistrationPoints,
BackendPluginRegistrationPoints,
BackendRegistrationPoints,
BackendFeature,
ExtensionPoint,
@@ -35,7 +35,13 @@ export type ExtensionPoint<T> = {
$$ref: 'extension-point';
};
/** @public */
/**
* The callbacks passed to the `register` method of a backend feature; this is
* essentially a superset of {@link BackendPluginRegistrationPoints} and
* {@link BackendModuleRegistrationPoints}.
*
* @public
*/
export interface BackendRegistrationPoints {
registerExtensionPoint<TExtensionPoint>(
ref: ExtensionPoint<TExtensionPoint>,
@@ -49,6 +55,38 @@ export interface BackendRegistrationPoints {
}): void;
}
/**
* The callbacks passed to the `register` method of a backend plugin.
*
* @public
*/
export interface BackendPluginRegistrationPoints {
registerExtensionPoint<TExtensionPoint>(
ref: ExtensionPoint<TExtensionPoint>,
impl: TExtensionPoint,
): void;
registerInit<Deps extends { [name in string]: unknown }>(options: {
deps: {
[name in keyof Deps]: ServiceRef<Deps[name]>;
};
init(deps: Deps): Promise<void>;
}): void;
}
/**
* The callbacks passed to the `register` method of a backend module.
*
* @public
*/
export interface BackendModuleRegistrationPoints {
registerInit<Deps extends { [name in string]: unknown }>(options: {
deps: {
[name in keyof Deps]: ServiceRef<Deps[name]> | ExtensionPoint<Deps[name]>;
};
init(deps: Deps): Promise<void>;
}): void;
}
/** @public */
export interface BackendFeature {
// TODO(Rugvip): Try to get rid of the ID at this level, allowing for a feature to register multiple features as a bundle
+10
View File
@@ -1,5 +1,15 @@
# @backstage/backend-tasks
## 0.4.3-next.1
### Patch Changes
- Updated dependencies
- @backstage/backend-common@0.18.2-next.1
- @backstage/config@1.0.6
- @backstage/errors@1.1.4
- @backstage/types@1.0.2
## 0.4.3-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-tasks",
"description": "Common distributed task management library for Backstage backends",
"version": "0.4.3-next.0",
"version": "0.4.3-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+13
View File
@@ -1,5 +1,18 @@
# @backstage/backend-test-utils
## 0.1.34-next.1
### Patch Changes
- Updated dependencies
- @backstage/cli@0.22.2-next.0
- @backstage/backend-common@0.18.2-next.1
- @backstage/backend-plugin-api@0.3.2-next.1
- @backstage/backend-app-api@0.3.2-next.1
- @backstage/config@1.0.6
- @backstage/types@1.0.2
- @backstage/plugin-auth-node@0.2.11-next.1
## 0.1.34-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-test-utils",
"description": "Test helpers library for Backstage backends",
"version": "0.1.34-next.0",
"version": "0.1.34-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+48
View File
@@ -1,5 +1,53 @@
# example-backend
## 0.2.80-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog-backend@1.7.2-next.1
- @backstage/plugin-tech-insights-backend@0.5.8-next.1
- @backstage/plugin-tech-insights-node@0.4.0-next.1
- @backstage/plugin-azure-devops-backend@0.3.21-next.1
- @backstage/backend-common@0.18.2-next.1
- @backstage/plugin-kubernetes-backend@0.9.3-next.1
- @backstage/plugin-scaffolder-backend@1.11.0-next.1
- @backstage/plugin-playlist-backend@0.2.5-next.1
- example-app@0.2.80-next.1
- @backstage/backend-tasks@0.4.3-next.1
- @backstage/catalog-client@1.3.1-next.0
- @backstage/catalog-model@1.1.6-next.0
- @backstage/config@1.0.6
- @backstage/integration@1.4.2
- @backstage/plugin-adr-backend@0.2.7-next.1
- @backstage/plugin-app-backend@0.3.42-next.1
- @backstage/plugin-auth-backend@0.17.5-next.1
- @backstage/plugin-auth-node@0.2.11-next.1
- @backstage/plugin-azure-sites-backend@0.1.4-next.1
- @backstage/plugin-badges-backend@0.1.36-next.1
- @backstage/plugin-catalog-node@1.3.3-next.1
- @backstage/plugin-code-coverage-backend@0.2.8-next.1
- @backstage/plugin-events-backend@0.2.3-next.1
- @backstage/plugin-events-node@0.2.3-next.1
- @backstage/plugin-explore-backend@0.0.4-next.1
- @backstage/plugin-graphql-backend@0.1.32-next.1
- @backstage/plugin-jenkins-backend@0.1.32-next.1
- @backstage/plugin-kafka-backend@0.2.35-next.1
- @backstage/plugin-permission-backend@0.5.17-next.1
- @backstage/plugin-permission-common@0.7.3
- @backstage/plugin-permission-node@0.7.5-next.1
- @backstage/plugin-proxy-backend@0.2.36-next.1
- @backstage/plugin-rollbar-backend@0.1.39-next.1
- @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.1
- @backstage/plugin-search-backend@1.2.3-next.1
- @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.1
- @backstage/plugin-search-backend-module-pg@0.5.3-next.1
- @backstage/plugin-search-backend-node@1.1.3-next.1
- @backstage/plugin-search-common@1.2.1
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.1
- @backstage/plugin-techdocs-backend@1.5.3-next.1
- @backstage/plugin-todo-backend@0.1.39-next.1
## 0.2.80-next.0
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend",
"version": "0.2.80-next.0",
"version": "0.2.80-next.1",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -2,8 +2,11 @@ apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: petstore
# This is an extra long description
description: The Petstore is an example API used to show features of the OpenAPI spec.
# This is an extra long description with Markdown
description: |
[The Petstore](http://petstore.example.com) is an example API used to show features of the OpenAPI spec.
- First item
- Second item
links:
- url: https://github.com/swagger-api/swagger-petstore
title: GitHub Repo
+16
View File
@@ -1,5 +1,21 @@
# @backstage/cli
## 0.22.2-next.0
### Patch Changes
- 561df21ea3: The `backstage-cli repo test` command now sets a default Jest `--workerIdleMemoryLimit` of 1GB. If needed to ensure that tests are not run in band, `--maxWorkers=2` is set as well. This is the recommended workaround for dealing with Jest workers leaking memory and eventually hitting the heap limit.
- 2815981057: Show module name causing error during build
- 66cf22fdc4: Updated dependency `esbuild` to `^0.17.0`.
- 6d3abfded1: Switch to inline source maps for test transpilation, simplifying editor setups.
- Updated dependencies
- @backstage/cli-common@0.1.11
- @backstage/config@1.0.6
- @backstage/config-loader@1.1.8
- @backstage/errors@1.1.4
- @backstage/release-manifests@0.0.8
- @backstage/types@1.0.2
## 0.22.1
### Patch Changes
-5
View File
@@ -22,7 +22,6 @@ const { version } = require('../package.json');
const envOptions = {
oldTests: Boolean(process.env.BACKSTAGE_OLD_TESTS),
enableSourceMaps: Boolean(process.env.ENABLE_SOURCE_MAPS),
};
const transformIgnorePattern = [
@@ -130,7 +129,6 @@ async function getProjectConfig(targetPath, extraConfig) {
'\\.(mjs|cjs|js)$': [
require.resolve('./jestSwcTransform'),
{
sourceMaps: envOptions.enableSourceMaps || !envOptions.oldTests,
jsc: {
parser: {
syntax: 'ecmascript',
@@ -141,7 +139,6 @@ async function getProjectConfig(targetPath, extraConfig) {
'\\.jsx$': [
require.resolve('./jestSwcTransform'),
{
sourceMaps: envOptions.enableSourceMaps || !envOptions.oldTests,
jsc: {
parser: {
syntax: 'ecmascript',
@@ -158,7 +155,6 @@ async function getProjectConfig(targetPath, extraConfig) {
'\\.ts$': [
require.resolve('./jestSwcTransform'),
{
sourceMaps: envOptions.enableSourceMaps || !envOptions.oldTests,
jsc: {
parser: {
syntax: 'typescript',
@@ -169,7 +165,6 @@ async function getProjectConfig(targetPath, extraConfig) {
'\\.tsx$': [
require.resolve('./jestSwcTransform'),
{
sourceMaps: envOptions.enableSourceMaps || !envOptions.oldTests,
jsc: {
parser: {
syntax: 'typescript',

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