Merge branch 'master' into jenkins/jobrun-table
Signed-off-by: Abhay-soni-developer <abhaysoni.developer@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-proxy-backend': patch
|
||||
---
|
||||
|
||||
Add the route name to an error message that appears when the backend
|
||||
proxy wasn't well configured. This will help users to understand the
|
||||
issue and fix the right configuration.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/backend-tasks': patch
|
||||
---
|
||||
|
||||
When starting a task that existed before, with a faster schedule than it
|
||||
previously had, the task will now correctly obey the faster schedule
|
||||
immediately. Before this fix, the new schedule was only obeyed after the next
|
||||
pending (according to the old schedule) run had completed.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend-module-oauth2-provider': minor
|
||||
---
|
||||
|
||||
New module for `@backstage/plugin-auth-backend` that adds a `oauth2` auth provider.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
---
|
||||
|
||||
Fixed a bug where requests to the proxy endpoint would fail for clusters with `caFile` configured
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Restored functionality to `OwnedEntityPicker` by converting deprecated `ui:options` input to `catalogFilter`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-newrelic': patch
|
||||
---
|
||||
|
||||
Fixed bug in NewRelicComponent component where table would not sort correctly for numerical values.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Minor internal tweak to handle `classnames` update
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-import': minor
|
||||
---
|
||||
|
||||
Slight change to the `PreparePullRequestFormProps`, because of an update to `react-hook-form`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-adr': patch
|
||||
---
|
||||
|
||||
support for i18n feature
|
||||
+47
-2
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"mode": "pre",
|
||||
"mode": "exit",
|
||||
"tag": "next",
|
||||
"initialVersions": {
|
||||
"example-app": "0.2.86",
|
||||
@@ -241,46 +241,67 @@
|
||||
"@backstage/frontend-plugin-api": "0.0.0",
|
||||
"@backstage/plugin-auth-backend-module-gitlab-provider": "0.0.0",
|
||||
"@backstage/backend-plugin-manager": "0.0.0",
|
||||
"@backstage/plugin-permission-backend-module-allow-all-policy": "0.0.0"
|
||||
"@backstage/plugin-permission-backend-module-allow-all-policy": "0.0.0",
|
||||
"app-next-example-plugin": "0.0.0",
|
||||
"@backstage/plugin-auth-backend-module-oauth2-provider": "0.0.0",
|
||||
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.0.0"
|
||||
},
|
||||
"changesets": [
|
||||
"big-bananas-sleep",
|
||||
"big-masks-divide",
|
||||
"big-spies-agree",
|
||||
"blue-rats-drop",
|
||||
"brave-books-pretend",
|
||||
"brave-carrots-occur",
|
||||
"calm-cups-smile",
|
||||
"catalog-everybody-to-the-limit",
|
||||
"chatty-goats-mate",
|
||||
"chatty-spiders-serve",
|
||||
"chilly-balloons-enjoy",
|
||||
"chilly-parrots-yell",
|
||||
"clean-houses-invent",
|
||||
"cold-apricots-poke",
|
||||
"create-app-1692704146",
|
||||
"create-app-1693311380",
|
||||
"cuddly-avocados-warn",
|
||||
"curvy-roses-march",
|
||||
"cyan-roses-relate",
|
||||
"dirty-boxes-give",
|
||||
"dirty-carrots-notice",
|
||||
"dirty-cars-poke",
|
||||
"dirty-cars-smoke",
|
||||
"dirty-garlics-kiss",
|
||||
"dirty-years-travel",
|
||||
"dry-wasps-occur",
|
||||
"dull-eyes-pay",
|
||||
"dull-tables-joke",
|
||||
"early-rules-taste",
|
||||
"early-trains.draw",
|
||||
"eight-radios-listen",
|
||||
"eight-timers-sin",
|
||||
"eighty-emus-float",
|
||||
"eighty-fans-provide",
|
||||
"empty-rings-type",
|
||||
"fair-paws-flash",
|
||||
"few-nails-smile",
|
||||
"fifty-adults-shake",
|
||||
"forty-rocks-jog",
|
||||
"four-masks-fry",
|
||||
"fresh-candles-warn",
|
||||
"friendly-pugs-lick",
|
||||
"funny-ligers-matter",
|
||||
"funny-timers-retire",
|
||||
"giant-coats-brush",
|
||||
"gorgeous-coins-attack",
|
||||
"great-chairs-swim",
|
||||
"grumpy-bikes-beg",
|
||||
"grumpy-papayas-tie",
|
||||
"grumpy-ties-know",
|
||||
"healthy-spiders-arrive",
|
||||
"healthy-tools-count",
|
||||
"hip-seahorses-exist",
|
||||
"honest-ads-rush",
|
||||
"hungry-cherries-speak",
|
||||
"hungry-dots-design",
|
||||
"khaki-pigs-accept",
|
||||
"khaki-spiders-sniff",
|
||||
@@ -288,7 +309,10 @@
|
||||
"late-hounds-yell",
|
||||
"late-roses-dream",
|
||||
"lazy-pumas-hope",
|
||||
"lazy-pumas-shop",
|
||||
"lazy-rice-rule",
|
||||
"lemon-donuts-clap",
|
||||
"light-drinks-rush",
|
||||
"long-flowers-sort",
|
||||
"loud-apricots-destroy",
|
||||
"lovely-years-sniff",
|
||||
@@ -296,28 +320,35 @@
|
||||
"lucky-chicken-lie",
|
||||
"many-tips-attend",
|
||||
"mean-carpets-provide",
|
||||
"mean-planes-smoke",
|
||||
"mean-queens-act",
|
||||
"mighty-crabs-cheat",
|
||||
"modern-trees-add",
|
||||
"nasty-cherries-exercise",
|
||||
"nasty-forks-beg",
|
||||
"nasty-snails-complain",
|
||||
"nasty-worms-share",
|
||||
"new-sheep-cover",
|
||||
"nice-forks-remain",
|
||||
"ninety-horses-remember",
|
||||
"ninety-news-visit",
|
||||
"old-geese-drive",
|
||||
"orange-houses-fly",
|
||||
"pink-cups-rescue",
|
||||
"pink-months-hammer",
|
||||
"plenty-lamps-pump",
|
||||
"polite-forks-grin",
|
||||
"polite-plums-share",
|
||||
"poor-olives-own",
|
||||
"poor-years-appear",
|
||||
"popular-clocks-whisper",
|
||||
"popular-coins-tap",
|
||||
"popular-readers-allow",
|
||||
"pretty-otters-whisper",
|
||||
"proud-lamps-cross",
|
||||
"red-pens-knock",
|
||||
"renovate-2ebf420",
|
||||
"renovate-36e7f58",
|
||||
"renovate-76185f9",
|
||||
"renovate-b129f45",
|
||||
"renovate-bbda8e8",
|
||||
@@ -325,27 +356,41 @@
|
||||
"repo-tools-boo-descriptions-two-electric-boogaloo",
|
||||
"repo-tools-boo-descriptions",
|
||||
"repo-tools-ci-toldya-so",
|
||||
"rotten-bees-wave",
|
||||
"rude-dolphins-reply",
|
||||
"short-planets-argue",
|
||||
"silent-icons-deny",
|
||||
"silent-numbers-retire",
|
||||
"silly-emus-remain",
|
||||
"six-radios-smile",
|
||||
"six-wolves-admire",
|
||||
"slow-ducks-hunt",
|
||||
"slow-queens-visit",
|
||||
"smart-islands-jog",
|
||||
"stale-points-breathe",
|
||||
"strange-frogs-count",
|
||||
"stupid-ants-change",
|
||||
"sweet-hairs-complain",
|
||||
"sweet-pens-hunt",
|
||||
"swift-frogs-drop",
|
||||
"tall-countries-float",
|
||||
"tall-items-clap",
|
||||
"tall-peas-visit",
|
||||
"tame-jokes-do",
|
||||
"tender-garlics-report",
|
||||
"thick-pets-drive",
|
||||
"thin-dryers-repeat",
|
||||
"three-hounds-wonder",
|
||||
"tricky-melons-fold",
|
||||
"twelve-elephants-pay",
|
||||
"twenty-worms-enjoy",
|
||||
"warm-llamas-bake",
|
||||
"warm-panthers-lick",
|
||||
"weak-tomatoes-dance",
|
||||
"wet-donuts-fry",
|
||||
"wise-tables-add",
|
||||
"witty-ants-cover",
|
||||
"witty-pans-flash",
|
||||
"yellow-trains-protect",
|
||||
"yellow-yaks-behave",
|
||||
"young-ants-nail",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@backstage/plugin-home-react': patch
|
||||
'@backstage/plugin-home': patch
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Updated dependency `@rjsf/utils` to `5.13.0`.
|
||||
Updated dependency `@rjsf/core-v5` to `npm:@rjsf/core@5.13.0`.
|
||||
Updated dependency `@rjsf/material-ui-v5` to `npm:@rjsf/material-ui@5.13.0`.
|
||||
Updated dependency `@rjsf/validator-ajv8` to `5.13.0`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
When running `version:bump` it will now log duplicates instead of throwing an error
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-vault-backend': patch
|
||||
'@backstage/plugin-vault': patch
|
||||
---
|
||||
|
||||
Added ability to override vault secret engine value on catalog entity level using annotation `vault.io/secrets-engine`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-tech-radar': patch
|
||||
---
|
||||
|
||||
Fixed `RadarTimeline` text formatting.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Improved the `parseEntityRef` Scaffolder filter by introducing the ability for users to provide default kind and/or namespace values. The filter now takes
|
||||
2 arguments, similarly to the original [parseEntityRef](https://github.com/backstage/backstage/blob/v1.17.2/packages/catalog-model/src/entity/ref.ts#L77).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Removed the experimental `package fix` command that was used to automatically add dependencies to `package.json`, but has since been replaced by the `no-undeclared-imports` rule from `@backstage/eslint-plugin`.
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-gitlab': minor
|
||||
---
|
||||
|
||||
Fix Gitlab.com user ingestion by scoping GitlabOrgDiscoveryEntityProvider to a group.
|
||||
|
||||
**BREAKING** The `group` parameter is now required Gitlab.com Org Data integrations and the backend will fail to start without this option configured.
|
||||
|
||||
```diff
|
||||
catalog:
|
||||
providers:
|
||||
gitlab:
|
||||
yourProviderId:
|
||||
host: gitlab.com
|
||||
orgEnabled: true
|
||||
+ group: org/teams
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
adding a .zip download to dry run results page, including zip.js as dependency
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
**DEPRECATION**: Deprecated `ScaffolderEntitiesProcessor`, which should now instead be imported from `@backstage/plugin-catalog-backend-module-scaffolder-entity-model`.
|
||||
|
||||
`catalogModuleTemplateKind` was also moved to that package and renamed to `catalogModuleScaffolderEntityModel`, without any deprecation since it was an alpha export.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-scaffolder-entity-model': minor
|
||||
---
|
||||
|
||||
Added a dedicated module to collect the `ScaffolderEntitiesProcessor` and `catalogModuleTemplateKind`.
|
||||
@@ -448,3 +448,5 @@ zoomable
|
||||
zsh
|
||||
Pulumi
|
||||
Lightsail
|
||||
PR
|
||||
rebasing
|
||||
@@ -98,6 +98,9 @@ jobs:
|
||||
- name: verify api reference
|
||||
run: node scripts/verify-api-reference.js
|
||||
|
||||
- name: verify catalog-info.yaml consistency
|
||||
run: yarn backstage-repo-tools generate-catalog-info --ci
|
||||
|
||||
- name: lint openapi yaml files
|
||||
run: yarn backstage-repo-tools schema openapi lint
|
||||
|
||||
|
||||
+287
-31
@@ -10,11 +10,83 @@ Backstage is released under the Apache 2.0 License, and original creations contr
|
||||
|
||||
You can find out more about the types of contributions over at [getting involved](https://backstage.io/docs/getting-started/getting-involved)!
|
||||
|
||||
If you need help, just jump into our [Discord chatroom](https://discord.gg/backstage-687207715902193673).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project adheres to the [CNCF Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code.
|
||||
|
||||
[code-of-conduct]: https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md
|
||||
|
||||
## Security Issues?
|
||||
|
||||
See [SECURITY](SECURITY.md).
|
||||
|
||||
## Accessibility
|
||||
|
||||
We encourage you to catch any accessibility issues already in the development phase of new features to Backstage, see our [Accessibility documentation](https://backstage.io/docs/accessibility/) for more details.
|
||||
|
||||
## Get Started!
|
||||
|
||||
So...feel ready to jump in? Let's do this. 👏🏻💯
|
||||
|
||||
Start by reading our [Getting Started for Contributors](https://backstage.io/docs/getting-started/contributors) page to get yourself setup with a fresh copy of Backstage ready for your contributions. If you need help, just jump into our [Discord chatroom](https://discord.gg/backstage-687207715902193673).
|
||||
### Cloning the Repository
|
||||
|
||||
Ok. So you're gonna want some code right? Go ahead and fork the repository into your own GitHub account and clone that code to your local machine. GitHub's [Fork a repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo) documentation has a great step by step guide if you are not sure how to do this.
|
||||
|
||||
If you cloned a fork, you can add the upstream dependency like so:
|
||||
|
||||
```bash
|
||||
git remote add upstream git@github.com:backstage/backstage
|
||||
git pull upstream master
|
||||
```
|
||||
|
||||
After you have cloned the Backstage repository, you should run the following commands once to set things up for development:
|
||||
|
||||
```bash
|
||||
cd backstage # change to root directory of project
|
||||
|
||||
yarn install # fetch dependency packages - may take a while
|
||||
yarn tsc # does a first run of type generation and checks
|
||||
```
|
||||
|
||||
### Serving the Example App
|
||||
|
||||
Open a terminal window and start the web app by using the following command from the project root. Make sure you have run the above mentioned commands first.
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
This is going to start two things, the frontend (:3000) and the backend (:7007).
|
||||
|
||||
This should open a local instance of Backstage in your browser, otherwise open one of the URLs printed in the terminal.
|
||||
|
||||
By default, Backstage will start on port 3000, however you can override this by setting an environment variable `PORT` on your local machine. e.g. `export PORT=8080` then running `yarn start`. Or `PORT=8080 yarn start`.
|
||||
|
||||
Once successfully started, you should see the following message in your terminal window:
|
||||
|
||||
```sh
|
||||
$ concurrently "yarn start" "yarn start-backend"
|
||||
$ yarn workspace example-app start
|
||||
$ yarn workspace example-backend start
|
||||
$ backstage-cli app:serve
|
||||
$ backstage-cli backend:dev
|
||||
[0] Loaded config from app-config.yaml
|
||||
[1] Build succeeded
|
||||
[0] ℹ 「wds」: Project is running at http://localhost:3000/
|
||||
[0] ℹ 「wds」: webpack output is served from /
|
||||
[0] ℹ 「wds」: Content not from webpack is served from $BACKSTAGE_DIR/packages/app/public
|
||||
[0] ℹ 「wds」: 404s will fallback to /index.html
|
||||
[0] ℹ 「wdm」: wait until bundle finished: /
|
||||
[1] 2021-02-12T20:58:17.614Z backstage info Loaded config from app-config.yaml
|
||||
```
|
||||
|
||||
You'll see how you get both logs for the frontend `webpack-dev-server` which serves the react app ([0]) and the backend ([1]);
|
||||
|
||||
Visit <http://localhost:3000> and you should see the bleeding edge of Backstage ready for contributions!
|
||||
|
||||
If you want to get a better understanding of the layout of the repo not that you have a local copy running feel free to review the [Backstage Project Structure](https://backstage.io/docs/getting-started/project-structure) documentation.
|
||||
|
||||
## Coding Guidelines
|
||||
|
||||
@@ -28,6 +100,163 @@ Also be sure to skim through our [ADRs](docs/architecture-decisions) to see if t
|
||||
|
||||
If there are any updates in `markdown` file please make sure to run `yarn run lint:docs`. Though it is checked on `lint-staged`. It is required to install [vale](https://docs.errata.ai/vale/install) separately and make sure it is accessed by global command.
|
||||
|
||||
### Editor
|
||||
|
||||
The Backstage development environment does not require any specific editor, but it is intended to be used with one that has built-in linting and type-checking. The development server does not include any checks by default, but they can be enabled using the `--check` flag. Note that using the flag may consume more system resources and slow things down.
|
||||
|
||||
## Package Scripts
|
||||
|
||||
There are many commands to be found in the root [package.json](https://github.com/backstage/backstage/blob/master/package.json), here are some useful ones:
|
||||
|
||||
```shell
|
||||
yarn start # Start serving the example app, use --check to include type checks and linting
|
||||
|
||||
yarn storybook # Start local storybook, useful for working on components in @backstage/core-components
|
||||
|
||||
yarn workspace @backstage/plugin-api-docs start # Serve api-docs plugin only, also supports --check
|
||||
|
||||
yarn tsc # Run typecheck, use --watch for watch mode
|
||||
yarn tsc:full # Run full type checking, for example without skipLibCheck, use in CI
|
||||
|
||||
yarn build:backend # Build the backend package, depends on tsc
|
||||
yarn build:all # Build published versions of packages, depends on tsc
|
||||
yarn build:api-reports # Build API Reports used for documentation
|
||||
|
||||
yarn lint # lint packages that have changed since later commit on origin/master
|
||||
yarn lint:all # lint all packages
|
||||
yarn lind:docs # lint all the Markdown files
|
||||
yarn lint:type-deps # verify that @types/* dependencies are placed correctly in packages
|
||||
|
||||
yarn test # test packages that have changed since later commit on origin/master
|
||||
yarn test:all # test all packages
|
||||
|
||||
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 new # Create a new module
|
||||
```
|
||||
|
||||
> See [package.json](https://github.com/backstage/backstage/blob/master/package.json) for other yarn commands/options.
|
||||
|
||||
## Local configuration
|
||||
|
||||
Backstage allows you to specify the configuration used while running the application on your computer. Local configuration is read from `app-config.local.yaml`. This file is ignored by Git, which means that you can safely use it to reference secrets like GitHub tokens without worrying about these secrets, inadvertently ending up in the Git repository. You do not need to copy everything from the default config to the local config. The `app-config.local.yaml` file will be merged with `app-config.yaml` and overwrite the default app configs.
|
||||
|
||||
> NOTE: If you want to add your own configuration values to access in the frontend you also need to mark those values as visible using configuration schema, either in the app or in your own plugin. For more information, see [Defining Configuration](https://backstage.io/docs/conf/defining/).
|
||||
|
||||
You can learn more about the local configuration in the [Static Configuration in Backstage](https://backstage.io/docs/conf/) section.
|
||||
|
||||
## Creating Changesets
|
||||
|
||||
We use [changesets](https://github.com/atlassian/changesets) to help us prepare releases. They help us make sure that every package affected by a change gets a proper version number and an entry in its `CHANGELOG.md`. To make the process of generating releases easy, it helps when contributors include changesets with their pull requests.
|
||||
|
||||
### When to use a changeset?
|
||||
|
||||
Any time a patch, minor, or major change aligning to [Semantic Versioning](https://semver.org) is made to any published package in `packages/` or `plugins/`, a changeset should be used. It helps to align your change to the [Backstage package versioning policy](https://backstage.io/docs/overview/versioning-policy#package-versioning-policy) for the package you are changing, for example, when to provide additional clarity on deprecation or impacting changes which will then be included into CHANGELOGs.
|
||||
|
||||
In general, changesets are only needed for changes to packages within `packages/` or `plugins/` directories, and only for the packages that are not marked as `private`. Changesets are also not needed for changes that do not affect the published version of each package, for example changes to tests or in-line source code comments.
|
||||
|
||||
Changesets **are** needed for new packages, as that is what triggers the package to be part of the next release. They are also needed for changes to `README.md` files so that the updates are reflected on the NPM page for the changed package.
|
||||
|
||||
### How to create a changeset
|
||||
|
||||
1. Run `yarn changeset` from the root of the repo
|
||||
2. Select which packages you want to include a changeset for
|
||||
3. Select impact of the change you're introducing. If the package you are changing is at version `0.x`, use `minor` for breaking changes and `patch` otherwise. If the package is at `1.0.0` or higher, use `major` for breaking changes, `minor` for backwards compatible API changes, and `patch` otherwise. See the [Semantic Versioning specification](https://semver.org/#semantic-versioning-specification-semver) for more details.
|
||||
4. Explain your changes in the generated changeset. See [examples of well written changesets](#writing-changesets).
|
||||
5. Add generated changeset to Git
|
||||
6. Push the commit with your changeset to the branch associated with your PR
|
||||
7. Accept our gratitude for making the release process easier on the maintainers
|
||||
|
||||
### Writing changesets
|
||||
|
||||
Changesets are an important part of the development process. They are used to generate Changelog entries for all changes to the project. Ultimately they are read by the end users to learn about important changes and fixes to the project. Some of these fixes might require manual intervention from users so it's important to write changesets that users understand and can take action on.
|
||||
|
||||
Here are some important do's and don'ts when writing changesets:
|
||||
|
||||
### Changeset should give a clear description to what has changed
|
||||
|
||||
#### Bad
|
||||
|
||||
```md
|
||||
---
|
||||
'@backstage/catalog': patch
|
||||
---
|
||||
|
||||
Fixed table layout
|
||||
```
|
||||
|
||||
#### Good
|
||||
|
||||
```md
|
||||
---
|
||||
'@backstage/catalog': patch
|
||||
---
|
||||
|
||||
Fixed bug in EntityTable component where table layout did not readjust properly below 1080x768 pixels.
|
||||
```
|
||||
|
||||
### Breaking changes not caught by the type checker should be clearly marked with bold **BREAKING** text
|
||||
|
||||
#### Bad
|
||||
|
||||
```md
|
||||
---
|
||||
'@backstage/catalog': minor
|
||||
---
|
||||
|
||||
getEntity is now a function that returns a Promise.
|
||||
```
|
||||
|
||||
#### Good
|
||||
|
||||
```md
|
||||
---
|
||||
'@backstage/catalog': minor
|
||||
---
|
||||
|
||||
**BREAKING** The getEntity function now returns a Promise and **must** be awaited from now on.
|
||||
```
|
||||
|
||||
### Changes to code should include a diff of the files that need updating
|
||||
|
||||
#### Bad
|
||||
|
||||
```md
|
||||
---
|
||||
'@backstage/catalog': patch
|
||||
---
|
||||
|
||||
**BREAKING** The catalogEngine now requires a flux capacitor to be passed.
|
||||
```
|
||||
|
||||
#### Good
|
||||
|
||||
````md
|
||||
---
|
||||
'@backstage/catalog': patch
|
||||
---
|
||||
|
||||
**BREAKING** The catalog createRouter now requires that a `FluxCapacitor` is
|
||||
passed to the router.
|
||||
|
||||
These changes are **required** to `packages/backend/src/plugins/catalog.ts`
|
||||
|
||||
```diff
|
||||
+ import { FluxCapacitor } from '@backstage/time';
|
||||
+ const fluxCapacitor = new FluxCapacitor();
|
||||
return await createRouter({
|
||||
entitiesCatalog,
|
||||
locationAnalyzer,
|
||||
locationService,
|
||||
+ fluxCapacitor,
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
});
|
||||
```
|
||||
````
|
||||
|
||||
## Developer Certificate of Origin
|
||||
|
||||
As with other CNCF projects, Backstage has adopted a [Developers Certificate of Origin (DCO)](https://developercertificate.org/). A DCO is a lightweight way for a developer to certify that they wrote or otherwise have the right to submit code or documentation to a project.
|
||||
@@ -62,44 +291,71 @@ Signed-off-by: Jane Smith <jane.smith@example.com>
|
||||
|
||||
In case you forgot to add the line to your most recent commit, you can amend the commit message from the History tab before pushing your branch (GitHub Desktop 2.9 or later).
|
||||
|
||||
## Creating Changesets
|
||||
## API Reports
|
||||
|
||||
We use [changesets](https://github.com/atlassian/changesets) to help us prepare releases. They help us make sure that every package affected by a change gets a proper version number and an entry in its `CHANGELOG.md`. To make the process of generating releases easy, it helps when contributors include changesets with their pull requests.
|
||||
Backstage uses [API Extractor](https://api-extractor.com/) and TSDoc comments to generate API Reports in Markdown format. These reports are what drive the [API Reference documentation](https://backstage.io/docs/reference/). What this means is that if you are making changes to the API or adding a new plugin then you will need either generate a new API Report or update an existing API Report. If you don't do this the CI build will fail when you create your Pull Request.
|
||||
|
||||
### When to use a changeset?
|
||||
There are two ways you can do this:
|
||||
|
||||
Any time a patch, minor, or major change aligning to [Semantic Versioning](https://semver.org) is made to any published package in `packages/` or `plugins/`, a changeset should be used. It helps to align your change to the [Backstage package versioning policy](https://backstage.io/docs/overview/versioning-policy#package-versioning-policy) for the package you are changing, for example, when to provide additional clarity on deprecation or impacting changes which will then be included into CHANGELOGs.
|
||||
1. You can run `yarn build:api-reports` from the root of the project and it will go through all of the existing API Reports and update them or create new ones as needed. This may take a while but is generally the best method if you are new to this.
|
||||
2. You can run `yarn build:api-reports plugins/<your-plugin-with-changes>` from the root and it will update the existing API Report or create a new one.
|
||||
|
||||
In general, changesets are only needed for changes to packages within `packages/` or `plugins/` directories, and only for the packages that are not marked as `private`. Changesets are also not needed for changes that do not affect the published version of each package, for example changes to tests or in-line source code comments.
|
||||
> Note: the above commands assume you've run `yarn install` before hand or recently
|
||||
|
||||
Changesets **are** needed for new packages, as that is what triggers the package to be part of the next release.
|
||||
Each plugin/package has its own API Report which means you might see more then one file updated or created depending on your changes. These changes will then need to be committed as well.
|
||||
|
||||
### How to create a changeset
|
||||
## Submitting a Pull Request
|
||||
|
||||
1. Run `yarn changeset`
|
||||
2. Select which packages you want to include a changeset for
|
||||
3. Select impact of the change you're introducing. If the package you are changing is at version `0.x`, use `minor` for breaking changes and `patch` otherwise. If the package is at `1.0.0` or higher, use `major` for breaking changes, `minor` for backwards compatible API changes, and `patch` otherwise. See the [Semantic Versioning specification](https://semver.org/#semantic-versioning-specification-semver) for more details.
|
||||
4. Explain your changes in the generated changeset. See [examples of well written changesets](https://backstage.io/docs/getting-started/contributors#writing-changesets).
|
||||
5. Add generated changeset to Git
|
||||
6. Push the commit with your changeset to the branch associated with your PR
|
||||
7. Accept our gratitude for making the release process easier on the maintainers
|
||||
When you've got your contribution working, tested, and committed to your branch it's time to create a Pull Request (PR). If you are unsure how to do this GitHub's [Creating a pull request from a fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) documentation will help you with that. Once you create your PR you will be presented with a template in the PR's description that looks like this:
|
||||
|
||||
For more information, check out [adding a changeset](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md) documentation in the changesets repository.
|
||||
```md
|
||||
## Hey, I just made a Pull Request!
|
||||
|
||||
## Merging to Master
|
||||
<!-- Please describe what you added, and add a screenshot if possible.
|
||||
That makes it easier to understand the change so we can :shipit: faster. -->
|
||||
|
||||
#### :heavy_check_mark: Checklist
|
||||
|
||||
<!--- Please include the following in your Pull Request when applicable: -->
|
||||
|
||||
- [ ] A changeset describing the change and affected packages. ([more info](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#creating-changesets))
|
||||
- [ ] Added or updated documentation
|
||||
- [ ] Tests for new functionality and regression tests for bug fixes
|
||||
- [ ] Screenshots attached (for UI changes)
|
||||
- [ ] All your commits have a `Signed-off-by` line in the message. ([more info](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#developer-certificate-of-origin))
|
||||
```
|
||||
|
||||
From here all you need to do is fill in the information as requested by the template. Please do not remove this as it helps both you and the reviewers confirm that the various tasks have been completed.
|
||||
|
||||
Here are some examples of good PR descriptions:
|
||||
|
||||
- <https://github.com/backstage/backstage/pull/19473>
|
||||
- <https://github.com/backstage/backstage/pull/19623>
|
||||
- <https://github.com/backstage/backstage/pull/15881>
|
||||
- <https://github.com/backstage/backstage/pull/16401>
|
||||
|
||||
## Review Process
|
||||
|
||||
Once you've submitted a Pull Request (PR) the various bots will come out and do their work:
|
||||
|
||||
- assigning reviewers from the various areas impacted by changes in your PR
|
||||
- adding labels to help make reviewing PRs easier
|
||||
- checking for missing changesets or confirming them
|
||||
- checking for commits for their DCO (Developer Certificate of Origin)
|
||||
- kick of the various CI builds
|
||||
|
||||
Once these have been completed it's just a matter of being patient as the reviewers have time they will begin to review your PR. When the review begins there may be a few layers to this but the general rule is that you need approval from one of the core maintainers and one from the specific area impacted by your PR. You may also have someone from the community review your changes, this can really help speed things up as they may catch some early items making the review for the maintainers simpler. Once you have the two (2) approvals it's ready to be merged, this task is also done by the maintainers.
|
||||
|
||||
### Review Tips
|
||||
|
||||
Here are a few things that can help as you go through the review process:
|
||||
|
||||
- You'll want to make sure all the automated checks are passing as generally the PR won't get a review if something like the CI build is failing
|
||||
- PRs get automatically assigned so you don't need to ping people, they will be notified and have a process of their own for this
|
||||
- If you are waiting for a review or mid-review and your PR goes stale one of the easiest ways to clear the stale bot is by simply rebasing your PR
|
||||
- There are times where you might run into conflict with the `yarn.lock` during a rebase, to help with that make sure your `master` branch is up to date and then in your branch run `git checkout master yarn.lock` and then run `yarn install`, this will get you a conflict free `yarn.lock` file you can commit
|
||||
- If Vale finds issues with your documentation but it's a code reference you can fix it by putting backticks (`) around it. Now if it is a special word or maybe a name there are two ways you can fix that by adding it to the list of accepted words in the [accept.txt file](https://github.com/backstage/backstage/blob/master/.github/vale/Vocab/Backstage/accept.txt) and them committing that change
|
||||
|
||||
### Merging to Master
|
||||
|
||||
For those contributors who have earned write access to the repository, when a pull request is approved, in general we prefer the author of the PR to perform the merge themselves. This allows them to own accountability for the change and they likely know best how or when to address pending fixes or additional follow-ups. In this way, we all help contribute to the project's successful outcomes.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project adheres to the [CNCF Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code.
|
||||
|
||||
[code-of-conduct]: https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md
|
||||
|
||||
## Security Issues?
|
||||
|
||||
See [SECURITY](SECURITY.md).
|
||||
|
||||
## Accessibility
|
||||
|
||||
We encourage you to catch any accessibility issues already in the development phase of new features to Backstage, see our [Accessibility documentation](./docs/accessibility/index.md) for more details.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<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="<mxfile scale="1.5" border="20"><diagram id="gKBvn7eBFHudv9VMIRD-" name="Page-1">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=</diagram></mxfile>" 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="<mxfile scale="1.5" border="20"><diagram id="gKBvn7eBFHudv9VMIRD-" name="Page-1">3Vldb9owFP01PBblCyiPHaXdHiZVYtPaRzcxiVVjI8dA6K+fHTuJEzOahZQiUqmKj79y7zn3+iYM/Nkqe2RgnfykEcQDz4mygX8/8Lxg6on/EtgrYORNFBAzFCnIrYAFeocadDS6QRFMawM5pZijdR0MKSEw5DUMMEZ39WFLiuu7rkEMLWARAmyjf1DEE4X6gVPh3yGKk2LnW93xCsK3mNEN0dsNPH+ZX6p7BYql9Pg0ARHdGZA/H/gzRilXd6tsBrH0bOE1Ne/hH73lYzNIeJsJmqYtwBtt+TdhASRRqp+P7wuX5FZBOc8Z+N92CeJwsQah7N0JDQgs4SssWq64XSKMZxRTls/152P5J/CUM/oGjZ5xfskZlHADV5fAbYu0kVvIOMwMSFv4COkKcrYXQ3Tvja+9rcV4U3h/V1EbOBpLDFoLuoFWU1wuXblU3GivHvawb3l4AdkWhfCaPOw2PDyxHXz7Sf6dWv59YnQrsoflXhiJENdNQgms+xNmiD8b9y+ShuFIt+4zzUre2BcNEt3JZCOar5iGb78SRBT8gHC5MCnyW5DTAxg32nXOJUW6c3qMmZRuWKjNCnR6BCyGetRIQdLgo+wxiAFH23rOO0SGnvpEkXiQaghdLlOxZ5OtcodWBLp2DvqddmXPGU5GJoEf0Cce8tlsGKTLZjUtb30a7TLQkDh87jCKxUr3KxRFOLeQMvQuNAHKqO9HIH5LgejwdoaO492qORehmcAOeryJEbmmnNo8tcoce4akOrL8O884JCmiRMA5pdfk6ubxdU5XFxVvbweYY+a/Kh1+zQlWpli3nmInH+XYVpltfIajrzWPdqF3yjHmdTjGGj4++zHW5XA6QGHbw6l3CscWg+K9doOvqlL3pl+X6sqnrRz8gwhJyUEdw8SZTo04cYdO0LLiq6Ljxey7+IpPmvMEGRLOh+x/cqVnB1rQd6C1LvmqMVldXoUqm3JTluhJR9Zxmws5jYWU/dZCHWrQA99OOqr5KkSpDGhEo3c8GnvU8vhytOw3qsmuWvY+iIkepWzXLh1r0CuSslmAuUd1HIE0yXd2TxBw71XPCQJuJFFf1OtT4xqNugm6ue5nKtr+QjA7oc6ovVJ5l/lK5bV7pWoIrPM7Vn/KLNThNNQxkZ+dqsvtJjr19cpapt0mnQUpmtWPOGp49TuZP/8L</diagram></mxfile>" style="background-color: rgb(255, 255, 255);">
|
||||
<defs/>
|
||||
<g>
|
||||
<rect x="19.5" y="19.5" width="600" height="60" fill="#e6e6e6" stroke="#666666" stroke-width="1.5" pointer-events="all"/>
|
||||
@@ -105,21 +105,21 @@
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<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"/>
|
||||
<path d="M 499.5 289.5 L 388.68 289.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 381.18 289.5 L 388.68 287 L 388.68 292 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: 183px; margin-left: 293px;">
|
||||
<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: 193px; 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
|
||||
Provide
|
||||
</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 x="293" y="196" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Provide
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
@@ -171,7 +171,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</foreignObject>
|
||||
<text x="53" y="112" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
<text x="53" y="111" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Install
|
||||
</text>
|
||||
</switch>
|
||||
@@ -181,7 +181,7 @@
|
||||
<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 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: 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
|
||||
@@ -212,6 +212,24 @@
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 499.5 259.5 L 388.68 259.5" fill="none" stroke="rgb(0, 0, 0)" stroke-width="1.5" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||
<path d="M 381.18 259.5 L 388.68 257 L 388.68 262 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: 173px; 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="176" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="9px" text-anchor="middle">
|
||||
Call
|
||||
</text>
|
||||
</switch>
|
||||
</g>
|
||||
</g>
|
||||
<switch>
|
||||
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 21 KiB |
+7
-7
@@ -10,6 +10,13 @@ configure Backstage to have any number of authentication providers, but only
|
||||
one of these will typically be used for sign-in, with the rest being used to provide
|
||||
access to external resources.
|
||||
|
||||
> NOTE: Identity management and the Sign-In page in Backstage is NOT a method for blocking
|
||||
> access for unauthorized users. The identity system only serves to provide a personalized
|
||||
> experience and access to a Backstage Identity Token, which can be passed to backend plugins.
|
||||
> This also means that your Backstage backend APIs are by default unauthenticated.
|
||||
> Thus, if your Backstage instance is exposed to the Internet, anyone can access
|
||||
> information in the Backstage. You can learn more [here](../overview/threat-model.md#integrator-responsibilities).
|
||||
|
||||
## Built-in Authentication Providers
|
||||
|
||||
Backstage comes with many common authentication providers in the core library:
|
||||
@@ -60,13 +67,6 @@ the local `auth.environment` setting will be selected.
|
||||
|
||||
## Sign-In Configuration
|
||||
|
||||
> NOTE: Identity management and the `SignInPage` in Backstage is NOT a method
|
||||
> for blocking access for unauthorized users, that either requires additional
|
||||
> backend implementation or a separate service like Google's Identity-Aware
|
||||
> Proxy. The identity system only serves to provide a personalized experience
|
||||
> and access to a Backstage Identity Token, which can be passed to backend
|
||||
> plugins.
|
||||
|
||||
Using an authentication provider for sign-in is something you need to configure
|
||||
both in the frontend app, as well as the `auth` backend plugin. For information
|
||||
on how to configure the backend app, see [Sign-in Identities and Resolvers](./identity-resolver.md).
|
||||
|
||||
@@ -43,15 +43,15 @@ Services are also a customization point for individual backend installations. Yo
|
||||
|
||||
Many plugins have ways in which you can extend them, for example entity providers for the Catalog, or custom actions for the Scaffolder. These extension patterns are now encoded into Extension Points.
|
||||
|
||||
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 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 or modules themselves, based on what customizations each of them want 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 deprecate individual Extension Points over time, rather than dealing with a single large API surface.
|
||||
Extension Points are exported separately from the plugin or module instance itself, and it is possible to 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
|
||||
|
||||
Modules use the plugin Extension Points to add new features for plugins. They might for example add an individual Catalog Entity Provider, or one or more Scaffolder Actions. Modules are basically plugins for plugins.
|
||||
Modules use Extension Points to add new features to other plugins or modules. They might for example add an individual Catalog Entity Provider, or one or more Scaffolder Actions.
|
||||
|
||||
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.
|
||||
Each module may only use Extension Points that belong to a single plugin, and the module must be deployed together with that plugin in the same backend instance. Modules may only communicate with their plugin or other modules through the 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.
|
||||
|
||||
|
||||
@@ -17,24 +17,27 @@ Below is a simple example of a backend that installs only the catalog plugin and
|
||||
|
||||
```ts
|
||||
import { createBackend } from '@backstage/backend-defaults';
|
||||
import { catalogPlugin } from '@backstage/plugin-catalog-backend';
|
||||
import scaffolderPlugin from '@backstage/plugin-scaffolder-backend';
|
||||
|
||||
// Create your backend instance
|
||||
const backend = createBackend();
|
||||
|
||||
// Install all desired features
|
||||
backend.add(catalogPlugin());
|
||||
// Install desired features
|
||||
backend.add(import('@backstage/plugin-catalog-backend'));
|
||||
|
||||
// Features can also be installed using an explicit reference
|
||||
backend.add(scaffolderPlugin());
|
||||
|
||||
// Start up the backend
|
||||
await backend.start();
|
||||
backend.start();
|
||||
```
|
||||
|
||||
`createBackend` is responsible for creating your backend instance, and wiring up all the services that you have provided. It deals with creating default implementations of all the [core services](../core-services/01-index.md) that are used by the plugins, and also provides a way to override the default implementations with your own. You can read more about creating services and overriding them in the [building backends docs](../building-backends/01-index.md).
|
||||
We call `createBackend` to create a new backend instance, which is responsible for wiring together all of the features that we provide to the app. It also provides default implementations of all [core services](../core-services/01-index.md) for use in plugins. No real work is done at the point of creating the backend though, it's all deferred to the `backend.start()` call.
|
||||
|
||||
The backend instance has the ability to add features to the backend which are done using the `.add` method. Features are either plugins or modules, and you can read more about them in the [building plugins and modules docs](../building-plugins-and-modules/01-index.md). By default, a backend instance has no default features, and the services are responsible for wiring everything together.
|
||||
To add any feature to a backend instance you use the `.add(...)` method. Features are either plugins, modules, or service factories. You can read more about building plugins and modules in the [building plugins and modules docs](../building-plugins-and-modules/01-index.md), as well as how to install services factories in the [building backends docs](../building-backends/01-index.md).
|
||||
|
||||
At a high level, when you call `createBackend`, it will create a new backend instance, which has a registry of all the services that are currently registered, and by adding features to the backend instance and calling the `.start()` method it will ensure that all the dependencies are wired up correctly and the `registerInit` methods are called in the correct order.
|
||||
Once you have added all desired features we call the `.start()` method. This causes the backend to start up and initialize all features. When starting up the backend will validate all features to make sure that there are no conflicts. For example making sure that there are no circular dependencies.
|
||||
|
||||
Underneath the hood, `createBackend` calls `createSpecializedBackend` from `@backstage/backend-app-api` which is responsible for actually creating the backend instance, but with no services or no features. You can think of `createBackend` more of a 'batteries included' approach, and `createSpecializedBackend` a little more low level.
|
||||
Underneath the hood, `createBackend` calls `createSpecializedBackend` from `@backstage/backend-app-api` which is responsible for actually creating the backend instance, without any services or features. You can think of `createBackend` more of a 'batteries included' approach, while `createSpecializedBackend` is more low level.
|
||||
|
||||
As mentioned previously there's also the ability to create multiple of these backends in your project so that you can split apart your backend and deploy different backends that can scale independently of each other. For instance you might choose to deploy a backend with only the catalog plugin enabled, and one with just the scaffolder plugin enabled.
|
||||
|
||||
@@ -88,42 +88,6 @@ export const fooServiceFactory = createServiceFactory({
|
||||
|
||||
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: [fooServiceFactory()],
|
||||
});
|
||||
```
|
||||
|
||||
Note that we call `fooServiceFactory` 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 fooServiceFactory = 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: [fooServiceFactory({ 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.
|
||||
@@ -227,3 +191,40 @@ Note that we don't use the `fooServiceRef` when creating our service factory, bu
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
## Service Factory Options
|
||||
|
||||
> NOTE: This pattern is discouraged, only use it when necessary. If possible you should prefer to make services configurable via static configuration instead.
|
||||
|
||||
When declaring a service factory it's possible to include an options callback. This allows you to customize the factory through code when installing it in the backend. For example, this is how you install an explicit factory instance in the backend without any options:
|
||||
|
||||
```ts
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(fooServiceFactory());
|
||||
```
|
||||
|
||||
Note that we call `fooServiceFactory` to create the service factory instance. This is because `createServiceFactory` always returns a factory function that creates the actual service factory. To add options to your service factory, you wrap the object passed to `createServiceFactory` in a callback that accepts the desired options. Note that the options must always be optional. For example:
|
||||
|
||||
```ts
|
||||
export interface FooFactoryOptions {
|
||||
transform: (foo: string) => string;
|
||||
}
|
||||
|
||||
export const fooServiceFactory = createServiceFactory(
|
||||
(options?: FooFactoryOptions) => ({
|
||||
service: fooServiceRef,
|
||||
factory() {
|
||||
return new DefaultFooService(options?.transform);
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
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();
|
||||
|
||||
backend.add(fooServiceFactory({ transform: foo => foo.toUpperCase() }));
|
||||
```
|
||||
|
||||
@@ -41,44 +41,32 @@ The `env` object passed to the `register` callback contains different methods th
|
||||
The `createBackendPlugin` return value is exported as `examplePlugin`, which is a factory function used to create the actual plugin instance. For example, to install the plugin in your backend instance, you would do the following:
|
||||
|
||||
```ts
|
||||
import { examplePlugin } from 'backstage-plugin-example-backend';
|
||||
|
||||
backend.add(examplePlugin());
|
||||
```
|
||||
|
||||
The reason for why our plugin instance has been wrapped up in a factory function is so that you can always chose to add options to your plugin in the future, without breaking existing usage. To add options you wrap the object passed to `createBackendPlugin` in a callback that accepts the desired options. For example:
|
||||
By convention every plugin package should export its plugin instance as the default export from the package:
|
||||
|
||||
```ts
|
||||
export interface ExamplePluginOptions {
|
||||
skipHello: boolean;
|
||||
}
|
||||
|
||||
export const examplePlugin = createBackendPlugin(
|
||||
(options?: ExamplePluginOptions) => ({
|
||||
pluginId: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
async init({ logger }) {
|
||||
if (!options?.skipHello) {
|
||||
logger.info('Hello from example plugin');
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
// plugins/example-backend/src/index.ts
|
||||
export { examplePlugin as default } from './plugin.ts';
|
||||
```
|
||||
|
||||
Now your plugin accepts an optional options object, which can be used to configure each plugin instance. To supply options to the plugin, you pass them to the plugin factory method:
|
||||
This allows you to install the plugin in your backend instance by just referencing the package:
|
||||
|
||||
```ts
|
||||
backend.add(examplePlugin({ skipHello: true }));
|
||||
backend.add(import('backstage-plugin-example-backend'));
|
||||
```
|
||||
|
||||
It is also possible to make the options required, simply remove the `?` from the parameter declaration. This will be reflected in the returned factory function, which will now require the options parameter.
|
||||
To make your plugins customizable you should generally prefer to use [static configuration](../../conf/defining.md). By convention plugins should place their configuration under a top-level configuration key that matches the plugin ID. For example, our example plugin might be configured as follows:
|
||||
|
||||
Options are a simple way to allow for more lightweight customization of a plugin, but they do not allow for more complex extensions that require access to services. For that, you need to create and register extension points for your plugin, which are covered in the [next section](./05-extension-points.md).
|
||||
```yaml
|
||||
example:
|
||||
message: Welcome to the example plugin
|
||||
```
|
||||
|
||||
For situations where static configuration is too limiting, you can instead register extension points for your plugin. Extension Points are covered in the [next section](./05-extension-points.md).
|
||||
|
||||
## Rules of Plugins
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ description: Extension points of backend plugins
|
||||
|
||||
> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.**
|
||||
|
||||
While plugins are able to accept options for lightweight forms of customization and extension, you quickly hit a limit where you need something more powerful to allow users to extend your plugin. For this purpose, the backend system provides a mechanism for plugins to provide extension points, which can be used to expose deeper customizations for your plugin. Extension points are used by modules, which are installed in the backend adjacent to plugins. Modules are covered more in-depth in the [next section](./06-modules.md).
|
||||
While plugins are able to use static configuration for lightweight forms of customization, you can quickly hit a limit where you need something more powerful to allow users to extend your plugin. For this purpose, the backend system provides a mechanism for plugins to provide extension points, which can be used to expose deeper customizations for your plugin. Extension points are used by modules, which are installed in the backend adjacent to plugins. Modules are covered more in-depth in the [next section](./06-modules.md).
|
||||
|
||||
Extension points are quite similar to services, in that they both encapsulate an interface in a reference object. The key difference is that extension points are registered and provided by plugins themselves, and do not have any factory associated with them. Extension points for a given plugin are also only accessible to modules that extend that same plugin.
|
||||
|
||||
Extension points should always be exported from a plugin node library package, for example `@backstage/plugin-catalog-node`. This is to allow for modules to avoid a direct dependency on the plugin, and make it easier to evolve extension points over time. You can export as many different extension points as you want, just be mindful of the complexity of the API surface. It is however often better to export multiple extension points with few methods, rather than few extension points with many methods, as that tends to be easier to maintain.
|
||||
Plugin extension points should always be exported from a plugin node library package, for example `@backstage/plugin-catalog-node`. This is to allow for modules to avoid a direct dependency on the plugin, and make it easier to evolve extension points over time. You can export as many different extension points as you want, just be mindful of the complexity of the API surface. It is however often better to export multiple extension points with few methods, rather than few extension points with many methods, as that tends to be easier to maintain.
|
||||
|
||||
## Defining an Extension Point
|
||||
|
||||
@@ -36,28 +36,29 @@ export const scaffolderActionsExtensionPoint =
|
||||
For modules to be able to use your extension point, an implementation of it must be registered by the plugin. This is done using the `registerExtensionPoint` method in the `register` callback of the plugin definition.
|
||||
|
||||
```ts
|
||||
class ActionsExtension implements ScaffolderActionsExtensionPoint {
|
||||
addActions(...actions: TemplateAction<any>[]): void { ... }
|
||||
|
||||
getRegisteredActions() { ... }
|
||||
}
|
||||
|
||||
export const scaffolderPlugin = createBackendPlugin(
|
||||
{
|
||||
pluginId: 'scaffolder',
|
||||
register(env) {
|
||||
const actionsExtensions = new ActionsExtension();
|
||||
const actions = new Map<string, TemplateAction<any>>();
|
||||
|
||||
env.registerExtensionPoint(
|
||||
scaffolderActionsExtensionPoint,
|
||||
actionsExtensions,
|
||||
{
|
||||
addAction(action) {
|
||||
if (actions.has(action.id)) {
|
||||
throw new Error(`Scaffolder actions with ID '${action.id}' has already been installed`);
|
||||
}
|
||||
actions.set(action.id, action);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
env.registerInit({
|
||||
deps: { ... },
|
||||
async init({ ... }) {
|
||||
const actions = actionsExtension.getRegisteredActions();
|
||||
|
||||
// Use the registered actions when setting up the scaffolder ...
|
||||
const installedActions = Array.from(actions.values());
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -65,9 +66,11 @@ export const scaffolderPlugin = createBackendPlugin(
|
||||
);
|
||||
```
|
||||
|
||||
There are a couple of things to note here. The first is that our `ActionsExtension` class both implements the `ScaffolderActionsExtensionPoint` interface, but also has additional public methods. These methods won't be available to the modules that use this extension, but we can use them here in the implementation of our plugin. Note also that the `ActionsExtension` class is _not_ exported to the outside, since it's only for the internal use of this plugin during its setup phase.
|
||||
Note that we create a closure that adds to a shared `actions` structure when `addAction` is called by users of your extension point. It is safe for us to then access our `actions` in the `init` method of our plugin, since all modules that extend our plugin will be completely initialized before our plugin gets initialized. That means that at the point where our `init` method is called, all actions have been added and can be accessed.
|
||||
|
||||
The second is that we create our `ActionsExtension` instance within the `register` method, and then access it directly in our `init` method. This is both safe to do and an intended convenience. All modules that extend our plugin will be completely initialized before our plugin gets initialized, which means that at the point where our `init` method is called, all actions have been added and can be accessed.
|
||||
## Module Extension Points
|
||||
|
||||
Just like plugins, modules can also provide their own extension points. The API for registering and using extension points is the same as for plugins. However, modules should typically only use extension points to allow for complex internal customizations by users of the plugin module. It is therefore preferred to export the extension point directly from the module package, rather than creating a separate node library for that purpose.
|
||||
|
||||
## Extension Point Design
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ description: Modules for backend plugins
|
||||
|
||||
> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.**
|
||||
|
||||
Backend modules are used to extend [plugins](./04-plugins.md) with additional features or change existing behavior. They must always be installed in the same backend instance as the plugin that they extend, and may only extend a single plugin. Modules interact with their target plugin using the [extension points](./05-extension-points.md) registered by the plugin, while also being able to depend on the [services](./03-services.md) of that plugin.
|
||||
Backend modules are used to extend [plugins](./04-plugins.md) or sometimes other modules with additional features or change existing behavior. They must always be installed in the same backend instance as the plugin that they extend, and may only extend a single plugin. Modules interact with their target plugin using the [extension points](./05-extension-points.md) registered by the plugin, while also being able to depend on the [services](./03-services.md) of that plugin.
|
||||
|
||||
Both modules and plugins register an `init` method that is called during startup. In order to ensure that modules have registered all their extensions before the plugin starts up, all modules for each plugin are completely initialized before the plugin itself is initialized. In practice this means that all promises returned by each `init` method of the modules need to resolve before the plugin `init` method is called. This also means that it is not possible to further interact with the extension points once the `init` method has resolved.
|
||||
|
||||
@@ -19,6 +19,7 @@ A module depends on the extension points exported by the target plugin's library
|
||||
The following is an example on how to create a module that adds a new processor using the `catalogProcessingExtensionPoint`:
|
||||
|
||||
```ts
|
||||
// plugins/catalog-backend-module-example-processor/src/module.ts
|
||||
import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
|
||||
import { MyCustomProcessor } from './MyCustomProcessor';
|
||||
@@ -42,4 +43,19 @@ export const catalogModuleExampleCustomProcessor = createBackendModule({
|
||||
|
||||
Notice that we're placing the extension point we want to interact with in the `deps` option, while also depending on the logger service at the same time. When initializing modules we can depend on both extension points and services interchangeably. You can also depend on multiple extension points at once, in case the implementation of the module requires it.
|
||||
|
||||
It is typically best to keep modules slim and to each only add a single new feature. It is often the case that it is better to create two separate modules rather than one that provides both features. The one limitation here is that modules can not interact with each other and need to be self contained.
|
||||
Just like plugins there is a convention that every module package should export its module instance as the default export from the package:
|
||||
|
||||
```ts
|
||||
// plugins/catalog-backend-module-example-processor/src/index.ts
|
||||
export { catalogModuleExampleCustomProcessor as default } from './module.ts';
|
||||
```
|
||||
|
||||
This allows you to install the module in your backend instance by just referencing the package:
|
||||
|
||||
```ts
|
||||
backend.add(
|
||||
import('backstage-plugin-catalog-backend-module-example-processor'),
|
||||
);
|
||||
```
|
||||
|
||||
Each module package should only contain a single module, but this module may extend multiple extension points. A module may also use configuration to conditionally enable or disable certain extensions. This pattern should only be used for extensions that are related to each other, otherwise it is best to create a separate module package with its own module.
|
||||
|
||||
@@ -20,27 +20,23 @@ A minimal Backstage backend is very lightweight. It is a single package with a `
|
||||
When you create a new project with `@backstage/create-app`, you'll get a backend package with a `src/index.ts` that looks something like this:
|
||||
|
||||
```ts
|
||||
import { createBackend } from '@backstage/backend-defaults';
|
||||
import { appPlugin } from '@backstage/plugin-app-backend';
|
||||
import { catalogPlugin } from '@backstage/plugin-catalog-backend';
|
||||
import {
|
||||
scaffolderPlugin,
|
||||
catalogModuleTemplateKind,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
import { createBackend } from '@backstage/backend-defaults'; // Omitted in the examples below
|
||||
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(appPlugin());
|
||||
backend.add(catalogPlugin());
|
||||
backend.add(catalogModuleTemplateKind());
|
||||
backend.add(scaffolderPlugin());
|
||||
backend.add(import('@backstage/plugin-app-backend'));
|
||||
backend.add(import('@backstage/plugin-catalog-backend'));
|
||||
backend.add(import('@backstage/plugin-scaffolder-backend'));
|
||||
backend.add(
|
||||
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
|
||||
);
|
||||
|
||||
backend.start();
|
||||
```
|
||||
|
||||
There will be a couple more plugins and modules in the initial setup, but the overall layout is the same.
|
||||
|
||||
What we're doing in this file is creating a new backend using `createBackend`, and then installing a collection of different plugins and modules that we want to be part of that backend. Plugins are standalone features, while modules augment existing plugins. Each module can only target a single plugin, and that plugin must also be present in the same backend. Finally, we start up the backend by calling the `start` method.
|
||||
What we're doing in this file is creating a new backend using `createBackend`, and then installing a collection of different plugins, modules, and services that we want to be part of that backend. Plugins are standalone features, modules augment existing plugins or modules, while services can be used to override behavior for deeper customizations. Each module can only target a single plugin, and that plugin must also be present in the same backend. Finally, we start up the backend by calling the `start` method.
|
||||
|
||||
## Customization
|
||||
|
||||
@@ -63,13 +59,13 @@ For example, let's say we want to customize the core configuration service to en
|
||||
```ts
|
||||
import { rootConfigServiceFactory } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
rootConfigServiceFactory({
|
||||
remote: { reloadIntervalSeconds: 60 },
|
||||
}),
|
||||
],
|
||||
});
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(
|
||||
rootConfigServiceFactory({
|
||||
remote: { reloadIntervalSeconds: 60 },
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
This will make it possible to pass URLs as configuration targets, and those URLs will be polled every 60 seconds for changes.
|
||||
@@ -83,22 +79,22 @@ When overriding services you are not limited to the existing implementations, yo
|
||||
To override a service, you provide it in the `services` option just like above, but this time we need to use `createServiceFactory` to create our factory. For example, if you want to replace the default `LoggerService` with your own, it might look like this:
|
||||
|
||||
```ts
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
createServiceFactory({
|
||||
service: coreServices.logger,
|
||||
deps: {
|
||||
rootLogger: coreServices.rootLogger,
|
||||
plugin: coreServices.pluginMetadata,
|
||||
config: coreServices.config,
|
||||
},
|
||||
factory({ rootLogger, plugin, config }) {
|
||||
const labels = readCustomLogLabelsForPlugin(config, plugin); // custom logic
|
||||
return rootLogger.child(labels);
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(
|
||||
createServiceFactory({
|
||||
service: coreServices.logger,
|
||||
deps: {
|
||||
rootLogger: coreServices.rootLogger,
|
||||
plugin: coreServices.pluginMetadata,
|
||||
config: coreServices.rootConfig,
|
||||
},
|
||||
factory({ rootLogger, plugin, config }) {
|
||||
const labels = readCustomLogLabelsForPlugin(config, plugin); // custom logic
|
||||
return rootLogger.child(labels);
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
The `LoggerService` is responsible for creating a specialized logger instance for each plugin, while the `RootLoggerService` is the actual logging implementation. The default implementation of `LoggerService` will decorate the logger with a `plugin` label that contains the plugin ID. Here in our custom implementation we read out additional labels from the configuration and add those as well.
|
||||
@@ -128,22 +124,22 @@ packages/
|
||||
You can now trim down the `src/index.ts` files to only include the plugins and modules that you want to be part of that backend. For example, if you want to split out the scaffolder plugin, you might end up with something like this:
|
||||
|
||||
```ts
|
||||
// packages/backend-a/src/index.ts, imports omitted
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(appPlugin());
|
||||
backend.add(catalogPlugin());
|
||||
backend.add(catalogModuleTemplateKind());
|
||||
backend.add(import('@backstage/plugin-app-backend'));
|
||||
backend.add(import('@backstage/plugin-catalog-backend'));
|
||||
backend.add(
|
||||
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
|
||||
);
|
||||
backend.start();
|
||||
```
|
||||
|
||||
And `backend-b`, don't forget to clean up dependencies in `package.json` as well:
|
||||
|
||||
```ts
|
||||
// packages/backend-b/src/index.ts, imports omitted
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(scaffolderPlugin());
|
||||
backend.add(import('@backstage/plugin-scaffolder-backend'));
|
||||
backend.start();
|
||||
```
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ import { coreServices } from '@backstage/backend-plugin-api';
|
||||
const legacyPlugin = makeLegacyPlugin(
|
||||
{
|
||||
cache: coreServices.cache,
|
||||
config: coreServices.config,
|
||||
config: coreServices.rootConfig,
|
||||
database: coreServices.database,
|
||||
discovery: coreServices.discovery,
|
||||
logger: coreServices.logger,
|
||||
@@ -232,18 +232,13 @@ The app backend plugin that serves the frontend from the backend can trivially
|
||||
be used in its new form.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
/* highlight-add-next-line */
|
||||
import { appPlugin } from '@backstage/plugin-app-backend';
|
||||
|
||||
const backend = createBackend();
|
||||
/* highlight-add-next-line */
|
||||
backend.add(appPlugin({ appPackageName: 'app' }));
|
||||
backend.add(import('@backstage/plugin-app-backend'));
|
||||
```
|
||||
|
||||
This is an example of how options can be passed into some backend plugins. The
|
||||
app plugin specifically needs to know the name of the package that holds the
|
||||
frontend code. This is the `"name"` field in that package's `package.json`,
|
||||
typically found in your `packages/app` folder. By default it's just plain "app".
|
||||
If you need to override the app package name, which otherwise defaults to `"app"`,
|
||||
you can do so via the `app.packageName` configuration key.
|
||||
|
||||
You should be able to delete the `plugins/app.ts` file at this point.
|
||||
|
||||
@@ -252,21 +247,18 @@ You should be able to delete the `plugins/app.ts` file at this point.
|
||||
A basic installation of the catalog plugin looks as follows.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
/* highlight-add-start */
|
||||
import { catalogPlugin } from '@backstage/plugin-catalog-backend';
|
||||
import { catalogModuleTemplateKind } from '@backstage/plugin-scaffolder-backend';
|
||||
/* highlight-add-end */
|
||||
|
||||
const backend = createBackend();
|
||||
/* highlight-add-start */
|
||||
backend.add(catalogPlugin());
|
||||
backend.add(catalogModuleTemplateKind());
|
||||
backend.add(import('@backstage/plugin-catalog-backend'));
|
||||
backend.add(
|
||||
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
|
||||
);
|
||||
/* highlight-add-end */
|
||||
```
|
||||
|
||||
Note that this also installs a module from the scaffolder, namely the one which
|
||||
enables the use of the `Template` kind. In the unlikely event that you do not
|
||||
use templates at all, you can remove those lines.
|
||||
Note that this also installs the scaffolder module for the catalog, which
|
||||
enables the use of the `Template` kind. In the event that you do not
|
||||
use templates at all, you can remove that line.
|
||||
|
||||
If you have other customizations made to `plugins/catalog.ts`, such as adding
|
||||
custom processors or entity providers, read on. Otherwise, you should be able to
|
||||
@@ -305,8 +297,10 @@ const catalogModuleCustomExtensions = createBackendModule({
|
||||
/* highlight-add-end */
|
||||
|
||||
const backend = createBackend();
|
||||
backend.add(catalogPlugin());
|
||||
backend.add(catalogModuleTemplateKind());
|
||||
backend.add(import('@backstage/plugin-catalog-backend'));
|
||||
backend.add(
|
||||
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
|
||||
);
|
||||
/* highlight-add-next-line */
|
||||
backend.add(catalogModuleCustomExtensions());
|
||||
```
|
||||
@@ -330,12 +324,9 @@ implementations that they represent, and being exported from there.
|
||||
A basic installation of the events plugin looks as follows.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
/* highlight-add-next-line */
|
||||
import { eventsPlugin } from '@backstage/plugin-events-backend';
|
||||
|
||||
const backend = createBackend();
|
||||
/* highlight-add-next-line */
|
||||
backend.add(eventsPlugin());
|
||||
backend.add(import('@backstage/plugin-events-backend'));
|
||||
```
|
||||
|
||||
If you have other customizations made to `plugins/events.ts`, such as adding
|
||||
@@ -374,7 +365,7 @@ const eventsModuleCustomExtensions = createBackendModule({
|
||||
/* highlight-add-end */
|
||||
|
||||
const backend = createBackend();
|
||||
backend.add(eventsPlugin());
|
||||
backend.add(import('@backstage/plugin-events-backend'));
|
||||
/* highlight-add-next-line */
|
||||
backend.add(eventsModuleCustomExtensions());
|
||||
```
|
||||
@@ -398,12 +389,9 @@ implementations that they represent, and being exported from there.
|
||||
A basic installation of the scaffolder plugin looks as follows.
|
||||
|
||||
```ts title="packages/backend/src/index.ts"
|
||||
/* highlight-add-next-line */
|
||||
import { scaffolderPlugin } from '@backstage/plugin-scaffolder-backend';
|
||||
|
||||
const backend = createBackend();
|
||||
/* highlight-add-next-line */
|
||||
backend.add(scaffolderPlugin());
|
||||
backend.add(import('@backstage/plugin-scaffolder-backend'));
|
||||
```
|
||||
|
||||
If you have other customizations made to `plugins/scaffolder.ts`, such as adding
|
||||
@@ -442,7 +430,7 @@ const scaffolderModuleCustomExtensions = createBackendModule({
|
||||
/* highlight-add-end */
|
||||
|
||||
const backend = createBackend();
|
||||
backend.add(scaffolderPlugin());
|
||||
backend.add(import('@backstage/plugin-scaffolder-backend'));
|
||||
/* highlight-add-next-line */
|
||||
backend.add(scaffolderModuleCustomExtensions());
|
||||
```
|
||||
|
||||
@@ -27,6 +27,7 @@ To create a Backend plugin, run `yarn new`, select `backend-plugin`, and fill ou
|
||||
A basic backend plugin might look as follows:
|
||||
|
||||
```ts
|
||||
// src/plugin.ts
|
||||
import {
|
||||
createBackendPlugin,
|
||||
coreServices,
|
||||
@@ -55,6 +56,9 @@ export const examplePlugin = createBackendPlugin({
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// src/index.ts
|
||||
export { examplePlugin as default } from './plugin';
|
||||
```
|
||||
|
||||
When you depend on `plugin` scoped services, you'll receive an instance of them
|
||||
@@ -91,6 +95,7 @@ The following is an example of how to create a module that adds a new processor
|
||||
using the `catalogProcessingExtensionPoint`:
|
||||
|
||||
```ts
|
||||
// src/module.ts
|
||||
import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
|
||||
import { MyCustomProcessor } from './MyCustomProcessor';
|
||||
@@ -110,6 +115,9 @@ export const catalogModuleExampleCustomProcessor = createBackendModule({
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// src/index.ts
|
||||
export { catalogModuleExampleCustomProcessor as default } from './module';
|
||||
```
|
||||
|
||||
See [the article on naming patterns](../architecture/07-naming-patterns.md) for
|
||||
@@ -122,10 +130,11 @@ initializing modules we can depend on both extension points and services
|
||||
interchangeably. You can also depend on multiple extension points at once, in
|
||||
case the implementation of the module requires it.
|
||||
|
||||
It is typically best to keep modules slim and to each only add a single new
|
||||
feature. It is often the case that it is better to create two separate modules
|
||||
rather than one that provides both features. The one limitation here is that
|
||||
modules can not interact with each other and need to be self contained.
|
||||
Each module package should only contain a single module, but this module may
|
||||
extend multiple extension points. A module may also use configuration to
|
||||
conditionally enable or disable certain extensions. This pattern should only be
|
||||
used for extensions that are related to each other, otherwise it is best to
|
||||
create a separate module package with its own module.
|
||||
|
||||
### HTTP Handlers
|
||||
|
||||
@@ -187,34 +196,25 @@ export const examplesExtensionPoint =
|
||||
id: 'example.examples',
|
||||
});
|
||||
|
||||
// This is the implementation of the extension point, which is internal to your plugin.
|
||||
class ExamplesExtension implements ExamplesExtensionPoint {
|
||||
#examples: Example[] = [];
|
||||
|
||||
addExample(example: Example): void {
|
||||
this.#examples.push(example);
|
||||
}
|
||||
|
||||
// Note that this method is internal to this implementation
|
||||
getRegisteredExamples() {
|
||||
return this.#examples;
|
||||
}
|
||||
}
|
||||
|
||||
// The following shows how your plugin would register the extension point
|
||||
// and use the features that other modules have registered.
|
||||
export const examplePlugin = createBackendPlugin({
|
||||
pluginId: 'example',
|
||||
register(env) {
|
||||
const examplesExtensions = new ExamplesExtension();
|
||||
env.registerExtensionPoint(examplesExtensionPoint, examplesExtensions);
|
||||
// We can share data between the extension point implementation and our init method.
|
||||
const examples = new Array<Example>();
|
||||
|
||||
// This registers the implementation of the extension point, which is internal to your plugin.
|
||||
env.registerExtensionPoint(examplesExtensionPoint, {
|
||||
addExample(example) {
|
||||
examples.push(example);
|
||||
},
|
||||
});
|
||||
|
||||
env.registerInit({
|
||||
deps: { logger: coreServices.logger },
|
||||
async init({ logger }) {
|
||||
// We can access `examplesExtension` directly, giving us access to the internal interface.
|
||||
const examples = examplesExtension.getRegisteredExamples();
|
||||
|
||||
// We can access `examples` directly
|
||||
logger.info(`The following examples have been registered: ${examples}`);
|
||||
},
|
||||
});
|
||||
@@ -224,12 +224,10 @@ export const examplePlugin = createBackendPlugin({
|
||||
|
||||
This is a very common type of extension point, one where modules are given the opportunity to register features to be used by the plugin. In this case modules are able to register examples that are then used by our examples plugin.
|
||||
|
||||
Note that the public extension point interface only needs to expose the `addExample` method, while the `getRegisteredExamples()` method is kept internal to the plugin.
|
||||
|
||||
### Configuration
|
||||
|
||||
Your plugin or module can leverage the app configuration to configure its own
|
||||
internal behavior. You do this by adding a dependency on `coreServices.config`
|
||||
internal behavior. You do this by adding a dependency on `coreServices.rootConfig`
|
||||
and reading from that. This pattern is a good fit especially for customization
|
||||
that needs to be different across environments.
|
||||
|
||||
@@ -240,7 +238,7 @@ export const examplePlugin = createBackendPlugin({
|
||||
pluginId: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: { config: coreServices.config },
|
||||
deps: { config: coreServices.rootConfig },
|
||||
async init({ config }) {
|
||||
// Here you can read from the current config as you see fit, e.g.:
|
||||
const value = config.getOptionalString('example.value');
|
||||
@@ -254,54 +252,3 @@ Before adding custom configuration options, make sure to read [the configuration
|
||||
docs](../../conf/index.md), in particular the section on [defining configuration
|
||||
for your own plugins](../../conf/defining.md) which explains how to establish a
|
||||
configuration schema for your specific plugin.
|
||||
|
||||
### Options
|
||||
|
||||
You'll have noted that the return values from `createBackendPlugin` and
|
||||
`createBackendModule` are actually factory functions. These can be made to
|
||||
accept options that shall be passed in at initialization time.
|
||||
|
||||
This pattern can be a good fit for fairly simple, static configuration values.
|
||||
|
||||
```ts
|
||||
export interface ExampleOptions {
|
||||
silent?: boolean;
|
||||
}
|
||||
|
||||
export const examplePlugin = createBackendPlugin(
|
||||
(options?: ExampleOptions) => ({
|
||||
pluginId: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
// Omitted dependencies but they remain the same as above
|
||||
},
|
||||
async init(
|
||||
{
|
||||
/* ... */
|
||||
},
|
||||
) {
|
||||
// Here you can access the given options and act accordingly, e.g.:
|
||||
if (!options?.silent) {
|
||||
// ...
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
The return type from `createBackendPlugin` and `createBackendModule` will mimic
|
||||
this, resulting in a factory function that accepts an optional options object.
|
||||
You can also make it required to pass in options, by removing the optionality
|
||||
(the question mark on the options) above.
|
||||
|
||||
```ts
|
||||
backend.add(examplePlugin({ silent: true }));
|
||||
```
|
||||
|
||||
Use this pattern sparingly. There is a big convenience benefit in allowing
|
||||
people to easily install backend plugins without having to always pass in a
|
||||
large number of options, and these options cannot easily be made dynamic based
|
||||
on the environment etc.
|
||||
|
||||
@@ -36,8 +36,10 @@ describe('myPlugin', () => {
|
||||
const fakeConfig = { myPlugin: { value: 7 } };
|
||||
|
||||
const { server } = await startTestBackend({
|
||||
features: [myPlugin()],
|
||||
services: [mockServices.rootConfig.factory({ data: fakeConfig })],
|
||||
features: [
|
||||
myPlugin(),
|
||||
mockServices.rootConfig.factory({ data: fakeConfig }),
|
||||
],
|
||||
});
|
||||
|
||||
const response = await request(server).get('/api/example/get-value');
|
||||
@@ -150,8 +152,10 @@ your test database.
|
||||
```ts
|
||||
const { knex, subject } = await createSubject(databaseId);
|
||||
const { server } = await startTestBackend({
|
||||
features: [myPlugin()],
|
||||
services: [[coreServices.database, { getClient: async () => knex }]],
|
||||
features: [
|
||||
myPlugin(),
|
||||
mockServices.database.mock({ getClient: async () => knex }),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
@@ -166,3 +170,37 @@ it'll take into account when present.
|
||||
- `BACKSTAGE_TEST_DATABASE_POSTGRES13_CONNECTION_STRING`
|
||||
- `BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING`
|
||||
- `BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING`
|
||||
|
||||
## Testing Service Factories
|
||||
|
||||
To facilitate testing of service factories, the `@backstage/backend-test-utils`
|
||||
package provides a `ServiceFactoryTester` helper that lets you instantiate services
|
||||
in a controlled context.
|
||||
|
||||
The following example shows how to test a service factory where we also provide
|
||||
a mocked implementation of the `rootConfig` service.
|
||||
|
||||
```ts
|
||||
import {
|
||||
mockServices,
|
||||
ServiceFactoryTester,
|
||||
} from '@backstage/backend-test-utils';
|
||||
import { myServiceFactory } from './myServiceFactory.ts';
|
||||
|
||||
describe('myServiceFactory', () => {
|
||||
it('should provide value', async () => {
|
||||
const fakeConfig = { myConfiguredValue: 7 };
|
||||
|
||||
const tester = ServiceFactoryTester.from(myServiceFactory, {
|
||||
dependencies: [mockServices.rootConfig.factory({ data: fakeConfig })],
|
||||
});
|
||||
|
||||
const myService = await tester.get('test-plugin');
|
||||
|
||||
expect(myService.getValue()).toBe(7);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
The service factory tester also provides mocked implementations of the majority
|
||||
of all core services by default.
|
||||
|
||||
@@ -51,7 +51,7 @@ export const kubernetesPlugin = createBackendPlugin({
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
config: coreServices.config,
|
||||
config: coreServices.rootConfig,
|
||||
catalogApi: catalogServiceRef,
|
||||
discovery: coreServices.discovery,
|
||||
// The http router service is used to register the router created by the KubernetesBuilder.
|
||||
|
||||
@@ -61,13 +61,13 @@ You can configure these additional options by adding an override for the core se
|
||||
```ts
|
||||
import { httpRouterServiceFactory } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
httpRouterServiceFactory({
|
||||
getPath: (pluginId: string) => `/plugins/${pluginId}`,
|
||||
}),
|
||||
],
|
||||
});
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(
|
||||
httpRouterServiceFactory({
|
||||
getPath: (pluginId: string) => `/plugins/${pluginId}`,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
## Root HTTP Router
|
||||
@@ -118,31 +118,31 @@ You can configure the root HTTP Router service by passing the options to the `cr
|
||||
```ts
|
||||
import { rootHttpRouterServiceFactory } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
rootHttpRouterServiceFactory({
|
||||
configure: ({ app, middleware, routes, config, logger, lifecycle }) => {
|
||||
// the built in middleware is provided through an option in the configure function
|
||||
app.use(middleware.helmet());
|
||||
app.use(middleware.cors());
|
||||
app.use(middleware.compression());
|
||||
const backend = createBackend();
|
||||
|
||||
// you can add you your own middleware in here
|
||||
app.use(custom.logging());
|
||||
backend.add(
|
||||
rootHttpRouterServiceFactory({
|
||||
configure: ({ app, middleware, routes, config, logger, lifecycle }) => {
|
||||
// the built in middleware is provided through an option in the configure function
|
||||
app.use(middleware.helmet());
|
||||
app.use(middleware.cors());
|
||||
app.use(middleware.compression());
|
||||
|
||||
// here the routes that are registered by other plugins
|
||||
app.use(routes);
|
||||
// you can add you your own middleware in here
|
||||
app.use(custom.logging());
|
||||
|
||||
// some other middleware that comes after the other routes
|
||||
app.use(middleware.notFound());
|
||||
app.use(middleware.error());
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
// here the routes that are registered by other plugins
|
||||
app.use(routes);
|
||||
|
||||
// some other middleware that comes after the other routes
|
||||
app.use(middleware.notFound());
|
||||
app.use(middleware.error());
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
## Config
|
||||
## Root Config
|
||||
|
||||
This service allows you to read configuration values out of your `app-config` YAML files.
|
||||
|
||||
@@ -162,7 +162,7 @@ createBackendPlugin({
|
||||
env.registerInit({
|
||||
deps: {
|
||||
log: coreServices.logger,
|
||||
config: coreServices.config,
|
||||
config: coreServices.rootConfig,
|
||||
},
|
||||
async init({ log, config }) {
|
||||
const baseUrl = config.getString('backend.baseUrl');
|
||||
@@ -185,19 +185,19 @@ You can configure these additional options by adding an override for the core se
|
||||
```ts
|
||||
import { rootConfigServiceFactory } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
rootConfigServiceFactory({
|
||||
argv: [
|
||||
'--config',
|
||||
'/backstage/app-config.development.yaml',
|
||||
'--config',
|
||||
'/backstage/app-config.yaml',
|
||||
],
|
||||
remote: { reloadIntervalSeconds: 60 },
|
||||
}),
|
||||
],
|
||||
});
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(
|
||||
rootConfigServiceFactory({
|
||||
argv: [
|
||||
'--config',
|
||||
'/backstage/app-config.development.yaml',
|
||||
'--config',
|
||||
'/backstage/app-config.yaml',
|
||||
],
|
||||
remote: { reloadIntervalSeconds: 60 },
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
## Logging
|
||||
@@ -243,34 +243,34 @@ The following example is how you can override the root logger service to add add
|
||||
import { coreServices } from '@backstage/backend-plugin-api';
|
||||
import { WinstonLogger } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
createServiceFactory({
|
||||
service: coreServices.rootLogger,
|
||||
deps: {
|
||||
config: coreServices.config,
|
||||
},
|
||||
async factory({ config }) {
|
||||
const logger = WinstonLogger.create({
|
||||
meta: {
|
||||
service: 'backstage',
|
||||
// here's some additional information that is not part of the
|
||||
// original implementation
|
||||
podName: 'myk8spod',
|
||||
},
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? format.json()
|
||||
: WinstonLogger.colorFormat(),
|
||||
transports: [new transports.Console()],
|
||||
});
|
||||
const backend = createBackend();
|
||||
|
||||
return logger;
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
backend.add(
|
||||
createServiceFactory({
|
||||
service: coreServices.rootLogger,
|
||||
deps: {
|
||||
config: coreServices.rootConfig,
|
||||
},
|
||||
async factory({ config }) {
|
||||
const logger = WinstonLogger.create({
|
||||
meta: {
|
||||
service: 'backstage',
|
||||
// here's some additional information that is not part of the
|
||||
// original implementation
|
||||
podName: 'myk8spod',
|
||||
},
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? format.json()
|
||||
: WinstonLogger.colorFormat(),
|
||||
transports: [new transports.Console()],
|
||||
});
|
||||
|
||||
return logger;
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
## Cache
|
||||
@@ -440,14 +440,14 @@ You can configure these additional options by adding an override for the core se
|
||||
```ts
|
||||
import { identityServiceFactory } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
identityServiceFactory({
|
||||
issuer: 'backstage',
|
||||
algorithms: ['ES256', 'RS256'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(
|
||||
identityServiceFactory({
|
||||
issuer: 'backstage',
|
||||
algorithms: ['ES256', 'RS256'],
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
## Lifecycle
|
||||
@@ -532,19 +532,19 @@ class MyCustomLifecycleService implements RootLifecycleService {
|
||||
}
|
||||
}
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
createServiceFactory({
|
||||
service: coreServices.rootLifecycle,
|
||||
deps: {
|
||||
logger: coreServices.rootLogger,
|
||||
},
|
||||
async factory({ logger }) {
|
||||
return new MyCustomLifecycleService(logger);
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(
|
||||
createServiceFactory({
|
||||
service: coreServices.rootLifecycle,
|
||||
deps: {
|
||||
logger: coreServices.rootLogger,
|
||||
},
|
||||
async factory({ logger }) {
|
||||
return new MyCustomLifecycleService(logger);
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
## Permissions
|
||||
|
||||
@@ -467,7 +467,7 @@ The next step is to create a custom processor for your new entity kind. This
|
||||
will be used within the catalog to make sure that it's able to ingest and
|
||||
validate entities of our new kind. Just like with the definition package, you
|
||||
can find inspiration in for example the existing
|
||||
[ScaffolderEntitiesProcessor](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts).
|
||||
[ScaffolderEntitiesProcessor](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-scaffolder-entity-model/src/processor/ScaffolderEntitiesProcessor.ts).
|
||||
We also provide a high-level example of what a catalog process for a custom
|
||||
entity might look like:
|
||||
|
||||
|
||||
@@ -627,3 +627,98 @@ output things. You can grab that output using `steps.$stepId.output.$property`.
|
||||
You can read more about all the `inputs` and `outputs` defined in the actions in
|
||||
code part of the `JSONSchema`, or you can read more about our
|
||||
[built in actions](./builtin-actions.md).
|
||||
|
||||
## Built in Filters
|
||||
|
||||
Template filters are functions that help you transform data, extract specific information,
|
||||
and perform various operations in Scaffolder Templates.
|
||||
|
||||
This section introduces the built-in filters provided by Backstage and offers examples of
|
||||
how to use them in the Scaffolder templates. It's important to mention that Backstage also leverages the
|
||||
native filters from the Nunjucks library. For a complete list of these native filters and their usage,
|
||||
refer to the [Nunjucks documentation](https://mozilla.github.io/nunjucks/templating.html#builtin-filters).
|
||||
|
||||
### parseRepoUrl
|
||||
|
||||
The `parseRepoUrl` filter parse a repository URL into
|
||||
its components, such as `owner`, repository `name`, and more.
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```yaml
|
||||
- id: log
|
||||
name: Parse Repo URL
|
||||
action: debug:log
|
||||
input:
|
||||
extra: ${{ parameters.repoUrl | parseRepoUrl }}
|
||||
```
|
||||
|
||||
- **Input**: `github.com?repo=backstage&org=backstage`
|
||||
- **Output**: [RepoSpec](https://github.com/backstage/backstage/blob/v1.17.2/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.ts#L39)
|
||||
|
||||
### parseEntityRef
|
||||
|
||||
The `parseEntityRef` filter allows you to extract different parts of
|
||||
an entity reference, such as the `kind`, `namespace`, and `name`.
|
||||
|
||||
**Usage example**
|
||||
|
||||
1. Without context
|
||||
|
||||
```yaml
|
||||
- id: log
|
||||
name: Parse Entity Reference
|
||||
action: debug:log
|
||||
input:
|
||||
extra: ${{ parameters.owner | parseEntityRef }}
|
||||
```
|
||||
|
||||
- **Input**: `group:techdocs`
|
||||
- **Output**: [CompoundEntityRef](https://github.com/backstage/backstage/blob/v1.17.2/packages/catalog-model/src/types.ts#L23)
|
||||
|
||||
2. With context
|
||||
|
||||
```yaml
|
||||
- id: log
|
||||
name: Parse Entity Reference
|
||||
action: debug:log
|
||||
input:
|
||||
extra: ${{ parameters.owner | parseEntityRef({ defaultKind:"group", defaultNamespace:"another-namespace" }) }}
|
||||
```
|
||||
|
||||
- **Input**: `techdocs`
|
||||
- **Output**: [CompoundEntityRef](https://github.com/backstage/backstage/blob/v1.17.2/packages/catalog-model/src/types.ts#L23)
|
||||
|
||||
### pick
|
||||
|
||||
This `pick` filter allows you to select specific properties from an object.
|
||||
|
||||
**Usage Example**
|
||||
|
||||
```yaml
|
||||
- id: log
|
||||
name: Pick
|
||||
action: debug:log
|
||||
input:
|
||||
extra: ${{ parameters.owner | parseEntityRef | pick('name') }}
|
||||
```
|
||||
|
||||
- **Input**: `{ kind: 'Group', namespace: 'default', name: 'techdocs' }`
|
||||
- **Output**: `techdocs`
|
||||
|
||||
### projectSlug
|
||||
|
||||
The `projectSlug` filter generates a project slug from a repository URL
|
||||
|
||||
**Usage Example**
|
||||
|
||||
```yaml
|
||||
- id: log
|
||||
name: Project Slug
|
||||
action: debug:log
|
||||
input:
|
||||
extra: ${{ parameters.repoUrl | projectSlug }}
|
||||
```
|
||||
|
||||
- **Input**: `github.com?repo=backstage&org=backstage`
|
||||
- **Output**: `backstage/backstage`
|
||||
|
||||
@@ -5,228 +5,10 @@ title: Contributors
|
||||
description: Documentation on how to get set up for doing development on the Backstage repository
|
||||
---
|
||||
|
||||
This section describes how to get set up for doing development on the Backstage
|
||||
repository.
|
||||
Our vision for Backstage is for it to become the trusted standard toolbox (read: UX layer) for the open source infrastructure landscape. Think of it like Kubernetes for developer experience. We realize this is an ambitious goal. We can’t do it alone.
|
||||
|
||||
## Cloning the Repository
|
||||
Therefore we want to create a strong community of contributors -- all working together to create the kind of delightful experience that our developers deserve.
|
||||
|
||||
Ok. So you're gonna want some code right? Go ahead and fork the repository into
|
||||
your own GitHub account and clone that code to your local machine or you can
|
||||
grab the one for the origin like so:
|
||||
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. ❤️
|
||||
|
||||
```bash
|
||||
git clone git@github.com:backstage/backstage --depth 1
|
||||
```
|
||||
|
||||
If you cloned a fork, you can add the upstream dependency like so:
|
||||
|
||||
```bash
|
||||
git remote add upstream git@github.com:backstage/backstage
|
||||
git pull upstream master
|
||||
```
|
||||
|
||||
After you have cloned the Backstage repository, you should run the following
|
||||
commands once to set things up for development:
|
||||
|
||||
```bash
|
||||
$ cd backstage # change to root directory of project
|
||||
|
||||
$ yarn install # fetch dependency packages - may take a while
|
||||
$ yarn tsc # does a first run of type generation and checks
|
||||
```
|
||||
|
||||
## Serving the Example App
|
||||
|
||||
Open a terminal window and start the web app by using the following command from
|
||||
the project root. Make sure you have run the above mentioned commands first.
|
||||
|
||||
```bash
|
||||
$ yarn dev
|
||||
```
|
||||
|
||||
This is going to start two things, the frontend (:3000) and the backend (:7007).
|
||||
|
||||
This should open a local instance of Backstage in your browser, otherwise open
|
||||
one of the URLs printed in the terminal.
|
||||
|
||||
By default, Backstage will start on port 3000, however you can override this by
|
||||
setting an environment variable `PORT` on your local machine. e.g.
|
||||
`export PORT=8080` then running `yarn start`. Or `PORT=8080 yarn start`.
|
||||
|
||||
Once successfully started, you should see the following message in your terminal
|
||||
window:
|
||||
|
||||
```sh
|
||||
$ concurrently "yarn start" "yarn start-backend"
|
||||
$ yarn workspace example-app start
|
||||
$ yarn workspace example-backend start
|
||||
$ backstage-cli app:serve
|
||||
$ backstage-cli backend:dev
|
||||
[0] Loaded config from app-config.yaml
|
||||
[1] Build succeeded
|
||||
[0] ℹ 「wds」: Project is running at http://localhost:3000/
|
||||
[0] ℹ 「wds」: webpack output is served from /
|
||||
[0] ℹ 「wds」: Content not from webpack is served from $BACKSTAGE_DIR/packages/app/public
|
||||
[0] ℹ 「wds」: 404s will fallback to /index.html
|
||||
[0] ℹ 「wdm」: wait until bundle finished: /
|
||||
[1] 2021-02-12T20:58:17.614Z backstage info Loaded config from app-config.yaml
|
||||
```
|
||||
|
||||
You'll see how you get both logs for the frontend `webpack-dev-server` which
|
||||
serves the react app ([0]) and the backend ([1]);
|
||||
|
||||
Visit http://localhost:3000 and you should see the bleeding edge of Backstage
|
||||
ready for contributions!
|
||||
|
||||
## Editor
|
||||
|
||||
The Backstage development environment does not require any specific editor, but
|
||||
it is intended to be used with one that has built-in linting and type-checking.
|
||||
The development server does not include any checks by default, but they can be
|
||||
enabled using the `--check` flag. Note that using the flag may consume more
|
||||
system resources and slow things down.
|
||||
|
||||
## Package Scripts
|
||||
|
||||
There are many commands to be found in the root
|
||||
[package.json](https://github.com/backstage/backstage/blob/master/package.json),
|
||||
here are some useful ones:
|
||||
|
||||
```python
|
||||
yarn start # Start serving the example app, use --check to include type checks and linting
|
||||
|
||||
yarn storybook # Start local storybook, useful for working on components in @backstage/core-components
|
||||
|
||||
yarn workspace @backstage/plugin-api-docs start # Serve api-docs plugin only, also supports --check
|
||||
|
||||
yarn tsc # Run typecheck, use --watch for watch mode
|
||||
yarn tsc:full # Run full type checking, for example without skipLibCheck, use in CI
|
||||
|
||||
yarn build:backend # Build the backend package, depends on tsc
|
||||
yarn build:all # Build published versions of packages, depends on tsc
|
||||
|
||||
yarn lint # lint packages that have changed since later commit on origin/master
|
||||
yarn lint:all # lint all packages
|
||||
yarn lint:type-deps # verify that @types/* dependencies are placed correctly in packages
|
||||
|
||||
yarn test # test packages that have changed since later commit on origin/master
|
||||
yarn test:all # test all packages
|
||||
|
||||
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 new # Create a new module
|
||||
```
|
||||
|
||||
> See
|
||||
> [package.json](https://github.com/backstage/backstage/blob/master/package.json)
|
||||
> for other yarn commands/options.
|
||||
|
||||
## Local configuration
|
||||
|
||||
Backstage allows you to specify the configuration used while running the
|
||||
application on your computer. Local configuration is read from
|
||||
`app-config.local.yaml`. This file is ignored by Git, which means that you can
|
||||
safely use it to reference secrets like GitHub tokens without worrying about
|
||||
these secrets, inadvertently ending up in the Git repository. You do not need to
|
||||
copy everything from the default config to the local config.
|
||||
`app-config.local.yaml` will be merged with `app-config.yaml` and overwrite the
|
||||
default app configs.
|
||||
|
||||
> NOTE: If you want to add your own configuration values to access in the
|
||||
> frontend you also need to mark those values as visible using configuration
|
||||
> schema, either in the app or in your own plugin. For more information, see
|
||||
> [Defining Configuration](../conf/defining.md).
|
||||
|
||||
You can learn more about the local configuration in
|
||||
[Static Configuration in Backstage](../conf/) section.
|
||||
|
||||
## Writing changesets
|
||||
|
||||
Changesets are an important part of the development process. They are used to
|
||||
generate Changelog entries for all changes to the project. Ultimately they are
|
||||
read by the end users to learn about important changes and fixes to the project.
|
||||
Some of these fixes might require manual intervention from users so it's
|
||||
important to write changesets that users understand and can take action on.
|
||||
|
||||
Here are some important do's and don'ts when writing changesets:
|
||||
|
||||
### Changeset should give a clear description to what has changed
|
||||
|
||||
#### Bad
|
||||
|
||||
```
|
||||
---
|
||||
'@backstage/catalog': patch
|
||||
---
|
||||
Fixed table layout
|
||||
```
|
||||
|
||||
#### Good
|
||||
|
||||
```
|
||||
---
|
||||
'@backstage/catalog': patch
|
||||
---
|
||||
|
||||
Fixed bug in EntityTable component where table layout did not readjust properly below 1080x768 pixels.
|
||||
```
|
||||
|
||||
### Breaking changes not caught by the type checker should be clearly marked with bold **BREAKING** text
|
||||
|
||||
#### Bad
|
||||
|
||||
```
|
||||
---
|
||||
'@backstage/catalog': minor
|
||||
---
|
||||
|
||||
getEntity is now a function that returns a Promise.
|
||||
```
|
||||
|
||||
#### Good
|
||||
|
||||
```
|
||||
---
|
||||
'@backstage/catalog': minor
|
||||
---
|
||||
|
||||
**BREAKING** The getEntity function now returns a Promise and **must** be awaited from now on.
|
||||
```
|
||||
|
||||
### Changes to code should include a diff of the files that need updating
|
||||
|
||||
#### Bad
|
||||
|
||||
```
|
||||
---
|
||||
'@backstage/catalog': patch
|
||||
---
|
||||
|
||||
**BREAKING** The catalogEngine now requires a flux capacitor to be passed.
|
||||
```
|
||||
|
||||
#### Good
|
||||
|
||||
---
|
||||
'@backstage/catalog': patch
|
||||
---
|
||||
|
||||
**BREAKING** The catalog createRouter now requires that a `FluxCapacitor` is
|
||||
passed to the router.
|
||||
|
||||
These changes are **required** to `packages/backend/src/plugins/catalog.ts`
|
||||
|
||||
```diff
|
||||
+ import { FluxCapacitor } from '@backstage/time';
|
||||
+ const fluxCapacitor = new FluxCapacitor();
|
||||
return await createRouter({
|
||||
entitiesCatalog,
|
||||
locationAnalyzer,
|
||||
locationService,
|
||||
+ fluxCapacitor,
|
||||
logger: env.logger,
|
||||
config: env.config,
|
||||
});
|
||||
```
|
||||
To get you started we've put together a [Contributors Guide in the Backstage GitHub repo](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) that has all the information you need
|
||||
|
||||
@@ -11,7 +11,7 @@ A Backstage App is a monorepo setup with `lerna` that includes everything you
|
||||
need to run Backstage in your own environment.
|
||||
|
||||
If you intend to contribute a plugin, new feature, or bug fix to the Backstage project, you
|
||||
may want to read the [Contributors](./contributors.md) guide instead.
|
||||
may want to read the [Contributors](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) guide instead.
|
||||
|
||||
## Create an app
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ system using tools like apt-get, npm, yarn, curl. Docker knowledge is also
|
||||
helpful for making the best use of your Backstage installation.
|
||||
|
||||
If you are planning to contribute plugins or to the project in general, we advise
|
||||
you to use the [Contributors](contributors.md) guide to do a repository-based installation.
|
||||
you to use the [Contributors](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) guide to do a repository-based installation.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
|
||||
@@ -65,11 +65,52 @@ catalog:
|
||||
yourProviderId:
|
||||
host: gitlab.com
|
||||
orgEnabled: true
|
||||
group: org/teams # Optional. Must not end with slash. Accepts only groups under the provided path (which will be stripped)
|
||||
group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only groups under the provided path (which will be stripped)
|
||||
groupPattern: '[\s\S]*' # Optional. Filters found groups based on provided pattern. Defaults to `[\s\S]*`, which means to not filter anything
|
||||
```
|
||||
|
||||
### Groups
|
||||
|
||||
When the `group` parameter is provided, the corresponding path prefix will be
|
||||
stripped out from each matching group when computing the unique entity name.
|
||||
e.g. If `group` is `org/teams`, the name for `org/teams/avengers/gotg` will be
|
||||
`avengers-gotg`.
|
||||
|
||||
For gitlab.com, when `orgEnabled: true`, the `group` parameter is required in
|
||||
order to limit the ingestion to a group within your organisation. `Group`
|
||||
entities will only be ingested for the configured group, or its descendant groups,
|
||||
but not any ancestor groups higher than the configured group path. Only groups
|
||||
which contain members will be ingested.
|
||||
|
||||
### Users
|
||||
|
||||
For self hosted, all `User` entities are ingested from the entire instance.
|
||||
|
||||
For gitlab.com `User` entities for users who have [direct or inherited membership](https://docs.gitlab.com/ee/user/project/members/index.html#membership-types)
|
||||
of the top-level group for the configured group path will be ingested.
|
||||
|
||||
### Limiting `User` and `Group` entity ingestion in the provider
|
||||
|
||||
Optionally, you can limit the entity types ingested by the provider when using
|
||||
`orgEnabled: true` with the following `rules` configuration to limit it to only
|
||||
`User` and `Group` entities.
|
||||
|
||||
```yaml
|
||||
catalog:
|
||||
providers:
|
||||
gitlab:
|
||||
yourOrgDataProviderId:
|
||||
host: gitlab.com
|
||||
orgEnabled: true
|
||||
group: org/teams
|
||||
rules:
|
||||
- allow: [Group, User]
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**NOTE**: If any groups that are being ingested are empty groups (i.e. do not
|
||||
contain any projects) and the user which provisioned the token is shared with a
|
||||
higher level group via [group sharing](https://docs.gitlab.com/ee/user/group/manage.html#share-a-group-with-another-group)
|
||||
and you don't see the expected number of `Group` entities in the catalog you may
|
||||
be hitting this [Gitlab issue](https://gitlab.com/gitlab-org/gitlab/-/issues/267996).
|
||||
|
||||
@@ -62,7 +62,7 @@ steps:
|
||||
- **Bundling** - Combines a package and all of its dependencies into a
|
||||
production-ready bundle
|
||||
|
||||
These steps are generally kept isolated form each other, with each step focusing
|
||||
These steps are generally kept isolated from each other, with each step focusing
|
||||
on its specific task. For example, we do not do linting or type checking
|
||||
together with the building or bundling. This is so that we can provide more
|
||||
flexibility and avoid duplicate work, improving performance. It is strongly
|
||||
|
||||
@@ -266,12 +266,10 @@ class GoogleCloudLogger implements LoggerService {
|
||||
}
|
||||
|
||||
// packages/backend/src/index.ts
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
// supplies additional or replacement services to the backend
|
||||
GoogleCloudLogger.factory(),
|
||||
],
|
||||
});
|
||||
const backend = createBackend();
|
||||
|
||||
// supplies additional or replacement services to the backend
|
||||
backend.add(GoogleCloudLogger.factory());
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Search extension for Azure Cognitive Search
|
||||
author: AP Communications
|
||||
authorUrl: https://www.ap-com.co.jp/en/
|
||||
category: Search
|
||||
description: Search extension plugin to create backstage search indexes into Azure Cognitive Search.
|
||||
documentation: https://github.com/ap-communications/platt-backstage-plugin/tree/main/plugins/search-backend-module-cognitive-search
|
||||
npmPackageName: '@platt/plugin-search-backend-module-cognitive-search'
|
||||
addedDate: '2023-09-13'
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
title: Veecode GitHub Workflows
|
||||
author: Veecode Platform
|
||||
authorUrl: https://github.com/veecode-platform
|
||||
category: CI/CD
|
||||
description: The Github Workflows plugin provides an alternative for manually triggering GitHub workflows from within your Backstage component.
|
||||
documentation: https://github.com/veecode-platform/platform-backstage-plugins/tree/master/plugins/github-workflows
|
||||
iconUrl: https://veecode-platform.github.io/support/imgs/logo_2.svg
|
||||
npmPackageName: '@veecode-platform/backstage-plugin-github-workflows'
|
||||
tags:
|
||||
- ci
|
||||
- cd
|
||||
- github
|
||||
- workflows
|
||||
addedDate: '2023-09-12'
|
||||
+43
-43
@@ -2604,90 +2604,90 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-arm64@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.82"
|
||||
"@swc/core-darwin-arm64@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.84"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-x64@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.82"
|
||||
"@swc/core-darwin-x64@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.84"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.82"
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.84"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.82"
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.84"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.82"
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.84"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.82"
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.84"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-musl@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.82"
|
||||
"@swc/core-linux-x64-musl@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.84"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.82"
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.84"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.82"
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.84"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.82":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.82"
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.84":
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.84"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:^1.3.46":
|
||||
version: 1.3.82
|
||||
resolution: "@swc/core@npm:1.3.82"
|
||||
version: 1.3.84
|
||||
resolution: "@swc/core@npm:1.3.84"
|
||||
dependencies:
|
||||
"@swc/core-darwin-arm64": 1.3.82
|
||||
"@swc/core-darwin-x64": 1.3.82
|
||||
"@swc/core-linux-arm-gnueabihf": 1.3.82
|
||||
"@swc/core-linux-arm64-gnu": 1.3.82
|
||||
"@swc/core-linux-arm64-musl": 1.3.82
|
||||
"@swc/core-linux-x64-gnu": 1.3.82
|
||||
"@swc/core-linux-x64-musl": 1.3.82
|
||||
"@swc/core-win32-arm64-msvc": 1.3.82
|
||||
"@swc/core-win32-ia32-msvc": 1.3.82
|
||||
"@swc/core-win32-x64-msvc": 1.3.82
|
||||
"@swc/core-darwin-arm64": 1.3.84
|
||||
"@swc/core-darwin-x64": 1.3.84
|
||||
"@swc/core-linux-arm-gnueabihf": 1.3.84
|
||||
"@swc/core-linux-arm64-gnu": 1.3.84
|
||||
"@swc/core-linux-arm64-musl": 1.3.84
|
||||
"@swc/core-linux-x64-gnu": 1.3.84
|
||||
"@swc/core-linux-x64-musl": 1.3.84
|
||||
"@swc/core-win32-arm64-msvc": 1.3.84
|
||||
"@swc/core-win32-ia32-msvc": 1.3.84
|
||||
"@swc/core-win32-x64-msvc": 1.3.84
|
||||
"@swc/types": ^0.1.4
|
||||
peerDependencies:
|
||||
"@swc/helpers": ^0.5.0
|
||||
@@ -2715,7 +2715,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
"@swc/helpers":
|
||||
optional: true
|
||||
checksum: 4c4adbed22071c0af935129a6fe7cc35d1688a5c1a069efdd8c97740930fa7eaf324e75dc88634a4ea0520330f6c88101d5aa5cf7ed6e02d336cc46ee7131ea3
|
||||
checksum: dee45823923c29dde579ed1121c4392c937826d575c87f62399ba7a0b27cacfeb05da97b65cf49a721a50127bb1e22ca5c07defa784ec2a47fed33e3498ef1b9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ nav:
|
||||
- Customize the look-and-feel of your App: 'getting-started/app-custom-theme.md'
|
||||
- Keeping Backstage Updated: 'getting-started/keeping-backstage-updated.md'
|
||||
- Key Concepts: 'getting-started/concepts.md'
|
||||
- Contributors: 'getting-started/contributors.md'
|
||||
- Project Structure: 'getting-started/project-structure.md'
|
||||
- Local Development:
|
||||
- CLI:
|
||||
|
||||
+8
-1
@@ -48,7 +48,7 @@
|
||||
"@types/react": "^17",
|
||||
"@types/react-dom": "^17"
|
||||
},
|
||||
"version": "1.18.0-next.2",
|
||||
"version": "1.18.0-next.3",
|
||||
"dependencies": {
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@manypkg/get-packages": "^1.1.3"
|
||||
@@ -96,6 +96,13 @@
|
||||
"*.md": [
|
||||
"node ./scripts/check-docs-quality"
|
||||
],
|
||||
"{plugins,packages}/*/catalog-info.yaml": [
|
||||
"yarn backstage-repo-tools generate-catalog-info --ci"
|
||||
],
|
||||
"{.github/CODEOWNERS,package.json}": [
|
||||
"yarn backstage-repo-tools generate-catalog-info",
|
||||
"git add */catalog-info.yaml"
|
||||
],
|
||||
"./yarn.lock": [
|
||||
"node ./scripts/verify-lockfile-duplicates --fix"
|
||||
],
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @backstage/app-defaults
|
||||
|
||||
## 1.4.3-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
- Updated dependencies
|
||||
- @backstage/core-app-api@1.10.0-next.3
|
||||
- @backstage/core-components@0.13.5-next.3
|
||||
- @backstage/core-plugin-api@1.6.0-next.3
|
||||
- @backstage/plugin-permission-react@0.4.15-next.3
|
||||
- @backstage/theme@0.4.2-next.0
|
||||
|
||||
## 1.4.3-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/app-defaults",
|
||||
"description": "Provides the default wiring of a Backstage App",
|
||||
"version": "1.4.3-next.2",
|
||||
"version": "1.4.3-next.3",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# app-next-example-plugin
|
||||
|
||||
## 0.0.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/frontend-plugin-api@0.1.0-next.0
|
||||
- @backstage/core-components@0.13.5-next.3
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: app-next-example-plugin
|
||||
title: app-next-example-plugin
|
||||
description: Backstage internal example plugin
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-frontend-plugin
|
||||
owner: maintainers
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "app-next-example-plugin",
|
||||
"description": "Backstage internal example plugin",
|
||||
"version": "0.0.0",
|
||||
"version": "0.0.1-next.0",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
export const ExamplePage = createPageExtension({
|
||||
id: 'example.page',
|
||||
defaultPath: '/example',
|
||||
component: () => import('./Component').then(m => <m.Component />),
|
||||
loader: () => import('./Component').then(m => <m.Component />),
|
||||
});
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -1,5 +1,82 @@
|
||||
# example-app-next
|
||||
|
||||
## 0.0.1-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-home@0.5.8-next.3
|
||||
- @backstage/frontend-plugin-api@0.1.0-next.0
|
||||
- @backstage/frontend-app-api@0.1.0-next.0
|
||||
- @backstage/plugin-graphiql@0.2.54-next.3
|
||||
- @backstage/cli@0.22.13-next.3
|
||||
- @backstage/plugin-kubernetes@0.10.3-next.3
|
||||
- @backstage/app-defaults@1.4.3-next.3
|
||||
- @backstage/catalog-model@1.4.2-next.2
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/core-app-api@1.10.0-next.3
|
||||
- @backstage/core-components@0.13.5-next.3
|
||||
- @backstage/core-plugin-api@1.6.0-next.3
|
||||
- @backstage/integration-react@1.1.19-next.3
|
||||
- @backstage/plugin-adr@0.6.7-next.3
|
||||
- @backstage/plugin-airbrake@0.3.24-next.3
|
||||
- @backstage/plugin-apache-airflow@0.2.15-next.3
|
||||
- @backstage/plugin-api-docs@0.9.11-next.3
|
||||
- @backstage/plugin-azure-devops@0.3.6-next.3
|
||||
- @backstage/plugin-azure-sites@0.1.13-next.3
|
||||
- @backstage/plugin-badges@0.2.48-next.3
|
||||
- @backstage/plugin-catalog-common@1.0.16-next.2
|
||||
- @backstage/plugin-catalog-graph@0.2.36-next.3
|
||||
- @backstage/plugin-catalog-import@0.9.14-next.3
|
||||
- @backstage/plugin-catalog-react@1.8.4-next.3
|
||||
- @backstage/plugin-catalog-unprocessed-entities@0.1.3-next.3
|
||||
- @backstage/plugin-circleci@0.3.24-next.3
|
||||
- @backstage/plugin-cloudbuild@0.3.24-next.3
|
||||
- @backstage/plugin-code-coverage@0.2.17-next.3
|
||||
- @backstage/plugin-cost-insights@0.12.13-next.3
|
||||
- @backstage/plugin-devtools@0.1.4-next.3
|
||||
- @backstage/plugin-dynatrace@7.0.4-next.3
|
||||
- @backstage/plugin-entity-feedback@0.2.7-next.3
|
||||
- @backstage/plugin-explore@0.4.10-next.3
|
||||
- @backstage/plugin-gcalendar@0.3.18-next.3
|
||||
- @backstage/plugin-gcp-projects@0.3.41-next.3
|
||||
- @backstage/plugin-github-actions@0.6.5-next.3
|
||||
- @backstage/plugin-gocd@0.1.30-next.3
|
||||
- @backstage/plugin-jenkins@0.8.6-next.3
|
||||
- @backstage/plugin-kafka@0.3.24-next.3
|
||||
- @backstage/plugin-lighthouse@0.4.9-next.3
|
||||
- @backstage/plugin-linguist@0.1.9-next.3
|
||||
- @backstage/plugin-linguist-common@0.1.2-next.0
|
||||
- @backstage/plugin-microsoft-calendar@0.1.7-next.3
|
||||
- @backstage/plugin-newrelic@0.3.40-next.3
|
||||
- @backstage/plugin-newrelic-dashboard@0.2.17-next.3
|
||||
- @backstage/plugin-octopus-deploy@0.2.6-next.3
|
||||
- @backstage/plugin-org@0.6.14-next.3
|
||||
- @backstage/plugin-pagerduty@0.6.5-next.3
|
||||
- @backstage/plugin-permission-react@0.4.15-next.3
|
||||
- @backstage/plugin-playlist@0.1.16-next.3
|
||||
- @backstage/plugin-puppetdb@0.1.7-next.3
|
||||
- @backstage/plugin-rollbar@0.4.24-next.3
|
||||
- @backstage/plugin-scaffolder@1.15.0-next.3
|
||||
- @backstage/plugin-scaffolder-react@1.5.5-next.3
|
||||
- @backstage/plugin-search@1.4.0-next.3
|
||||
- @backstage/plugin-search-common@1.2.6-next.2
|
||||
- @backstage/plugin-search-react@1.7.0-next.3
|
||||
- @backstage/plugin-sentry@0.5.9-next.3
|
||||
- @backstage/plugin-shortcuts@0.3.14-next.3
|
||||
- @backstage/plugin-stack-overflow@0.1.20-next.3
|
||||
- @backstage/plugin-stackstorm@0.1.6-next.3
|
||||
- @backstage/plugin-tech-insights@0.3.16-next.3
|
||||
- @backstage/plugin-tech-radar@0.6.8-next.3
|
||||
- @backstage/plugin-techdocs@1.7.0-next.3
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.1.0-next.3
|
||||
- @backstage/plugin-techdocs-react@1.1.10-next.3
|
||||
- @backstage/plugin-todo@0.2.26-next.3
|
||||
- @backstage/plugin-user-settings@0.7.9-next.3
|
||||
- @backstage/theme@0.4.2-next.0
|
||||
- app-next-example-plugin@0.0.1-next.0
|
||||
- @internal/plugin-catalog-customized@0.0.14-next.3
|
||||
|
||||
## 0.0.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app-next",
|
||||
"version": "0.0.1-next.1",
|
||||
"version": "0.0.1-next.2",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
|
||||
@@ -36,7 +36,7 @@ const IndexPage = createPageExtension({
|
||||
id: 'index',
|
||||
defaultPath: '/',
|
||||
routeRef: indexRouteRef,
|
||||
component: async () => {
|
||||
loader: async () => {
|
||||
const Component = () => {
|
||||
const page1Link = useRouteRef(page1RouteRef);
|
||||
return (
|
||||
@@ -59,7 +59,7 @@ const Page1 = createPageExtension({
|
||||
id: 'page1',
|
||||
defaultPath: '/page1',
|
||||
routeRef: page1RouteRef,
|
||||
component: async () => {
|
||||
loader: async () => {
|
||||
const Component = () => {
|
||||
const indexLink = useRouteRef(indexRouteRef);
|
||||
// const page2Link = useRouteRef(page2RouteRef);
|
||||
|
||||
@@ -1,5 +1,80 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.87-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-home@0.5.8-next.3
|
||||
- @backstage/plugin-graphiql@0.2.54-next.3
|
||||
- @backstage/cli@0.22.13-next.3
|
||||
- @backstage/plugin-kubernetes@0.10.3-next.3
|
||||
- @backstage/app-defaults@1.4.3-next.3
|
||||
- @backstage/catalog-model@1.4.2-next.2
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/core-app-api@1.10.0-next.3
|
||||
- @backstage/core-components@0.13.5-next.3
|
||||
- @backstage/core-plugin-api@1.6.0-next.3
|
||||
- @backstage/integration-react@1.1.19-next.3
|
||||
- @backstage/plugin-adr@0.6.7-next.3
|
||||
- @backstage/plugin-airbrake@0.3.24-next.3
|
||||
- @backstage/plugin-apache-airflow@0.2.15-next.3
|
||||
- @backstage/plugin-api-docs@0.9.11-next.3
|
||||
- @backstage/plugin-azure-devops@0.3.6-next.3
|
||||
- @backstage/plugin-azure-sites@0.1.13-next.3
|
||||
- @backstage/plugin-badges@0.2.48-next.3
|
||||
- @backstage/plugin-catalog-common@1.0.16-next.2
|
||||
- @backstage/plugin-catalog-graph@0.2.36-next.3
|
||||
- @backstage/plugin-catalog-import@0.9.14-next.3
|
||||
- @backstage/plugin-catalog-react@1.8.4-next.3
|
||||
- @backstage/plugin-catalog-unprocessed-entities@0.1.3-next.3
|
||||
- @backstage/plugin-circleci@0.3.24-next.3
|
||||
- @backstage/plugin-cloudbuild@0.3.24-next.3
|
||||
- @backstage/plugin-code-coverage@0.2.17-next.3
|
||||
- @backstage/plugin-cost-insights@0.12.13-next.3
|
||||
- @backstage/plugin-devtools@0.1.4-next.3
|
||||
- @backstage/plugin-dynatrace@7.0.4-next.3
|
||||
- @backstage/plugin-entity-feedback@0.2.7-next.3
|
||||
- @backstage/plugin-explore@0.4.10-next.3
|
||||
- @backstage/plugin-gcalendar@0.3.18-next.3
|
||||
- @backstage/plugin-gcp-projects@0.3.41-next.3
|
||||
- @backstage/plugin-github-actions@0.6.5-next.3
|
||||
- @backstage/plugin-gocd@0.1.30-next.3
|
||||
- @backstage/plugin-jenkins@0.8.6-next.3
|
||||
- @backstage/plugin-kafka@0.3.24-next.3
|
||||
- @backstage/plugin-lighthouse@0.4.9-next.3
|
||||
- @backstage/plugin-linguist@0.1.9-next.3
|
||||
- @backstage/plugin-linguist-common@0.1.2-next.0
|
||||
- @backstage/plugin-microsoft-calendar@0.1.7-next.3
|
||||
- @backstage/plugin-newrelic@0.3.40-next.3
|
||||
- @backstage/plugin-newrelic-dashboard@0.2.17-next.3
|
||||
- @backstage/plugin-nomad@0.1.5-next.3
|
||||
- @backstage/plugin-octopus-deploy@0.2.6-next.3
|
||||
- @backstage/plugin-org@0.6.14-next.3
|
||||
- @backstage/plugin-pagerduty@0.6.5-next.3
|
||||
- @backstage/plugin-permission-react@0.4.15-next.3
|
||||
- @backstage/plugin-playlist@0.1.16-next.3
|
||||
- @backstage/plugin-puppetdb@0.1.7-next.3
|
||||
- @backstage/plugin-rollbar@0.4.24-next.3
|
||||
- @backstage/plugin-scaffolder@1.15.0-next.3
|
||||
- @backstage/plugin-scaffolder-react@1.5.5-next.3
|
||||
- @backstage/plugin-search@1.4.0-next.3
|
||||
- @backstage/plugin-search-common@1.2.6-next.2
|
||||
- @backstage/plugin-search-react@1.7.0-next.3
|
||||
- @backstage/plugin-sentry@0.5.9-next.3
|
||||
- @backstage/plugin-shortcuts@0.3.14-next.3
|
||||
- @backstage/plugin-stack-overflow@0.1.20-next.3
|
||||
- @backstage/plugin-stackstorm@0.1.6-next.3
|
||||
- @backstage/plugin-tech-insights@0.3.16-next.3
|
||||
- @backstage/plugin-tech-radar@0.6.8-next.3
|
||||
- @backstage/plugin-techdocs@1.7.0-next.3
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.1.0-next.3
|
||||
- @backstage/plugin-techdocs-react@1.1.10-next.3
|
||||
- @backstage/plugin-todo@0.2.26-next.3
|
||||
- @backstage/plugin-user-settings@0.7.9-next.3
|
||||
- @backstage/theme@0.4.2-next.0
|
||||
- @internal/plugin-catalog-customized@0.0.14-next.3
|
||||
|
||||
## 0.2.87-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.87-next.2",
|
||||
"version": "0.2.87-next.3",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @backstage/backend-app-api
|
||||
|
||||
## 0.5.3-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 154632d8753b: Add support for discovering additional service factories during startup.
|
||||
- cb7fc410ed99: The experimental backend feature discovery now only considers default exports from packages. It no longer filters packages to include based on the package role, except that `'cli'` packages are ignored. However, the `"backstage"` field is still required in `package.json`.
|
||||
- 3b30b179cb38: Add support for installing features as package imports, for example `backend.add(import('my-plugin'))`.
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/plugin-permission-node@0.7.14-next.3
|
||||
- @backstage/backend-plugin-api@0.6.3-next.3
|
||||
- @backstage/backend-common@0.19.5-next.3
|
||||
- @backstage/backend-tasks@0.5.8-next.3
|
||||
- @backstage/cli-common@0.1.12
|
||||
- @backstage/cli-node@0.1.4-next.0
|
||||
- @backstage/config-loader@1.5.0-next.3
|
||||
- @backstage/plugin-auth-node@0.3.0-next.3
|
||||
|
||||
## 0.5.3-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-app-api",
|
||||
"description": "Core API used by Backstage backend apps",
|
||||
"version": "0.5.3-next.2",
|
||||
"version": "0.5.3-next.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.19.5-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.5.3-next.3
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/integration@1.7.0-next.3
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/backend-plugin-api@0.6.3-next.3
|
||||
- @backstage/backend-dev-utils@0.1.1
|
||||
- @backstage/cli-common@0.1.12
|
||||
- @backstage/config-loader@1.5.0-next.3
|
||||
- @backstage/integration-aws-node@0.1.6-next.2
|
||||
|
||||
## 0.19.5-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.19.5-next.2",
|
||||
"version": "0.19.5-next.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/backend-defaults
|
||||
|
||||
## 0.2.3-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.5.3-next.3
|
||||
- @backstage/backend-plugin-api@0.6.3-next.3
|
||||
- @backstage/backend-common@0.19.5-next.3
|
||||
|
||||
## 0.2.3-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-defaults",
|
||||
"description": "Backend defaults used by Backstage backend apps",
|
||||
"version": "0.2.3-next.2",
|
||||
"version": "0.2.3-next.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
# example-backend-next
|
||||
|
||||
## 0.0.15-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-techdocs-backend@1.7.0-next.3
|
||||
- @backstage/plugin-proxy-backend@0.4.0-next.3
|
||||
- @backstage/plugin-adr-backend@0.4.0-next.3
|
||||
- @backstage/plugin-azure-devops-backend@0.4.0-next.3
|
||||
- @backstage/plugin-badges-backend@0.3.0-next.3
|
||||
- @backstage/plugin-catalog-backend-module-unprocessed@0.3.0-next.3
|
||||
- @backstage/plugin-devtools-backend@0.2.0-next.3
|
||||
- @backstage/plugin-entity-feedback-backend@0.2.0-next.3
|
||||
- @backstage/plugin-lighthouse-backend@0.3.0-next.3
|
||||
- @backstage/plugin-linguist-backend@0.5.0-next.3
|
||||
- @backstage/plugin-todo-backend@0.3.0-next.3
|
||||
- @backstage/plugin-app-backend@0.3.51-next.3
|
||||
- @backstage/plugin-catalog-backend@1.13.0-next.3
|
||||
- @backstage/plugin-kubernetes-backend@0.11.6-next.3
|
||||
- @backstage/plugin-permission-backend@0.5.26-next.3
|
||||
- @backstage/plugin-permission-backend-module-allow-all-policy@0.1.0-next.1
|
||||
- @backstage/plugin-scaffolder-backend@1.17.0-next.3
|
||||
- @backstage/plugin-search-backend@1.4.3-next.3
|
||||
- @backstage/plugin-search-backend-module-catalog@0.1.7-next.3
|
||||
- @backstage/plugin-search-backend-module-explore@0.1.7-next.3
|
||||
- @backstage/plugin-search-backend-module-techdocs@0.1.7-next.3
|
||||
- @backstage/plugin-permission-common@0.7.8-next.2
|
||||
- @backstage/plugin-permission-node@0.7.14-next.3
|
||||
- @backstage/backend-plugin-api@0.6.3-next.3
|
||||
- @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.0-next.0
|
||||
- @backstage/backend-defaults@0.2.3-next.3
|
||||
- @backstage/backend-tasks@0.5.8-next.3
|
||||
- @backstage/plugin-auth-node@0.3.0-next.3
|
||||
- @backstage/plugin-search-backend-node@1.2.7-next.3
|
||||
|
||||
## 0.0.15-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend-next",
|
||||
"version": "0.0.15-next.2",
|
||||
"version": "0.0.15-next.3",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -34,6 +34,7 @@
|
||||
"@backstage/plugin-azure-devops-backend": "workspace:^",
|
||||
"@backstage/plugin-badges-backend": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^",
|
||||
"@backstage/plugin-devtools-backend": "workspace:^",
|
||||
"@backstage/plugin-entity-feedback-backend": "workspace:^",
|
||||
|
||||
@@ -23,6 +23,9 @@ backend.add(import('@backstage/plugin-app-backend/alpha'));
|
||||
backend.add(import('@backstage/plugin-azure-devops-backend'));
|
||||
backend.add(import('@backstage/plugin-badges-backend'));
|
||||
backend.add(import('@backstage/plugin-catalog-backend-module-unprocessed'));
|
||||
backend.add(
|
||||
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
|
||||
);
|
||||
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
|
||||
backend.add(import('@backstage/plugin-devtools-backend'));
|
||||
backend.add(import('@backstage/plugin-entity-feedback-backend'));
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @backstage/backend-openapi-utils
|
||||
|
||||
## 0.0.4-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-openapi-utils",
|
||||
"description": "OpenAPI typescript support.",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @backstage/backend-plugin-api
|
||||
|
||||
## 0.6.3-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ba4506076e2d: Ensure that root scoped services cannot accept (at a type level) plugin scoped deps
|
||||
- 474b792d6a43: Service factory functions are now marked as feature factories that can be installed in the backend.
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/plugin-permission-common@0.7.8-next.2
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/backend-tasks@0.5.8-next.3
|
||||
- @backstage/plugin-auth-node@0.3.0-next.3
|
||||
|
||||
## 0.6.3-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-plugin-api",
|
||||
"description": "Core API used by Backstage backend plugins",
|
||||
"version": "0.6.3-next.2",
|
||||
"version": "0.6.3-next.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @backstage/backend-plugin-manager
|
||||
|
||||
## 0.0.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-backend@1.13.0-next.3
|
||||
- @backstage/plugin-events-backend@0.2.12-next.3
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/plugin-permission-common@0.7.8-next.2
|
||||
- @backstage/plugin-search-common@1.2.6-next.2
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/plugin-permission-node@0.7.14-next.3
|
||||
- @backstage/backend-plugin-api@0.6.3-next.3
|
||||
- @backstage/backend-common@0.19.5-next.3
|
||||
- @backstage/backend-tasks@0.5.8-next.3
|
||||
- @backstage/cli-common@0.1.12
|
||||
- @backstage/cli-node@0.1.4-next.0
|
||||
- @backstage/plugin-auth-node@0.3.0-next.3
|
||||
- @backstage/plugin-events-node@0.2.12-next.3
|
||||
- @backstage/plugin-scaffolder-node@0.2.3-next.3
|
||||
- @backstage/plugin-search-backend-node@1.2.7-next.3
|
||||
|
||||
## 0.0.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-backend-plugin-manager
|
||||
title: '@backstage/backend-plugin-manager'
|
||||
description: Backstage plugin management backend
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-node-library
|
||||
owner: maintainers
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-plugin-manager",
|
||||
"description": "Backstage plugin management backend",
|
||||
"version": "0.0.1-next.0",
|
||||
"version": "0.0.1-next.1",
|
||||
"private": true,
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/backend-tasks
|
||||
|
||||
## 0.5.8-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/backend-common@0.19.5-next.3
|
||||
|
||||
## 0.5.8-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-tasks",
|
||||
"description": "Common distributed task management library for Backstage backends",
|
||||
"version": "0.5.8-next.2",
|
||||
"version": "0.5.8-next.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -330,6 +330,48 @@ describe('TaskWorker', () => {
|
||||
const before = fn1.mock.calls.length;
|
||||
await promise2;
|
||||
expect(fn1.mock.calls.length).toBeGreaterThan(before);
|
||||
|
||||
await knex.destroy();
|
||||
},
|
||||
);
|
||||
|
||||
it.each(databases.eachSupportedId())(
|
||||
'next_run_start_at is always the min between schedule changes, %p',
|
||||
async databaseId => {
|
||||
const knex = await databases.init(databaseId);
|
||||
await migrateBackendTasks(knex);
|
||||
|
||||
const fn = jest.fn(
|
||||
async () => new Promise<void>(resolve => setTimeout(resolve, 50)),
|
||||
);
|
||||
const settings: TaskSettingsV2 = {
|
||||
version: 2,
|
||||
cadence: '*/15 * * * *',
|
||||
initialDelayDuration: 'PT2M',
|
||||
timeoutAfterDuration: 'PT1M',
|
||||
};
|
||||
|
||||
const worker = new TaskWorker('task99', fn, knex, logger);
|
||||
await worker.persistTask(settings);
|
||||
const row1 = (await knex<DbTasksRow>(DB_TASKS_TABLE))[0];
|
||||
|
||||
const settings2 = {
|
||||
...settings,
|
||||
cadence: '*/2 * * * *',
|
||||
initialDelayDuration: 'PT1M',
|
||||
};
|
||||
await worker.persistTask(settings2);
|
||||
const row2 = (await knex<DbTasksRow>(DB_TASKS_TABLE))[0];
|
||||
|
||||
expect(row2.next_run_start_at).not.toStrictEqual(row1.next_run_start_at);
|
||||
|
||||
const settings3 = { ...settings };
|
||||
await worker.persistTask(settings3);
|
||||
const row3 = (await knex<DbTasksRow>(DB_TASKS_TABLE))[0];
|
||||
|
||||
expect(row3.next_run_start_at).toStrictEqual(row2.next_run_start_at);
|
||||
|
||||
await knex.destroy();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -192,14 +192,36 @@ export class TaskWorker {
|
||||
|
||||
// It's OK if the task already exists; if it does, just replace its
|
||||
// settings with the new value and start the loop as usual.
|
||||
const settingsJson = JSON.stringify(settings);
|
||||
await this.knex<DbTasksRow>(DB_TASKS_TABLE)
|
||||
.insert({
|
||||
id: this.taskId,
|
||||
settings_json: JSON.stringify(settings),
|
||||
settings_json: settingsJson,
|
||||
next_run_start_at: startAt,
|
||||
})
|
||||
.onConflict('id')
|
||||
.merge(['settings_json']);
|
||||
.merge(
|
||||
this.knex.client.config.client.includes('mysql')
|
||||
? {
|
||||
settings_json: settingsJson,
|
||||
next_run_start_at: this.knex.raw(
|
||||
`CASE WHEN ?? < ?? THEN ?? ELSE ?? END`,
|
||||
[startAt, 'next_run_start_at', startAt, 'next_run_start_at'],
|
||||
),
|
||||
}
|
||||
: {
|
||||
settings_json: this.knex.ref('excluded.settings_json'),
|
||||
next_run_start_at: this.knex.raw(
|
||||
`CASE WHEN ?? < ?? THEN ?? ELSE ?? END`,
|
||||
[
|
||||
'excluded.next_run_start_at',
|
||||
`${DB_TASKS_TABLE}.next_run_start_at`,
|
||||
'excluded.next_run_start_at',
|
||||
`${DB_TASKS_TABLE}.next_run_start_at`,
|
||||
],
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @backstage/backend-test-utils
|
||||
|
||||
## 0.2.3-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 202e52c5e361: Add support for installing backend features via module imports, for example `startTestBackend({ features: [import('my-plugin')] })`.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.5.3-next.3
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/backend-plugin-api@0.6.3-next.3
|
||||
- @backstage/backend-common@0.19.5-next.3
|
||||
- @backstage/plugin-auth-node@0.3.0-next.3
|
||||
|
||||
## 0.2.3-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-test-utils",
|
||||
"description": "Test helpers library for Backstage backends",
|
||||
"version": "0.2.3-next.2",
|
||||
"version": "0.2.3-next.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,64 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.87-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-techdocs-backend@1.7.0-next.3
|
||||
- @backstage/plugin-proxy-backend@0.4.0-next.3
|
||||
- @backstage/plugin-adr-backend@0.4.0-next.3
|
||||
- @backstage/plugin-auth-backend@0.19.0-next.3
|
||||
- @backstage/plugin-azure-devops-backend@0.4.0-next.3
|
||||
- @backstage/plugin-badges-backend@0.3.0-next.3
|
||||
- @backstage/plugin-catalog-backend-module-unprocessed@0.3.0-next.3
|
||||
- @backstage/plugin-devtools-backend@0.2.0-next.3
|
||||
- @backstage/plugin-entity-feedback-backend@0.2.0-next.3
|
||||
- @backstage/plugin-kafka-backend@0.3.0-next.3
|
||||
- @backstage/plugin-lighthouse-backend@0.3.0-next.3
|
||||
- @backstage/plugin-linguist-backend@0.5.0-next.3
|
||||
- @backstage/plugin-todo-backend@0.3.0-next.3
|
||||
- @backstage/plugin-app-backend@0.3.51-next.3
|
||||
- @backstage/plugin-catalog-backend@1.13.0-next.3
|
||||
- @backstage/plugin-events-backend@0.2.12-next.3
|
||||
- @backstage/plugin-kubernetes-backend@0.11.6-next.3
|
||||
- @backstage/plugin-permission-backend@0.5.26-next.3
|
||||
- @backstage/plugin-scaffolder-backend@1.17.0-next.3
|
||||
- @backstage/plugin-search-backend@1.4.3-next.3
|
||||
- @backstage/plugin-search-backend-module-catalog@0.1.7-next.3
|
||||
- @backstage/plugin-search-backend-module-elasticsearch@1.3.6-next.3
|
||||
- @backstage/plugin-search-backend-module-explore@0.1.7-next.3
|
||||
- @backstage/plugin-search-backend-module-pg@0.5.12-next.3
|
||||
- @backstage/plugin-search-backend-module-techdocs@0.1.7-next.3
|
||||
- @backstage/catalog-client@1.4.4-next.2
|
||||
- @backstage/catalog-model@1.4.2-next.2
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/integration@1.7.0-next.3
|
||||
- @backstage/plugin-permission-common@0.7.8-next.2
|
||||
- @backstage/plugin-search-common@1.2.6-next.2
|
||||
- @backstage/plugin-permission-node@0.7.14-next.3
|
||||
- @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.0-next.0
|
||||
- example-app@0.2.87-next.3
|
||||
- @backstage/backend-common@0.19.5-next.3
|
||||
- @backstage/plugin-explore-backend@0.0.13-next.3
|
||||
- @backstage/backend-tasks@0.5.8-next.3
|
||||
- @backstage/plugin-auth-node@0.3.0-next.3
|
||||
- @backstage/plugin-azure-sites-backend@0.1.13-next.3
|
||||
- @backstage/plugin-catalog-node@1.4.4-next.3
|
||||
- @backstage/plugin-code-coverage-backend@0.2.17-next.3
|
||||
- @backstage/plugin-events-node@0.2.12-next.3
|
||||
- @backstage/plugin-graphql-backend@0.1.41-next.3
|
||||
- @backstage/plugin-jenkins-backend@0.2.6-next.3
|
||||
- @backstage/plugin-nomad-backend@0.1.5-next.3
|
||||
- @backstage/plugin-playlist-backend@0.3.7-next.3
|
||||
- @backstage/plugin-rollbar-backend@0.1.48-next.3
|
||||
- @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.4-next.3
|
||||
- @backstage/plugin-scaffolder-backend-module-rails@0.4.20-next.3
|
||||
- @backstage/plugin-search-backend-node@1.2.7-next.3
|
||||
- @backstage/plugin-tech-insights-backend@0.5.17-next.3
|
||||
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.35-next.3
|
||||
- @backstage/plugin-tech-insights-node@0.4.9-next.3
|
||||
|
||||
## 0.2.87-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.87-next.2",
|
||||
"version": "0.2.87-next.3",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -40,6 +40,7 @@
|
||||
"@backstage/plugin-azure-sites-backend": "workspace:^",
|
||||
"@backstage/plugin-badges-backend": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^",
|
||||
"@backstage/plugin-catalog-node": "workspace:^",
|
||||
"@backstage/plugin-code-coverage-backend": "workspace:^",
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
|
||||
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
|
||||
import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend';
|
||||
import { ScaffolderEntitiesProcessor } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model';
|
||||
import { UnprocessedEntitiesModule } from '@backstage/plugin-catalog-backend-module-unprocessed';
|
||||
import { Router } from 'express';
|
||||
import { PluginEnvironment } from '../types';
|
||||
import { DemoEventBasedEntityProvider } from './DemoEventBasedEntityProvider';
|
||||
import { UnprocessedEntitiesModule } from '@backstage/plugin-catalog-backend-module-unprocessed';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/catalog-client
|
||||
|
||||
## 1.4.4-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.4.2-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
|
||||
## 1.4.4-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/catalog-client",
|
||||
"description": "An isomorphic client for the catalog backend",
|
||||
"version": "1.4.4-next.1",
|
||||
"version": "1.4.4-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/catalog-model
|
||||
|
||||
## 1.4.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/types@1.1.1-next.0
|
||||
|
||||
## 1.4.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/catalog-model",
|
||||
"description": "Types and validators that help describe the model of a Backstage Catalog",
|
||||
"version": "1.4.2-next.1",
|
||||
"version": "1.4.2-next.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/cli-node
|
||||
|
||||
## 0.1.4-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/cli-common@0.1.12
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli-node",
|
||||
"description": "Node.js library for Backstage CLIs",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.22.13-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4d5eeec52d80: Add ESM loader for the experimental backend start command.
|
||||
- 3494c502aba7: Added a new `repo fix` command that fixes auto-fixable problems in all packages. Initially the command fixes package export declarations, as well as marks all non-bundled frontend packages as side-effect free. Marking packages as free of side-effects can drastically reduce the Webpack bundle size.
|
||||
- f36113ca2305: Add experimental support for frontend package discovery.
|
||||
- a23fce763c6a: Fixed a bug where package exports entry points could not be `.tsx` files.
|
||||
- 4af4defcc114: When running `version:bump` it will now log duplicates instead of throwing an error
|
||||
- 956d226eeeee: Add `"sideEffects": false` to `package.json` in frontend package templates. This can be added to existing packages using the new `yarn fix` command.
|
||||
- cd7331587eb3: Removed the experimental `package fix` command that was used to automatically add dependencies to `package.json`, but has since been replaced by the `no-undeclared-imports` rule from `@backstage/eslint-plugin`.
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.4.2-next.2
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/integration@1.7.0-next.3
|
||||
- @backstage/release-manifests@0.0.10-next.1
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/cli-common@0.1.12
|
||||
- @backstage/cli-node@0.1.4-next.0
|
||||
- @backstage/config-loader@1.5.0-next.3
|
||||
- @backstage/eslint-plugin@0.1.3
|
||||
|
||||
## 0.22.13-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"version": "0.22.13-next.2",
|
||||
"version": "0.22.13-next.3",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 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 { paths } from '../lib/paths';
|
||||
import { ESLint } from 'eslint';
|
||||
import { join as joinPath, basename } from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import { isChildPath } from '@backstage/cli-common';
|
||||
import { PackageGraph } from '@backstage/cli-node';
|
||||
|
||||
function isTestPath(filePath: string) {
|
||||
if (!isChildPath(joinPath(paths.targetDir, 'src'), filePath)) {
|
||||
return true;
|
||||
}
|
||||
const name = basename(filePath);
|
||||
return (
|
||||
name.startsWith('setupTests.') ||
|
||||
name.includes('.test.') ||
|
||||
name.includes('.stories.')
|
||||
);
|
||||
}
|
||||
|
||||
export async function command() {
|
||||
const pkgJsonPath = paths.resolveTarget('package.json');
|
||||
const pkg = await fs.readJson(pkgJsonPath);
|
||||
if (pkg.workspaces) {
|
||||
throw new Error(
|
||||
'Adding dependencies to the workspace root is not supported',
|
||||
);
|
||||
}
|
||||
|
||||
const packages = await PackageGraph.listTargetPackages();
|
||||
const localPackageVersions = new Map(
|
||||
packages.map(p => [p.packageJson.name, p.packageJson.version]),
|
||||
);
|
||||
|
||||
const eslint = new ESLint({
|
||||
cwd: paths.targetDir,
|
||||
overrideConfig: {
|
||||
plugins: ['monorepo'],
|
||||
rules: {
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: [
|
||||
`!${joinPath(paths.targetDir, 'src/**')}`,
|
||||
joinPath(paths.targetDir, 'src/**/*.test.*'),
|
||||
joinPath(paths.targetDir, 'src/**/*.stories.*'),
|
||||
joinPath(paths.targetDir, 'src/setupTests.*'),
|
||||
],
|
||||
optionalDependencies: true,
|
||||
peerDependencies: true,
|
||||
bundledDependencies: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
extensions: ['jsx', 'ts', 'tsx', 'mjs', 'cjs'],
|
||||
});
|
||||
|
||||
const results = await eslint.lintFiles(['.']);
|
||||
|
||||
const addedDeps = new Set<string>();
|
||||
const addedDevDeps = new Set<string>();
|
||||
const removedDevDeps = new Set<string>();
|
||||
|
||||
for (const result of results) {
|
||||
for (const message of result.messages) {
|
||||
// Just in case
|
||||
if (message.ruleId !== 'import/no-extraneous-dependencies') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = message.message.match(/^'([^']*)' should be listed/);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
const packageName = match[1];
|
||||
if (!localPackageVersions.has(packageName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.message.endsWith('not devDependencies.')) {
|
||||
addedDeps.add(packageName);
|
||||
removedDevDeps.add(packageName);
|
||||
} else if (isTestPath(result.filePath)) {
|
||||
addedDevDeps.add(packageName);
|
||||
} else {
|
||||
addedDeps.add(packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addedDeps.size || addedDevDeps.size || removedDevDeps.size) {
|
||||
for (const name of addedDeps) {
|
||||
if (!pkg.dependencies) {
|
||||
pkg.dependencies = {};
|
||||
}
|
||||
pkg.dependencies[name] = `^${localPackageVersions.get(name)}`;
|
||||
}
|
||||
for (const name of addedDevDeps) {
|
||||
if (!pkg.devDependencies) {
|
||||
pkg.devDependencies = {};
|
||||
}
|
||||
pkg.devDependencies[name] = `^${localPackageVersions.get(name)}`;
|
||||
}
|
||||
for (const name of removedDevDeps) {
|
||||
delete pkg.devDependencies[name];
|
||||
}
|
||||
if (Object.keys(pkg.devDependencies).length === 0) {
|
||||
delete pkg.devDependencies;
|
||||
}
|
||||
|
||||
if (pkg.dependencies) {
|
||||
pkg.dependencies = Object.fromEntries(
|
||||
Object.entries(pkg.dependencies).sort(([a], [b]) => a.localeCompare(b)),
|
||||
);
|
||||
}
|
||||
if (pkg.devDependencies) {
|
||||
pkg.devDependencies = Object.fromEntries(
|
||||
Object.entries(pkg.devDependencies).sort(([a], [b]) =>
|
||||
a.localeCompare(b),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await fs.writeJson(pkgJsonPath, pkg, { spaces: 2 });
|
||||
}
|
||||
}
|
||||
@@ -168,12 +168,6 @@ export function registerScriptCommand(program: Command) {
|
||||
.description('Run tests, forwarding args to Jest, defaulting to watch mode')
|
||||
.action(lazy(() => import('./test').then(m => m.default)));
|
||||
|
||||
command
|
||||
.command('fix', { hidden: true })
|
||||
.description('Applies automated fixes to the package. [EXPERIMENTAL]')
|
||||
.option('--deps', 'Only fix monorepo dependencies in package.json')
|
||||
.action(lazy(() => import('./fix').then(m => m.command)));
|
||||
|
||||
command
|
||||
.command('clean')
|
||||
.description('Delete cache directories')
|
||||
|
||||
@@ -29,6 +29,7 @@ import { YarnInfoInspectData } from '../../lib/versioning/packages';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { rest } from 'msw';
|
||||
import { NotFoundError } from '@backstage/errors';
|
||||
import { Lockfile } from '../../lib/versioning/Lockfile';
|
||||
|
||||
// Remove log coloring to simplify log matching
|
||||
jest.mock('chalk', () => ({
|
||||
@@ -224,7 +225,7 @@ describe('bump', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should bump backstage dependencies but not them installed', async () => {
|
||||
it('should bump backstage dependencies but not install them', async () => {
|
||||
mockFs({
|
||||
'/yarn.lock': lockfileMock,
|
||||
'/package.json': JSON.stringify({
|
||||
@@ -453,68 +454,36 @@ describe('bump', () => {
|
||||
jest.spyOn(runObj, 'run').mockResolvedValue(undefined);
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://versions.backstage.io/v1/releases/1.0.0/manifest.json',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
releaseVersion: '2.0.0',
|
||||
packages: [
|
||||
{ name: '@backstage/core', version: '5.0.0' },
|
||||
{ name: '@backstage/core-api', version: '5.0.0' },
|
||||
],
|
||||
}),
|
||||
),
|
||||
'https://versions.backstage.io/v1/releases/999.0.1/manifest.json',
|
||||
(_, res, ctx) => res(ctx.status(404), ctx.json({})),
|
||||
),
|
||||
);
|
||||
const { log: logs } = await withLogCollector(['log'], async () => {
|
||||
await expect(
|
||||
bump({ pattern: null, release: '1.0.0' } as unknown as Command),
|
||||
).rejects.toThrow('Duplicate versions present after package bump');
|
||||
bump({ pattern: null, release: '999.0.1' } as unknown as Command),
|
||||
).rejects.toThrow('No release found for 999.0.1 version');
|
||||
});
|
||||
expect(logs.filter(Boolean)).toEqual([
|
||||
'Using default pattern glob @backstage/*',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'Package info not found, ignoring package @backstage/theme',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'Checking for updates of @backstage/core-api',
|
||||
'Package info not found, ignoring package @backstage/theme',
|
||||
'Some packages are outdated, updating',
|
||||
'bumping @backstage/core in a to ^5.0.0',
|
||||
'bumping @backstage/core in b to ^5.0.0',
|
||||
'Your project is now at version 2.0.0, which has been written to backstage.json',
|
||||
'Running yarn install to install new versions',
|
||||
'⚠️ The following packages may have breaking changes:',
|
||||
' @backstage/core : 1.0.3 ~> 5.0.0',
|
||||
' https://github.com/backstage/backstage/blob/master/packages/core/CHANGELOG.md',
|
||||
'Version bump complete!',
|
||||
]);
|
||||
|
||||
expect(runObj.run).toHaveBeenCalledTimes(1);
|
||||
expect(runObj.run).toHaveBeenCalledWith(
|
||||
'yarn',
|
||||
['install'],
|
||||
expect.any(Object),
|
||||
);
|
||||
expect(runObj.run).toHaveBeenCalledTimes(0);
|
||||
|
||||
const packageA = await fs.readJson('/packages/a/package.json');
|
||||
expect(packageA).toEqual({
|
||||
name: 'a',
|
||||
dependencies: {
|
||||
'@backstage/core': '^5.0.0',
|
||||
'@backstage/core': '^1.0.5',
|
||||
},
|
||||
});
|
||||
const packageB = await fs.readJson('/packages/b/package.json');
|
||||
expect(packageB).toEqual({
|
||||
name: 'b',
|
||||
dependencies: {
|
||||
'@backstage/core': '^5.0.0',
|
||||
'@backstage/core': '^1.0.3',
|
||||
'@backstage/theme': '^1.0.0',
|
||||
},
|
||||
});
|
||||
expect(await fs.readJson('/backstage.json')).toEqual({ version: '2.0.0' });
|
||||
});
|
||||
|
||||
it('should prefer versions from the highest manifest version when main is not specified', async () => {
|
||||
@@ -825,6 +794,97 @@ describe('bump', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should log duplicates', async () => {
|
||||
jest.spyOn(Lockfile.prototype, 'analyze').mockReturnValue({
|
||||
invalidRanges: [],
|
||||
newVersions: [],
|
||||
newRanges: [
|
||||
{
|
||||
name: 'first-duplicate',
|
||||
oldRange: 'first-duplicate',
|
||||
newRange: 'first-duplicate',
|
||||
oldVersion: '1.0.0',
|
||||
newVersion: '2.0.0',
|
||||
},
|
||||
{
|
||||
name: 'second-duplicate',
|
||||
oldRange: 'second-duplicate',
|
||||
newRange: 'second-duplicate',
|
||||
oldVersion: '1.0.0',
|
||||
newVersion: '2.0.0',
|
||||
},
|
||||
{
|
||||
name: 'third-duplicate',
|
||||
oldRange: 'third-duplicate',
|
||||
newRange: 'third-duplicate',
|
||||
oldVersion: '1.0.0',
|
||||
newVersion: '2.0.0',
|
||||
},
|
||||
],
|
||||
});
|
||||
mockFs({
|
||||
'/yarn.lock': lockfileMock,
|
||||
'/package.json': JSON.stringify({
|
||||
workspaces: {
|
||||
packages: ['packages/*'],
|
||||
},
|
||||
}),
|
||||
'/packages/a/package.json': JSON.stringify({
|
||||
name: 'a',
|
||||
dependencies: {
|
||||
'@backstage/core': '^1.0.5',
|
||||
},
|
||||
}),
|
||||
'/packages/b/package.json': JSON.stringify({
|
||||
name: 'b',
|
||||
dependencies: {
|
||||
'@backstage/core': '^1.0.3',
|
||||
'@backstage/theme': '^1.0.0',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
jest
|
||||
.spyOn(paths, 'resolveTargetRoot')
|
||||
.mockImplementation((...path) => resolvePath('/', ...path));
|
||||
jest.spyOn(runObj, 'run').mockResolvedValue(undefined);
|
||||
worker.use(
|
||||
rest.get(
|
||||
'https://versions.backstage.io/v1/tags/main/manifest.json',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
packages: [],
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
const { log: logs } = await withLogCollector(['log'], async () => {
|
||||
await bump({ pattern: null, release: 'main' } as unknown as Command);
|
||||
});
|
||||
expect(logs.filter(Boolean)).toEqual([
|
||||
'Using default pattern glob @backstage/*',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'Checking for updates of @backstage/core-api',
|
||||
'Some packages are outdated, updating',
|
||||
'unlocking @backstage/core@^1.0.3 ~> 1.0.6',
|
||||
'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7',
|
||||
'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7',
|
||||
'bumping @backstage/core in a to ^1.0.6',
|
||||
'bumping @backstage/core in b to ^1.0.6',
|
||||
'bumping @backstage/theme in b to ^2.0.0',
|
||||
'Running yarn install to install new versions',
|
||||
'⚠️ The following packages may have breaking changes:',
|
||||
' @backstage/theme : 1.0.0 ~> 2.0.0',
|
||||
' https://github.com/backstage/backstage/blob/master/packages/theme/CHANGELOG.md',
|
||||
'Version bump complete!',
|
||||
'The following packages have duplicates but have been allowed:',
|
||||
'first-duplicate, second-duplicate, third-duplicate',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bumpBackstageJsonVersion', () => {
|
||||
|
||||
@@ -314,10 +314,6 @@ export default async (opts: OptionValues) => {
|
||||
),
|
||||
});
|
||||
|
||||
if (result.newVersions.length > 0) {
|
||||
throw new Error('Duplicate versions present after package bump');
|
||||
}
|
||||
|
||||
const forbiddenNewRanges = result.newRanges.filter(({ name }) =>
|
||||
forbiddenDuplicatesFilter(name),
|
||||
);
|
||||
@@ -328,6 +324,19 @@ export default async (opts: OptionValues) => {
|
||||
.join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
const allowedDuplicates = result.newRanges.filter(
|
||||
({ name }) => !forbiddenDuplicatesFilter(name),
|
||||
);
|
||||
|
||||
if (allowedDuplicates.length > 0) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'The following packages have duplicates but have been allowed:',
|
||||
),
|
||||
);
|
||||
console.log(chalk.yellow(allowedDuplicates.map(i => i.name).join(', ')));
|
||||
}
|
||||
};
|
||||
|
||||
export function createStrictVersionFinder(options: {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/config-loader
|
||||
|
||||
## 1.5.0-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/types@1.1.1-next.0
|
||||
- @backstage/cli-common@0.1.12
|
||||
|
||||
## 1.5.0-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user