Merge branch 'master' into migrating_k8s_frontend
Signed-off-by: Nurit Izrailov <38442135+nuritizra@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Use ES2022 in CLI bundler
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
'@backstage/plugin-search-react': patch
|
||||
'@backstage/plugin-home': patch
|
||||
---
|
||||
|
||||
Updated alpha definitions of extension data references.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Move the `Link` component to the `RoutedTabs` instead of the `HeaderTabs` component
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
---
|
||||
|
||||
Add ability to customise form fields in the UI by exposing `uiSchema` and `formContext` in `FormProps`
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Added a new `IconBundleBlueprint` that lets you create icon bundle extensions that can be installed in an App in order to override or add new app icons.
|
||||
|
||||
```tsx
|
||||
import { IconBundleBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
const exampleIconBundle = IconBundleBlueprint.make({
|
||||
name: 'example-bundle',
|
||||
params: {
|
||||
icons: {
|
||||
user: MyOwnUserIcon,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': patch
|
||||
---
|
||||
|
||||
Support icon overriding with the new `IconBundleBlueprint` API.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-defaults': patch
|
||||
---
|
||||
|
||||
The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Updated default backend plugin to use `RootConfigService` instead of `Config`. This also removes the dependency on `@backstage/config` as it's no longer used.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-graph': patch
|
||||
---
|
||||
|
||||
Memoize entity graph nodes when applying an `entityFilter` to prevent repeated redraws
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
The experimental module federation build now has the ability to force the use of development versions of `react` and `react-dom` by setting the `FORCE_REACT_DEVELOPMENT` flag.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
---
|
||||
|
||||
support `ajv-errors` for scaffolder validation to allow for customizing the error messages
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-devtools-backend': patch
|
||||
---
|
||||
|
||||
Removed unused code for lockfile analysis.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend-module-microsoft-provider': patch
|
||||
---
|
||||
|
||||
Updated the Microsoft authenticator to accurately define required scopes, but to also omit the required and additional scopes when requesting resource scopes.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search-backend-module-pg': patch
|
||||
---
|
||||
|
||||
Removing `@backstage/backend-app-api` dependency
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Remove usage of deprecated functionality from @backstage/config-loader
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Added test cases for gitlab:issue:edit examples
|
||||
+51
-1
@@ -188,5 +188,55 @@
|
||||
"@backstage/plugin-user-settings-backend": "0.2.21",
|
||||
"@backstage/plugin-user-settings-common": "0.0.1"
|
||||
},
|
||||
"changesets": []
|
||||
"changesets": [
|
||||
"blue-pumas-cheer",
|
||||
"bright-trainers-brake",
|
||||
"chilly-trains-sleep",
|
||||
"cool-insects-remember",
|
||||
"cuddly-zebras-crash",
|
||||
"dry-squids-tap",
|
||||
"dull-ghosts-double",
|
||||
"early-trees-dance",
|
||||
"eighty-mirrors-flow",
|
||||
"flat-plums-grow",
|
||||
"forty-ties-agree",
|
||||
"forty-ties-disagree",
|
||||
"friendly-feet-refuse",
|
||||
"gentle-dryers-smile",
|
||||
"grumpy-owls-suffer",
|
||||
"heavy-numbers-love",
|
||||
"hip-hairs-exist",
|
||||
"late-games-protect",
|
||||
"light-pianos-exercise",
|
||||
"little-bulldogs-guess",
|
||||
"little-suns-fly",
|
||||
"mighty-dolls-retire",
|
||||
"modern-parrots-protect",
|
||||
"neat-gifts-join",
|
||||
"new-scissors-try",
|
||||
"nice-peas-retire",
|
||||
"nine-cherries-decide",
|
||||
"nine-glasses-nail",
|
||||
"ninety-icons-smile",
|
||||
"pink-gorillas-brake",
|
||||
"plenty-tools-exist",
|
||||
"rich-mugs-dress",
|
||||
"selfish-bees-think",
|
||||
"six-rats-kick",
|
||||
"slow-toes-jog",
|
||||
"small-spoons-shout",
|
||||
"soft-gorillas-refuse",
|
||||
"spotty-planets-accept",
|
||||
"strange-papayas-beg",
|
||||
"strong-otters-compete",
|
||||
"stupid-dots-relate",
|
||||
"swift-kings-sparkle",
|
||||
"thirty-paws-hope",
|
||||
"tiny-oranges-pretend",
|
||||
"tough-lies-repair",
|
||||
"violet-jokes-wave",
|
||||
"wicked-bobcats-teach",
|
||||
"wild-eggs-exist",
|
||||
"witty-bears-behave"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/config-loader': patch
|
||||
---
|
||||
|
||||
Add boolean `allowMissingDefaultConfig` option to `ConfigSources.default` and
|
||||
`ConfigSources.defaultForTargets`, which results in omission of a ConfigSource
|
||||
for the default app-config.yaml configuration file if it's not present.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Added test cases for gitlab:projectAccessToken:create example
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-home': patch
|
||||
---
|
||||
|
||||
Fixed a bug on the WelcomeTitle component where the welcome message wasn't correct when the language was set to Spanish
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
'@backstage/cli': minor
|
||||
---
|
||||
|
||||
**BREAKING**: The lockfile (`yarn.lock`) dependency analysis and mutations have been removed from several commands.
|
||||
|
||||
The `versions:bump` command will no longer attempt to bump and deduplicate dependencies by modifying the lockfile, it will only update `package.json` files.
|
||||
|
||||
The `versions:check` command has been removed, since its only purpose was verification and mutation of the lockfile. We recommend using the `yarn dedupe` command instead, or the `yarn-deduplicate` package if you're using Yarn classic.
|
||||
|
||||
The check that was built into the `package start` command has been removed, it will no longer warn about lockfile mismatches.
|
||||
|
||||
The packages in the Backstage ecosystem handle package duplications much better now than when these CLI features were first introduced, so the need for these features has diminished. By removing them, we drastically reduce the integration between the Backstage CLI and Yarn, making it much easier to add support for other package managers in the future.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-test-utils': patch
|
||||
---
|
||||
|
||||
The default services for `startTestBackend` and `ServiceFactoryTester` now includes the Root Health Service.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Cleaned up codebase of RepoUrlPicker
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Added test cases for gitlab:pipeline:trigger examples
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Add support for dynamic plugins via the EXPERIMENTAL_MODULE_FEDERATION environment variable when running `yarn start`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
---
|
||||
|
||||
The request to delete the session cookie when running the app in protected mode is now done with a plain `fetch` rather than `FetchApi`. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout.
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
---
|
||||
|
||||
Extension data references can now be defined in a way that encapsulates the ID string in the type, in addition to the data type itself. The old way of creating extension data references is deprecated and will be removed in a future release.
|
||||
|
||||
For example, the following code:
|
||||
|
||||
```ts
|
||||
export const myExtension = createExtensionDataRef<MyType>('my-plugin.my-data');
|
||||
```
|
||||
|
||||
Should be updated to the following:
|
||||
|
||||
```ts
|
||||
export const myExtension = createExtensionDataRef<MyType>().with({
|
||||
id: 'my-plugin.my-data',
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Fix issue with `RepoUrlPicker` not refreshing the credentials for a different host
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fix for `repo build --all` not properly detecting the experimental public entry point.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-react': patch
|
||||
---
|
||||
|
||||
feat: Hide visibility of CookieAuthRedirect
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Add custom action for merge request: **auto**
|
||||
|
||||
The **Auto** action selects the committed action between _create_ and _update_.
|
||||
|
||||
The **Auto** action fetches files using the **/projects/repository/tree endpoint**.
|
||||
After fetching, it checks if the file exists locally and in the repository. If it does, it chooses **update**; otherwise, it chooses **create**.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/integration': patch
|
||||
---
|
||||
|
||||
Updated functions for `getHarnessEditContentsUrl`, `getHarnessFileContentsUrl`, `getHarnessArchiveUrl`, `getHarnessLatestCommitUrl` and `parseHarnessUrl` to handle account and org level urls
|
||||
@@ -7,6 +7,7 @@ ADRs
|
||||
airbrake
|
||||
Airbrake
|
||||
Airbrakes
|
||||
ajv
|
||||
Alaria
|
||||
Alef
|
||||
allowlisted
|
||||
@@ -84,7 +85,9 @@ debounce
|
||||
Debounce
|
||||
debuggability
|
||||
declaratively
|
||||
deduplicate
|
||||
deduplicated
|
||||
deduplication
|
||||
deliverables
|
||||
denormalized
|
||||
dependabot
|
||||
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
@@ -67,8 +67,6 @@ auth:
|
||||
clientSecret: ${AZURE_CLIENT_SECRET}
|
||||
tenantId: ${AZURE_TENANT_ID}
|
||||
domainHint: ${AZURE_TENANT_ID}
|
||||
additionalScopes:
|
||||
- Mail.Send
|
||||
signIn:
|
||||
resolvers:
|
||||
# typically you would pick one of these
|
||||
@@ -86,7 +84,7 @@ The Microsoft provider is a structure with three mandatory configuration keys:
|
||||
Leave blank if your app registration is multi tenant.
|
||||
When specified, this reduces login friction for users with accounts in multiple tenants by automatically filtering away accounts from other tenants.
|
||||
For more details, see [Home Realm Discovery](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/home-realm-discovery-policy)
|
||||
- `additionalScopes` (optional): List of scopes for the App Registration. The default and mandatory value is ['user.read'].
|
||||
- `additionalScopes` (optional): List of scopes for the App Registration, to be requested in addition to the required ones.
|
||||
|
||||
### Resolvers
|
||||
|
||||
|
||||
@@ -26,6 +26,25 @@ parameters:
|
||||
ui:help: 'Hint: additional description...'
|
||||
```
|
||||
|
||||
#### Custom validation error message
|
||||
|
||||
```yaml
|
||||
parameters:
|
||||
- title: Fill in some steps
|
||||
properties:
|
||||
name:
|
||||
title: Simple text input
|
||||
type: string
|
||||
description: Description about input
|
||||
maxLength: 8
|
||||
pattern: '^([a-zA-Z][a-zA-Z0-9]*)(-[a-zA-Z0-9]+)*$'
|
||||
ui:autofocus: true
|
||||
ui:help: 'Hint: additional description...'
|
||||
errorMessage:
|
||||
properties:
|
||||
name: '1-8 alphanumeric tokens (first starts with letter) delimited by -'
|
||||
```
|
||||
|
||||
### Multi line text input
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -533,6 +533,11 @@ catalogFilter:
|
||||
metadata.annotations.github.com/team-slug: { exists: true }
|
||||
```
|
||||
|
||||
#### Custom validation messages
|
||||
|
||||
You may specify custom JSON Schema validation messages as supported by the
|
||||
[ajv-errors](https://github.com/ajv-validator/ajv-errors) plugin library to [ajv](https://github.com/ajv-validator/ajv).
|
||||
|
||||
## `spec.steps` - `Action[]`
|
||||
|
||||
The `steps` is an array of the things that you want to happen part of this
|
||||
|
||||
@@ -91,7 +91,9 @@ To create a new extension data reference to represent a type of shared extension
|
||||
|
||||
```ts
|
||||
export const reactElementExtensionDataRef =
|
||||
createExtensionDataRef<React.JSX.Element>('my-plugin.reactElement');
|
||||
createExtensionDataRef<React.JSX.Element>().with({
|
||||
id: 'my-plugin.reactElement',
|
||||
});
|
||||
```
|
||||
|
||||
The `ExtensionDataRef` can then be used to describe an output property of the extension. This will enforce typing on the return value of the extension factory:
|
||||
|
||||
@@ -98,9 +98,9 @@ export interface SearchResultItemExtensionData {
|
||||
}
|
||||
|
||||
export const searchResultItemExtensionDataRef =
|
||||
createExtensionDataRef<SearchResultItemExtensionData>(
|
||||
'search.search-result-item',
|
||||
);
|
||||
createExtensionDataRef<SearchResultItemExtensionData>().with({
|
||||
id: 'search.search-result-item',
|
||||
});
|
||||
```
|
||||
|
||||
#### Grouped Extension Data
|
||||
@@ -109,8 +109,12 @@ This way of defining extension data is similar to the standalone way, but it use
|
||||
|
||||
```ts
|
||||
export const coreExtensionData = {
|
||||
reactElement: createExtensionDataRef<ReactElement>('core.react-element'),
|
||||
routePath: createExtensionDataRef<string>('core.route-path'),
|
||||
reactElement: createExtensionDataRef<ReactElement>().with({
|
||||
id: 'core.react-element',
|
||||
}),
|
||||
routePath: createExtensionDataRef<string>().with({
|
||||
id: 'core.route-path',
|
||||
}),
|
||||
};
|
||||
```
|
||||
|
||||
@@ -125,9 +129,9 @@ export function createGraphiQLEndpointExtension(options) {
|
||||
|
||||
// Use a TypeScript namespace to merge the extension data references with the extension creator
|
||||
export namespace createGraphiQLEndpointExtension {
|
||||
export const endpointDataRef = createExtensionDataRef</* ... */>(
|
||||
'graphiql.graphiql-endpoint.endpoint',
|
||||
);
|
||||
export const endpointDataRef = createExtensionDataRef</* ... */>().with({
|
||||
id: 'graphiql.graphiql-endpoint.endpoint',
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ This extension is the first extension attached to the extension tree. It is resp
|
||||
| themes | The app themes list. | [createThemeExtension.themeDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension.themedataref) | false | See [default themes](#default-theme-extensions). | [createThemeExtension](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension) |
|
||||
| components | The app components list. | [createComponentExtension.componentDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension.componentdataref) | false | See [default components](#default-components-extensions). | [createComponentExtension](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension) |
|
||||
| translations | The app translations list. | [createTranslationExtension.translationDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension.translationdataref) | false | - | [createTranslationExtension](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension) |
|
||||
| icons | The app icons list. | [IconBundleBlueprint.dataRefs.icons](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint.dataRefs.icons) | true | - | [IconBundleBlueprint](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint) |
|
||||
|
||||
#### Default theme extensions
|
||||
|
||||
|
||||
@@ -314,6 +314,31 @@ const app = createApp({
|
||||
});
|
||||
```
|
||||
|
||||
### `icons`
|
||||
|
||||
Icons are now installed as extensions, using the `IconBundleBlueprint` to make new instances which can be added to the app.
|
||||
|
||||
```ts
|
||||
import { IconBundleBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
const exampleIconBundle = IconBundleBlueprint.make({
|
||||
name: 'example-bundle',
|
||||
params: {
|
||||
icons: {
|
||||
user: MyOwnUserIcon,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const app = createApp({
|
||||
features: [
|
||||
createExtensionOverrides({
|
||||
extensions: [exampleIconBundle],
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### `bindRoutes`
|
||||
|
||||
Route bindings can still be done using this option, but you now also have the ability to bind routes using static configuration instead. See the section on [binding routes](../architecture/07-routes.md#binding-external-route-references) for more information.
|
||||
|
||||
@@ -38,6 +38,10 @@ Sign-in page extension have a single purpose - to implement a custom sign-in pag
|
||||
|
||||
Theme extensions provide custom themes for the app. They are always attached to the app extension and you can have any number of themes extensions installed in an app at once, letting the user choose which theme to use.
|
||||
|
||||
### Icons - [Reference](../../reference/frontend-plugin-api.iconbundleblueprint.md)
|
||||
|
||||
Icon bundle extensions provide the ability to replace or provide new icons to the app. You can use the above blueprint to make new extension instances which can be installed into the app.
|
||||
|
||||
### Translation - [Reference](../../reference/frontend-plugin-api.createtranslationextension.md)
|
||||
|
||||
Translation extension provide custom translation messages for the app. They can be used both to override the default english messages to custom ones, as well as provide translations for additional languages.
|
||||
|
||||
@@ -63,18 +63,16 @@ When a given dependency version is the _same_ between different packages, the
|
||||
dependency is hoisted to the main `node_modules` folder in the monorepo root to
|
||||
be shared between packages. When _different_ versions of the same dependency are
|
||||
encountered, Yarn creates a `node_modules` folder within a particular package.
|
||||
This can lead to multiple versions of the same package being installed and used
|
||||
in the same app.
|
||||
|
||||
This can lead to confusing situations with type definitions, or anything with
|
||||
global state. React [Context](https://reactjs.org/docs/context.html), for
|
||||
example, depends on global referential equality. This can cause problems in
|
||||
Backstage with API lookup, or config loading.
|
||||
All Backstage core packages are implemented in such as way that package
|
||||
duplication is **not** a problem. For example, duplicate installations of
|
||||
packages like `@backstage/core-plugin-api`, `@backstage/core-components`,
|
||||
`@backstage/plugin-catalog-react`, and `@backstage/backend-plugin-api` are all
|
||||
acceptable.
|
||||
|
||||
To help resolve these situations, the Backstage CLI has
|
||||
[versions:check](https://backstage.io/docs/tooling/cli/03-commands#versionscheck). This
|
||||
will validate versions of `@backstage` packages in your app to check for
|
||||
duplicate definitions:
|
||||
|
||||
```bash
|
||||
# Add --fix to attempt automatic resolution in yarn.lock
|
||||
yarn backstage-cli versions:check
|
||||
```
|
||||
While package duplication might be acceptable in many cases, you might want to
|
||||
deduplicate packages for the purpose of optimizing bundle size and installation
|
||||
speed. We recommend using deduplication utilities such as `yarn dedupe` to trim
|
||||
down the number of duplicate packages.
|
||||
|
||||
@@ -20,6 +20,8 @@ Run your Backstage app with `yarn dev`. Navigate to `http://localhost:3000`.
|
||||
|
||||
If you're not already logged in, you should see a login screen like this,
|
||||
|
||||

|
||||
|
||||
To login, you should choose the "Github" provider and click the "Sign in" button. This will redirect you to a Github OAuth page. Verify that the scopes mentioned on that page match the setup you did in [the authentication tutorial](./config/authentication.md). Once you click "Confirm", you will be brought back to the Backstage interface and signed in!
|
||||
|
||||
If you are already logged in, you will be automatically brought to your Backstage instance.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,6 @@ repo [command] Command that run across an entire
|
||||
package [command] Lifecycle scripts for individual packages
|
||||
migrate [command] Migration utilities
|
||||
versions:bump [options] Bump Backstage packages to the latest versions
|
||||
versions:check [options] Check Backstage package versioning
|
||||
clean Delete cache directories [DEPRECATED]
|
||||
build-workspace <workspace-dir> [packages...] Builds a temporary dist workspace from the provided
|
||||
packages
|
||||
@@ -327,8 +326,7 @@ Options:
|
||||
## versions\:bump
|
||||
|
||||
Bump all `@backstage` packages to the latest versions. This checks for updates
|
||||
in the package registry, and will update entries both in `yarn.lock` and
|
||||
`package.json` files when necessary.
|
||||
in the package registry, and will update entries `package.json` files when necessary.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli versions:bump [options]
|
||||
@@ -339,23 +337,6 @@ Options:
|
||||
--release <version|next|main> Bump to a specific Backstage release line or version (default: "main")
|
||||
```
|
||||
|
||||
## versions\:check
|
||||
|
||||
Validate `@backstage` dependencies within the repo, making sure that there are
|
||||
no duplicates of packages that might lead to breakages.
|
||||
|
||||
By supplying the `--fix` flag the command will attempt to fix any conflict that
|
||||
can be resolved by editing `yarn.lock`, but will not attempt to search for
|
||||
remote updates or modify any `package.json` files.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli versions:check [options]
|
||||
|
||||
Options:
|
||||
--fix Fix any auto-fixable versioning problems
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## build-workspace
|
||||
|
||||
Builds a mirror of the workspace using the packaged production version of each
|
||||
|
||||
@@ -100,3 +100,47 @@ With that, Backstage's cli and backend will detect public entry point and serve
|
||||
5. Finally, as soon as you log in, you will be redirected to the main app home page (inspect the page and see that the protected bundle was served from the app backend after the redirect).
|
||||
|
||||
That's it!
|
||||
|
||||
## New Frontend System
|
||||
|
||||
If your app uses the new frontend system, you can still use the public entry point feature. The `index-public-experimental.tsx` file does end up looking a bit different in this case:
|
||||
|
||||
```tsx title="in packages/app/src/index-public-experimental.tsx"
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { CookieAuthRedirect } from '@backstage/plugin-auth-react';
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
import {
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
createExtensionOverrides,
|
||||
createSignInPageExtension,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
const signInPage = createSignInPageExtension({
|
||||
name: 'guest',
|
||||
loader: async () => props => <SignInPage {...props} providers={['guest']} />,
|
||||
});
|
||||
|
||||
const authRedirectExtension = createExtension({
|
||||
namespace: 'app',
|
||||
name: 'layout',
|
||||
attachTo: { id: 'app/root', input: 'children' },
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
factory: () => ({
|
||||
element: <CookieAuthRedirect />,
|
||||
}),
|
||||
});
|
||||
|
||||
const app = createApp({
|
||||
features: [
|
||||
createExtensionOverrides({
|
||||
extensions: [signInPage, authRedirectExtension],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(app.createRoot());
|
||||
```
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
title: DORA Metrics
|
||||
author: Okay
|
||||
authorUrl: https://www.okayhq.com
|
||||
category: Metrics
|
||||
description: Embed dashboards (like DORA metrics) in your team or service pages from any dev tools (including Github, Gitlab, Jira, Argo, CircleCI, Buildkite, Pagerduty, Rollbar, Sentry, etc).
|
||||
documentation: https://github.com/OkayHQ/backstage-plugin
|
||||
iconUrl: /img/okay.png
|
||||
npmPackageName: '@okayhq/backstage-plugin'
|
||||
addedDate: '2022-06-16'
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "root",
|
||||
"version": "1.29.0",
|
||||
"version": "1.30.0-next.0",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/app-defaults
|
||||
|
||||
## 1.5.9-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.10-next.0
|
||||
- @backstage/core-app-api@1.14.1-next.0
|
||||
- @backstage/core-plugin-api@1.9.3
|
||||
- @backstage/theme@0.5.6
|
||||
- @backstage/plugin-permission-react@0.4.24
|
||||
|
||||
## 1.5.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/app-defaults",
|
||||
"version": "1.5.8",
|
||||
"version": "1.5.9-next.0",
|
||||
"description": "Provides the default wiring of a Backstage App",
|
||||
"backstage": {
|
||||
"role": "web-library"
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# app-next-example-plugin
|
||||
|
||||
## 0.0.14-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/frontend-plugin-api@0.6.8-next.0
|
||||
- @backstage/core-components@0.14.10-next.0
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-next-example-plugin",
|
||||
"version": "0.0.13",
|
||||
"version": "0.0.14-next.0",
|
||||
"description": "Backstage internal example plugin",
|
||||
"backstage": {
|
||||
"role": "frontend-plugin",
|
||||
|
||||
@@ -1,5 +1,48 @@
|
||||
# example-app-next
|
||||
|
||||
## 0.0.14-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/cli@0.27.0-next.0
|
||||
- @backstage/frontend-plugin-api@0.6.8-next.0
|
||||
- @backstage/plugin-catalog-react@1.12.3-next.0
|
||||
- @backstage/plugin-search-react@1.7.14-next.0
|
||||
- @backstage/plugin-home@0.7.8-next.0
|
||||
- @backstage/core-components@0.14.10-next.0
|
||||
- @backstage/plugin-scaffolder-react@1.11.0-next.0
|
||||
- @backstage/frontend-app-api@0.7.4-next.0
|
||||
- @backstage/plugin-catalog-graph@0.4.8-next.0
|
||||
- @backstage/plugin-scaffolder@1.23.1-next.0
|
||||
- @backstage/core-app-api@1.14.1-next.0
|
||||
- @backstage/plugin-auth-react@0.1.5-next.0
|
||||
- @backstage/app-defaults@1.5.9-next.0
|
||||
- @backstage/catalog-model@1.5.0
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/core-compat-api@0.2.8-next.0
|
||||
- @backstage/core-plugin-api@1.9.3
|
||||
- @backstage/integration-react@1.1.30-next.0
|
||||
- @backstage/theme@0.5.6
|
||||
- @backstage/plugin-api-docs@0.11.8-next.0
|
||||
- @backstage/plugin-app-visualizer@0.1.9-next.0
|
||||
- @backstage/plugin-catalog@1.21.2-next.0
|
||||
- @backstage/plugin-catalog-common@1.0.25
|
||||
- @backstage/plugin-catalog-import@0.12.2-next.0
|
||||
- @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0
|
||||
- @backstage/plugin-kubernetes@0.11.13-next.0
|
||||
- @backstage/plugin-kubernetes-cluster@0.0.14-next.0
|
||||
- @backstage/plugin-notifications@0.2.4-next.0
|
||||
- @backstage/plugin-org@0.6.28-next.0
|
||||
- @backstage/plugin-permission-react@0.4.24
|
||||
- @backstage/plugin-search@1.4.15-next.0
|
||||
- @backstage/plugin-search-common@1.2.13
|
||||
- @backstage/plugin-signals@0.0.9-next.0
|
||||
- @backstage/plugin-techdocs@1.10.8-next.0
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0
|
||||
- @backstage/plugin-techdocs-react@1.2.7-next.0
|
||||
- @backstage/plugin-user-settings@0.8.10-next.0
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app-next",
|
||||
"version": "0.0.13",
|
||||
"version": "0.0.14-next.0",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -36,19 +36,14 @@ import { convertLegacyApp } from '@backstage/core-compat-api';
|
||||
import { FlatRoutes } from '@backstage/core-app-api';
|
||||
import { Route } from 'react-router';
|
||||
import { CatalogImportPage } from '@backstage/plugin-catalog-import';
|
||||
import {
|
||||
createApiFactory,
|
||||
configApiRef,
|
||||
SignInPageProps,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { createApiFactory, configApiRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
ScmAuth,
|
||||
ScmIntegrationsApi,
|
||||
scmIntegrationsApiRef,
|
||||
} from '@backstage/integration-react';
|
||||
import { createSignInPageExtension } from '@backstage/frontend-plugin-api';
|
||||
import { SignInPage } from '@backstage/core-components';
|
||||
import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha';
|
||||
import { signInPageOverrides } from './overrides/SignInPage';
|
||||
|
||||
/*
|
||||
|
||||
@@ -91,12 +86,6 @@ const homePageExtension = createExtension({
|
||||
},
|
||||
});
|
||||
|
||||
const signInPage = createSignInPageExtension({
|
||||
name: 'guest',
|
||||
loader: async () => (props: SignInPageProps) =>
|
||||
<SignInPage {...props} providers={['guest']} />,
|
||||
});
|
||||
|
||||
const scmAuthExtension = createApiExtension({
|
||||
factory: ScmAuth.createDefaultApiFactory(),
|
||||
});
|
||||
@@ -123,13 +112,13 @@ const app = createApp({
|
||||
homePlugin,
|
||||
appVisualizerPlugin,
|
||||
kubernetesPlugin,
|
||||
signInPageOverrides,
|
||||
...collectedLegacyPlugins,
|
||||
createExtensionOverrides({
|
||||
extensions: [
|
||||
homePageExtension,
|
||||
scmAuthExtension,
|
||||
scmIntegrationApi,
|
||||
signInPage,
|
||||
notFoundErrorPage,
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { CookieAuthRedirect } from '@backstage/plugin-auth-react';
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
import { signInPageOverrides } from './overrides/SignInPage';
|
||||
import {
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
createExtensionOverrides,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
const authRedirectExtension = createExtension({
|
||||
namespace: 'app',
|
||||
name: 'layout',
|
||||
attachTo: { id: 'app/root', input: 'children' },
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
factory: () => ({
|
||||
element: <CookieAuthRedirect />,
|
||||
}),
|
||||
});
|
||||
|
||||
const app = createApp({
|
||||
features: [
|
||||
signInPageOverrides,
|
||||
createExtensionOverrides({
|
||||
extensions: [authRedirectExtension],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(app.createRoot());
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2024 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 React from 'react';
|
||||
import { SignInPage } from '@backstage/core-components';
|
||||
import {
|
||||
createExtensionOverrides,
|
||||
createSignInPageExtension,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
const signInPage = createSignInPageExtension({
|
||||
name: 'guest',
|
||||
loader: async () => props => <SignInPage {...props} providers={['guest']} />,
|
||||
});
|
||||
|
||||
export const signInPageOverrides = createExtensionOverrides({
|
||||
extensions: [signInPage],
|
||||
});
|
||||
@@ -1,5 +1,46 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.100-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/cli@0.27.0-next.0
|
||||
- @backstage/plugin-catalog-react@1.12.3-next.0
|
||||
- @backstage/plugin-search-react@1.7.14-next.0
|
||||
- @backstage/plugin-home@0.7.8-next.0
|
||||
- @backstage/core-components@0.14.10-next.0
|
||||
- @backstage/plugin-scaffolder-react@1.11.0-next.0
|
||||
- @backstage/frontend-app-api@0.7.4-next.0
|
||||
- @backstage/plugin-catalog-graph@0.4.8-next.0
|
||||
- @backstage/plugin-scaffolder@1.23.1-next.0
|
||||
- @backstage/core-app-api@1.14.1-next.0
|
||||
- @backstage/plugin-auth-react@0.1.5-next.0
|
||||
- @backstage/app-defaults@1.5.9-next.0
|
||||
- @backstage/catalog-model@1.5.0
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/core-plugin-api@1.9.3
|
||||
- @backstage/integration-react@1.1.30-next.0
|
||||
- @backstage/theme@0.5.6
|
||||
- @backstage/plugin-api-docs@0.11.8-next.0
|
||||
- @backstage/plugin-catalog@1.21.2-next.0
|
||||
- @backstage/plugin-catalog-common@1.0.25
|
||||
- @backstage/plugin-catalog-import@0.12.2-next.0
|
||||
- @backstage/plugin-catalog-unprocessed-entities@0.2.7-next.0
|
||||
- @backstage/plugin-devtools@0.1.17-next.0
|
||||
- @backstage/plugin-kubernetes@0.11.13-next.0
|
||||
- @backstage/plugin-kubernetes-cluster@0.0.14-next.0
|
||||
- @backstage/plugin-notifications@0.2.4-next.0
|
||||
- @backstage/plugin-org@0.6.28-next.0
|
||||
- @backstage/plugin-permission-react@0.4.24
|
||||
- @backstage/plugin-search@1.4.15-next.0
|
||||
- @backstage/plugin-search-common@1.2.13
|
||||
- @backstage/plugin-signals@0.0.9-next.0
|
||||
- @backstage/plugin-techdocs@1.10.8-next.0
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.1.13-next.0
|
||||
- @backstage/plugin-techdocs-react@1.2.7-next.0
|
||||
- @backstage/plugin-user-settings@0.8.10-next.0
|
||||
|
||||
## 0.2.99
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.99",
|
||||
"version": "0.2.100-next.0",
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# @backstage/backend-app-api
|
||||
|
||||
## 0.8.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.23.4-next.0
|
||||
- @backstage/config-loader@1.8.2-next.0
|
||||
- @backstage/backend-plugin-api@0.7.1-next.0
|
||||
- @backstage/backend-tasks@0.5.28-next.0
|
||||
- @backstage/cli-common@0.1.14
|
||||
- @backstage/cli-node@0.2.7
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/types@1.1.1
|
||||
- @backstage/plugin-auth-node@0.4.18-next.0
|
||||
- @backstage/plugin-permission-node@0.8.1-next.0
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/backend-app-api",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.1-next.0",
|
||||
"description": "Core API used by Backstage backend apps",
|
||||
"backstage": {
|
||||
"role": "node-library"
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.23.4-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ba8571e: Setup user agent header for AWS sdk clients, this enables users to better track API calls made from Backstage to AWS APIs through things like CloudTrail.
|
||||
- 7e13b7a: The remaining exports in the package have now been deprecated:
|
||||
|
||||
- `cacheToPluginCacheManager`
|
||||
- `createLegacyAuthAdapters`
|
||||
- `LegacyCreateRouter`
|
||||
- `legacyPlugin`
|
||||
- `loggerToWinstonLogger`
|
||||
- `makeLegacyPlugin`
|
||||
|
||||
Users of these export should fully [migrate to the new backend system](https://backstage.io/docs/backend-system/building-backends/migrating).
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/integration@1.14.0-next.0
|
||||
- @backstage/config-loader@1.8.2-next.0
|
||||
- @backstage/backend-dev-utils@0.1.4
|
||||
- @backstage/backend-plugin-api@0.7.1-next.0
|
||||
- @backstage/cli-common@0.1.14
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/integration-aws-node@0.1.12
|
||||
- @backstage/types@1.1.1
|
||||
- @backstage/plugin-auth-node@0.4.18-next.0
|
||||
|
||||
## 0.23.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"version": "0.23.3",
|
||||
"version": "0.23.4-next.0",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"backstage": {
|
||||
"role": "node-library"
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @backstage/backend-defaults
|
||||
|
||||
## 0.4.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4e79d19: The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`.
|
||||
- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens.
|
||||
- 8e967da: Fixed the routing of the new health check service, the health endpoints should now properly be available at `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness`.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.23.4-next.0
|
||||
- @backstage/integration@1.14.0-next.0
|
||||
- @backstage/config-loader@1.8.2-next.0
|
||||
- @backstage/backend-app-api@0.8.1-next.0
|
||||
- @backstage/backend-dev-utils@0.1.4
|
||||
- @backstage/backend-plugin-api@0.7.1-next.0
|
||||
- @backstage/cli-common@0.1.14
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/integration-aws-node@0.1.12
|
||||
- @backstage/types@1.1.1
|
||||
- @backstage/plugin-auth-node@0.4.18-next.0
|
||||
- @backstage/plugin-events-node@0.3.9-next.0
|
||||
- @backstage/plugin-permission-node@0.8.1-next.0
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="express" />
|
||||
/// <reference types="node" />
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
@@ -17,10 +18,17 @@ import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { RequestHandler } from 'express';
|
||||
import { RequestListener } from 'http';
|
||||
import { RootConfigService } from '@backstage/backend-plugin-api';
|
||||
import { RootHealthService } from '@backstage/backend-plugin-api';
|
||||
import { RootHttpRouterService } from '@backstage/backend-plugin-api';
|
||||
import { Router } from 'express';
|
||||
import type { Server } from 'node:http';
|
||||
import { ServiceFactory } from '@backstage/backend-plugin-api';
|
||||
|
||||
// @public (undocumented)
|
||||
export function createHealthRouter(options: {
|
||||
health: RootHealthService;
|
||||
}): Router;
|
||||
|
||||
// @public
|
||||
export function createHttpServer(
|
||||
listener: RequestListener,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/backend-defaults",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.2-next.0",
|
||||
"description": "Backend defaults used by Backstage backend apps",
|
||||
"backstage": {
|
||||
"role": "node-library"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { RootHealthService } from '@backstage/backend-plugin-api';
|
||||
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
@@ -16,9 +14,13 @@ import { RootHealthService } from '@backstage/backend-plugin-api';
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { RootHealthService } from '@backstage/backend-plugin-api';
|
||||
import Router from 'express-promise-router';
|
||||
import { Request, Response } from 'express';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function createHealthRouter(options: { health: RootHealthService }) {
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ export {
|
||||
DefaultRootHttpRouter,
|
||||
type DefaultRootHttpRouterOptions,
|
||||
} from './DefaultRootHttpRouter';
|
||||
export { createHealthRouter } from './createHealthRouter';
|
||||
export * from './http';
|
||||
export {
|
||||
rootHttpRouterServiceFactory,
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ServiceFactoryTester,
|
||||
mockServices,
|
||||
} from '@backstage/backend-test-utils';
|
||||
import { Express } from 'express';
|
||||
import request from 'supertest';
|
||||
import { rootHttpRouterServiceFactory } from './rootHttpRouterServiceFactory';
|
||||
import { coreServices } from '@backstage/backend-plugin-api';
|
||||
|
||||
describe('rootHttpRouterServiceFactory', () => {
|
||||
it('should make the health endpoints available', async () => {
|
||||
let app: Express | undefined = undefined;
|
||||
|
||||
const tester = ServiceFactoryTester.from(
|
||||
rootHttpRouterServiceFactory({
|
||||
configure(options) {
|
||||
options.applyDefaults();
|
||||
app = options.app;
|
||||
},
|
||||
}),
|
||||
{
|
||||
dependencies: [
|
||||
mockServices.rootConfig.factory({
|
||||
data: {
|
||||
app: { baseUrl: 'http://localhost' },
|
||||
backend: {
|
||||
baseUrl: 'http://localhost',
|
||||
listen: { host: '', port: 0 },
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
// Trigger creation of the http service, accessing the app instance through the configure callback
|
||||
await tester.getSubject();
|
||||
|
||||
await request(app!)
|
||||
.get('/.backstage/health/v1/liveness')
|
||||
.expect(200, { status: 'ok' });
|
||||
|
||||
await request(app!).get('/.backstage/health/v1/readiness').expect(503, {
|
||||
message: 'Backend has not started yet',
|
||||
status: 'error',
|
||||
});
|
||||
|
||||
const lifecycle = await tester.getService(coreServices.rootLifecycle);
|
||||
|
||||
await (lifecycle as any).startup(); // Trigger startup by calling the private startup method
|
||||
|
||||
await request(app!).get('/.backstage/health/v1/readiness').expect(200, {
|
||||
status: 'ok',
|
||||
});
|
||||
|
||||
expect('test').toBe('test');
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,31 @@
|
||||
# @backstage/backend-dynamic-feature-service
|
||||
|
||||
## 0.2.16-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.23.4-next.0
|
||||
- @backstage/plugin-catalog-backend@1.24.1-next.0
|
||||
- @backstage/config-loader@1.8.2-next.0
|
||||
- @backstage/backend-app-api@0.8.1-next.0
|
||||
- @backstage/backend-plugin-api@0.7.1-next.0
|
||||
- @backstage/backend-tasks@0.5.28-next.0
|
||||
- @backstage/cli-common@0.1.14
|
||||
- @backstage/cli-node@0.2.7
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/types@1.1.1
|
||||
- @backstage/plugin-app-node@0.1.23-next.0
|
||||
- @backstage/plugin-auth-node@0.4.18-next.0
|
||||
- @backstage/plugin-events-backend@0.3.10-next.0
|
||||
- @backstage/plugin-events-node@0.3.9-next.0
|
||||
- @backstage/plugin-permission-common@0.8.0
|
||||
- @backstage/plugin-permission-node@0.8.1-next.0
|
||||
- @backstage/plugin-scaffolder-node@0.4.9-next.0
|
||||
- @backstage/plugin-search-backend-node@1.2.28-next.0
|
||||
- @backstage/plugin-search-common@1.2.13
|
||||
|
||||
## 0.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-dynamic-feature-service",
|
||||
"description": "Backstage dynamic feature service",
|
||||
"version": "0.2.15",
|
||||
"version": "0.2.16-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# example-backend-legacy
|
||||
|
||||
## 0.2.101-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.23.4-next.0
|
||||
- @backstage/plugin-scaffolder-backend-module-rails@0.4.40-next.0
|
||||
- @backstage/plugin-scaffolder-backend-module-gitlab@0.4.5-next.0
|
||||
- @backstage/plugin-catalog-backend@1.24.1-next.0
|
||||
- @backstage/plugin-catalog-node@1.12.5-next.0
|
||||
- @backstage/plugin-devtools-backend@0.3.9-next.0
|
||||
- @backstage/integration@1.14.0-next.0
|
||||
- @backstage/plugin-search-backend-module-pg@0.5.33-next.0
|
||||
- example-app@0.2.100-next.0
|
||||
- @backstage/backend-tasks@0.5.28-next.0
|
||||
- @backstage/catalog-client@1.6.5
|
||||
- @backstage/catalog-model@1.5.0
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/plugin-app-backend@0.3.72-next.0
|
||||
- @backstage/plugin-auth-backend@0.22.10-next.0
|
||||
- @backstage/plugin-auth-node@0.4.18-next.0
|
||||
- @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0
|
||||
- @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0
|
||||
- @backstage/plugin-events-backend@0.3.10-next.0
|
||||
- @backstage/plugin-events-node@0.3.9-next.0
|
||||
- @backstage/plugin-kubernetes-backend@0.18.4-next.0
|
||||
- @backstage/plugin-permission-backend@0.5.47-next.0
|
||||
- @backstage/plugin-permission-common@0.8.0
|
||||
- @backstage/plugin-permission-node@0.8.1-next.0
|
||||
- @backstage/plugin-proxy-backend@0.5.4-next.0
|
||||
- @backstage/plugin-scaffolder-backend@1.23.1-next.0
|
||||
- @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.24-next.0
|
||||
- @backstage/plugin-search-backend@1.5.15-next.0
|
||||
- @backstage/plugin-search-backend-module-catalog@0.1.29-next.0
|
||||
- @backstage/plugin-search-backend-module-elasticsearch@1.5.4-next.0
|
||||
- @backstage/plugin-search-backend-module-explore@0.1.29-next.0
|
||||
- @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0
|
||||
- @backstage/plugin-search-backend-node@1.2.28-next.0
|
||||
- @backstage/plugin-signals-backend@0.1.9-next.0
|
||||
- @backstage/plugin-signals-node@0.1.9-next.0
|
||||
- @backstage/plugin-techdocs-backend@1.10.10-next.0
|
||||
|
||||
## 0.2.100
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend-legacy",
|
||||
"version": "0.2.100",
|
||||
"version": "0.2.101-next.0",
|
||||
"backstage": {
|
||||
"role": "backend"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/backend-openapi-utils
|
||||
|
||||
## 0.1.16-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.7.1-next.0
|
||||
- @backstage/errors@1.2.4
|
||||
|
||||
## 0.1.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-openapi-utils",
|
||||
"description": "OpenAPI typescript support.",
|
||||
"version": "0.1.15",
|
||||
"version": "0.1.16-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @backstage/backend-plugin-api
|
||||
|
||||
## 0.7.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/cli-common@0.1.14
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/types@1.1.1
|
||||
- @backstage/plugin-auth-node@0.4.18-next.0
|
||||
- @backstage/plugin-permission-common@0.8.0
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/backend-plugin-api",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1-next.0",
|
||||
"description": "Core API used by Backstage backend plugins",
|
||||
"backstage": {
|
||||
"role": "node-library"
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/backend-tasks
|
||||
|
||||
## 0.5.28-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.23.4-next.0
|
||||
- @backstage/backend-plugin-api@0.7.1-next.0
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/types@1.1.1
|
||||
|
||||
## 0.5.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-tasks",
|
||||
"description": "Common distributed task management library for Backstage backends",
|
||||
"version": "0.5.27",
|
||||
"version": "0.5.28-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @backstage/backend-test-utils
|
||||
|
||||
## 0.4.5-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4e79d19: The default services for `startTestBackend` and `ServiceFactoryTester` now includes the Root Health Service.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-defaults@0.4.2-next.0
|
||||
- @backstage/backend-app-api@0.8.1-next.0
|
||||
- @backstage/backend-plugin-api@0.7.1-next.0
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/types@1.1.1
|
||||
- @backstage/plugin-auth-node@0.4.18-next.0
|
||||
- @backstage/plugin-events-node@0.3.9-next.0
|
||||
|
||||
## 0.4.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/backend-test-utils",
|
||||
"version": "0.4.4",
|
||||
"version": "0.4.5-next.0",
|
||||
"description": "Test helpers library for Backstage backends",
|
||||
"backstage": {
|
||||
"role": "node-library"
|
||||
|
||||
@@ -242,6 +242,15 @@ describe('TestBackend', () => {
|
||||
expect(res.body).toEqual({ message: 'pong' });
|
||||
});
|
||||
|
||||
it('should expose health check endpoints', async () => {
|
||||
const { server } = await startTestBackend({ features: [] });
|
||||
|
||||
const res = await request(server).get('/.backstage/health/v1/liveness');
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.body).toEqual({ status: 'ok' });
|
||||
});
|
||||
|
||||
it('should provide extension point implementations', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import express from 'express';
|
||||
// Direct internal import to avoid duplication
|
||||
// eslint-disable-next-line @backstage/no-forbidden-package-imports
|
||||
import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring/types';
|
||||
import { createHealthRouter } from '@backstage/backend-defaults/rootHttpRouter';
|
||||
|
||||
/** @public */
|
||||
export interface TestBackendOptions<TExtensionPoints extends any[]> {
|
||||
@@ -73,6 +74,7 @@ export const defaultServiceFactories = [
|
||||
mockServices.lifecycle.factory(),
|
||||
mockServices.logger.factory(),
|
||||
mockServices.permissions.factory(),
|
||||
mockServices.rootHealth.factory(),
|
||||
mockServices.rootLifecycle.factory(),
|
||||
mockServices.rootLogger.factory(),
|
||||
mockServices.scheduler.factory(),
|
||||
@@ -251,15 +253,18 @@ export async function startTestBackend<TExtensionPoints extends any[]>(
|
||||
config: coreServices.rootConfig,
|
||||
lifecycle: coreServices.rootLifecycle,
|
||||
rootLogger: coreServices.rootLogger,
|
||||
health: coreServices.rootHealth,
|
||||
},
|
||||
async factory({ config, lifecycle, rootLogger }) {
|
||||
async factory({ config, lifecycle, rootLogger, health }) {
|
||||
const router = DefaultRootHttpRouter.create();
|
||||
const logger = rootLogger.child({ service: 'rootHttpRouter' });
|
||||
|
||||
const app = express();
|
||||
|
||||
const middleware = MiddlewareFactory.create({ config, logger });
|
||||
const healthRouter = createHealthRouter({ health });
|
||||
|
||||
app.use(healthRouter);
|
||||
app.use(router.handler());
|
||||
app.use(middleware.notFound());
|
||||
app.use(middleware.error());
|
||||
|
||||
@@ -1,5 +1,42 @@
|
||||
# example-backend
|
||||
|
||||
## 0.0.29-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-defaults@0.4.2-next.0
|
||||
- @backstage/plugin-catalog-backend@1.24.1-next.0
|
||||
- @backstage/plugin-devtools-backend@0.3.9-next.0
|
||||
- @backstage/backend-plugin-api@0.7.1-next.0
|
||||
- @backstage/backend-tasks@0.5.28-next.0
|
||||
- @backstage/catalog-model@1.5.0
|
||||
- @backstage/plugin-app-backend@0.3.72-next.0
|
||||
- @backstage/plugin-auth-backend@0.22.10-next.0
|
||||
- @backstage/plugin-auth-backend-module-github-provider@0.1.20-next.0
|
||||
- @backstage/plugin-auth-backend-module-guest-provider@0.1.9-next.0
|
||||
- @backstage/plugin-auth-node@0.4.18-next.0
|
||||
- @backstage/plugin-catalog-backend-module-backstage-openapi@0.2.6-next.0
|
||||
- @backstage/plugin-catalog-backend-module-openapi@0.1.41-next.0
|
||||
- @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.21-next.0
|
||||
- @backstage/plugin-catalog-backend-module-unprocessed@0.4.10-next.0
|
||||
- @backstage/plugin-kubernetes-backend@0.18.4-next.0
|
||||
- @backstage/plugin-notifications-backend@0.3.4-next.0
|
||||
- @backstage/plugin-permission-backend@0.5.47-next.0
|
||||
- @backstage/plugin-permission-backend-module-allow-all-policy@0.1.20-next.0
|
||||
- @backstage/plugin-permission-common@0.8.0
|
||||
- @backstage/plugin-permission-node@0.8.1-next.0
|
||||
- @backstage/plugin-proxy-backend@0.5.4-next.0
|
||||
- @backstage/plugin-scaffolder-backend@1.23.1-next.0
|
||||
- @backstage/plugin-scaffolder-backend-module-github@0.4.1-next.0
|
||||
- @backstage/plugin-search-backend@1.5.15-next.0
|
||||
- @backstage/plugin-search-backend-module-catalog@0.1.29-next.0
|
||||
- @backstage/plugin-search-backend-module-explore@0.1.29-next.0
|
||||
- @backstage/plugin-search-backend-module-techdocs@0.1.28-next.0
|
||||
- @backstage/plugin-search-backend-node@1.2.28-next.0
|
||||
- @backstage/plugin-signals-backend@0.1.9-next.0
|
||||
- @backstage/plugin-techdocs-backend@1.10.10-next.0
|
||||
|
||||
## 0.0.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.0.28",
|
||||
"version": "0.0.29-next.0",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.27.0-next.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 32a38e1: **BREAKING**: The lockfile (`yarn.lock`) dependency analysis and mutations have been removed from several commands.
|
||||
|
||||
The `versions:bump` command will no longer attempt to bump and deduplicate dependencies by modifying the lockfile, it will only update `package.json` files.
|
||||
|
||||
The `versions:check` command has been removed, since its only purpose was verification and mutation of the lockfile. We recommend using the `yarn dedupe` command instead, or the `yarn-deduplicate` package if you're using Yarn classic.
|
||||
|
||||
The check that was built into the `package start` command has been removed, it will no longer warn about lockfile mismatches.
|
||||
|
||||
The packages in the Backstage ecosystem handle package duplications much better now than when these CLI features were first introduced, so the need for these features has diminished. By removing them, we drastically reduce the integration between the Backstage CLI and Yarn, making it much easier to add support for other package managers in the future.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7eb08a6: Add frontend-dynamic-container role to eslint config factory
|
||||
- fbc7819: Use ES2022 in CLI bundler
|
||||
- e53074f: Updated default backend plugin to use `RootConfigService` instead of `Config`. This also removes the dependency on `@backstage/config` as it's no longer used.
|
||||
- ee2b0e5: The experimental module federation build now has the ability to force the use of development versions of `react` and `react-dom` by setting the `FORCE_REACT_DEVELOPMENT` flag.
|
||||
- 239dffc: Remove usage of deprecated functionality from @backstage/config-loader
|
||||
- 0eedec3: Add support for dynamic plugins via the EXPERIMENTAL_MODULE_FEDERATION environment variable when running `yarn start`.
|
||||
- dc4fb4f: Fix for `repo build --all` not properly detecting the experimental public entry point.
|
||||
- Updated dependencies
|
||||
- @backstage/integration@1.14.0-next.0
|
||||
- @backstage/config-loader@1.8.2-next.0
|
||||
- @backstage/catalog-model@1.5.0
|
||||
- @backstage/cli-common@0.1.14
|
||||
- @backstage/cli-node@0.2.7
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/eslint-plugin@0.1.8
|
||||
- @backstage/release-manifests@0.0.11
|
||||
- @backstage/types@1.1.1
|
||||
|
||||
## 0.26.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -22,7 +22,6 @@ Commands:
|
||||
package [command]
|
||||
migrate [command]
|
||||
versions:bump [options]
|
||||
versions:check [options]
|
||||
versions:migrate [options]
|
||||
clean
|
||||
build-workspace [options] <workspace-dir> [packages...]
|
||||
@@ -607,16 +606,6 @@ Options:
|
||||
-h, --help
|
||||
```
|
||||
|
||||
### `backstage-cli versions:check`
|
||||
|
||||
```
|
||||
Usage: backstage-cli versions:check [options]
|
||||
|
||||
Options:
|
||||
--fix
|
||||
-h, --help
|
||||
```
|
||||
|
||||
### `backstage-cli versions:migrate`
|
||||
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"version": "0.26.11",
|
||||
"version": "0.27.0-next.0",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"backstage": {
|
||||
"role": "cli"
|
||||
|
||||
@@ -16,11 +16,9 @@
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { buildBundle } from '../../lib/bundler';
|
||||
import { buildBundle, getModuleFederationOptions } from '../../lib/bundler';
|
||||
import { getEnvironmentParallelism } from '../../lib/parallel';
|
||||
import { loadCliConfig } from '../../lib/config';
|
||||
import chalk from 'chalk';
|
||||
import { BuildOptions } from '../../lib/bundler/types';
|
||||
|
||||
interface BuildAppOptions {
|
||||
targetDir: string;
|
||||
@@ -29,29 +27,6 @@ interface BuildAppOptions {
|
||||
isModuleFederationRemote?: true;
|
||||
}
|
||||
|
||||
function getModuleFederationOptions(
|
||||
name: string,
|
||||
isRemote?: boolean,
|
||||
): BuildOptions['moduleFederation'] {
|
||||
if (!isRemote && !process.env.EXPERIMENTAL_MODULE_FEDERATION) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
`⚠️ WARNING: Module federation is experimental and will receive immediate breaking changes in the future.`,
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
mode: isRemote ? 'remote' : 'host',
|
||||
// The default output mode requires the name to be a usable as a code
|
||||
// symbol, there might be better options here but for now we need to
|
||||
// sanitize the name.
|
||||
name: name.replaceAll('@', '').replaceAll('/', '__').replaceAll('-', '_'),
|
||||
};
|
||||
}
|
||||
|
||||
export async function buildFrontend(options: BuildAppOptions) {
|
||||
const { targetDir, writeStats, configPaths } = options;
|
||||
const { name } = await fs.readJson(resolvePath(targetDir, 'package.json'));
|
||||
|
||||
@@ -396,7 +396,7 @@ export function registerCommands(program: Command) {
|
||||
.action(lazy(() => import('./versions/bump').then(m => m.default)));
|
||||
|
||||
program
|
||||
.command('versions:check')
|
||||
.command('versions:check', { hidden: true })
|
||||
.option('--fix', 'Fix any auto-fixable versioning problems')
|
||||
.description('Check Backstage package versioning')
|
||||
.action(lazy(() => import('./versions/lint').then(m => m.default)));
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { OptionValues } from 'commander';
|
||||
import { PackageRole } from '@backstage/cli-node';
|
||||
import { findRoleFromCommand } from '../../lib/role';
|
||||
import { startBackend, startBackendPlugin } from './startBackend';
|
||||
import { startFrontend } from './startFrontend';
|
||||
@@ -47,6 +48,13 @@ export async function command(opts: OptionValues): Promise<void> {
|
||||
case 'frontend-plugin':
|
||||
case 'frontend-plugin-module':
|
||||
return startFrontend({ entry: 'dev/index', ...options });
|
||||
case 'frontend-dynamic-container' as PackageRole: // experimental
|
||||
return startFrontend({
|
||||
entry: 'src/index',
|
||||
...options,
|
||||
skipOpenBrowser: true,
|
||||
isModuleFederationRemote: true,
|
||||
});
|
||||
default:
|
||||
throw new Error(
|
||||
`Start command is not supported for package role '${role}'`,
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { serveBundle } from '../../lib/bundler';
|
||||
import { readJson } from 'fs-extra';
|
||||
import { getModuleFederationOptions, serveBundle } from '../../lib/bundler';
|
||||
import { paths } from '../../lib/paths';
|
||||
|
||||
interface StartAppOptions {
|
||||
verifyVersions?: boolean;
|
||||
@@ -22,14 +24,23 @@ interface StartAppOptions {
|
||||
|
||||
checksEnabled: boolean;
|
||||
configPaths: string[];
|
||||
skipOpenBrowser?: boolean;
|
||||
isModuleFederationRemote?: boolean;
|
||||
}
|
||||
|
||||
export async function startFrontend(options: StartAppOptions) {
|
||||
const { name } = await readJson(paths.resolveTarget('package.json'));
|
||||
|
||||
const waitForExit = await serveBundle({
|
||||
entry: options.entry,
|
||||
checksEnabled: options.checksEnabled,
|
||||
configPaths: options.configPaths,
|
||||
verifyVersions: options.verifyVersions,
|
||||
skipOpenBrowser: options.skipOpenBrowser,
|
||||
moduleFederation: getModuleFederationOptions(
|
||||
name,
|
||||
options.isModuleFederationRemote,
|
||||
),
|
||||
});
|
||||
|
||||
await waitForExit();
|
||||
|
||||
@@ -23,7 +23,6 @@ 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';
|
||||
import {
|
||||
MockDirectory,
|
||||
createMockDirectory,
|
||||
@@ -117,17 +116,6 @@ const lockfileMock = `${HEADER}
|
||||
version "1.0.3"
|
||||
`;
|
||||
|
||||
// This is the lockfile that we produce to unlock versions before we run yarn install
|
||||
const lockfileMockResult = `${HEADER}
|
||||
"@backstage/core@^1.0.5":
|
||||
version "1.0.6"
|
||||
dependencies:
|
||||
"@backstage/core-api" "^1.0.6"
|
||||
|
||||
"@backstage/theme@^1.0.0":
|
||||
version "1.0.0"
|
||||
`;
|
||||
|
||||
// Avoid flakes by comparing sorted log lines. File system access is async, which leads to the log line order being indeterministic
|
||||
const expectLogsToMatch = (
|
||||
recievedLogs: String[],
|
||||
@@ -204,11 +192,7 @@ describe('bump', () => {
|
||||
'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',
|
||||
@@ -220,9 +204,8 @@ describe('bump', () => {
|
||||
'Version bump complete!',
|
||||
]);
|
||||
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(3);
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2);
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core');
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core-api');
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme');
|
||||
|
||||
expect(runObj.run).toHaveBeenCalledTimes(1);
|
||||
@@ -232,12 +215,6 @@ describe('bump', () => {
|
||||
expect.any(Object),
|
||||
);
|
||||
|
||||
const lockfileContents = await fs.readFile(
|
||||
mockDir.resolve('yarn.lock'),
|
||||
'utf8',
|
||||
);
|
||||
expect(lockfileContents).toBe(lockfileMockResult);
|
||||
|
||||
const packageA = await fs.readJson(
|
||||
mockDir.resolve('packages/a/package.json'),
|
||||
);
|
||||
@@ -312,11 +289,7 @@ describe('bump', () => {
|
||||
'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',
|
||||
@@ -328,9 +301,8 @@ describe('bump', () => {
|
||||
'Version bump complete!',
|
||||
]);
|
||||
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(3);
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2);
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core');
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core-api');
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme');
|
||||
|
||||
expect(runObj.run).not.toHaveBeenCalledWith(
|
||||
@@ -339,12 +311,6 @@ describe('bump', () => {
|
||||
expect.any(Object),
|
||||
);
|
||||
|
||||
const lockfileContents = await fs.readFile(
|
||||
mockDir.resolve('yarn.lock'),
|
||||
'utf8',
|
||||
);
|
||||
expect(lockfileContents).toBe(lockfileMockResult);
|
||||
|
||||
const packageA = await fs.readJson(
|
||||
mockDir.resolve('packages/a/package.json'),
|
||||
);
|
||||
@@ -425,12 +391,7 @@ describe('bump', () => {
|
||||
'Using default pattern glob @backstage/*',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'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/theme in b to ^5.0.0',
|
||||
'bumping @backstage/core in b to ^1.0.6',
|
||||
'bumping @backstage/core in a to ^1.0.6',
|
||||
@@ -443,9 +404,8 @@ describe('bump', () => {
|
||||
'Version bump complete!',
|
||||
]);
|
||||
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(2);
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(1);
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core');
|
||||
expect(mockFetchPackageInfo).not.toHaveBeenCalledWith('@backstage/theme');
|
||||
|
||||
expect(runObj.run).toHaveBeenCalledTimes(1);
|
||||
expect(runObj.run).toHaveBeenCalledWith(
|
||||
@@ -454,12 +414,6 @@ describe('bump', () => {
|
||||
expect.any(Object),
|
||||
);
|
||||
|
||||
const lockfileContents = await fs.readFile(
|
||||
mockDir.resolve('yarn.lock'),
|
||||
'utf8',
|
||||
);
|
||||
expect(lockfileContents).toBe(lockfileMockResult);
|
||||
|
||||
const packageA = await fs.readJson(
|
||||
mockDir.resolve('packages/a/package.json'),
|
||||
);
|
||||
@@ -629,12 +583,7 @@ describe('bump', () => {
|
||||
'Using default pattern glob @backstage/*',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'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/theme in b to ^5.0.0',
|
||||
'bumping @backstage/core in b to ^1.0.6',
|
||||
'bumping @backstage/core in a to ^1.0.6',
|
||||
@@ -658,21 +607,6 @@ describe('bump', () => {
|
||||
|
||||
"@backstage-extra/custom-two@^1.0.0":
|
||||
version "1.0.0"
|
||||
`;
|
||||
const customLockfileMockResult = `${HEADER}
|
||||
"@backstage-extra/custom-two@^1.0.0":
|
||||
version "1.0.0"
|
||||
|
||||
"@backstage-extra/custom@^1.1.0":
|
||||
version "1.1.0"
|
||||
|
||||
"@backstage/core@^1.0.5":
|
||||
version "1.0.6"
|
||||
dependencies:
|
||||
"@backstage/core-api" "^1.0.6"
|
||||
|
||||
"@backstage/theme@^1.0.0":
|
||||
version "1.0.0"
|
||||
`;
|
||||
mockDir.setContent({
|
||||
'yarn.lock': customLockfileMock,
|
||||
@@ -731,12 +665,7 @@ describe('bump', () => {
|
||||
'Checking for updates of @backstage-extra/custom',
|
||||
'Checking for updates of @backstage-extra/custom-two',
|
||||
'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-extra/custom@^1.0.1 ~> 1.1.0',
|
||||
'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-extra/custom in a to ^1.1.0',
|
||||
'bumping @backstage-extra/custom-two in a to ^2.0.0',
|
||||
@@ -754,7 +683,7 @@ describe('bump', () => {
|
||||
'Version bump complete!',
|
||||
]);
|
||||
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(5);
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(4);
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core');
|
||||
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme');
|
||||
|
||||
@@ -765,12 +694,6 @@ describe('bump', () => {
|
||||
expect.any(Object),
|
||||
);
|
||||
|
||||
const lockfileContents = await fs.readFile(
|
||||
mockDir.resolve('yarn.lock'),
|
||||
'utf8',
|
||||
);
|
||||
expect(lockfileContents).toEqual(customLockfileMockResult);
|
||||
|
||||
const packageA = await fs.readJson(
|
||||
mockDir.resolve('packages/a/package.json'),
|
||||
);
|
||||
@@ -798,7 +721,7 @@ describe('bump', () => {
|
||||
|
||||
it('should ignore not found packages', async () => {
|
||||
mockDir.setContent({
|
||||
'yarn.lock': lockfileMockResult,
|
||||
'yarn.lock': lockfileMock,
|
||||
'package.json': JSON.stringify({
|
||||
workspaces: {
|
||||
packages: ['packages/*'],
|
||||
@@ -848,21 +771,11 @@ describe('bump', () => {
|
||||
'Checking for updates of @backstage/theme',
|
||||
'Package info not found, ignoring package @backstage/core',
|
||||
'Package info not found, ignoring package @backstage/theme',
|
||||
'Checking for updates of @backstage/core',
|
||||
'Checking for updates of @backstage/theme',
|
||||
'Package info not found, ignoring package @backstage/core',
|
||||
'Package info not found, ignoring package @backstage/theme',
|
||||
'All Backstage packages are up to date!',
|
||||
]);
|
||||
|
||||
expect(runObj.run).toHaveBeenCalledTimes(0);
|
||||
|
||||
const lockfileContents = await fs.readFile(
|
||||
mockDir.resolve('yarn.lock'),
|
||||
'utf8',
|
||||
);
|
||||
expect(lockfileContents).toBe(lockfileMockResult);
|
||||
|
||||
const packageA = await fs.readJson(
|
||||
mockDir.resolve('packages/a/package.json'),
|
||||
);
|
||||
@@ -883,83 +796,6 @@ describe('bump', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it('should log duplicates', async () => {
|
||||
jest.spyOn(Lockfile.prototype, 'analyze').mockReturnValue({
|
||||
invalidRanges: [],
|
||||
newVersions: [],
|
||||
newRanges: [
|
||||
{
|
||||
name: '@backstage/backend-app-api',
|
||||
oldRange: '^1.0.0',
|
||||
newRange: '^2.0.0',
|
||||
oldVersion: '1.0.0',
|
||||
newVersion: '2.0.0',
|
||||
},
|
||||
],
|
||||
});
|
||||
mockDir.setContent({
|
||||
'yarn.lock': `${HEADER}
|
||||
"@backstage/backend-app-api@^1.0.0":
|
||||
version "1.0.0"
|
||||
`,
|
||||
'package.json': JSON.stringify({
|
||||
workspaces: {
|
||||
packages: ['packages/*'],
|
||||
},
|
||||
}),
|
||||
packages: {
|
||||
a: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'a',
|
||||
dependencies: {
|
||||
'@backstage/backend-app-api': '^1.0.0',
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
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: [
|
||||
{
|
||||
name: '@backstage/backend-app-api',
|
||||
version: '2.0.0',
|
||||
},
|
||||
],
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
const { log: logs } = await withLogCollector(['log', 'warn'], async () => {
|
||||
await bump({ pattern: null, release: 'main' } as unknown as Command);
|
||||
});
|
||||
expectLogsToMatch(logs, [
|
||||
'Using default pattern glob @backstage/*',
|
||||
'Checking for updates of @backstage/backend-app-api',
|
||||
'Checking for updates of @backstage/backend-app-api',
|
||||
'Some packages are outdated, updating',
|
||||
'bumping @backstage/backend-app-api in a to ^2.0.0',
|
||||
'Running yarn install to install new versions',
|
||||
'Checking for moved packages to the @backstage-community namespace...',
|
||||
'⚠️ The following packages may have breaking changes:',
|
||||
' @backstage/backend-app-api : 1.0.0 ~> 2.0.0',
|
||||
' https://github.com/backstage/backstage/blob/master/packages/backend-app-api/CHANGELOG.md',
|
||||
'Version bump complete!',
|
||||
' ⚠️ Warning! ⚠️',
|
||||
' The below package(s) have incompatible duplicate installations, likely due to a bad dependency in a plugin.',
|
||||
' You can investigate this by running `yarn why <package-name>`, and report the issue to the plugin maintainers.',
|
||||
' @backstage/backend-app-api',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bumpBackstageJsonVersion', () => {
|
||||
|
||||
@@ -24,7 +24,6 @@ import fs from 'fs-extra';
|
||||
import chalk from 'chalk';
|
||||
import ora from 'ora';
|
||||
import semver from 'semver';
|
||||
import { minimatch } from 'minimatch';
|
||||
import { OptionValues } from 'commander';
|
||||
import { isError, NotFoundError } from '@backstage/errors';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
@@ -36,7 +35,6 @@ import {
|
||||
Lockfile,
|
||||
YarnInfoInspectData,
|
||||
} from '../../lib/versioning';
|
||||
import { forbiddenDuplicatesFilter } from './lint';
|
||||
import { BACKSTAGE_JSON } from '@backstage/cli-common';
|
||||
import { runParallelWorkers } from '../../lib/parallel';
|
||||
import {
|
||||
@@ -44,7 +42,6 @@ import {
|
||||
getManifestByVersion,
|
||||
ReleaseManifest,
|
||||
} from '@backstage/release-manifests';
|
||||
import { PackageGraph } from '@backstage/cli-node';
|
||||
import { migrateMovedPackages } from './migrate';
|
||||
|
||||
function shouldUseGlobalAgent(): boolean {
|
||||
@@ -125,8 +122,6 @@ export default async (opts: OptionValues) => {
|
||||
|
||||
// Next check with the package registry to see which dependency ranges we need to bump
|
||||
const versionBumps = new Map<string, PkgVersionInfo[]>();
|
||||
// Track package versions that we want to remove from yarn.lock in order to trigger a bump
|
||||
const unlocked = Array<{ name: string; range: string; target: string }>();
|
||||
|
||||
await runParallelWorkers({
|
||||
parallelismFactor: 4,
|
||||
@@ -157,72 +152,13 @@ export default async (opts: OptionValues) => {
|
||||
},
|
||||
});
|
||||
|
||||
const filter = (name: string) => minimatch(name, pattern);
|
||||
|
||||
// Check for updates of transitive backstage dependencies
|
||||
await runParallelWorkers({
|
||||
parallelismFactor: 4,
|
||||
items: lockfile.keys(),
|
||||
async worker(name) {
|
||||
// Only check @backstage packages and friends, we don't want this to do a full update of all deps
|
||||
if (!filter(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let target: string;
|
||||
try {
|
||||
target = await findTargetVersion(name);
|
||||
} catch (error) {
|
||||
if (isError(error) && error.name === 'NotFoundError') {
|
||||
console.log(`Package info not found, ignoring package ${name}`);
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
for (const entry of lockfile.get(name) ?? []) {
|
||||
// Ignore lockfile entries that don't satisfy the version range, since
|
||||
// these can't cause the package to be locked to an older version
|
||||
if (!semver.satisfies(target, entry.range)) {
|
||||
continue;
|
||||
}
|
||||
// Unlock all entries that are within range but on the old version
|
||||
unlocked.push({ name, range: entry.range, target });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
console.log();
|
||||
|
||||
// Write all discovered version bumps to package.json in this repo
|
||||
if (versionBumps.size === 0 && unlocked.length === 0) {
|
||||
if (versionBumps.size === 0) {
|
||||
console.log(chalk.green('All Backstage packages are up to date!'));
|
||||
} else {
|
||||
console.log(chalk.yellow('Some packages are outdated, updating'));
|
||||
console.log();
|
||||
|
||||
if (unlocked.length > 0) {
|
||||
const removed = new Set<string>();
|
||||
for (const { name, range, target } of unlocked) {
|
||||
// Don't bother removing lockfile entries if they're already on the correct version
|
||||
const existingEntry = lockfile.get(name)?.find(e => e.range === range);
|
||||
if (existingEntry?.version === target) {
|
||||
continue;
|
||||
}
|
||||
const key = JSON.stringify({ name, range });
|
||||
if (!removed.has(key)) {
|
||||
removed.add(key);
|
||||
console.log(
|
||||
`${chalk.magenta('unlocking')} ${name}@${chalk.yellow(
|
||||
range,
|
||||
)} ~> ${chalk.yellow(target)}`,
|
||||
);
|
||||
lockfile.remove(name, range);
|
||||
}
|
||||
}
|
||||
await lockfile.save(lockfilePath);
|
||||
}
|
||||
|
||||
const breakingUpdates = new Map<string, { from: string; to: string }>();
|
||||
await runParallelWorkers({
|
||||
parallelismFactor: 4,
|
||||
@@ -334,38 +270,6 @@ export default async (opts: OptionValues) => {
|
||||
}
|
||||
|
||||
console.log();
|
||||
|
||||
// Finally we make sure the new lockfile doesn't have any duplicates
|
||||
const dedupLockfile = await Lockfile.load(lockfilePath);
|
||||
|
||||
const result = dedupLockfile.analyze({
|
||||
filter,
|
||||
localPackages: PackageGraph.fromPackages(
|
||||
await PackageGraph.listTargetPackages(),
|
||||
),
|
||||
});
|
||||
|
||||
const forbiddenNewRanges = result.newRanges.filter(({ name }) =>
|
||||
forbiddenDuplicatesFilter(name),
|
||||
);
|
||||
if (forbiddenNewRanges.length > 0) {
|
||||
console.log(chalk.yellow(' ⚠️ Warning! ⚠️'));
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
' The below package(s) have incompatible duplicate installations, likely due to a bad dependency in a plugin.',
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
' You can investigate this by running `yarn why <package-name>`, and report the issue to the plugin maintainers.',
|
||||
),
|
||||
);
|
||||
console.log();
|
||||
for (const { name } of forbiddenNewRanges) {
|
||||
console.log(chalk.yellow(` ${name}`));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function createStrictVersionFinder(options: {
|
||||
|
||||
@@ -14,116 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { OptionValues } from 'commander';
|
||||
import { Lockfile } from '../../lib/versioning';
|
||||
import { paths } from '../../lib/paths';
|
||||
import partition from 'lodash/partition';
|
||||
import { PackageGraph } from '@backstage/cli-node';
|
||||
|
||||
// Packages that we try to avoid duplicates for
|
||||
const INCLUDED = [/^@backstage\//];
|
||||
|
||||
export const includedFilter = (name: string) =>
|
||||
INCLUDED.some(pattern => pattern.test(name));
|
||||
|
||||
// Packages that are not allowed to have any duplicates
|
||||
const FORBID_DUPLICATES = [/^@backstage\/\w+-app-api$/, /^@backstage\/plugin-/];
|
||||
|
||||
// There are some packages that ARE explicitly allowed to have duplicates since
|
||||
// they handle that appropriately. This takes precedence over FORBID_DUPLICATES
|
||||
// above.
|
||||
const ALLOW_DUPLICATES = [
|
||||
/^@backstage\/core-plugin-api$/,
|
||||
// Duplicates of libraries are OK
|
||||
// TODO(Rugvip): Check this using package role instead
|
||||
/^@backstage\/plugin-.*-react$/,
|
||||
/^@backstage\/plugin-.*-node$/,
|
||||
/^@backstage\/plugin-.*-common$/,
|
||||
];
|
||||
|
||||
export const forbiddenDuplicatesFilter = (name: string) =>
|
||||
FORBID_DUPLICATES.some(pattern => pattern.test(name)) &&
|
||||
!ALLOW_DUPLICATES.some(pattern => pattern.test(name));
|
||||
|
||||
export default async (cmd: OptionValues) => {
|
||||
const fix = Boolean(cmd.fix);
|
||||
|
||||
let success = true;
|
||||
|
||||
const lockfilePath = paths.resolveTargetRoot('yarn.lock');
|
||||
const lockfile = await Lockfile.load(lockfilePath);
|
||||
const result = lockfile.analyze({
|
||||
filter: includedFilter,
|
||||
localPackages: PackageGraph.fromPackages(
|
||||
await PackageGraph.listTargetPackages(),
|
||||
),
|
||||
});
|
||||
|
||||
logArray(
|
||||
result.invalidRanges,
|
||||
"The following packages versions are invalid and can't be analyzed:",
|
||||
e => ` ${e.name} @ ${e.range}`,
|
||||
export default async () => {
|
||||
throw new Error(
|
||||
'This command has been removed, please consider alternatives such as `yarn dedupe` instead.',
|
||||
);
|
||||
|
||||
if (fix) {
|
||||
lockfile.replaceVersions(result.newVersions);
|
||||
await lockfile.save(lockfilePath);
|
||||
} else {
|
||||
const [newVersionsForbidden, newVersionsAllowed] = partition(
|
||||
result.newVersions,
|
||||
({ name }) => forbiddenDuplicatesFilter(name),
|
||||
);
|
||||
if (newVersionsForbidden.length && !fix) {
|
||||
success = false;
|
||||
}
|
||||
|
||||
logArray(
|
||||
newVersionsForbidden,
|
||||
'The following packages must be deduplicated, this can be done automatically with --fix',
|
||||
e =>
|
||||
` ${e.name} @ ${e.range} bumped from ${e.oldVersion} to ${e.newVersion}`,
|
||||
);
|
||||
logArray(
|
||||
newVersionsAllowed,
|
||||
'The following packages can be deduplicated, this can be done automatically with --fix',
|
||||
e =>
|
||||
` ${e.name} @ ${e.range} bumped from ${e.oldVersion} to ${e.newVersion}`,
|
||||
);
|
||||
}
|
||||
|
||||
const [newRangesForbidden, newRangesAllowed] = partition(
|
||||
result.newRanges,
|
||||
({ name }) => forbiddenDuplicatesFilter(name),
|
||||
);
|
||||
if (newRangesForbidden.length) {
|
||||
success = false;
|
||||
}
|
||||
|
||||
logArray(
|
||||
newRangesForbidden,
|
||||
'The following packages must be deduplicated by updating dependencies in package.json',
|
||||
e => ` ${e.name} @ ${e.oldRange} should be changed to ${e.newRange}`,
|
||||
);
|
||||
logArray(
|
||||
newRangesAllowed,
|
||||
'The following packages can be deduplicated by updating dependencies in package.json',
|
||||
e => ` ${e.name} @ ${e.oldRange} should be changed to ${e.newRange}`,
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
throw new Error('Failed versioning check');
|
||||
}
|
||||
};
|
||||
|
||||
function logArray<T>(arr: T[], header: string, each: (item: T) => string) {
|
||||
if (arr.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(header);
|
||||
console.log();
|
||||
for (const e of arr) {
|
||||
console.log(each(e));
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ export async function buildBundle(options: BuildOptions) {
|
||||
|
||||
const paths = resolveBundlingPaths(options);
|
||||
const publicPaths = await resolveOptionalBundlingPaths({
|
||||
targetDir: options.targetDir,
|
||||
entry: 'src/index-public-experimental',
|
||||
dist: 'dist/public',
|
||||
});
|
||||
|
||||
@@ -14,8 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BackendBundlingOptions, BundlingOptions } from './types';
|
||||
import { posix as posixPath, resolve as resolvePath } from 'path';
|
||||
import {
|
||||
BackendBundlingOptions,
|
||||
BundlingOptions,
|
||||
ModuleFederationOptions,
|
||||
} from './types';
|
||||
import { posix as posixPath, resolve as resolvePath, dirname } from 'path';
|
||||
import chalk from 'chalk';
|
||||
import webpack, { ProvidePlugin } from 'webpack';
|
||||
|
||||
import { BackstagePackage } from '@backstage/cli-node';
|
||||
@@ -28,12 +33,13 @@ import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
|
||||
import { LinkedPackageResolvePlugin } from './LinkedPackageResolvePlugin';
|
||||
import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin';
|
||||
import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin';
|
||||
import ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||
import { paths as cliPaths } from '../../lib/paths';
|
||||
import fs from 'fs-extra';
|
||||
import { getPackages } from '@manypkg/get-packages';
|
||||
import { isChildPath } from '@backstage/cli-common';
|
||||
import nodeExternals from 'webpack-node-externals';
|
||||
import { optimization } from './optimization';
|
||||
import { optimization as optimizationConfig } from './optimization';
|
||||
import pickBy from 'lodash/pickBy';
|
||||
import { readEntryPoints } from '../entryPoints';
|
||||
import { runPlain } from '../run';
|
||||
@@ -44,15 +50,42 @@ import { hasReactDomClient } from './hasReactDomClient';
|
||||
|
||||
const BUILD_CACHE_ENV_VAR = 'BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE';
|
||||
|
||||
export function resolveBaseUrl(config: Config): URL {
|
||||
export function resolveBaseUrl(
|
||||
config: Config,
|
||||
moduleFederation?: ModuleFederationOptions,
|
||||
): URL {
|
||||
const baseUrl = config.getOptionalString('app.baseUrl');
|
||||
|
||||
const defaultBaseUrl =
|
||||
moduleFederation?.mode === 'remote'
|
||||
? `http://localhost:${process.env.PORT ?? '3000'}`
|
||||
: 'http://localhost:3000';
|
||||
|
||||
try {
|
||||
return new URL(baseUrl ?? '/', 'http://localhost:3000');
|
||||
return new URL(baseUrl ?? '/', defaultBaseUrl);
|
||||
} catch (error) {
|
||||
throw new Error(`Invalid app.baseUrl, ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveEndpoint(
|
||||
config: Config,
|
||||
moduleFederation?: ModuleFederationOptions,
|
||||
): {
|
||||
host: string;
|
||||
port: number;
|
||||
} {
|
||||
const url = resolveBaseUrl(config, moduleFederation);
|
||||
|
||||
return {
|
||||
host: config.getOptionalString('app.listen.host') ?? url.hostname,
|
||||
port:
|
||||
config.getOptionalNumber('app.listen.port') ??
|
||||
Number(url.port) ??
|
||||
(url.protocol === 'https:' ? 443 : 80),
|
||||
};
|
||||
}
|
||||
|
||||
async function readBuildInfo() {
|
||||
const timestamp = Date.now();
|
||||
|
||||
@@ -93,7 +126,13 @@ export async function createConfig(
|
||||
paths: BundlingPaths,
|
||||
options: BundlingOptions,
|
||||
): Promise<webpack.Configuration> {
|
||||
const { checksEnabled, isDev, frontendConfig, publicSubPath = '' } = options;
|
||||
const {
|
||||
checksEnabled,
|
||||
isDev,
|
||||
frontendConfig,
|
||||
moduleFederation,
|
||||
publicSubPath = '',
|
||||
} = options;
|
||||
|
||||
const { plugins, loaders } = transforms(options);
|
||||
// Any package that is part of the monorepo but outside the monorepo root dir need
|
||||
@@ -101,12 +140,29 @@ export async function createConfig(
|
||||
const { packages } = await getPackages(cliPaths.targetDir);
|
||||
const externalPkgs = packages.filter(p => !isChildPath(paths.root, p.dir));
|
||||
|
||||
const validBaseUrl = resolveBaseUrl(frontendConfig);
|
||||
const validBaseUrl = resolveBaseUrl(frontendConfig, moduleFederation);
|
||||
let publicPath = validBaseUrl.pathname.replace(/\/$/, '');
|
||||
if (publicSubPath) {
|
||||
publicPath = `${publicPath}${publicSubPath}`.replace('//', '/');
|
||||
}
|
||||
|
||||
if (isDev) {
|
||||
const { host, port } = resolveEndpoint(
|
||||
options.frontendConfig,
|
||||
options.moduleFederation,
|
||||
);
|
||||
|
||||
plugins.push(
|
||||
new ReactRefreshPlugin({
|
||||
overlay: {
|
||||
sockProtocol: 'ws',
|
||||
sockHost: host,
|
||||
sockPort: port,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (checksEnabled) {
|
||||
plugins.push(
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
@@ -232,12 +288,53 @@ export async function createConfig(
|
||||
require.resolve('react-refresh'),
|
||||
];
|
||||
|
||||
const mode = isDev ? 'development' : 'production';
|
||||
const optimization = optimizationConfig(options);
|
||||
|
||||
if (
|
||||
mode === 'production' &&
|
||||
process.env.EXPERIMENTAL_MODULE_FEDERATION &&
|
||||
process.env.FORCE_REACT_DEVELOPMENT
|
||||
) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
`⚠️ WARNING: Forcing react and react-dom into development mode. This build should not be used in production.`,
|
||||
),
|
||||
);
|
||||
|
||||
const reactPackageDirs = [
|
||||
`${dirname(require.resolve('react/package.json'))}/`,
|
||||
`${dirname(require.resolve('react-dom/package.json'))}/`,
|
||||
];
|
||||
|
||||
// Don't define process.env.NODE_ENV with value matching config.mode. If we
|
||||
// don't set this to false, webpack will define the value of
|
||||
// process.env.NODE_ENV for us, and the definition below will be ignored.
|
||||
optimization.nodeEnv = false;
|
||||
|
||||
// Instead, provide a custom definition which always uses "development" if
|
||||
// the module is part of `react` or `react-dom`, and `config.mode` otherwise.
|
||||
plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': webpack.DefinePlugin.runtimeValue(
|
||||
({ module }) => {
|
||||
if (reactPackageDirs.some(val => module.resource.startsWith(val))) {
|
||||
return '"development"';
|
||||
}
|
||||
|
||||
return `"${mode}"`;
|
||||
},
|
||||
),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const withCache = yn(process.env[BUILD_CACHE_ENV_VAR], { default: false });
|
||||
|
||||
return {
|
||||
mode: isDev ? 'development' : 'production',
|
||||
mode,
|
||||
profile: false,
|
||||
optimization: optimization(options),
|
||||
optimization,
|
||||
bail: false,
|
||||
performance: {
|
||||
hints: false, // we check the gzip size instead
|
||||
|
||||
@@ -16,4 +16,5 @@
|
||||
|
||||
export { serveBackend } from './backend';
|
||||
export { buildBundle } from './bundle';
|
||||
export { getModuleFederationOptions } from './moduleFederation';
|
||||
export { serveBundle } from './server';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user