Merge branch 'master' of github.com:backstage/backstage into scaffolder-examples

This commit is contained in:
Brian Fletcher
2023-01-03 21:13:31 +00:00
551 changed files with 12995 additions and 2447 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': patch
---
Added `RootLifecycleService` and `rootLifecycleServiceRef`, as well as added a `labels` option to the existing `LifecycleServiceShutdownHook`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Removed unnecessary usage of `ThemeProvider` from the `ExampleComponent` test in the plugin template.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-bazaar': patch
---
Created soft cut on `ProjectCard` to indicate more content.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-test-utils': patch
'@backstage/backend-defaults': patch
---
Include implementations for the new `rootLifecycleServiceRef`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': minor
---
Allow custom repository roles to be configured on github repos
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-bazaar': patch
---
Added `isBazaarAvailable` helper to be used with the `EntitySwitch`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Bumped create-app version.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/repo-tools': patch
---
Use the project tsconfig in case of selection all packages
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-graph': patch
---
The link from the `CatalogGraphCard` to the `CatalogGraphPage` no longer includes an explicit `maxDepth` parameter, letting the `CatalogGraphPage` choose the initial `maxDepth` instead.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/backend-common': minor
---
**BREAKING**: Removed deprecated `read` method from the `UrlReader` interface. All implementations should use the `readUrl` method instead.
Migrated `UrlReader` and related types to `backend/backend-plugin-api`, types remain re-exported from `backend-common` for now.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Add experimental environment variable to enable caching for production builds.
+10
View File
@@ -0,0 +1,10 @@
---
'@backstage/plugin-catalog-backend-module-github': patch
---
Added support for event based updates in the `GithubOrgEntityProvider`!
Based on webhook events from GitHub the affected `User` or `Group` entity will be refreshed.
This includes adding new entities, refreshing existing ones, and removing obsolete ones.
Please find more information at
https://backstage.io/docs/integrations/github/org#installation-with-events-support
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': patch
---
Migrate `UrlReader` into this package to gradually remove the dependency on backend-common.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-explore-backend': patch
'@backstage/plugin-explore': patch
---
Updated `README.md` examples
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/repo-tools': patch
---
fix glob on windows os
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
Fix sizing of build log component to render all lines
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-events-backend': patch
---
The default event broker will now catch and log errors thrown by the `onEvent` method of subscribers. The returned promise from `publish` method will also not resolve until all subscribers have handled the event.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-plugin-api': patch
'@backstage/backend-common': patch
---
Moved `PluginEndpointDiscovery` type from backend-common to backend-plugin-api.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-app-backend': patch
---
The warning for missing app contents is now logged as an error instead, but only in production.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cost-insights': patch
---
Removed @backstage/test-utils dependency, since it was already in the devDependencies where it belongs. The main benefit is that this will exclude better-sqlite3 from the production build.
+1 -1
View File
@@ -1,5 +1,5 @@
---
'@backstage/plugin-stack-overflow-backend': minor
'@backstage/plugin-stack-overflow-backend': patch
---
Enable configuration override for StackOverflow backend plugin when instantiating the search indexer. This makes it possible to set different configuration for frontend and backend of the plugin.
+54 -1
View File
@@ -194,5 +194,58 @@
"@backstage/plugin-vault-backend": "0.2.5",
"@backstage/plugin-xcmetrics": "0.2.32"
},
"changesets": []
"changesets": [
"beige-rats-cheer",
"blue-carrots-cross",
"bright-pants-cry",
"clever-starfishes-destroy",
"clever-years-hang",
"cool-islands-laugh",
"cool-kings-raise",
"create-app-1672154523",
"curvy-ducks-explode",
"eight-dragons-accept",
"eleven-trains-double",
"famous-experts-sneeze",
"fifty-paws-attack",
"fifty-zoos-nail",
"fluffy-fans-sing",
"fluffy-forks-happen",
"forty-years-retire",
"funny-pianos-grow",
"good-foxes-fail",
"good-geckos-reflect",
"hungry-falcons-cross",
"khaki-baboons-impress",
"late-forks-rescue",
"light-rice-end",
"lucky-apricots-dress",
"metal-hotels-deliver",
"nasty-planets-end",
"nervous-ravens-cough",
"ninety-phones-tell",
"odd-kings-tell",
"old-planets-care",
"olive-eyes-sing",
"proud-birds-worry",
"renovate-3493165",
"renovate-968149a",
"rude-chicken-itch",
"search-break-loop",
"search-mele-kalikimaka",
"search-pressure-back",
"selfish-phones-smoke",
"silver-chicken-travel",
"spicy-lions-dream",
"strong-eyes-march",
"sweet-tomatoes-cheer",
"tasty-impalas-cross",
"tasty-impalas-mix",
"thick-stingrays-smile",
"tidy-flies-cheer",
"tricky-toys-teach",
"twenty-nails-camp",
"two-buckets-do",
"witty-eels-itch"
]
}
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-insights-backend': patch
---
Complete check results run when a single check errors so that we don't block other checks from working due to an error in a single check
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-techdocs-react': patch
'@backstage/plugin-techdocs': patch
---
Updated dependency `jss` to `~10.9.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': patch
---
Documented `coreServices` an all of its members.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-openapi': patch
---
Updated internal usage of UrlReader interface.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': minor
---
Add Github repository support for squash merge commit title and message options
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Avoid potential temporary directory conflict.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/config': patch
---
Adds the ability to coerce values to their boolean representatives.
Values such as `"true"` `1` `on` and `y` will become `true` when using `getBoolean` and the opposites `false`.
This happens particularly when such parameters are used with environmental substitution as environment variables are always strings.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/create-app': patch
---
Remove deprecated `create-plugin` script from the `default-app` template's `package.json.hbs`.
Also, update the documentation to not mention the `create-plugin` script and instead mention
the `new` script.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-app-api': patch
---
Updated implementations for the new `RootLifecycleService`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search-backend': patch
---
Allow max page limit for search results to be configurable
+1
View File
@@ -82,6 +82,7 @@ dependabot
deps
destructured
destructuring
Deutsche
dev
devops
devs
-131
View File
@@ -1,131 +0,0 @@
name: E2E Test Tugboat
on: deployment_status
jobs:
set-pending:
if: github.event.deployment_status.state != 'success' && github.event.deployment_status.state != 'failed'
name: Set pending waiting for Tugboat
runs-on: ubuntu-latest
steps:
# Set an initial commit status message to indicate that the tests are
# running.
- name: set pending status
uses: actions/github-script@v6
with:
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
debug: true
script: |
return github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: 'pending',
context: 'Backstage Tugboat E2E Tests',
description: 'Waiting for Tugboat to complete deployment',
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
});
run-tests:
# Only run after a successful Tugboat deployment.
if: github.event.deployment_status.state == 'success'
name: Run tests against Tugboat deployment
runs-on: ubuntu-latest
steps:
# Set an initial commit status message to indicate that the tests are
# running.
- name: set pending status
uses: actions/github-script@v6
with:
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
debug: true
script: |
return github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: 'pending',
context: 'Backstage Tugboat E2E Tests',
description: 'Running against tugboat preview',
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
});
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16.x'
- name: yarn install
run: yarn --cwd cypress install
# This is required because the environment_url param that Tugboat uses
# to tell us where the preview is located isn't supported unless you
# specify the custom Accept header when getting the deployment_status,
# and GitHub actions doesn't do that by default. So instead we have to
# load the status object manually and get the data we need.
# https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/
- name: get deployment status
id: get-status-env
uses: actions/github-script@v6
with:
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
result-encoding: string
script: |
const result = await github.rest.repos.getDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: context.payload.deployment.id,
status_id: context.payload.deployment_status.id,
headers: {
'Accept': 'application/vnd.github.ant-man-preview+json'
},
});
console.log(result);
return result.data.environment_url;
- name: cypress run
uses: cypress-io/github-action@v2
env:
CYPRESS_baseUrl: ${{steps.get-status-env.outputs.result}}
with:
config-file: ./cypress.json
working-directory: ./cypress
browser: chrome
install: false
headless: true
- name: update artifact
if: ${{ always() }}
uses: actions/upload-artifact@v3
with:
name: cypress-videos
path: ./cypress/cypress/videos
- name: set status
if: ${{ failure() }}
uses: actions/github-script@v6
with:
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
script: |
return github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: "error",
context: 'Backstage Tugboat E2E Tests',
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
});
- name: set status
if: ${{ success() }}
uses: actions/github-script@v6
with:
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
script: |
return github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: "success",
context: 'Backstage Tugboat E2E Tests',
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
});
-17
View File
@@ -1,17 +0,0 @@
services:
backstage:
image: tugboatqa/node:lts
expose: 7007
default: true
commands:
init:
- mkdir -p /etc/service/node
- echo "#!/bin/sh" > /etc/service/node/run
- echo "yarn --cwd ${TUGBOAT_ROOT} start-backend --config ${TUGBOAT_ROOT}/app-config.yaml --config ${TUGBOAT_ROOT}/.tugboat/tugboat.app-config.production.yaml" >> /etc/service/node/run
- chmod +x /etc/service/node/run
build:
- yarn install --immutable
- yarn workspace example-app build
start:
# wget the endpoint. Will retry every 2 seconds. 30 retries = 1m for service to come up. Plenty.
- wget -O /dev/null -o /dev/null --tries=30 --timeout=5 --retry-connrefused http://localhost:7007
@@ -1,10 +0,0 @@
app:
title: Backstage Tugboat Preview
baseUrl: ${TUGBOAT_DEFAULT_SERVICE_URL}
backend:
baseUrl: ${TUGBOAT_DEFAULT_SERVICE_URL}
cors:
origin: ${TUGBOAT_DEFAULT_SERVICE_URL}
methods: [GET, POST, PUT, DELETE]
credentials: true
+1
View File
@@ -224,3 +224,4 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
| [FanDuel](https://fanduel.com) | [Diego Herrera](https://github.com/diegoh), [Christy Campbell](https://github.com/FD-ChristopherCampbell) | We use backstage as our developer portal to provide visibility of our software, ownership, strategy, and the state of maturity across disciplines. |
| [Operate First](https://www.operate-first.cloud/) | [Tom Coufal](https://github.com/tumido), [Sam Kopecky](https://github.com/samokopecky) | Backstage provides us with a public service catalog and serves as a gateway to our community cloud. Our instance is publicly available to everyone [here](https://service-catalog.operate-first.cloud/) ([source](https://github.com/operate-first/service-catalog)) |
| [Tractable AI](https://tractable.ai/) | [Stephan Schielke](https://github.com/stephanschielke) | We are hitting a critical point in our scale (100+ engineers) and need to get a handle on discoverability and ownership. The Service Catalog, TechDocs and Search are essential to us to achieve that. |
| [Garanti BBVA Teknoloji](https://www.linkedin.com/company/garanti-teknoloji/) | [Caglar Cataloglu](https://github.com/crozwise) | We are using Backstage focusing on improving experience of developers, minimizing friction from idea to production. We call our portal as "Hyperspace" and very excited for our community (2000+ engineers) that finally we have a platform to boost our productivity!
-4
View File
@@ -2,10 +2,6 @@
Hey 👋 Welcome to the Cypress tests for Backstage. They're designed to be run against the `packages/app` folder in the main repo, and be some form of smoke tests to make sure that we don't break any core functionality.
They run part of the PR build, and are triggered from the `.github/workflows/tugboat.yml` file.
The main app gets built up part of a [Tugboat Build](https://tugboat.qa), which when complete, sends a `deployment event` to the PR triggering the aforementioned workflow.
### Running Locally
In order to make typescript happy, this `cypress` package is separate from all the Jest dependencies in the monorepo workspaces setup.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 263 KiB

+1 -1
View File
@@ -17,7 +17,7 @@ into multiple different services, each running a different set of plugins. This
is a more advanced approach and requires you to be able to route requests to
the appropriate backends based on the plugin ID. Both for ingress, but also
internal traffic between Backstage backends, which is done by creating a custom
implementation of the [PluginEndpointDiscover](../reference/backend-common.pluginendpointdiscovery.md) interface.
implementation of the [DiscoveryService](../reference/backend-plugin-api.discoveryservice.md) interface.
Lastly, you can also replicate the Backstage deployments across multiple regions.
This is not a pattern that there is built-in support for and typically only makes
@@ -111,10 +111,10 @@ export class FrobsProvider implements EntityProvider {
throw new Error('Not initialized');
}
const raw = await this.reader.read(
const response = await this.reader.readUrl(
`https://frobs-${this.env}.example.com/data`,
);
const data = JSON.parse(raw.toString());
const data = JSON.parse(await response.buffer()).toString();
/** [5] **/
const entities: Entity[] = frobsToEntities(data);
@@ -525,8 +525,8 @@ export class SystemXReaderProcessor implements CatalogProcessor {
// API. If you prefer, you can just use plain fetch here
// (from the node-fetch package), or any other method of
// your choosing.
const data = await this.reader.read(location.target);
const json = JSON.parse(data.toString());
const response = await this.reader.readUrl(location.target);
const json = JSON.parse((await response.buffer()).toString());
// Repeatedly call emit(processingResult.entity(location, <entity>))
} catch (error) {
const message = `Unable to read ${location.type}, ${error}`;
@@ -627,7 +627,7 @@ export class SystemXReaderProcessor implements CatalogProcessor {
// We send the ETag from the previous run if it exists.
// The previous ETag will be set in the headers for the outgoing request and system-x
// is going to throw NOT_MODIFIED (HTTP 304) if the ETag matches.
const response = await this.reader.readUrl?.(location.target, {
const response = await this.reader.readUrl(location.target, {
etag: cacheItem?.etag,
});
if (!response) {
+1 -1
View File
@@ -116,7 +116,7 @@ yarn clean # Remove all output folders and @backstage/cli cache
yarn diff # Make sure all plugins are up to date with the latest plugin template
yarn create-plugin # Create a new plugin
yarn new # Create a new module
```
> See
+1 -1
View File
@@ -49,7 +49,7 @@ installation. Running the command below will install Backstage. The wizard will
create a subdirectory inside your current working directory.
```bash
npx @backstage/create-app
npx @backstage/create-app@latest
```
The wizard will ask you for the name of the app, which will also be the name of the directory
+1 -1
View File
@@ -101,7 +101,7 @@ are separated out into their own folder, see further down.
- [`cli/`](https://github.com/backstage/backstage/tree/master/packages/cli) -
One of the biggest packages in our project, the `cli` is used to build, serve,
diff, create-plugins and more. In the early days of this project, we started
diff, create plugins and more. In the early days of this project, we started
out with calling tools directly - such as `eslint` - through `package.json`.
But as it was tricky to have a good development experience around that when we
change named tooling, we opted for wrapping those in our own CLI. That way
+47 -1
View File
@@ -17,7 +17,7 @@ entities that mirror your org setup.
> provide authentication. See the
> [GitHub auth provider](../../auth/github/provider.md) for that.
## Installation
## Installation without Events Support
This guide will use the Entity Provider method. If you for some reason prefer
the Processor method (not recommended), it is described separately below.
@@ -60,6 +60,52 @@ schedule it:
+ );
```
## Installation with Events Support
Please follow the installation instructions at
- https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md
- https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github/README.md
Additionally, you need to decide how you want to receive events from external sources like
- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md)
- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md)
Set up your provider
```diff
// packages/backend/src/plugins/catalogEventBasedProviders.ts
+import { GithubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github';
import { EntityProvider } from '@backstage/plugin-catalog-node';
import { EventSubscriber } from '@backstage/plugin-events-node';
import { PluginEnvironment } from '../types';
export default async function createCatalogEventBasedProviders(
- _: PluginEnvironment,
+ env: PluginEnvironment,
): Promise<Array<EntityProvider & EventSubscriber>> {
const providers: Array<
(EntityProvider & EventSubscriber) | Array<EntityProvider & EventSubscriber>
> = [];
- // add your event-based entity providers here
+ providers.push(
+ GithubOrgEntityProvider.fromConfig(env.config, {
+ id: 'production',
+ orgUrl: 'https://github.com/backstage',
+ logger: env.logger,
+ schedule: env.scheduler.createScheduledTaskRunner({
+ frequency: { minutes: 60 },
+ timeout: { minutes: 15 },
+ }),
+ }),
+ );
return providers.flat();
}
```
You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks).
The webhook will need to be configured to forward `organization`,`team` and `membership` events.
## Configuration
As mentioned above, you also must have some configuration in your app-config
+4 -4
View File
@@ -201,15 +201,15 @@ Usage: backstage-cli package postpack [options]
Restores the changes made by the prepack command
```
## create
## new
The `create` command opens up an interactive guide for you to create new things
The `new` command opens up an interactive guide for you to create new things
in your app. If you do not pass in any options it is completely interactive, but
it is possible to pre-select what you want to create using the `--select` flag,
and provide options using `--options`, for example:
and provide options using `--option`, for example:
```bash
backstage-cli create --select plugin --option id=foo
backstage-cli new --select plugin --option id=foo
```
This command is typically added as script in the root `package.json` to be
+2 -3
View File
@@ -116,9 +116,8 @@ For packages at version `1.0.0` or above, the following policy also applies:
before it can be removed.
- The release of breaking changes document a clear upgrade path in the
changelog, both when deprecations are introduced and when they are removed.
- Exports that have been marked as `@alpha` or `@beta` may receive breaking
changes without a deprecation period, but the changes must still adhere to
semver.
- Breaking changes to `@alpha` or `@beta` exports must result in at least a minor
version bump, and may be done without a deprecation period.
### Changes that are Not Considered Breaking
+1 -1
View File
@@ -28,7 +28,7 @@ lowercase characters separated by dashes, for example `carmen`, if it's a
package that adds an integration with a system named Carmen, for example. The
full NPM package name would then be something like
`@internal/plugin-carmen-backend`, depending on the other flags passed to the
`create-plugin` command, and your settings for the `create-plugin` command in
`new` command, and your settings for the `new` command in
your root `package.json`.
Creating the plugin will take a little while, so be patient. It will helpfully
+1 -1
View File
@@ -11,7 +11,7 @@ A Backstage Plugin adds functionality to Backstage.
To create a new plugin, make sure you've run `yarn install` and installed
dependencies, then run the following on your command line (a shortcut to
invoking the
[`backstage-cli create-plugin`](../local-dev/cli-commands.md#create-plugin))
[`backstage-cli new --select plugin`](../local-dev/cli-commands.md#new))
from the root of your project.
```bash
@@ -21,7 +21,7 @@ should have a separate package in a folder, which represents your plugin.
Example:
```
$ yarn create-plugin
$ yarn new --select plugin
> ? Enter an ID for the plugin [required] my-plugin
> ? Enter the owner(s) of the plugin. If specified, this will be added to CODEOWNERS for the plugin path. [optional]
+7 -25
View File
@@ -60,15 +60,7 @@ The generic interface of a URL Reader instance looks like this.
```ts
export type UrlReader = {
/* Used to read a single file and return its content. */
read(url: string): Promise<Buffer>;
/**
* A replacement for the read method that supports options and complex responses.
*
* Use this whenever it is available, as the read method will be deprecated and
* eventually removed in the future.
*/
readUrl?(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
/* Used to read a file tree and download as a directory. */
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
/* Used to search a file in a tree. */
@@ -102,8 +94,8 @@ backend plugins.
Once the reader instance is available inside the plugin, one of its methods can
directly be used with a URL. Some example usages -
- [`read`](https://github.com/backstage/backstage/blob/d5c83bb889b8142e343ebc4e4c0b90a02d1c1a3d/plugins/catalog-backend/src/ingestion/processors/codeowners/read.ts#L24-L33) -
Catalog using the `read` method to read the CODEOWNERS file in a repository.
- [`readUrl`](https://github.com/backstage/backstage/blob/a7607b5/plugins/catalog-backend/src/modules/codeowners/lib/read.ts#L24-L33) -
Catalog using the `readUrl` method to read the CODEOWNERS file in a repository.
- [`readTree`](https://github.com/backstage/backstage/blob/84a8788/plugins/techdocs-node/src/helpers.ts#L146-L167) -
TechDocs using the `readTree` method to download markdown files in order to
generate the documentation site.
@@ -155,11 +147,9 @@ all the methods of the `UrlReader` interface should be implemented. However it
is okay to start by implementing just one of them and create issues for the
remaining.
#### read
#### `readUrl`
NOTE: Use `readUrl` instead of `read`.
`read` method expects a user-friendly URL, something which can be copied from
`readUrl` method expects a user-friendly URL, something which can be copied from
the browser naturally when a person is browsing the provider in their browser.
- ✅ Valid URL :
@@ -168,18 +158,10 @@ the browser naturally when a person is browsing the provider in their browser.
`https://raw.githubusercontent.com/backstage/backstage/master/ADOPTERS.md`
- ❌ Not a valid URL : `https://github.com/backstage/backstage/ADOPTERS.md`
Upon receiving the URL, `read` converts the user-friendly URL into an API URL
Upon receiving the URL, `readUrl` converts the user-friendly URL into an API URL
which can be used to request the provider's API.
`read` then makes an authenticated request to the provider API and returns the
file's content.
#### `readUrl`
`readUrl` is a new interface that allows complex response objects and is
intended to replace the `read` method. This new method is currently optional to
implement which allows for a soft migration to `readUrl` instead of `read` in
the future.
`readUrl` then makes an authenticated request to the provider API and returns the response containing the file's contents and ETag(if the provider supports it).
#### `readTree`
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -28,7 +28,7 @@ organization to easily install and add to their Backstage installation.
# 1. A New Plugin
Sam chooses to develop this plugin in a standalone project and creates a new
plugin using `npx @backstage/cli create-plugin`, which detects that it's not
plugin using `npx @backstage/cli new --select plugin`, which detects that it's not
being run in an existing project and therefore creates a separate plugin repo.
Spinning up the frontend with `yarn start`, Sam goes to work with getting the
+2 -2
View File
@@ -29,8 +29,8 @@ title: Adding Custom Plugin to Existing Monorepo App
# The Skeleton Plugin
1. Start by using the built in creator. From the terminal and root of your
project run: `yarn create-plugin`
1. Start by using the built-in creator. From the terminal and root of your
project run: `yarn new --select plugin`
1. Enter a plugin ID. I used `github-playground`
1. When the process finishes, let's start the backend:
`yarn --cwd packages/backend start`
+3 -3
View File
@@ -6749,11 +6749,11 @@ __metadata:
linkType: hard
"json5@npm:^2.1.2, json5@npm:^2.2.1":
version: 2.2.1
resolution: "json5@npm:2.2.1"
version: 2.2.3
resolution: "json5@npm:2.2.3"
bin:
json5: lib/cli.js
checksum: 74b8a23b102a6f2bf2d224797ae553a75488b5adbaee9c9b6e5ab8b510a2fc6e38f876d4c77dea672d4014a44b2399e15f2051ac2b37b87f74c0c7602003543b
checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349
languageName: node
linkType: hard
@@ -0,0 +1,79 @@
---
title: Backstage Wrapped 2022
author: Francesco Corti & Suzanne Daniels
authorURL: https://github.com/fcorti
---
![wrapped header image](assets/2022-12-19/wrapped.png)
If 2021 was the year of growth for the Backstage project and community, 2022 can be easily defined as the year of maturity. Both the project and the community continued to grow at an incredible pace and the platform is now more stable, more secure, and more powerful than ever.
Our community is full of people from across the globe who bring incredible engagement and positive vibes to the project. And we finally got to experience this for the first time in real life during [BackstageCon](https://www.youtube.com/playlist?list=PLj6h78yzYM2OKySsTuiip3BqmdYZQRnSf), the very first in-person conference fully dedicated to Backstage, where hundreds of enthusiasts, the maintainers, adopters, and partners joined the event confirming the great momentum and the traction in the market.
But before anticipating too much, lets share some stats of this amazing 2022.
<!--truncate-->
## We grew … a lot!
Last year we celebrated 75 [public adopters](https://github.com/backstage/backstage/blob/master/ADOPTERS.md) and today we have over 600 adopters, confirming the interest around Backstage across all the industries, sectors, and dimensions. Companies like [Toyota North America](https://aws.amazon.com/solutions/case-studies/toyota-ecs-case-study/), Deutsche Bank, Mercedes-Benz, Procter & Gamble, Siemens, LinkedIn, and many more joined the community this year and are actively contributing in growing the product and its maturity.
![Accelerated growth of Public Backstage Adopters, from January 2021December 2022.](assets/2022-12-19/public-backstage-adopters-2022.png)
Not only are our adopters growing at an exponential rate, but so too are our contributors. Our [Discord server](https://discord.gg/backstage-687207715902193673) is a perfect example of the worlds of our adopters and contributors melding. On average, at any given hour of the day or night, there are more than 500 people online available to talk and provide support on any Backstage topic. Discord discussions run a full gamut of topics from technical support questions to best practices for onboarding engineers to Backstage basically, anything and everything an adopter may be interested to know and learn. At the very beginning of 2022, we “only” had 4k Discord members. Today, we have a growing membership of 8.2k.
Isnt it what we can call a great and vibrant community of enthusiasts?
The growth of the ecosystem is not limited to the adopters and contributors. The ecosystem also includes big tech companies interested in growing Backstage by including it as part of their offering and integrations. Our [collaboration with VMWare](https://youtube.com/watch?v=GAzKCQO8Vt0&si=EnSIkaIECMiOmarE) is a great example of this, and [RedHat](https://developers.redhat.com/articles/2022/10/24/red-hat-joins-backstageio-community) joined the party this year promising even faster growth in contributions and integrations for the Backstage project.
Before we go any further, lets take a quick look at some more numbers, mainly coming from the [Official Github repository](https://github.com/backstage/backstage). This year…
- Our contributors grew from a group of 500 to 900+
- Contributions to the project increased from 9k to 15k+
- The number of forks shot up from 2k to 3k+
- Backstage stars increased from 14k to almost 20k
- And lastly, we welcomed over 550 adopters into our community.
All of these people driving the enormous growth and maturity of the project are represented in the chart below, which shows cumulative activities per month for Backstage:
![Main Github metrics for Backstage.io.](assets/2022-12-19/github-metrics-for-backstage-io.png)
Wow… thats a lot of activity. Weve generated this animation showing all of your contributions to the Backstage repository in 2022, look at this project grow:
<iframe width="780" height="440" src="https://www.youtube.com/embed/GoWBvHpH5Cg" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>
## But wait… theres more
The growth of the community is so exciting to see. And with all this community growth, comes growth and maturity of the product, making Backstage better able to support adopters in their developer experience challenges. The Backstage open source project has almost [100 plugins](https://backstage.io/plugins), each one amending Backstage with a tool or service to improve not only adopters Backstage apps, but their unique developer experiences. And almost every week we learn of a new one being contributed, which is amazing.
The Backstage platform itself is leaving 2022 more mature than ever, thanks to milestones such as these:
- [Backstage is now beyond version 1](https://backstage.io/blog/2022/03/17/backstage-1.0).
- [Backstage had its first Security Audit ever and now can rely on a Threat Model](https://backstage.io/blog/2022/08/23/backstage-security-audit).
- [Backstage Learn helps adopters get started more easily](https://backstage.spotify.com/learn/).
- [Backstage reached incubating status as part of the CNCF ecosystem](https://www.cncf.io/blog/2022/03/15/backstage-project-joins-the-cncf-incubator/).
And like every mature project, now Backstage has also a mascot: Bowie the Beaver!
![Bowie the Beaver.](assets/2022-12-19/bowie-the-beaver.png)
Additionally, we launched a new [Special Interest Groups (SIGs)](https://github.com/backstage/community/tree/main/sigs) initiative this year, following the lead of Kubernetes. We believe Backstage SIGs will better coordinate contributions, grow the platform cohesively with the open source community, and allow contributors to dig even deeper as a community member. At this moment in time there two SIGs in place:
- The [Catalog SIG](https://github.com/backstage/community/blob/main/sigs/sig-catalog/README.md), covering all aspects of the systems and components related to the Software Catalog.
- The [Adoption SIG](https://github.com/backstage/community/blob/main/sigs/sig-adoption/README.md), covering all aspects of the adoption journey of Backstage.
Our plan is to open more SIGs in 2023 to engage more with the community and to keep driving towards cohesive growth for the community and project.
Last but not least, we mustn't overlook the first ever conference fully dedicated to Backstage: BackstageCon. What was special there? SO much. But in particular two things: seeing everyone in real life and the incredible mood and conversations between maintainers, adopters, partners and enthusiasts. Its hard to express just how positive and amazing the vibes were in a blog, but you can read our recap [here](https://backstage.io/blog/2022/10/28/backstagecon-kubecon-2022) or watch the sessions [here](https://www.youtube.com/playlist?list=PLj6h78yzYM2OKySsTuiip3BqmdYZQRnSf). And in the meantime, here are some great numbers from the event:
- 250 attendees or a 100% full venue and packed room.
- 14 sessions
- 17 speakers
## Goodbye, 2022. Hello, 2023!
After this incredible year, thanks to everyone in the global Backstage community who contributed to the open source project in 2022. We are already working on the goals for 2023 and as a roadmap teaser: we are very much committed to making the journey of adoption easier, faster, more valuable, and overall better. We would not be here today without our amazing community, so thank you for everything!
Looking forward to continuing collaborating together for an exciting 2023.
See you then! Happy holidays from everyone on the Backstage team at Spotify!
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

+1 -1
View File
@@ -46,7 +46,7 @@
"@types/react": "^17",
"@types/react-dom": "^17"
},
"version": "1.9.0",
"version": "1.10.0-next.1",
"dependencies": {
"@backstage/errors": "workspace:^",
"@manypkg/get-packages": "^1.1.3"
+22
View File
@@ -1,5 +1,27 @@
# @backstage/app-defaults
## 1.0.11-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-app-api@1.3.1-next.0
- @backstage/core-components@0.12.3-next.1
- @backstage/core-plugin-api@1.2.1-next.0
- @backstage/theme@0.2.16
- @backstage/plugin-permission-react@0.4.9-next.0
## 1.0.11-next.0
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.12.3-next.0
- @backstage/core-app-api@1.3.0
- @backstage/core-plugin-api@1.2.0
- @backstage/theme@0.2.16
- @backstage/plugin-permission-react@0.4.8
## 1.0.10
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/app-defaults",
"description": "Provides the default wiring of a Backstage App",
"version": "1.0.9",
"version": "1.0.11-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
+126
View File
@@ -1,5 +1,131 @@
# example-app
## 0.2.79-next.1
### Patch Changes
- Updated dependencies
- @backstage/cli@0.22.1-next.1
- @backstage/plugin-catalog-graph@0.2.26-next.1
- @backstage/plugin-explore@0.3.45-next.1
- @backstage/plugin-techdocs@1.4.3-next.1
- @backstage/plugin-cost-insights@0.12.3-next.1
- @backstage/config@1.0.6-next.0
- @backstage/app-defaults@1.0.11-next.1
- @backstage/catalog-model@1.1.5-next.1
- @backstage/core-app-api@1.3.1-next.0
- @backstage/core-components@0.12.3-next.1
- @backstage/core-plugin-api@1.2.1-next.0
- @backstage/integration-react@1.1.9-next.1
- @backstage/theme@0.2.16
- @backstage/plugin-airbrake@0.3.14-next.1
- @backstage/plugin-apache-airflow@0.2.7-next.1
- @backstage/plugin-api-docs@0.8.14-next.1
- @backstage/plugin-azure-devops@0.2.5-next.1
- @backstage/plugin-azure-sites@0.1.3-next.1
- @backstage/plugin-badges@0.2.38-next.1
- @backstage/plugin-catalog-common@1.0.10-next.1
- @backstage/plugin-catalog-import@0.9.4-next.1
- @backstage/plugin-catalog-react@1.2.4-next.1
- @backstage/plugin-circleci@0.3.14-next.1
- @backstage/plugin-cloudbuild@0.3.14-next.1
- @backstage/plugin-code-coverage@0.2.7-next.1
- @backstage/plugin-dynatrace@1.0.4-next.1
- @backstage/plugin-gcalendar@0.3.10-next.1
- @backstage/plugin-gcp-projects@0.3.33-next.1
- @backstage/plugin-github-actions@0.5.14-next.1
- @backstage/plugin-gocd@0.1.20-next.1
- @backstage/plugin-graphiql@0.2.46-next.1
- @backstage/plugin-home@0.4.30-next.1
- @backstage/plugin-jenkins@0.7.13-next.1
- @backstage/plugin-kafka@0.3.14-next.1
- @backstage/plugin-kubernetes@0.7.7-next.1
- @backstage/plugin-lighthouse@0.3.14-next.1
- @backstage/plugin-newrelic@0.3.32-next.1
- @backstage/plugin-newrelic-dashboard@0.2.7-next.1
- @backstage/plugin-org@0.6.4-next.1
- @backstage/plugin-pagerduty@0.5.7-next.1
- @backstage/plugin-permission-react@0.4.9-next.0
- @backstage/plugin-playlist@0.1.5-next.1
- @backstage/plugin-rollbar@0.4.14-next.1
- @backstage/plugin-scaffolder@1.10.0-next.1
- @backstage/plugin-search@1.0.7-next.1
- @backstage/plugin-search-common@1.2.1-next.0
- @backstage/plugin-search-react@1.3.2-next.1
- @backstage/plugin-sentry@0.4.7-next.1
- @backstage/plugin-shortcuts@0.3.6-next.1
- @backstage/plugin-stack-overflow@0.1.10-next.1
- @backstage/plugin-tech-insights@0.3.6-next.1
- @backstage/plugin-tech-radar@0.5.21-next.1
- @backstage/plugin-techdocs-module-addons-contrib@1.0.9-next.1
- @backstage/plugin-techdocs-react@1.1.2-next.1
- @backstage/plugin-todo@0.2.16-next.1
- @backstage/plugin-user-settings@0.6.2-next.1
- @internal/plugin-catalog-customized@0.0.6-next.1
## 0.2.79-next.0
### Patch Changes
- Updated dependencies
- @backstage/cli@0.22.1-next.0
- @backstage/plugin-scaffolder@1.10.0-next.0
- @backstage/catalog-model@1.1.5-next.0
- @backstage/plugin-catalog-react@1.2.4-next.0
- @backstage/core-components@0.12.3-next.0
- @backstage/plugin-techdocs-react@1.1.2-next.0
- @backstage/plugin-techdocs@1.4.3-next.0
- @backstage/plugin-explore@0.3.45-next.0
- @backstage/app-defaults@1.0.11-next.0
- @backstage/config@1.0.5
- @backstage/core-app-api@1.3.0
- @backstage/core-plugin-api@1.2.0
- @backstage/integration-react@1.1.9-next.0
- @backstage/theme@0.2.16
- @backstage/plugin-airbrake@0.3.14-next.0
- @backstage/plugin-apache-airflow@0.2.7-next.0
- @backstage/plugin-api-docs@0.8.14-next.0
- @backstage/plugin-azure-devops@0.2.5-next.0
- @backstage/plugin-azure-sites@0.1.3-next.0
- @backstage/plugin-badges@0.2.38-next.0
- @backstage/plugin-catalog-common@1.0.10-next.0
- @backstage/plugin-catalog-graph@0.2.26-next.0
- @backstage/plugin-catalog-import@0.9.4-next.0
- @backstage/plugin-circleci@0.3.14-next.0
- @backstage/plugin-cloudbuild@0.3.14-next.0
- @backstage/plugin-code-coverage@0.2.7-next.0
- @backstage/plugin-cost-insights@0.12.3-next.0
- @backstage/plugin-dynatrace@1.0.4-next.0
- @backstage/plugin-gcalendar@0.3.10-next.0
- @backstage/plugin-gcp-projects@0.3.33-next.0
- @backstage/plugin-github-actions@0.5.14-next.0
- @backstage/plugin-gocd@0.1.20-next.0
- @backstage/plugin-graphiql@0.2.46-next.0
- @backstage/plugin-home@0.4.30-next.0
- @backstage/plugin-jenkins@0.7.13-next.0
- @backstage/plugin-kafka@0.3.14-next.0
- @backstage/plugin-kubernetes@0.7.7-next.0
- @backstage/plugin-lighthouse@0.3.14-next.0
- @backstage/plugin-newrelic@0.3.32-next.0
- @backstage/plugin-newrelic-dashboard@0.2.7-next.0
- @backstage/plugin-org@0.6.4-next.0
- @backstage/plugin-pagerduty@0.5.7-next.0
- @backstage/plugin-permission-react@0.4.8
- @backstage/plugin-playlist@0.1.5-next.0
- @backstage/plugin-rollbar@0.4.14-next.0
- @backstage/plugin-search@1.0.7-next.0
- @backstage/plugin-search-common@1.2.0
- @backstage/plugin-search-react@1.3.2-next.0
- @backstage/plugin-sentry@0.4.7-next.0
- @backstage/plugin-shortcuts@0.3.6-next.0
- @backstage/plugin-stack-overflow@0.1.10-next.0
- @backstage/plugin-tech-insights@0.3.6-next.0
- @backstage/plugin-tech-radar@0.5.21-next.0
- @backstage/plugin-techdocs-module-addons-contrib@1.0.9-next.0
- @backstage/plugin-todo@0.2.16-next.0
- @backstage/plugin-user-settings@0.6.2-next.0
- @internal/plugin-catalog-customized@0.0.6-next.0
## 0.2.79
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-app",
"version": "0.2.78",
"version": "0.2.79-next.1",
"private": true,
"backstage": {
"role": "frontend"
+12
View File
@@ -1,5 +1,17 @@
# @backstage/backend-app-api
## 0.2.5-next.0
### Patch Changes
- 6cfd4d7073: Updated implementations for the new `RootLifecycleService`.
- Updated dependencies
- @backstage/backend-plugin-api@0.2.1-next.0
- @backstage/backend-common@0.18.0-next.0
- @backstage/backend-tasks@0.4.1-next.0
- @backstage/errors@1.1.4
- @backstage/plugin-permission-node@0.7.3-next.0
## 0.2.4
### Patch Changes
+20 -11
View File
@@ -4,19 +4,21 @@
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { Config } from '@backstage/config';
import { CacheService } from '@backstage/backend-plugin-api';
import { ConfigService } from '@backstage/backend-plugin-api';
import { DatabaseService } from '@backstage/backend-plugin-api';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
import { HttpRouterService } from '@backstage/backend-plugin-api';
import { LifecycleService } from '@backstage/backend-plugin-api';
import { LoggerService } from '@backstage/backend-plugin-api';
import { PermissionsService } from '@backstage/backend-plugin-api';
import { PluginCacheManager } from '@backstage/backend-common';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { PluginTaskScheduler } from '@backstage/backend-tasks';
import { RootLifecycleService } from '@backstage/backend-plugin-api';
import { RootLoggerService } from '@backstage/backend-plugin-api';
import { SchedulerService } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceRef } from '@backstage/backend-plugin-api';
import { TokenManager } from '@backstage/backend-common';
import { TokenManagerService } from '@backstage/backend-plugin-api';
import { UrlReader } from '@backstage/backend-common';
// @public (undocumented)
@@ -32,10 +34,12 @@ export interface Backend {
// @public (undocumented)
export const cacheFactory: (
options?: undefined,
) => ServiceFactory<PluginCacheManager>;
) => ServiceFactory<CacheService>;
// @public (undocumented)
export const configFactory: (options?: undefined) => ServiceFactory<Config>;
export const configFactory: (
options?: undefined,
) => ServiceFactory<ConfigService>;
// @public (undocumented)
export function createSpecializedBackend(
@@ -51,7 +55,7 @@ export interface CreateSpecializedBackendOptions {
// @public (undocumented)
export const databaseFactory: (
options?: undefined,
) => ServiceFactory<PluginDatabaseManager>;
) => ServiceFactory<DatabaseService>;
// @public (undocumented)
export const discoveryFactory: (
@@ -83,15 +87,20 @@ export const permissionsFactory: (
options?: undefined,
) => ServiceFactory<PermissionsService>;
// @public
export const rootLifecycleFactory: (
options?: undefined,
) => ServiceFactory<RootLifecycleService>;
// @public (undocumented)
export const rootLoggerFactory: (
options?: undefined,
) => ServiceFactory<LoggerService>;
) => ServiceFactory<RootLoggerService>;
// @public (undocumented)
export const schedulerFactory: (
options?: undefined,
) => ServiceFactory<PluginTaskScheduler>;
) => ServiceFactory<SchedulerService>;
// @public (undocumented)
export type ServiceOrExtensionPoint<T = unknown> =
@@ -101,7 +110,7 @@ export type ServiceOrExtensionPoint<T = unknown> =
// @public (undocumented)
export const tokenManagerFactory: (
options?: undefined,
) => ServiceFactory<TokenManager>;
) => ServiceFactory<TokenManagerService>;
// @public (undocumented)
export const urlReaderFactory: (
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-app-api",
"description": "Core API used by Backstage backend apps",
"version": "0.2.4",
"version": "0.2.5-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -26,4 +26,5 @@ export { tokenManagerFactory } from './tokenManagerService';
export { urlReaderFactory } from './urlReaderService';
export { httpRouterFactory } from './httpRouterService';
export { lifecycleFactory } from './lifecycleService';
export { rootLifecycleFactory } from './rootLifecycleService';
export type { HttpRouterFactoryOptions } from './httpRouterService';
@@ -14,65 +14,10 @@
* limitations under the License.
*/
import {
LifecycleService,
createServiceFactory,
coreServices,
loggerToWinstonLogger,
LifecycleServiceShutdownHook,
} from '@backstage/backend-plugin-api';
import { Logger } from 'winston';
const CALLBACKS = ['SIGTERM', 'SIGINT', 'beforeExit'];
export class BackendLifecycleImpl {
constructor(private readonly logger: Logger) {
CALLBACKS.map(signal => process.on(signal, () => this.shutdown()));
}
#isCalled = false;
#shutdownTasks: Array<LifecycleServiceShutdownHook & { pluginId: string }> =
[];
addShutdownHook(
options: LifecycleServiceShutdownHook & { pluginId: string },
): void {
this.#shutdownTasks.push(options);
}
async shutdown(): Promise<void> {
if (this.#isCalled) {
return;
}
this.#isCalled = true;
this.logger.info(`Running ${this.#shutdownTasks.length} shutdown tasks...`);
await Promise.all(
this.#shutdownTasks.map(hook =>
Promise.resolve()
.then(() => hook.fn())
.catch(e => {
this.logger.error(
`Shutdown hook registered by plugin '${hook.pluginId}' failed with: ${e}`,
);
})
.then(() =>
this.logger.info(
`Successfully ran shutdown hook registered by plugin ${hook.pluginId}`,
),
),
),
);
}
}
class PluginScopedLifecycleImpl implements LifecycleService {
constructor(
private readonly lifecycle: BackendLifecycleImpl,
private readonly pluginId: string,
) {}
addShutdownHook(options: LifecycleServiceShutdownHook): void {
this.lifecycle.addShutdownHook({ ...options, pluginId: this.pluginId });
}
}
/**
* Allows plugins to register shutdown hooks that are run when the process is about to exit.
@@ -80,15 +25,20 @@ class PluginScopedLifecycleImpl implements LifecycleService {
export const lifecycleFactory = createServiceFactory({
service: coreServices.lifecycle,
deps: {
logger: coreServices.rootLogger,
plugin: coreServices.pluginMetadata,
rootLifecycle: coreServices.rootLifecycle,
pluginMetadata: coreServices.pluginMetadata,
},
async factory({ logger }) {
const rootLifecycle = new BackendLifecycleImpl(
loggerToWinstonLogger(logger),
);
return async ({ plugin }) => {
return new PluginScopedLifecycleImpl(rootLifecycle, plugin.getId());
async factory({ rootLifecycle }) {
return async ({ pluginMetadata }) => {
const plugin = pluginMetadata.getId();
return {
addShutdownHook(options: LifecycleServiceShutdownHook): void {
rootLifecycle.addShutdownHook({
...options,
labels: { ...options?.labels, plugin },
});
},
};
};
},
});
@@ -15,14 +15,14 @@
*/
import { getVoidLogger } from '@backstage/backend-common';
import { BackendLifecycleImpl } from './lifecycleService';
import { BackendLifecycleImpl } from './rootLifecycleService';
describe('lifecycleService', () => {
it('should execute registered shutdown hook', async () => {
const service = new BackendLifecycleImpl(getVoidLogger());
const hook = jest.fn();
service.addShutdownHook({
pluginId: 'test',
labels: { plugin: 'test' },
fn: async () => {
hook();
},
@@ -37,7 +37,7 @@ describe('lifecycleService', () => {
it('should not throw errors', async () => {
const service = new BackendLifecycleImpl(getVoidLogger());
service.addShutdownHook({
pluginId: 'test',
labels: { plugin: 'test' },
fn: async () => {
throw new Error('oh no');
},
@@ -0,0 +1,69 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
createServiceFactory,
coreServices,
loggerToWinstonLogger,
LifecycleServiceShutdownHook,
RootLifecycleService,
} from '@backstage/backend-plugin-api';
import { Logger } from 'winston';
const CALLBACKS = ['SIGTERM', 'SIGINT', 'beforeExit'];
export class BackendLifecycleImpl implements RootLifecycleService {
constructor(private readonly logger: Logger) {
CALLBACKS.map(signal => process.on(signal, () => this.shutdown()));
}
#isCalled = false;
#shutdownTasks: Array<LifecycleServiceShutdownHook> = [];
addShutdownHook(options: LifecycleServiceShutdownHook): void {
this.#shutdownTasks.push(options);
}
async shutdown(): Promise<void> {
if (this.#isCalled) {
return;
}
this.#isCalled = true;
this.logger.info(`Running ${this.#shutdownTasks.length} shutdown tasks...`);
await Promise.all(
this.#shutdownTasks.map(async hook => {
try {
await hook.fn();
this.logger.info(`Shutdown hook succeeded`, hook.labels);
} catch (error) {
this.logger.error(`Shutdown hook failed, ${error}`, hook.labels);
}
}),
);
}
}
/**
* Allows plugins to register shutdown hooks that are run when the process is about to exit.
* @public */
export const rootLifecycleFactory = createServiceFactory({
service: coreServices.rootLifecycle,
deps: {
logger: coreServices.rootLogger,
},
async factory({ logger }) {
return new BackendLifecycleImpl(loggerToWinstonLogger(logger));
},
});
@@ -20,7 +20,7 @@ import {
coreServices,
ServiceRef,
} from '@backstage/backend-plugin-api';
import { BackendLifecycleImpl } from '../services/implementations/lifecycleService';
import { BackendLifecycleImpl } from '../services/implementations/rootLifecycleService';
import {
BackendRegisterInit,
EnumerableServiceHolder,
@@ -182,14 +182,13 @@ export class BackendInitializer {
}
const lifecycleService = await this.#serviceHolder.get(
coreServices.lifecycle,
coreServices.rootLifecycle,
'root',
);
// TODO(Rugvip): Find a better way to do this
const lifecycle = (lifecycleService as any)?.lifecycle;
if (lifecycle instanceof BackendLifecycleImpl) {
await lifecycle.shutdown();
if (lifecycleService instanceof BackendLifecycleImpl) {
await lifecycleService.shutdown();
} else {
throw new Error('Unexpected lifecycle service implementation');
}
+20
View File
@@ -1,5 +1,25 @@
# @backstage/backend-common
## 0.18.0-next.0
### Minor Changes
- 5e2cebe9a3: **BREAKING**: Removed deprecated `read` method from the `UrlReader` interface. All implementations should use the `readUrl` method instead.
Migrated `UrlReader` and related types to `backend/backend-plugin-api`, types remain re-exported from `backend-common` for now.
### Patch Changes
- 6f02d23b01: Moved `PluginEndpointDiscovery` type from backend-common to backend-plugin-api.
- Updated dependencies
- @backstage/backend-plugin-api@0.2.1-next.0
- @backstage/config@1.0.6-next.0
- @backstage/cli-common@0.1.11
- @backstage/config-loader@1.1.8-next.0
- @backstage/errors@1.1.4
- @backstage/integration@1.4.2-next.0
- @backstage/types@1.0.2
## 0.17.0
### Minor Changes
+22 -65
View File
@@ -30,12 +30,23 @@ import { KubeConfig } from '@kubernetes/client-node';
import { LoadConfigOptionsRemote } from '@backstage/config-loader';
import { Logger } from 'winston';
import { MergeResult } from 'isomorphic-git';
import { DiscoveryService as PluginEndpointDiscovery } from '@backstage/backend-plugin-api';
import { PushResult } from 'isomorphic-git';
import { Readable } from 'stream';
import { ReadCommitResult } from 'isomorphic-git';
import { ReadTreeOptions } from '@backstage/backend-plugin-api';
import { ReadTreeResponse } from '@backstage/backend-plugin-api';
import { ReadTreeResponseDirOptions } from '@backstage/backend-plugin-api';
import { ReadTreeResponseFile } from '@backstage/backend-plugin-api';
import { ReadUrlOptions } from '@backstage/backend-plugin-api';
import { ReadUrlResponse } from '@backstage/backend-plugin-api';
import { RequestHandler } from 'express';
import { Router } from 'express';
import { SearchOptions } from '@backstage/backend-plugin-api';
import { SearchResponse } from '@backstage/backend-plugin-api';
import { SearchResponseFile } from '@backstage/backend-plugin-api';
import { Server } from 'http';
import { UrlReaderService as UrlReader } from '@backstage/backend-plugin-api';
import { V1PodTemplateSpec } from '@kubernetes/client-node';
import * as winston from 'winston';
import { Writable } from 'stream';
@@ -520,11 +531,7 @@ export interface PluginDatabaseManager {
};
}
// @public
export type PluginEndpointDiscovery = {
getBaseUrl(pluginId: string): Promise<string>;
getExternalBaseUrl(pluginId: string): Promise<string>;
};
export { PluginEndpointDiscovery };
// @public
export type ReaderFactory = (options: {
@@ -533,30 +540,11 @@ export type ReaderFactory = (options: {
treeResponseFactory: ReadTreeResponseFactory;
}) => UrlReaderPredicateTuple[];
// @public
export type ReadTreeOptions = {
filter?(
path: string,
info?: {
size: number;
},
): boolean;
etag?: string;
signal?: AbortSignal;
};
export { ReadTreeOptions };
// @public
export type ReadTreeResponse = {
files(): Promise<ReadTreeResponseFile[]>;
archive(): Promise<NodeJS.ReadableStream>;
dir(options?: ReadTreeResponseDirOptions): Promise<string>;
etag: string;
};
export { ReadTreeResponse };
// @public
export type ReadTreeResponseDirOptions = {
targetDir?: string;
};
export { ReadTreeResponseDirOptions };
// @public
export interface ReadTreeResponseFactory {
@@ -587,24 +575,11 @@ export type ReadTreeResponseFactoryOptions = {
) => boolean;
};
// @public
export type ReadTreeResponseFile = {
path: string;
content(): Promise<Buffer>;
};
export { ReadTreeResponseFile };
// @public
export type ReadUrlOptions = {
etag?: string;
signal?: AbortSignal;
};
export { ReadUrlOptions };
// @public
export type ReadUrlResponse = {
buffer(): Promise<Buffer>;
stream?(): Readable;
etag?: string;
};
export { ReadUrlResponse };
// @public
export class ReadUrlResponseFactory {
@@ -652,23 +627,11 @@ export type RunContainerOptions = {
pullImage?: boolean;
};
// @public
export type SearchOptions = {
etag?: string;
signal?: AbortSignal;
};
export { SearchOptions };
// @public
export type SearchResponse = {
files: SearchResponseFile[];
etag: string;
};
export { SearchResponse };
// @public
export type SearchResponseFile = {
url: string;
content(): Promise<Buffer>;
};
export { SearchResponseFile };
// @public
export class ServerTokenManager implements TokenManager {
@@ -755,13 +718,7 @@ export interface TokenManager {
}>;
}
// @public
export type UrlReader = {
read(url: string): Promise<Buffer>;
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
};
export { UrlReader };
// @public
export type UrlReaderPredicateTuple = {
+2 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.17.0",
"version": "0.18.0-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -34,6 +34,7 @@
"test:kubernetes": "backstage-cli package test -t KubernetesContainerRunner --no-watch"
},
"dependencies": {
"@backstage/backend-plugin-api": "workspace:^",
"@backstage/cli-common": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/config-loader": "workspace:^",
+1 -47
View File
@@ -14,50 +14,4 @@
* limitations under the License.
*/
/**
* The PluginEndpointDiscovery is used to provide a mechanism for backend
* plugins to discover the endpoints for itself or other backend plugins.
*
* The purpose of the discovery API is to allow for many different deployment
* setups and routing methods through a central configuration, instead
* of letting each individual plugin manage that configuration.
*
* Implementations of the discovery API can be as simple as a URL pattern
* using the pluginId, but could also have overrides for individual plugins,
* or query a separate discovery service.
*
* @public
*/
export type PluginEndpointDiscovery = {
/**
* Returns the internal HTTP base URL for a given plugin, without a trailing slash.
*
* The returned URL should point to an internal endpoint for the plugin, with
* the shortest route possible. The URL should be used for service-to-service
* communication within a Backstage backend deployment.
*
* This method must always be called just before making a request, as opposed to
* fetching the URL when constructing an API client. That is to ensure that more
* flexible routing patterns can be supported.
*
* For example, asking for the URL for `catalog` may return something
* like `http://10.1.2.3/api/catalog`
*/
getBaseUrl(pluginId: string): Promise<string>;
/**
* Returns the external HTTP base backend URL for a given plugin, without a trailing slash.
*
* The returned URL should point to an external endpoint for the plugin, such that
* it is reachable from the Backstage frontend and other external services. The returned
* URL should be usable for example as a callback / webhook URL.
*
* The returned URL should be stable and in general not change unless other static
* or external configuration is changed. Changes should not come as a surprise
* to an operator of the Backstage backend.
*
* For example, asking for the URL for `catalog` may return something
* like `https://backstage.example.com/api/catalog`
*/
getExternalBaseUrl(pluginId: string): Promise<string>;
};
export type { DiscoveryService as PluginEndpointDiscovery } from '@backstage/backend-plugin-api';
@@ -117,7 +117,7 @@ export function parseUrl(
}
/**
* Implements a {@link UrlReader} for AWS S3 buckets.
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS S3 buckets.
*
* @public
*/
@@ -40,7 +40,7 @@ import {
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
/**
* Implements a {@link UrlReader} for Azure repos.
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure repos.
*
* @public
*/
@@ -42,7 +42,7 @@ import {
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
/**
* Implements a {@link UrlReader} for files from Bitbucket Cloud.
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Cloud.
*
* @public
*/
@@ -41,7 +41,7 @@ import {
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
/**
* Implements a {@link UrlReader} for files from Bitbucket Server APIs.
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Server APIs.
*
* @public
*/
@@ -43,7 +43,7 @@ import {
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
/**
* Implements a {@link UrlReader} for files from Bitbucket v1 and v2 APIs, such
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket v1 and v2 APIs, such
* as the one exposed by Bitbucket Cloud itself.
*
* @public
@@ -63,7 +63,7 @@ const parsePortPredicate = (port: string | undefined) => {
};
/**
* A {@link UrlReader} that does a plain fetch of the URL.
* A {@link @backstage/backend-plugin-api#UrlReaderService} that does a plain fetch of the URL.
*
* @public
*/
@@ -52,7 +52,7 @@ const createTemporaryDirectory = async (workDir: string): Promise<string> =>
await fs.mkdtemp(joinPath(workDir, '/gerrit-clone-'));
/**
* Implements a {@link UrlReader} for files in Gerrit.
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files in Gerrit.
*
* @remarks
* To be able to link to Git contents for Gerrit providers in a user friendly
@@ -36,7 +36,7 @@ import {
import { Readable } from 'stream';
/**
* Implements a {@link UrlReader} for the Gitea v1 api.
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for the Gitea v1 api.
*
* @public
*/
@@ -51,7 +51,7 @@ export type GhBlobResponse =
RestEndpointMethodTypes['git']['getBlob']['response']['data'];
/**
* Implements a {@link UrlReader} for files through the GitHub v3 APIs, such as
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files through the GitHub v3 APIs, such as
* the one exposed by GitHub itself.
*
* @public
@@ -42,7 +42,7 @@ import { trimEnd, trimStart } from 'lodash';
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
/**
* Implements a {@link UrlReader} for files on GitLab.
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files on GitLab.
*
* @public
*/
@@ -51,7 +51,7 @@ const parseURL = (
};
/**
* Implements a {@link UrlReader} for files on Google GCS.
* Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files on Google GCS.
*
* @public
*/
@@ -70,7 +70,6 @@ describe('UrlReaderPredicateMux', () => {
mux.register({
predicate: url => url.hostname === 'foo',
reader: {
read: jest.fn(),
readUrl: jest.fn(),
readTree: jest.fn(),
search: jest.fn(),
@@ -45,18 +45,6 @@ export class UrlReaderPredicateMux implements UrlReader {
this.readers.push(tuple);
}
async read(url: string): Promise<Buffer> {
const parsed = new URL(url);
for (const { predicate, reader } of this.readers) {
if (predicate(parsed)) {
return reader.read(url);
}
}
throw new NotAllowedError(notAllowedMessage(url));
}
async readUrl(
url: string,
options?: ReadUrlOptions,
@@ -32,7 +32,7 @@ import { AwsS3UrlReader } from './AwsS3UrlReader';
import { GiteaUrlReader } from './GiteaUrlReader';
/**
* Creation options for {@link UrlReaders}.
* Creation options for {@link @backstage/backend-plugin-api#UrlReaderService}.
*
* @public
*/
@@ -46,13 +46,13 @@ export type UrlReadersOptions = {
};
/**
* Helps construct {@link UrlReader}s.
* Helps construct {@link @backstage/backend-plugin-api#UrlReaderService}s.
*
* @public
*/
export class UrlReaders {
/**
* Creates a custom {@link UrlReader} wrapper for your own set of factories.
* Creates a custom {@link @backstage/backend-plugin-api#UrlReaderService} wrapper for your own set of factories.
*/
static create(options: UrlReadersOptions): UrlReader {
const { logger, config, factories } = options;
@@ -73,7 +73,7 @@ export class UrlReaders {
}
/**
* Creates a {@link UrlReader} wrapper that includes all the default factories
* Creates a {@link @backstage/backend-plugin-api#UrlReaderService} wrapper that includes all the default factories
* from this package.
*
* Any additional factories passed will be loaded before the default ones.
+20 -280
View File
@@ -17,56 +17,38 @@
import { Readable } from 'stream';
import { Logger } from 'winston';
import { Config } from '@backstage/config';
import {
UrlReaderService,
ReadTreeResponse,
} from '@backstage/backend-plugin-api';
export type {
UrlReaderService as UrlReader,
ReadTreeOptions,
ReadTreeResponse,
ReadTreeResponseDirOptions,
ReadTreeResponseFile,
ReadUrlResponse,
ReadUrlOptions,
SearchOptions,
SearchResponse,
SearchResponseFile,
} from '@backstage/backend-plugin-api';
/**
* A generic interface for fetching plain data from URLs.
*
* @public
*/
export type UrlReader = {
/**
* Reads a single file and return its content.
* @deprecated use readUrl instead.
*/
read(url: string): Promise<Buffer>;
/**
* Reads a single file and return its content.
*
* @remarks
*
* This is a replacement for the read method that supports options and
* complex responses.
*
* Use this as the read method will be removed in a future release.
*/
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
/**
* Reads a full or partial file tree.
*/
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
/**
* Searches for a file in a tree using a glob pattern.
*/
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
};
/**
* A predicate that decides whether a specific {@link UrlReader} can handle a
* A predicate that decides whether a specific {@link @backstage/backend-plugin-api#UrlReaderService} can handle a
* given URL.
*
* @public
*/
export type UrlReaderPredicateTuple = {
predicate: (url: URL) => boolean;
reader: UrlReader;
reader: UrlReaderService;
};
/**
* A factory function that can read config to construct zero or more
* {@link UrlReader}s along with a predicate for when it should be used.
* {@link @backstage/backend-plugin-api#UrlReaderService}s along with a predicate for when it should be used.
*
* @public
*/
@@ -76,72 +58,6 @@ export type ReaderFactory = (options: {
treeResponseFactory: ReadTreeResponseFactory;
}) => UrlReaderPredicateTuple[];
/**
* An options object for readUrl operations.
*
* @public
*/
export type ReadUrlOptions = {
/**
* An ETag which can be provided to check whether a
* {@link UrlReader.readUrl} response has changed from a previous execution.
*
* @remarks
*
* In the {@link UrlReader.readUrl} response, an ETag is returned along with
* the data. The ETag is a unique identifier of the data, usually the commit
* SHA or ETag from the target.
*
* When an ETag is given in ReadUrlOptions, {@link UrlReader.readUrl} will
* first compare the ETag against the ETag of the target. If they match,
* {@link UrlReader.readUrl} will throw a
* {@link @backstage/errors#NotModifiedError} indicating that the response
* will not differ from the previous response which included this particular
* ETag. If they do not match, {@link UrlReader.readUrl} will return the rest
* of the response along with a new ETag.
*/
etag?: string;
/**
* An abort signal to pass down to the underlying request.
*
* @remarks
*
* Not all reader implementations may take this field into account.
*/
signal?: AbortSignal;
};
/**
* A response object for {@link UrlReader.readUrl} operations.
*
* @public
*/
export type ReadUrlResponse = {
/**
* Returns the data that was read from the remote URL.
*/
buffer(): Promise<Buffer>;
/**
* Returns the data that was read from the remote URL as a Readable stream.
*
* @remarks
*
* This method will be required in a future release.
*/
stream?(): Readable;
/**
* Etag returned by content provider.
*
* @remarks
*
* Can be used to compare and cache responses when doing subsequent calls.
*/
etag?: string;
};
/**
* An options object for {@link ReadUrlResponseFactory} factory methods.
*
@@ -151,119 +67,6 @@ export type ReadUrlResponseFactoryFromStreamOptions = {
etag?: string;
};
/**
* An options object for {@link UrlReader.readTree} operations.
*
* @public
*/
export type ReadTreeOptions = {
/**
* A filter that can be used to select which files should be included.
*
* @remarks
*
* The path passed to the filter function is the relative path from the URL
* that the file tree is fetched from, without any leading '/'.
*
* For example, given the URL https://github.com/my/repo/tree/master/my-dir, a file
* at https://github.com/my/repo/blob/master/my-dir/my-subdir/my-file.txt will
* be represented as my-subdir/my-file.txt
*
* If no filter is provided, all files are extracted.
*/
filter?(path: string, info?: { size: number }): boolean;
/**
* An ETag which can be provided to check whether a
* {@link UrlReader.readTree} response has changed from a previous execution.
*
* @remarks
*
* In the {@link UrlReader.readTree} response, an ETag is returned along with
* the tree blob. The ETag is a unique identifier of the tree blob, usually
* the commit SHA or ETag from the target.
*
* When an ETag is given as a request option, {@link UrlReader.readTree} will
* first compare the ETag against the ETag on the target branch. If they
* match, {@link UrlReader.readTree} will throw a
* {@link @backstage/errors#NotModifiedError} indicating that the response
* will not differ from the previous response which included this particular
* ETag. If they do not match, {@link UrlReader.readTree} will return the
* rest of the response along with a new ETag.
*/
etag?: string;
/**
* An abort signal to pass down to the underlying request.
*
* @remarks
*
* Not all reader implementations may take this field into account.
*/
signal?: AbortSignal;
};
/**
* Options that control {@link ReadTreeResponse.dir} execution.
*
* @public
*/
export type ReadTreeResponseDirOptions = {
/**
* The directory to write files to.
*
* @remarks
*
* Defaults to the OS tmpdir, or `backend.workingDirectory` if set in config.
*/
targetDir?: string;
};
/**
* A response object for {@link UrlReader.readTree} operations.
*
* @public
*/
export type ReadTreeResponse = {
/**
* Returns an array of all the files inside the tree, and corresponding
* functions to read their content.
*/
files(): Promise<ReadTreeResponseFile[]>;
/**
* Returns the tree contents as a binary archive, using a stream.
*/
archive(): Promise<NodeJS.ReadableStream>;
/**
* Extracts the tree response into a directory and returns the path of the
* directory.
*
* **NOTE**: It is the responsibility of the caller to remove the directory after use.
*/
dir(options?: ReadTreeResponseDirOptions): Promise<string>;
/**
* Etag returned by content provider.
*
* @remarks
*
* Can be used to compare and cache responses when doing subsequent calls.
*/
etag: string;
};
/**
* Represents a single file in a {@link UrlReader.readTree} response.
*
* @public
*/
export type ReadTreeResponseFile = {
path: string;
content(): Promise<Buffer>;
};
/**
* Options that control execution of {@link ReadTreeResponseFactory} methods.
*
@@ -315,66 +118,3 @@ export interface ReadTreeResponseFactory {
options: FromReadableArrayOptions,
): Promise<ReadTreeResponse>;
}
/**
* An options object for search operations.
*
* @public
*/
export type SearchOptions = {
/**
* An etag can be provided to check whether the search response has changed from a previous execution.
*
* In the search() response, an etag is returned along with the files. The etag is a unique identifier
* of the current tree, usually the commit SHA or etag from the target.
*
* When an etag is given in SearchOptions, search will first compare the etag against the etag
* on the target branch. If they match, search will throw a NotModifiedError indicating that the search
* response will not differ from the previous response which included this particular etag. If they mismatch,
* search will return the rest of SearchResponse along with a new etag.
*/
etag?: string;
/**
* An abort signal to pass down to the underlying request.
*
* @remarks
*
* Not all reader implementations may take this field into account.
*/
signal?: AbortSignal;
};
/**
* The output of a search operation.
*
* @public
*/
export type SearchResponse = {
/**
* The files that matched the search query.
*/
files: SearchResponseFile[];
/**
* A unique identifier of the current remote tree, usually the commit SHA or etag from the target.
*/
etag: string;
};
/**
* Represents a single file in a search response.
*
* @public
*/
export type SearchResponseFile = {
/**
* The full URL to the file.
*/
url: string;
/**
* The binary contents of the file.
*/
content(): Promise<Buffer>;
};
+9
View File
@@ -1,5 +1,14 @@
# @backstage/backend-defaults
## 0.1.5-next.0
### Patch Changes
- 6cfd4d7073: Include implementations for the new `rootLifecycleServiceRef`.
- Updated dependencies
- @backstage/backend-plugin-api@0.2.1-next.0
- @backstage/backend-app-api@0.2.5-next.0
## 0.1.4
### 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.4",
"version": "0.1.5-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -23,6 +23,7 @@ import {
discoveryFactory,
httpRouterFactory,
lifecycleFactory,
rootLifecycleFactory,
loggerFactory,
permissionsFactory,
rootLoggerFactory,
@@ -45,6 +46,7 @@ export const defaultServiceFactories = [
urlReaderFactory,
httpRouterFactory,
lifecycleFactory,
rootLifecycleFactory,
];
/**
+20
View File
@@ -1,5 +1,25 @@
# example-backend-next
## 0.0.7-next.1
### Patch Changes
- Updated dependencies
- @backstage/backend-defaults@0.1.5-next.0
- @backstage/plugin-scaffolder-backend@1.10.0-next.1
- @backstage/plugin-app-backend@0.3.40-next.0
- @backstage/plugin-catalog-backend@1.7.0-next.1
## 0.0.7-next.0
### Patch Changes
- Updated dependencies
- @backstage/plugin-scaffolder-backend@1.9.1-next.0
- @backstage/plugin-catalog-backend@1.7.0-next.0
- @backstage/backend-defaults@0.1.4
- @backstage/plugin-app-backend@0.3.39
## 0.0.6
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend-next",
"version": "0.0.6",
"version": "0.0.7-next.1",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
+13
View File
@@ -1,5 +1,18 @@
# @backstage/backend-plugin-api
## 0.2.1-next.0
### Patch Changes
- 6cfd4d7073: Added `RootLifecycleService` and `rootLifecycleServiceRef`, as well as added a `labels` option to the existing `LifecycleServiceShutdownHook`.
- 5e2cebe9a3: Migrate `UrlReader` into this package to gradually remove the dependency on backend-common.
- 6f02d23b01: Moved `PluginEndpointDiscovery` type from backend-common to backend-plugin-api.
- Updated dependencies
- @backstage/backend-common@0.18.0-next.0
- @backstage/config@1.0.6-next.0
- @backstage/backend-tasks@0.4.1-next.0
- @backstage/plugin-permission-common@0.7.3-next.0
## 0.2.0
### Minor Changes
+100 -67
View File
@@ -3,18 +3,18 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
/// <reference types="node" />
import { Config } from '@backstage/config';
import { Handler } from 'express';
import { Logger } from 'winston';
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { PluginCacheManager } from '@backstage/backend-common';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { PluginTaskScheduler } from '@backstage/backend-tasks';
import { Readable } from 'stream';
import { TokenManager } from '@backstage/backend-common';
import { TransportStreamOptions } from 'winston-transport';
import { UrlReader } from '@backstage/backend-common';
// @public (undocumented)
export interface BackendFeature {
@@ -66,35 +66,28 @@ export interface BackendRegistrationPoints {
}
// @public (undocumented)
export type CacheService = PluginCacheManager;
export interface CacheService extends PluginCacheManager {}
// @public (undocumented)
const cacheServiceRef: ServiceRef<PluginCacheManager, 'plugin'>;
export interface ConfigService extends Config {}
// @public (undocumented)
export type ConfigService = Config;
// @public (undocumented)
const configServiceRef: ServiceRef<Config, 'root'>;
declare namespace coreServices {
export {
configServiceRef as config,
httpRouterServiceRef as httpRouter,
loggerServiceRef as logger,
urlReaderServiceRef as urlReader,
cacheServiceRef as cache,
databaseServiceRef as database,
discoveryServiceRef as discovery,
tokenManagerServiceRef as tokenManager,
permissionsServiceRef as permissions,
schedulerServiceRef as scheduler,
rootLoggerServiceRef as rootLogger,
pluginMetadataServiceRef as pluginMetadata,
lifecycleServiceRef as lifecycle,
};
// @public
export namespace coreServices {
const cache: ServiceRef<CacheService, 'plugin'>;
const config: ServiceRef<ConfigService, 'root'>;
const database: ServiceRef<DatabaseService, 'plugin'>;
const discovery: ServiceRef<DiscoveryService, 'plugin'>;
const httpRouter: ServiceRef<HttpRouterService, 'plugin'>;
const lifecycle: ServiceRef<LifecycleService, 'plugin'>;
const logger: ServiceRef<LoggerService, 'plugin'>;
const permissions: ServiceRef<PermissionsService, 'plugin'>;
const pluginMetadata: ServiceRef<PluginMetadataService, 'plugin'>;
const rootLifecycle: ServiceRef<RootLifecycleService, 'root'>;
const rootLogger: ServiceRef<RootLoggerService, 'root'>;
const scheduler: ServiceRef<SchedulerService, 'plugin'>;
const tokenManager: ServiceRef<TokenManagerService, 'plugin'>;
const urlReader: ServiceRef<UrlReaderService, 'plugin'>;
}
export { coreServices };
// @public
export function createBackendModule<
@@ -161,16 +154,13 @@ export function createServiceRef<T>(options: {
}): ServiceRef<T, 'root'>;
// @public (undocumented)
export type DatabaseService = PluginDatabaseManager;
export interface DatabaseService extends PluginDatabaseManager {}
// @public (undocumented)
const databaseServiceRef: ServiceRef<PluginDatabaseManager, 'plugin'>;
// @public (undocumented)
export type DiscoveryService = PluginEndpointDiscovery;
// @public (undocumented)
const discoveryServiceRef: ServiceRef<PluginEndpointDiscovery, 'plugin'>;
// @public
export interface DiscoveryService {
getBaseUrl(pluginId: string): Promise<string>;
getExternalBaseUrl(pluginId: string): Promise<string>;
}
// @public
export type ExtensionPoint<T> = {
@@ -186,23 +176,18 @@ export interface HttpRouterService {
use(handler: Handler): void;
}
// @public (undocumented)
const httpRouterServiceRef: ServiceRef<HttpRouterService, 'plugin'>;
// @public (undocumented)
export interface LifecycleService {
addShutdownHook(options: LifecycleServiceShutdownHook): void;
}
// @public (undocumented)
const lifecycleServiceRef: ServiceRef<LifecycleService, 'plugin'>;
// @public (undocumented)
export type LifecycleServiceShutdownHook = {
fn: () => void | Promise<void>;
labels?: Record<string, string>;
};
// @public (undocumented)
// @public
export interface LoggerService {
// (undocumented)
child(meta: LogMeta): LoggerService;
@@ -216,9 +201,6 @@ export interface LoggerService {
warn(message: string, meta?: Error | LogMeta): void;
}
// @public (undocumented)
const loggerServiceRef: ServiceRef<LoggerService, 'plugin'>;
// @public (undocumented)
export function loggerToWinstonLogger(
logger: LoggerService,
@@ -231,10 +213,7 @@ export type LogMeta = {
};
// @public (undocumented)
export type PermissionsService = PermissionEvaluator | PermissionAuthorizer;
// @public (undocumented)
const permissionsServiceRef: ServiceRef<PermissionsService, 'plugin'>;
export interface PermissionsService extends PermissionEvaluator {}
// @public (undocumented)
export interface PluginMetadataService {
@@ -242,20 +221,76 @@ export interface PluginMetadataService {
getId(): string;
}
// @public (undocumented)
const pluginMetadataServiceRef: ServiceRef<PluginMetadataService, 'plugin'>;
// @public
export type ReadTreeOptions = {
filter?(
path: string,
info?: {
size: number;
},
): boolean;
etag?: string;
signal?: AbortSignal;
};
// @public
export type ReadTreeResponse = {
files(): Promise<ReadTreeResponseFile[]>;
archive(): Promise<NodeJS.ReadableStream>;
dir(options?: ReadTreeResponseDirOptions): Promise<string>;
etag: string;
};
// @public
export type ReadTreeResponseDirOptions = {
targetDir?: string;
};
// @public
export type ReadTreeResponseFile = {
path: string;
content(): Promise<Buffer>;
};
// @public
export type ReadUrlOptions = {
etag?: string;
signal?: AbortSignal;
};
// @public
export type ReadUrlResponse = {
buffer(): Promise<Buffer>;
stream?(): Readable;
etag?: string;
};
// @public (undocumented)
export type RootLoggerService = LoggerService;
export interface RootLifecycleService extends LifecycleService {}
// @public (undocumented)
const rootLoggerServiceRef: ServiceRef<LoggerService, 'root'>;
export interface RootLoggerService extends LoggerService {}
// @public (undocumented)
export type SchedulerService = PluginTaskScheduler;
export interface SchedulerService extends PluginTaskScheduler {}
// @public (undocumented)
const schedulerServiceRef: ServiceRef<PluginTaskScheduler, 'plugin'>;
// @public
export type SearchOptions = {
etag?: string;
signal?: AbortSignal;
};
// @public
export type SearchResponse = {
files: SearchResponseFile[];
etag: string;
};
// @public
export type SearchResponseFile = {
url: string;
content(): Promise<Buffer>;
};
// @public (undocumented)
export type ServiceFactory<TService = unknown> =
@@ -297,19 +332,17 @@ export type ServiceRef<
};
// @public (undocumented)
export type TokenManagerService = TokenManager;
// @public (undocumented)
const tokenManagerServiceRef: ServiceRef<TokenManager, 'plugin'>;
export interface TokenManagerService extends TokenManager {}
// @public (undocumented)
export type TypesToServiceRef<T> = {
[key in keyof T]: ServiceRef<T[key]>;
};
// @public (undocumented)
export type UrlReaderService = UrlReader;
// @public (undocumented)
const urlReaderServiceRef: ServiceRef<UrlReader, 'plugin'>;
// @public
export interface UrlReaderService {
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
search(url: string, options?: SearchOptions): Promise<SearchResponse>;
}
```

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